Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Implement ScrollView sticky headers on Android #9456

Closed

Conversation

janicduplessis
Copy link
Contributor

@janicduplessis janicduplessis commented Aug 17, 2016

This adds support for sticky headers on Android. The implementation if based primarily on the iOS one (https://github.com/facebook/react-native/blob/master/React/Views/RCTScrollView.m#L272) and adds some stuff that was missing to be able to handle z-index, view clipping, view hierarchy optimization and touch handling properly.

Some notable changes:

  • Add ChildDrawingOrderDelegate interface to allow changing the ViewGroup drawing order using ViewGroup#getChildDrawingOrder. This is used to change the content view drawing order to make sure headers are drawn over the other cells. Right now I'm only reversing the drawing order as drawing only the header views last added a lot of complexity especially because of view clipping and I don't think it should cause issues.
  • Add collapsableChildren prop that works like collapsable but applies to every child of the view. This is needed to be able to reference sticky headers by their indices otherwise some subviews can get optimized out and break indexes.
  • Make TouchTargetHelper take drawing order into consideration when finding the touch target.
  • Take translate into consideration when clipping subviews.

Test plan
Tested using the UIExplorer main menu on android.
Tested that touches get dispatched to the sticky header when over other touchable views.
Tested that touchables inside a sticky header work properly.

@ghost
Copy link

ghost commented Aug 17, 2016

By analyzing the blame information on this pull request, we identified @astreet and @rigdern to be potential reviewers.

@ghost ghost added GH Review: review-needed CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. labels Aug 17, 2016
@satya164
Copy link
Contributor

cc @brentvatne :D

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 17, 2016
@brentvatne
Copy link
Collaborator

@janicduplessis - tried it out, seems great! any idea about the CI failures?

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 18, 2016
@janicduplessis
Copy link
Contributor Author

Looks like the instrumentation tests are failing, I'll run them locally to see what is going on.

@sahrens
Copy link
Contributor

sahrens commented Aug 18, 2016

Did you consider implementing this with the new native-driven Animated.event? Seems like it would be a little awkward to describe with Animated, but doable.

@brentvatne
Copy link
Collaborator

Did you consider implementing this with the new native-driven Animated.event? Seems like it would be a little awkward to describe with Animated, but doable.

@sahrens - probably doable, but I think we should wait for offload Animated and Animated event stuff to be more mature first, then switch the iOS and Android implementations of sticky headers at the same time.

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 19, 2016
@nihgwu
Copy link
Contributor

nihgwu commented Aug 19, 2016

bravo

@janicduplessis
Copy link
Contributor Author

@sahrens I agree with @brentvatne, it would be really nice to eventually convert it but for now I think this is better.

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 19, 2016
@@ -152,6 +175,22 @@ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
}

@Override
public View hitTest(float[] coordinates) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed because our touch handling doesn't respect drawing order? If so, can we just make our normal touch handling handle drawing order so that we don't have to add a new touch handling code path?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, good idea, I just checked and AOSP does use getChildDrawingOrder when dispatching a touch event to subviews.

@astreet
Copy link
Contributor

astreet commented Aug 23, 2016

Re collapsableChildren vs cloning for the collapsable prop: is there actually a perf concern here? If possible, I'd really rather not add another prop we need to support.

@ghost
Copy link

ghost commented Aug 24, 2016

@janicduplessis updated the pull request - view changes

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 24, 2016
@facebook-github-bot
Copy link
Contributor

@janicduplessis updated the pull request - view changes

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 24, 2016
@ghost
Copy link

ghost commented Aug 24, 2016

@janicduplessis updated the pull request - view changes

@ghost
Copy link

ghost commented Aug 24, 2016

@janicduplessis updated the pull request - view changes

@janicduplessis
Copy link
Contributor Author

janicduplessis commented Aug 24, 2016

@astreet Yea, unfounded perf concerns :), changed it to cloning child elements in JS. We can change it in tthe future if it is actually an issue.

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 24, 2016
@ghost
Copy link

ghost commented Aug 24, 2016

@janicduplessis updated the pull request - view changes

@nihgwu
Copy link
Contributor

nihgwu commented Sep 15, 2016

