Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop Android from Layouting all my Views

I'm currently developing a tablet app which intensly uses the ViewPager Widget. I also got multiple Viewpagers on Screen at once.

Now I'm experiencing the following Problem: If one ViewPager scrolls to the next/previous Page, it (of course) has to recalculate it's layout and add/ remove Views. I noticed that the requestLayout calls right up to the top of the View Hierarchy, therefore invalidating ALL of my Views on the Tablet Screen (which are a lot!). This is very costly.

My question now is: is there a possibility to implement a Frame around the ViewPager which does the initial Layout and then does not propagate layout- requests up the View Hierarchy as I know that after the initial layout, the frame stays the same size and will not change.

I came up with the following Frame, but it doesn't work quite well, because it does not work 100% of the time.

public class MyFrame extends FrameLayout
{
    // VARIABLE CONTROLLING THE DISPATCH OF THE LAYOUT
    // REQUEST UP THE VIEW HIERARCHY
    private boolean doLayout = true;

    public MyFrame(Context context)
    {
        super(context);
        doLayout = true;
    }

    @Override
    public void requestLayout()
    {
        if (doLayout) // DO THE LAYOUT REQUEST UP TO THE TOP
            super.requestLayout();
        else
        {
            // JUST MEASURE MYSELF AND MY CHILDREN
            measure(MeasureSpec.getMode(MeasureSpec.AT_MOST),
            MeasureSpec.getMode(MeasureSpec.AT_MOST));
            layout(getLeft(), getTop(), getRight(), getBottom());
        }
        doLayout = false;
    }
}

Thanks for any advice!

like image 247
saberrider Avatar asked Mar 26 '12 08:03

saberrider


People also ask

Which layout is better in Android Studio?

LinearLayout is perfect for displaying views in a single row or column. You can add layout_weights to the child views if you need to specify the space distribution. Use a RelativeLayout, or even better a ConstraintLayout, if you need to position views in relation to siblings views or parent views.

Which layout is faster in Android?

Measurement results: ConstraintLayout is faster As these results show, ConstraintLayout is likely to be more performant than traditional layouts. Moreover, ConstraintLayout has other features that help you build complex and performant layouts, as discussed in the benefits of a ConstraintLayout object section.


1 Answers

I know the question is a bit old, but my answer might help someone else as your question and Colin's answer helped me.

I have exactly the same problem as you do. And there are two solutions for it. First you need to make sure that your ViewPager has its *layout_width* and *layout_height* set to *match_parent*, and that view hierarcy is organized in such a way that Android won't come to conclusion that it needs to re-layout any of the ViewPager parent layouts. For example, say you have a RelativeLayout with two views of fixed sizes one below another and a ViewPager below the second view. In this case any change to ViewPager will propagate to the parent layout. However, if you put those two fixed size views and the ViewPager into a LinearLayout this won't happen, no layout request will get propagated beyond ViewPager. What's even better, layout request on one ViewPager page won't be propagated to other pages either.

The second solution(actually it is more the second part of the solution) is your FrameLayout, but modified like this:

public class LayoutStopperFrameLayout extends FrameLayout {

    private boolean doLayout;

    public LayoutStopperFrameLayout(Context context) {
        super(context);
        doLayout = true;
    }

    public LayoutStopperFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        doLayout = true;
    }

    public LayoutStopperFrameLayout(Context context, AttributeSet attrs,
            int defStyle) {
        super(context, attrs, defStyle);
        doLayout = true;
    }

    public void setPropagateRequestLayout(boolean doLayout) {
        this.doLayout = doLayout;
    }

    @Override
    public void requestLayout() {
        if (doLayout) {
            // DO THE LAYOUT REQUEST UP TO THE TOP
            super.requestLayout();
        }
    }
}

In my application I call setPropagateRequestLayout() in Fragment onStart and onStop methods to turn layout requests propagating off and on respectively.

like image 193
Milan Avatar answered Oct 31 '22 15:10

Milan