-
Notifications
You must be signed in to change notification settings - Fork 24.4k
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
Fixed Android bug causing to remove wrong view after reordering by zIndex #10954
Conversation
Commit 3d3b067 implemented zIndex support for Android. However after zIndex resorting of the views, the JS doesn't know about the new order. When dynamically removing the view from an array of views, JS sends the command to remove the view at certain index, which is not the same in Java since the order of items changed. Test Plan: Related issue and the simple empty react-native 0.37 app where it was tested: #8968 In `manageChildren` in `NativeViewHierarchyManager.java` there was a loop by `indicesToRemove`, call `viewManager.removeViewAt(viewToManage, indexToRemove)`. However if the view is animated and it's ID in the array of `tagsToDelete`, do nothing and delegate this job of removing item to the loop by `tagsToDelete`. Now we propagate `tagsToRemove` instead from `UIImplementation` to `NativeViewHierarchyOptimized` to `NativeViewHierarchyManager` and using it instead of `indicesToRemove`. Also by having the old `indicesToRemove` loop we having the case that the *wrong* view is removed, but then, *correct* view is dropped in `tagsToDelete` loop. In result we have inconsistency when removing one view but dropping another. It's described in more details in mentioned above related issue comments.
By analyzing the blame information on this pull request, we identified @rigdern and @janicduplessis to be potential reviewers. |
Also related to #9704 |
@Nullable ViewAtIndex[] viewsToAdd, | ||
@Nullable int[] tagsToDelete) { | ||
super(tag); | ||
mIndicesToRemove = indicesToRemove; | ||
mTagsToRemove = tagsToRemove; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why have both indicesToRemove
and tagsToRemove
? Isn't tagsToRemove
sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi,
I'm pretty sure tagsToRemove is sufficient, just wasn't sure enough if indices should be completely removed in all this chain. Probably yes, just kept them for any possible backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I remove indicesToRemove
in the end, or we should leave it for any backward compat case?
Also is there any news/plans on reviewing this one? :) Would be awesome to have it merged
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. I know it's a pretty darn amazing experience to have Android support for RN apps practically for free and I appreciate all the work that went into making it happen! And it would be very cool to have zIndex
support fixed on Android.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. I also appreciate the work that has gone into this PR. I would be excited to see if someone could be found to review this.
Thanks for the detailed description and fix! I'm trying to find someone to review this :) |
Can you add a test for this? It seems very likely to me that this bugfix would be subsequently broken in one way or another. |
Agreed we should have a test. However, the original patch implementing zIndex ordering is doing it in a pretty hacky way: we really shouldn't be changing the order of children in their parent. Someone correct me if there's actually a good reason for it, but this is the exact use case for |
(The alternative in my mind would be to enforce we never use the |
Any progress here? |
@hramos Not sure, since as I mentioned before, I'm not a pro in Java and in Java testing, and also @astreet suggested to maybe use children drawing order instead, but it's going too deep into Android part so I'm not sure I can handle it properly :) If someone from Android team could have a look onto this PR and add some unit tests for adding/removing children views to check if the correct view was removed after sorting by zIndex, would be great. |
I have a certain amount of magical power to make people write tests for other peoples' pull requests but I seem to have used it all up at the moment. @asgvard I think you should either dig in and figure out how to do this the right way and add tests and so on, or let this feature request drift on the winds of fate and let this pull request be closed. Depends what you are in the mood for ;-) |
Does it makes sense to go with this PR assuming the rendering method on Android going to change to Nodes soon? Does it mean that the whole zIndex implementation would be different? |
23 days ago @janicduplessis fixed zIndex mechanism in commit 9a51fa8 which as gone into master branch already. |
I guess that should be fixed by this commit. So I'll close this PR. |
Commit 3d3b067 implemented zIndex support for Android. However after zIndex resorting of the views, the JS doesn't know about the new order. When dynamically removing the view from an array of views, JS sends the command to remove the view at certain index, which is not the same in Java since the order of items changed.
Test Plan:
Related issue and the simple empty react-native 0.37 app where it was tested:
#8968
Test app code:
Starting screen:
Before fix, when trying to remove green, it removes blue instead:
After fix it removed green correctly:
When clicking toggle again, it adds green back, the blue is still ordered correctly by zIndex:
Description:
In
manageChildren
inNativeViewHierarchyManager.java
there was a loop byindicesToRemove
and a callviewManager.removeViewAt(viewToManage, indexToRemove)
. However if the view is animated and it's ID in the array oftagsToDelete
, do nothing and delegate this job of removing item to the loop bytagsToDelete
later.Now we propagate
tagsToRemove
fromUIImplementation
toNativeViewHierarchyOptimizer
toNativeViewHierarchyManager
and using it instead ofindicesToRemove
, because thetag
is reliable way of identifying the node, and the index is not reliable anymore because of internal reordering of the views.Also by having the old
indicesToRemove
loop we having the case that the wrong view is removed, but then, correct view is dropped intagsToDelete
loop. In result we have inconsistency when removing one view but dropping another. It's described in more details in mentioned above related issue comments.