-
-
Notifications
You must be signed in to change notification settings - Fork 600
fix(Fabric,iOS): header subviews do not support dynamic content changes #2905
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
Conversation
a28fe82 to
22e632b
Compare
refactor (method naming)
|
Caution This PR was an exploration of alternative to #2845 approach of solving #2714. The approach here was to simply do not call Note However, I might be able to fix this by sending navigation bar insets. Currently there is no padding in shadow node set & Yoga probably believes that it has more space than there is in reality. |
kkafar
left a comment
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.
Notes for future us
| RNSScreenStackHeaderConfigState(const RNSScreenStackHeaderConfigState &source) | ||
| : frameSize{source.frameSize}, edgeInsets{source.edgeInsets} {} | ||
| RNSScreenStackHeaderConfigState &operator=( | ||
| const RNSScreenStackHeaderConfigState &source) { | ||
| this->frameSize.width = source.frameSize.width; | ||
| this->frameSize.height = source.frameSize.height; | ||
| this->edgeInsets = source.edgeInsets; | ||
| return *this; | ||
| } | ||
|
|
||
| bool operator==(const RNSScreenStackHeaderConfigState &other) { | ||
| return this->frameSize == other.frameSize && | ||
| this->edgeInsets == other.edgeInsets; | ||
| } | ||
|
|
||
| bool operator!=(const RNSScreenStackHeaderConfigState &other) { | ||
| return this->frameSize != other.frameSize || | ||
| this->edgeInsets != other.edgeInsets; | ||
| } |
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.
Making it copyable simplifies working with this type in HostTree (component implementation)
| - (NSDirectionalEdgeInsets)computeEdgeInsetsOfNavigationBar:(nonnull UINavigationBar *)navigationBar | ||
| { | ||
| NSDirectionalEdgeInsets navBarMargins = [navigationBar directionalLayoutMargins]; | ||
| NSDirectionalEdgeInsets navBarContentMargins = [navigationBar.rnscreens_findContentView directionalLayoutMargins]; | ||
|
|
||
| BOOL isDisplayingBackButton = [self shouldBackButtonBeVisibleInNavigationBar:navigationBar]; | ||
|
|
||
| // 44.0 is just "closed eyes default". It is so on device I've tested with, nothing more. | ||
| UIView *barButtonView = isDisplayingBackButton ? navigationBar.rnscreens_findBackButtonWrapperView : nil; | ||
| CGFloat platformBackButtonWidth = barButtonView != nil ? barButtonView.frame.size.width : 44.0f; | ||
|
|
||
| const auto edgeInsets = NSDirectionalEdgeInsets{ | ||
| .leading = | ||
| navBarMargins.leading + navBarContentMargins.leading + (isDisplayingBackButton ? platformBackButtonWidth : 0), | ||
| .trailing = navBarMargins.trailing + navBarContentMargins.trailing, | ||
| }; | ||
|
|
||
| return edgeInsets; | ||
| } |
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.
This is so so. It works for now, but it's vulnerable to UIKit changes.
|
In case we ever find a use case that |
kligarski
left a comment
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.
Looks good.
…hanges (#2910) ## Description Fixes #2714 on Android Fixes #2815 on Android See #2905 for detailed description. ## Changes Removed call to `RNSScreenStaceaderSubviewShadowNode.setSize` in corresponding component descriptor. It seems that we do not need to enforce node size from HostTree. Setting appropriate content offset is enough for pressables to function correctly (assuming that native layout **does not change size of any subview**). I currently can't come up with any scenario where this would happen. ## Test code and steps to reproduce I've tested: * [x] `Test2714` introduced in PR with iOS fixes - #2905 * [x] Pressables in header - #2466, * [x] Header title truncation - #2325 (only few cases, as the list is long there) & noticed a regression (not related to this PR, described in comment below the PR description), * [x] Insets with orientation change (Android) - #2756 * [x] #2807 (on `TestHeaderTitle` with call to `setOptions` in `useLayoutEffect`) * [x] `Test2811` - #2811 * [x] #2812 (with snippet provided in that PR description) ## Checklist - [x] Included code example that can be used to test this change - [x] Ensured that CI passes

Description
Regression most likely introduced in 4.5.0 by #2466.
Fixes #2714 on iOS
Fixes #2815 on iOS
Supersedes #2845
This is a ugly hack to workaround issue with dynamic content change.
When the size of this shadow node contents (children) change due to JS
update, e.g. new icon is added, if the size is set for the yogaNode
corresponding to this shadow node, the enforced size will be used
and the size won't be updated by Yoga to reflect the contents size
change -> host tree won't get layout metrics update -> we won't trigger native
layout -> the views in header will be positioned incorrectly.
Important
This PR handles iOS only, however there is similar issue on Android. The issue can be reproduced on the same test example. Android will be handled in separate PR.
Changes
Test code and steps to reproduce
In this approach I've settled with:
RNSScreenStackHeaderSubviewShadowNode,Added
Test2714Most of the fragile header interactions must be tested:
TestHeaderTitle❌ This PR introduces regression here on iOS (Android not tested yet)✅ WorksTest2466(iOS works, Android code is unmodified here)setOptions#2812 (this PR does not touch Android)Test2714handling header item resizing.Checklist