-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow views to be collapsed when pointerEvents is set
Reviewed By: astreet Differential Revision: D4440164 fbshipit-source-id: 88a710affea229228f9c96b82d0bcf4c81f3205d
- Loading branch information
1 parent
29a996c
commit 88eeea0
Showing
3 changed files
with
16 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
88eeea0
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.
@javache @astreet Cool, this commit fixes a bug my team hit. I have a couple of questions after looking at this change:
pointerEvents
isauto
. Such views should not be layout-only but it looks like the code still treats them as layout-only. I imagine fixing this bug would regress perf in many apps because a lot of views would no longer be optimized away. To avoid that perf regression while fixing the bug, the default value ofpointerEvents
could be changed tobox-none
. Unfortunately, that would be a breaking change. Do you have any thoughts on this?setPointerEvents
doesn't properly handle thenull/undefined
case. Rather than reverting the view to its defaultpointerEvents
state ofauto
, the function looks like it's a no-op.88eeea0
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.
I don't follow, can you point to what code you're talking about?
Also, with this change, we should only be collapsing more Views, since previously all values of pointerEvents made the view non-collapsable.
Good catch! Want to send a PR? ;)
88eeea0
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.
Can you give a scenario for this? I assumed that if a view was completely layout-only and then also set pointerEvents to
auto
that shouldn't change any behaviour (since it's the default).88eeea0
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.
Let me elaborate on point (1). Rereading this commit, I see that my thoughts on a heuristic for layout-only
pointerEvents
event differ from yours. I think that if a View can be the target of a touch event then it cannot be layout-only. This means thesepointerEvents
values are not layout-only:auto
(default)box-only
And these
pointerEvents
values are layout-only:none
box-none
Why? If a View can be the target of touch events (
pointerEvents
auto
orbox-only
) then somebody might be listening to Gesture Responder Events on that View. However, if that View is optimized away, those events will never fire.If I'm right, then we should:
auto
from the layout-only heuristic and addnone
to the layout-only heuristic.auto
(a non layout-only value). Currently, the absence of apointerEvents
prop (aka the default value) is incorrectly treated as layout-only. To fix this bug, we might want to do one of these things:auto
but ensure these views don't get optimized away. This will probably lead to a perf regression because many Views will no longer be able to be optimized away.box-none
so we fix the bug and views can be optimized away by default. This would be a breaking change although I don't have a sense for how bad the breaking impact would be.I know I didn't directly answer the questions you asked. If this elaboration still leaves you with questions, let me know and I'll answer them.
Regarding point (2):
I'm not sure when I'll get around to it. If this bug still isn't fixed when I have some free time, I'll send a PR.
88eeea0
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.
@astreet @javache -- at mentioning you in case you didn't get a notification about the comment I added last week.
88eeea0
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.
'none' cannot be a layout-only property, since it has implications on its subviews. If we were to remove the a View with pointerEvents = 'only', the subviews would receive pointerEvents where they previously didn't.
I still don't completely understand how 'auto' can be an issue here. If there was something listening to the events, we should also be getting an
onClick
property here, which would invalidate the isLayoutOnly logic. If that wasn't a case, we would have already been dropping views that didn't specify anything for pointerEvents. Or are you saying this was a bug even before this change?88eeea0
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.
Well, 'auto' is the default, so making views that have auto explicitly set collapsable isn't changing existing behavior really. That doesn't mean there isn't a possible bug here. Specifically, I think you might hit a bug if you have a collapsed view with no children that is supposed to receive a touch event: in that case, the view wouldn't be enumerated here:
react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/TouchTargetHelper.java
Line 125 in 552c601
The reason other scenarios aren't affected is because of the way we do touch handling in RN: we deliver the touch event to JS with the deepest view that was touched on the native side. We then bubble that event up thought the JS view hierarchy, meaning collapsing isn't a problem unless it's the deepest views that are collapsed.
The reason
box-only
andnone
need to not be collapsed is because they stop touch event traversal to the View's children in native code, which means they need to be enumerated in the TouchTargetHelper code linked above.box-none
is ok to leave layout only since we do want to visit the View's children.I hope this makes sense, it's not the simplest thing in the world :P Also let me know if you think I'm wrong about something here, this is just based on me reading over the code just now.
That's fine, you've done enough on this issue, I'll fix it up today :)
88eeea0
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.
We don't send an
onClick
property to native on either platform afaik, so yes I think this could be a bug, but only in the scenario I mentioned above88eeea0
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.
@astreet @javache Thanks for the explanation. I now understand why a view with
pointerEvents
set tonone
cannot be collapsed in the current implementation.I think Andy understands the bug I was trying to describe when a view with
pointerEvents
set toauto
gets collapsed. This bug existed both before and after this commit. I want to elaborate on this scenario anyway. Imagine you have 2 views which are siblings. One is layout-only withpointerEvents
set toauto
and the other is aTouchableHighlight
. Suppose the layout-only view is positioned such that it entirely overlaps theTouchableHighlight
and it sits on top of theTouchableHighlight
. You'll experience different behaviors on iOS and Android due to Android's collapsing view optimization:TouchableHighlight
because the layout-only view will eat all of the input.TouchableHighlight
because the layout-only view has been optimized away.In practice, my team has run into this inconsistency between iOS and Android on several occasions and we workaround it by throwing in a
collapsable={false}
. :( I'd like to get this inconsistency fixed.To fix this, I was thinking that views with
pointerEvents
set toauto
cannot be optimized away. Because that's the default, such a change could cause a perf regression. This is why I mentioned we might want to consider changing the default tobox-none
which can be optimized away.Andy, you brought up Nodes and how this issue my be fixed in Nodes or require a different fix. I'm not familiar with Nodes so I don't have any comments on that in particular.
I think you understand the edge case I'm worried about with
auto
. How should we proceed?By the way, the
Navigator
was broken by this commit and a workaround ofcollapsable={false}
was added in a83af44. It seems like that might be an indication of a bug introduced by this commit. Do you have an understanding of the root cause?Thanks, I've seen you've already gone and fixed it (866ac17) 😄 .
88eeea0
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.
I agree with wanting to get this inconsistency fixed and trying to get to the bottom of the navigator issue. I'm checking with the nodes team on when they think we'll switch over to nodes in OSS. @javache has a task on him around investigating the navigator issue.
88eeea0
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.
A possible fix: if a view has any onTouch listeners set on it, automatically set collapsable=false.