OMG, failing still?

@ghost ghost closed this in 0e8b75b Sep 15, 2016
@janicduplessis
Copy link
Contributor Author

Landed now :D

nihgwu added a commit to nihgwu/react-native that referenced this pull request Sep 15, 2016
since facebook#9456 has been landed, it's the time to add ListViewPagingExample to the example list for Android
@kennethpdev
Copy link

Been waiting for this. Thank you!

ghost pushed a commit that referenced this pull request Sep 15, 2016
Summary:
since #9456 has been landed, it's the time to add ListViewPagingExample to the example list for Android
Closes #9930

Differential Revision: D3871517

fbshipit-source-id: dafa8ab2d704bcc5e7bc25b5fcec18a1a6cfa28a
ghost pushed a commit that referenced this pull request Sep 15, 2016
Summary:
This adds support for sticky headers on Android. The implementation if based primarily on the iOS one (https://github.com/facebook/react-native/blob/master/React/Views/RCTScrollView.m#L272) and adds some stuff that was missing to be able to handle z-index, view clipping, view hierarchy optimization and touch handling properly.

Some notable changes:
- Add `ChildDrawingOrderDelegate` interface to allow changing the `ViewGroup` drawing order using `ViewGroup#getChildDrawingOrder`. This is used to change the content view drawing order to make sure headers are drawn over the other cells. Right now I'm only reversing the drawing order as drawing only the header views last added a lot of complexity especially because of view clipping and I don't think it should cause issues.

- Add `collapsableChildren` prop that works like `collapsable` but applies to every child of the view. This is needed to be able to reference sticky headers by their indices otherwise some subviews can get optimized out and break indexes.
Closes #9456

Differential Revision: D3827366

Pulled By: fred2028

fbshipit-source-id: d346068734c5b987518794ab23e13914ed13b5c4
@ide
Copy link
Contributor

ide commented Sep 15, 2016

Reverted in d0d1712

@astreet Could you paste stack traces / the reason for the revert here so we can fix it?

@brentvatne brentvatne reopened this Sep 15, 2016
@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 15, 2016
@janicduplessis janicduplessis removed Import Failed Import Started This pull request has been imported. This does not imply the PR has been approved. labels Sep 15, 2016
@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 15, 2016
@astreet
Copy link
Contributor

astreet commented Sep 16, 2016

Yep, sorry for posting after the fact, this got reverted after I left for the day. We hit a couple problems after this landed:

  1. The next-gen version of the RN Android rendering stack (nodes) doesn't use ReactViewGroup (and therefore doesn't use ReactViewManager). This was fixed in 5c3f954 (but this was also reverted as part of the revert of the larger stickyheader commit). When we re-land, we should incorporate this fix.
  2. We got this bug report from adsmanager that bisects to this diff ("our scrollview has 2 views, 1 on top of another, lets say A on top of B. We can swipe A horizontally to reveal B. With this diff, B is always shown instead of A"). I haven't had a chance to try to repro, but I imagine this has to do with the drawing order changes. I'll try to provide more information when I get a chance to look into it, but I had them go ahead and revert since they have a release coming up in a few days.

@astreet
Copy link
Contributor

astreet commented Sep 16, 2016

Looking into this more, one of the things that broke was that ListView automatically enables sticky headers for section headers. Some of the code in adsmanager for android apparently doesn't properly identify what things are section headers vs. normal rows and we now have random rows sticking to the top ha.

I think before this diff lands, we need to have whether stick headers are enabled for ListView customizable. And, given the design patterns on the two platforms, it should probably be enabled by default on iOS (as it is currently) and DISABLED by default on Android. Blindly copying design patterns from iOS to Android, like with sticky headers, is one of those things that identifies your framework as a lowest-common denominator crossplatform solution which we don't want. That being said, I think there are legit use cases for it, I just don't want it to become a 'thing' for RN apps on Android.

@astreet
Copy link
Contributor

astreet commented Sep 16, 2016

I haven't been able to get a repro for the rendering issue that was described to me (where B renders over A), but I have a feeling it's because stickyHeaderIndices is causing us to identify the wrong View as being sticky somehow.

