question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Android native UI components are not re-layout on dynamically added views

See original GitHub issue

Is 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:open
  • Created 6 years ago
  • Reactions:53
  • Comments:40 (4 by maintainers)

github_iconTop GitHub Comments

33reactions
jedi4evercommented, Jan 24, 2019

A couple of findings:

Adding the following to the view that gets returned works:

void setupLayoutHack() {

        Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
            @Override
            public void doFrame(long frameTimeNanos) {
                manuallyLayoutChildren();
                getViewTreeObserver().dispatchOnGlobalLayout();
                    Choreographer.getInstance().postFrameCallback(this);
            }
        });
    }

    void manuallyLayoutChildren() {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
            child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
        }
    }

@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)

28reactions
irgendeinichcommented, Mar 2, 2018

@charpeni What I ended up doing is just calling the layout methods inside a FrameCallback. I’ve got something like this in my custom View returned by the ViewManager.

Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
    @Override
    public void doFrame(long frameTimeNanos) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY),
                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY));
            child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
        }
        getViewTreeObserver().dispatchOnGlobalLayout();
    }
    Choreographer.getInstance().postFrameCallback(this);
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Adding a view dynamically not showing view - Stack Overflow
First Initialize your Layout to which you want to add subview. For example
Read more >
Android native UI components are not re-layout on dynamically ...
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...
Read more >
!(Fun times) with Android Native UI Components | by ... - Medium
Native UI components do not re-layout on dynamic view changes. This one took a while to figure out. Our view height would change...
Read more >
Custom View Components | Android Developers
Android offers a sophisticated and powerful componentized model for building your UI, based on the fundamental layout classes: View and ...
Read more >
How To Layout React Native Views Hierarchy ... - ADocLib
Android native UI components are not relayout on dynamically The issue can be ... a way to tell reactnative that we have added...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found