FitSystemWindows

在繪制View時(shí),首先由根布局往下傳WindowInsets,SystemBar的尺寸在WindowInsets 中表示出來,比如Insets:(0, 63 , 0, 126), 表示StatusBar高度63,NavigationBar高度126。

根據(jù)默認(rèn)的實(shí)現(xiàn),如果設(shè)置了fitSystemWindows = true,就會(huì)根據(jù)WindowInsets來設(shè)置padding,調(diào)用insets.consumeSystemWindowInsets()表示這個(gè)WindowInsets被消耗了,之后就不會(huì)往下傳。所以如果在布局文件了有多個(gè)View設(shè)置了fitSystemWindows = true,那只有第一個(gè)起作用。

要自己根據(jù)WindowInsets來做處理,可復(fù)寫onApplyWindowInsets方法,也可以注冊(cè)監(jiān)聽setOnApplyWindowInsetsListener。

一個(gè)實(shí)現(xiàn)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;
    }
}

這個(gè)自定義View在onApplyWindowInsets中根據(jù)上面?zhèn)飨聛淼腤indowInsets做了相應(yīng)的處理,但是并沒有調(diào)用insets.consumeSystemWindowInsets(),所以WindowInsets還是會(huì)繼續(xù)往下傳,這樣可以解決同一個(gè)布局里面只有第一個(gè)fitSystemWindows = true才起作用的問題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容