關(guān)于使用BGASwipeBackLayout-Android結(jié)合StatusBarUtil的問(wèn)題

背景

在寫(xiě)Reading的過(guò)程中,想實(shí)現(xiàn)仿IOS右滑關(guān)閉Activity的效果,在網(wǎng)上找到了BGASwipeBackLayout-Android
,看著效果不錯(cuò),剛巧這個(gè)庫(kù)也使用的猴子的StatusBarUtil
,在使用的過(guò)程中,效果確實(shí)不錯(cuò),同時(shí)這個(gè)庫(kù)也支持了右滑關(guān)閉Activity時(shí)候沉浸式通知欄,但是Reading里面用到了DrawerLayout,結(jié)合BGASwipeBackLayout-Android使用的時(shí)候出現(xiàn)了下面的問(wèn)題,就是當(dāng)從主Activity進(jìn)入二層界面再返回的時(shí)候,底部Tab會(huì)彈一下再上來(lái),效果有些炸眼....

2018-08-25 00_05_55.gif

解決

想要解決這個(gè)問(wèn)題無(wú)非從兩個(gè)角度去思考

  • BGASwipeBackLayout-Android
  • StatusBarUtil

浩哥的BGA是通過(guò)修改support-v4 包中 SlidingPaneLayout 的源碼來(lái)實(shí)現(xiàn)滑動(dòng)返回布局,源碼在BGASwipeBackLayout.java這里,大概過(guò)了一下,感覺(jué)還是挺復(fù)雜的。放棄了,然后通過(guò)查看浩哥支持的為滑動(dòng)界面設(shè)置狀態(tài)欄顏色的方法

/**
     * 為滑動(dòng)返回界面設(shè)置狀態(tài)欄顏色
     *
     * @param activity 需要設(shè)置的activity
     * @param color    狀態(tài)欄顏色值
     */
    public static void setColorForSwipeBack(Activity activity, int color) {
        setColorForSwipeBack(activity, color, DEFAULT_STATUS_BAR_ALPHA);
    }
 /**
     * 為滑動(dòng)返回界面設(shè)置狀態(tài)欄顏色
     *
     * @param activity       需要設(shè)置的activity
     * @param color          狀態(tài)欄顏色值
     * @param statusBarAlpha 狀態(tài)欄透明度
     */
    public static void setColorForSwipeBack(Activity activity, @ColorInt int color,
                                            @IntRange(from = 0, to = 255) int statusBarAlpha) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

            ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content));
            View rootView = contentView.getChildAt(0);
            int statusBarHeight = getStatusBarHeight(activity);
            if (rootView != null && rootView instanceof CoordinatorLayout) {
                final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView;
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    coordinatorLayout.setFitsSystemWindows(false);
                    contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
                    boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight;
                    if (isNeedRequestLayout) {
                        contentView.setPadding(0, statusBarHeight, 0, 0);
                        coordinatorLayout.post(new Runnable() {
                            @Override
                            public void run() {
                                coordinatorLayout.requestLayout();
                            }
                        });
                    }
                } else {
                    coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha));
                }
            } else {
                contentView.setPadding(0, statusBarHeight, 0, 0);
                contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
            }
            setTransparentForWindow(activity);
        }
    }

這段代碼我們可以看到通過(guò)獲取根布局,如果跟布局是CoordinatorLayout的話,設(shè)置paddingTop,并且設(shè)置顏色重繪。否則給contentView設(shè)置了paddingTop并且設(shè)置顏色。參考這段代碼,我們找到了猴子的為DrawerLayout提供的沉浸式代碼

/**
     * 為DrawerLayout 布局設(shè)置狀態(tài)欄變色
     *
     * @param activity       需要設(shè)置的activity
     * @param drawerLayout   DrawerLayout
     * @param color          狀態(tài)欄顏色值
     * @param statusBarAlpha 狀態(tài)欄透明度
     */
    public static void setColorForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color,
                                               @IntRange(from = 0, to = 255) int statusBarAlpha) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            return;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
        } else {
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        }
        // 生成一個(gè)狀態(tài)欄大小的矩形
        // 添加 statusBarView 到布局中
        ViewGroup contentLayout = (ViewGroup) drawerLayout.getChildAt(0);
        View fakeStatusBarView = contentLayout.findViewById(FAKE_STATUS_BAR_VIEW_ID);
        if (fakeStatusBarView != null) {
            if (fakeStatusBarView.getVisibility() == View.GONE) {
                fakeStatusBarView.setVisibility(View.VISIBLE);
            }
            fakeStatusBarView.setBackgroundColor(color);
        } else {
            contentLayout.addView(createStatusBarView(activity, color), 0);
        }
        // 內(nèi)容布局不是 LinearLayout 時(shí),設(shè)置padding top
        if (!(contentLayout instanceof LinearLayout) && contentLayout.getChildAt(1) != null) {
            contentLayout.getChildAt(1)
                    .setPadding(contentLayout.getPaddingLeft(), getStatusBarHeight(activity) + contentLayout.getPaddingTop(),
                            contentLayout.getPaddingRight(), contentLayout.getPaddingBottom());
        }
        // 設(shè)置屬性
        setDrawerLayoutProperty(drawerLayout, contentLayout);
        addTranslucentView(activity, statusBarAlpha);
    }

