FitSystemWindows

在绘制View时,首先由根布局往下传WindowInsets,SystemBar的尺寸在WindowInsets 中表示出来,比如Insets:(0, 63 , 0, 126), 表示StatusBar高度63,NavigationBar高度126。

根据默认的实现,如果设置了fitSystemWindows = true,就会根据WindowInsets来设置padding,调用insets.consumeSystemWindowInsets()表示这个WindowInsets被消耗了,之后就不会往下传。所以如果在布局文件了有多个View设置了fitSystemWindows = true,那只有第一个起作用。

要自己根据WindowInsets来做处理,可复写onApplyWindowInsets方法,也可以注册监听setOnApplyWindowInsetsListener

一个实现FitSystemWindows的自定义View

package com.devbrackets.android.exomedia.ui.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.WindowInsets;
import android.widget.RelativeLayout;

/**
 * A RelativeLayout that will abide by the fitsSystemWindows flag without
 * consuming the event since Android has been designed to only allow
 * one view with fitsSystemWindows=true at a time.
 */
public class FitsSystemWindowRelativeLayout extends RelativeLayout {
    private Rect originalPadding;

    public FitsSystemWindowRelativeLayout(Context context) {
        super(context);
        setup();
    }

    public FitsSystemWindowRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        setup();
    }

    public FitsSystemWindowRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setup();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public FitsSystemWindowRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        setup();
    }

    /**
     * Makes sure the padding is correct for the orientation
     */
    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        //If the system navigation bar can move, then clear out the previous insets before
        // fitSystemWindows(...) or onApplyWindowInsets(...) is called
        //This fixes the issue https://github.com/brianwernick/ExoMedia/issues/33
        if (navBarCanMove()) {
            setup();
        }
    }

    @Override
    @SuppressWarnings("deprecation")
    protected boolean fitSystemWindows(@NonNull Rect insets) {
        updatePadding(insets);
        return false;
    }

    @Override
    @TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        Rect windowInsets = new Rect(
                insets.getSystemWindowInsetLeft(),
                insets.getSystemWindowInsetTop(),
                insets.getSystemWindowInsetRight(),
                insets.getSystemWindowInsetBottom()
        );

        fitSystemWindows(windowInsets);
        return insets;
    }

    /**
     * Updates the views padding so that any children views are correctly shown next to, and
     * below the system bars (NavigationBar and Status/SystemBar) instead of behind them.
     */
    private void setup() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            setFitsSystemWindows(true);
        }

        if (originalPadding == null) {
            originalPadding = new Rect(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());
        }

        updatePadding(new Rect());
    }

    /**
     * Updates the layouts padding by using the original padding and adding
     * the values found in the insets.
     *
     * @param insets The Rect containing the additional insets to use for padding
     */
    private void updatePadding(Rect insets) {
        int rightPadding = originalPadding.right + insets.right;
        int bottomPadding = originalPadding.bottom + insets.bottom;
        int topPadding = originalPadding.top + insets.top;

        setPadding(originalPadding.left, topPadding, rightPadding, bottomPadding);
    }

    /**
     * Determines if the Navigation controller bar can move.  This will typically only be
     * true for phones.
     *
     * @return True if the system navigation buttons can move sides
     */
    private boolean navBarCanMove() {
        return this.getResources().getConfiguration().smallestScreenWidthDp <= 600;
    }
}

这个自定义View在onApplyWindowInsets中根据上面传下来的WindowInsets做了相应的处理,但是并没有调用insets.consumeSystemWindowInsets(),所以WindowInsets还是会继续往下传,这样可以解决同一个布局里面只有第一个fitSystemWindows = true才起作用的问题。

你可能感兴趣的:(FitSystemWindows)