Android native UI components are not re-layout on dynamically added views
See original GitHub issueIs this a bug report?
Yes.
Have you read the Contributing Guidelines?
Yes.
Environment
Environment: OS: macOS High Sierra 10.13.2 Node: 8.9.4 Yarn: 1.3.2 npm: 5.6.0 Watchman: 4.9.0 Xcode: Xcode 9.2 Build version 9C40b Android Studio: 3.0 AI-171.4443003
Packages: (wanted => installed) react: 16.3.1 => 16.3.1 react-native: 0.55.4 => 0.55.4
Description
The issue can be noticed if you bridge to React Native the following views:
A view with elements that have a visibility to gone
on the initial render won’t be displayed after you’ve set is visibility to visible
. view.isShown()
will return true
, but it will not be there or it will be there but not really re-layout.
A view with elements that are dynamically added, simply by view.addView()
or let’s say you want to load an image with Fresco it will only work if it was loaded on the initial render.
I’ve noticed that native components are re-layout on hot reloading, but this.forceUpdate()
or changing props won’t trigger a re-layout. As an ugly workaround, if we interact with the native component height or width it will trigger a re-layout, so every time you want to toggle a visibility from gone to visible or dynamically adds views you can alter his size.
I’ve also implemented needsCustomLayoutForChildren
without notable change.
Expected Behavior (Native)
Here’s the native implementation directly inflated inside an Activity.
Actual Behavior (React Native)
Here’s the exact same layout as above, but bridged to react native and inflated inside SimpleViewManager
.
Reproducible Demo
https://github.com/charpeni/react-native-android-visibility-issue
Related to #5531 (Already flagged in RN 0.18).
Issue Analytics
- State:
- Created 6 years ago
- Reactions:53
- Comments:40 (4 by maintainers)
Top GitHub Comments
A couple of findings:
In the code of the ReactViewGroup there is indeed an explicit
// No-op since UIManagerModule handles actually laying out children.
- See https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/views/view/ReactViewGroup.java#L139To override
needsCustomLayoutForChildren
once needs to change the Manager from typeSimpleViewManager
moved toViewGroupManager
https://stackoverflow.com/questions/47830546/viewgroupmanager-vs-simpleviewmanager
I can confirm the needsCustomLayoutForChildren doesn’t work.
Adding the following to the view that gets returned works:
@irgendeinich thanks for the solution! Wonder if you can explain what this callback actual does, and why/when this does get triggered. And if this is expensive in layout effort when things change on your screen alot (like videoplayer).
Source: https://github.com/PSPDFKit/react-native/blob/8ecba78c024bdffc0cb18c83b7cc68ce61c135d9/android/src/main/java/com/pspdfkit/views/PdfView.java#L144
For the record: if the layout of the immediate children of the rootview change is does do a full relayout (for example on rotation of the device) by default (without this hack)
@charpeni What I ended up doing is just calling the layout methods inside a
FrameCallback
. I’ve got something like this in my customView
returned by theViewManager
.