從代碼來(lái)看,一眼看到代碼注釋//生成一個(gè)狀態(tài)欄大小的矩形,也就是說(shuō)支持DrawerLayout沉浸的原理是為跟布局設(shè)置 android:fitsSystemWindows="true",讓整個(gè)屏幕都可以放組件,同時(shí)加了一個(gè)狀態(tài)欄大小的矩形,并設(shè)置了顏色,這樣就滿足了DrawerLayout的沉浸式。

  • 1.fitsSystemWindow 默認(rèn)是true,就是組件都在屏幕內(nèi),但是不包括statusBar。設(shè)置成false后,整個(gè)屏幕都可以放置組件,沒(méi)有statusBar和window之分。
  • 2.android:fitsSystemWindows=“true”在布局中占有最高權(quán)限,如果明確設(shè)置為true,style設(shè)置fits為false是無(wú)效的;同理,只在布局中設(shè)置fits而沒(méi)有設(shè)置style也是無(wú)效的。

好了,分析到這里我們不難想出來(lái)解決辦法了,從浩哥提供的滑動(dòng)關(guān)閉界面的沉浸代碼中可以看到滑動(dòng)關(guān)閉的Activity并沒(méi)有設(shè)置android:fitsSystemWindows="true",那么這個(gè)Activity是有statusBar和window的區(qū)分的,通過(guò)設(shè)置了paddingTop來(lái)實(shí)現(xiàn)的,而猴子的setDrawerLayout支持的前提是為跟布局設(shè)置了android:fitsSystemWindows="true",也就是沒(méi)有了statusBar,所以最終看到的效果就是上面的動(dòng)態(tài)圖,進(jìn)入二級(jí)界面為了實(shí)現(xiàn)左滑界面的沉浸式,設(shè)置了浩哥的setColorForSwipeBack方法,當(dāng)返回到主Activity時(shí),由于主界面沒(méi)有了statusBar,所以你會(huì)看到底部的tab會(huì)向上移動(dòng)了一個(gè)statusBar的高度,最后解決的代碼如下:

/**
     * 為滑動(dòng)返回界面設(shè)置狀態(tài)欄顏色
     *
     * @param activity       需要設(shè)置的activity
     * @param color          狀態(tài)欄顏色值
     * @param statusBarAlpha 狀態(tài)欄透明度
     */
    public static void setColorForSwipeBackDrawerLayout(Activity activity, @ColorInt int color,
                                                        @IntRange(from = 0, to = 255) int statusBarAlpha) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {

            ViewGroup contentView = ((ViewGroup) activity.findViewById(android.R.id.content));
            View rootView = contentView.getChildAt(0);
            int statusBarHeight = getStatusBarHeight(activity);
            if (rootView != null && rootView instanceof CoordinatorLayout) {
                final CoordinatorLayout coordinatorLayout = (CoordinatorLayout) rootView;
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                    coordinatorLayout.setFitsSystemWindows(false);
                    contentView.setBackgroundColor(calculateStatusColor(color, statusBarAlpha));
                    boolean isNeedRequestLayout = contentView.getPaddingTop() < statusBarHeight;
                    if (isNeedRequestLayout) {
                        contentView.setPadding(0, statusBarHeight, 0, 0);
                        coordinatorLayout.post(new Runnable() {
                            @Override
                            public void run() {
                                coordinatorLayout.requestLayout();
                            }
                        });
                    }
                } else {
                    coordinatorLayout.setStatusBarBackgroundColor(calculateStatusColor(color, statusBarAlpha));
                }
            }
            setTransparentForWindow(activity);
        }
    }

為主Activity設(shè)置setColorForSwipeBackDrawerLayout方法,只需要把setPaddingTop刪除掉就可以了,運(yùn)行看效果我們發(fā)現(xiàn)從二級(jí)滑動(dòng)返回到主Activity后底部Tab不會(huì)再上移,但是DrawerLayout不支持沉浸了,所以我們?cè)僬{(diào)用一下猴子的代碼 就解決了該問(wèn)題。

      /**
     * 為DrawerLayout 布局設(shè)置狀態(tài)欄顏色,純色
     *
     * @param activity     需要設(shè)置的activity
     * @param drawerLayout DrawerLayout
     * @param color        狀態(tài)欄顏色值
     */
    public static void setColorNoTranslucentForDrawerLayout(Activity activity, DrawerLayout drawerLayout, @ColorInt int color) {
        setColorForDrawerLayout(activity, drawerLayout, color, 0);
    }

最后感謝兩位大佬的開(kāi)源...

王浩
BGASwipeBackLayout-Android

猴子
StatusBarUtil

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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