Android fitsSystemWindows not working when replacing fragments

前端 未结 4 394
说谎
说谎 2021-01-01 13:30

I have SingleFramgnetActivity whose purpose is only to hold and replace fragments inside it.

layout looks like this:



        
4条回答
  •  伪装坚强ぢ
    2021-01-01 14:03

    I think the problem revolves around onApplyWindowInsets getting called before the fragment view hierarchy gets attached. An effective solution is to get the following override on a view somewhere in the view hierarchy of the fragment.

      @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            // force window insets to get re-applied if we're being attached by a fragment.
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                requestApplyInsets();
            } else {
                //noinspection deprecation
                requestFitSystemWindows();
            }
        }
    

    A complete solution (if you don't have to use CoordinatorLayout) follows. Make sure fitSystemWindows=true does not appear ANYWHERE in views higher in the heirarchy. Maybe not anywhere else. I suspect (but am not sure) that consumeSystemWindowInsets eats the insets for views that are further on in the layout order of the view tree.

    package com.twoplay.xcontrols;
    
    import android.annotation.TargetApi;
    import android.content.Context;
    import android.graphics.Rect;
    import android.os.Build;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.WindowInsets;
    import android.widget.FrameLayout;
    
    public class FitSystemWindowsLayout extends FrameLayout {
        private boolean mFit = true;
    
        public FitSystemWindowsLayout(final Context context) {
            super(context);
            init();
        }
    
        public FitSystemWindowsLayout(final Context context, final AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public FitSystemWindowsLayout(final Context context, final AttributeSet attrs, final int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            setFitsSystemWindows(true);
        }
    
        public boolean isFit() {
            return mFit;
        }
    
        @Override
        protected void onAttachedToWindow() {
            super.onAttachedToWindow();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                requestApplyInsets();
            } else {
                //noinspection deprecation
                requestFitSystemWindows();
            }
    
        }
    
        public void setFit(final boolean fit) {
            if (mFit == fit) {
                return;
            }
    
            mFit = fit;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
                requestApplyInsets();
            } else {
                //noinspection deprecation
                requestFitSystemWindows();
            }
        }
    
        @SuppressWarnings("deprecation")
        @Override
        protected boolean fitSystemWindows(final Rect insets) {
            if (mFit) {
                setPadding(
                        insets.left,
                        insets.top,
                        insets.right,
                        insets.bottom
                );
                return true;
            } else {
                setPadding(0, 0, 0, 0);
                return false;
            }
        }
    
        @TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
        @Override
        public WindowInsets onApplyWindowInsets(final WindowInsets insets) {
            if (mFit) {
                setPadding(
                        insets.getSystemWindowInsetLeft(),
                        insets.getSystemWindowInsetTop(),
                        insets.getSystemWindowInsetRight(),
                        insets.getSystemWindowInsetBottom()
                );
                return insets.consumeSystemWindowInsets();
            } else {
                setPadding(0, 0, 0, 0);
                return insets;
            }
        }
    }
    

    Suspicion, not fact: that only one view in the entire hierarchy gets a chance to eat the window insets, UNLESS you have CoordinatorLayout in the hierarchy, which allows more than one direct child to have FitSystemWindow=true. If you do have a CoordinatorLayout, your mileage may vary.

    This entire feature in Android seems to be an unholy mess.

提交回复
热议问题