I'd really feel a lot better about this API if, instead of passing in indices, we wrapped the views that are supposed to be sticky in a custom native view that the ScrollView can identify. That way, we aren't hurt by collapsable optimizations and don't need to make sure stickyHeaderIndices and the ListView dataSource stay in sync.

@nihgwu
Copy link
Contributor

nihgwu commented Sep 16, 2016

ScrollView Sticky Header on Android is really important to me, I'm building a cross-platform app, it's really ugly without sticky header on Android, I've made a js workaround but far from satisfaction, so I build RN from source to use this feature, and it works great, although there are still some bugs but it's fine in my case.

I think it's deserve to be kept in the master branch for further improvement, while providing an option to disable it on Android for consistency, e.g. stickyHeaderIndices={[]}

@nihgwu
Copy link
Contributor

nihgwu commented Sep 16, 2016

And I've noticed the random sticking issue in UIExplorer, the example list in the drawer and React Native Examples has section headers but stick unexpectedly, while it's works well in ListViewPagingExample

@janicduplessis
Copy link
Contributor Author

@astreet I think I know why tbe rendering but you describe happens. Gonna have a look at this as well as the issues @nihgwu found out today.

I also agree that we should make this disabled by default on android and add a flag to listview to enable it. Thisatches better what is common on the platform and will also avoid making this a breaking change.

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 16, 2016
@janicduplessis
Copy link
Contributor Author

Also for using a custom native view for headers I agree this would be a better and more reliable API but it should still be possible to make indices work, it's just a matter of fixing a few remaining bugs then it will be stable.

@nihgwu
Copy link
Contributor

nihgwu commented Sep 16, 2016

I add a renderStickyHeader in my workaround ListView for Android implemented in js , but it looks silly as there is already renderSectionHeader means to render sticky header on iOS

@janicduplessis
Copy link
Contributor Author

I'll close this PR and open a new one since we already shipped this, not sure if the bot will work properly.

rozele pushed a commit to microsoft/react-native-windows that referenced this pull request Sep 27, 2016
Summary:
This adds support for sticky headers on Android. The implementation if based primarily on the iOS one (https://github.com/facebook/react-native/blob/master/React/Views/RCTScrollView.m#L272) and adds some stuff that was missing to be able to handle z-index, view clipping, view hierarchy optimization and touch handling properly.

Some notable changes:
- Add `ChildDrawingOrderDelegate` interface to allow changing the `ViewGroup` drawing order using `ViewGroup#getChildDrawingOrder`. This is used to change the content view drawing order to make sure headers are drawn over the other cells. Right now I'm only reversing the drawing order as drawing only the header views last added a lot of complexity especially because of view clipping and I don't think it should cause issues.

- Add `collapsableChildren` prop that works like `collapsable` but applies to every child of the view. This is needed to be able to reference sticky headers by their indices otherwise some subviews can get optimized out and break indexes.
Closes facebook/react-native#9456

Differential Revision: D3827366

fbshipit-source-id: cab044cfdbe2ccb98e1ecd3e02ed3ceaa253eb78
rozele pushed a commit to microsoft/react-native-windows that referenced this pull request Sep 27, 2016
Summary:
This adds support for sticky headers on Android. The implementation if based primarily on the iOS one (https://github.com/facebook/react-native/blob/master/React/Views/RCTScrollView.m#L272) and adds some stuff that was missing to be able to handle z-index, view clipping, view hierarchy optimization and touch handling properly.

Some notable changes:
- Add `ChildDrawingOrderDelegate` interface to allow changing the `ViewGroup` drawing order using `ViewGroup#getChildDrawingOrder`. This is used to change the content view drawing order to make sure headers are drawn over the other cells. Right now I'm only reversing the drawing order as drawing only the header views last added a lot of complexity especially because of view clipping and I don't think it should cause issues.

- Add `collapsableChildren` prop that works like `collapsable` but applies to every child of the view. This is needed to be able to reference sticky headers by their indices otherwise some subviews can get optimized out and break indexes.
Closes facebook/react-native#9456

Differential Revision: D3827366

Pulled By: fred2028

fbshipit-source-id: d346068734c5b987518794ab23e13914ed13b5c4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants