對Toolbar的封裝-實現漸變標題欄與沉浸適配 [復制鏈接]

2019-6-5 10:07
hellokenken 閱讀:381 評論:1 贊:1
Tag:  

引言

看過上篇文章的演示,就應該能看到我們在滑動返回的時候,頂部的狀態欄其實是沒和我們的頁面一起滑動的,本篇就此問題進行適配,讓標題欄沉浸到狀態欄中,而且還是能夠適配現在市面上所見的異形屏。

正文

我們要實現下面這樣的一個標題欄,支持沉浸圖片或者純色,還需要提供 helper,為以后需求變更做準備。

圖片描述

分析

首先來分析一下我們的布局,在默認的情況下,我們的整個屏幕分為三部分(沒有考慮虛擬狀態欄):狀態欄、標題欄、內容區域。對于狀態欄來說我們只能設置顏色,而像我們上面的需求他應該是一個 Drawable 或者是一張純圖片。

然后在我們的實現中其實是用AppBarLayout包裹著Toolbar,我們操作的也是AppBarLayout,Toolbar保持原狀。

實現思路

我們的實現思路也很簡單,很多時候是沒有一個思路的開頭,導致無法進行。

1. 設置狀態欄的顏色為透明和讓整個布局沉浸到狀態欄中

關于狀態欄操作的開源庫的話,之前已經引入過StatusBarUtil,操作簡單也方便,有興趣的可以去看一下。

我們就用 第九篇 文章中的模板, 先新建一個Activity,不記得的朋友可以倒回去看看。看一下運行起來的頁面吧,默認狀態下什么都沒有。

xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".module.example.StatusToolBarActivity">

    <android.support.design.widget.AppBarLayout
        style="@style/BaseAppBarLayoutStyle">

        <android.support.v7.widget.Toolbar
style="@style/BaseToolbarStyle"
app:popupTheme="@style/AppTheme.PopupOverlay">

<TextView
    style="@style/ToolBarNavTextStyle"
    android:text="@string/nav_call_back" />

<TextView
    style="@style/ToolBarTitleStyle"
    android:text="@string/title_activity_status_tool_bar" />
        </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_status_tool_bar" />

</android.support.design.widget.CoordinatorLayout>

運行效果

圖片描述

然后在我們的 Activity的onCreate 中加上這段代碼:

// 設置沉浸和狀態欄的顏色為透明
StatusBarUtil.setTranslucentForImageView(this, 0, null);

看一下效果吧:

圖片描述

從上圖可以看出,我們的 AppBarLayout 已經沉浸到狀態欄中了,而且在滑動返回的時候也顯示的十分自然、符合直覺。但是能看到 AppBarLayout 的位置和內容明顯有點偏了,接下來就是對此進行適配。

2. 更改AppBarLayout的高度和Padding

這里適配起來也是比較簡單的,因為我們是直接把 AppBarLayout 沉浸到了狀態欄中,所以我們只需要在 Activity 中獲取到 AppBarLayout,將 AppBarLayout 的高度更改為原本的高度+狀態欄的高度,且把PaddingTo設置為狀態欄的高度,將ToolBar背景顏色的更改為完全透明,其它屬性爆出不變。
關于獲取 AppBarLayout ,在上一篇中我們封裝過 BaseAppBarLayoutStyle ,里面有id/base_appbar。具體看代碼吧。

    /**
     * 初始化標題欄
     */
    private void initBaseToolBar() {
        // 設置為透明色 mToolBar 已經在base中獲取過了
        mToolBar.setBackgroundColor(0x00000000);
        mToolBar.setTitle("");
        // 設置全透明
        mToolBar.getBackground().setAlpha(0);
        // appbar
        AppBarLayout mAppBarLayout = findViewById(R.id.base_appbar);
        // 狀態欄高度 getStatusBarHeight只是一個獲取高度的方法
        int statusBarHeight = getStatusBarHeight(mActivity);
        //大于 19  設置沉浸和padding
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (mAppBarLayout != null) {
    ViewGroup.MarginLayoutParams appbarLayoutParam = (ViewGroup.MarginLayoutParams) mAppBarLayout.getLayoutParams();
    // 更改高度 toolbar_height 的高度是可配置的
    appbarLayoutParam.height = (int) (getResources().getDimension(R.dimen.toolbar_height) + statusBarHeight);
    // 設置padding
    mAppBarLayout.setPadding(mAppBarLayout.getPaddingLeft(),
statusBarHeight,
mAppBarLayout.getPaddingRight(),
mAppBarLayout.getPaddingBottom());

    //重新設置回去
    mAppBarLayout.setLayoutParams(appbarLayoutParam);
}
        }
        // 設置沉浸和狀態欄的顏色為透明
        StatusBarUtil.setTranslucentForImageView(this, 0, null);
    }

    /**
     * 獲取狀態欄高度
     *
     * @param context context
     * @return 狀態欄高度
     */
    private int getStatusBarHeight(Context context) {
        // 獲得狀態欄高度
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        return context.getResources().getDimensionPixelSize(resourceId);
    }

運行起來看看效果吧。

圖片描述

看上去我們已經完美,接下來我們就嘗試直接將背景顏色更改為 Drawable,為了更顯眼,我特地選了一個鮮艷的顏色寫了一個shape,代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient
        android:angle="45"
        android:endColor="#03a4f9"
        android:startColor="#ff76D2" />
</shape>

然后為設置為AppBarLayout 的背景即可,運行起來看看吧(Gif 看上去顏色有點失真,但是實際上是很圓滑的)。

圖片描述

從圖中基本可以看到,基本上已經實現了最開始提的需求。其實到了這一步,我們的ToolBar已經能夠滿足絕大多數需求了,五彩斑斕的標題欄就此誕生~~

4. 預埋相關設置

接下來就是將初始化 ToolBar 的代碼和原本 CandyBaseActivity 的合并在一起,并增加一些其它的設置,方便后續的使用。

在封裝到CandyBaseActivity 需要注意以下情況:

  • 并不是每個 Activity 都需要底層初始化 ToolBar 的,類似于圖片沉浸和特殊效果的頁面。

  • 所以 initToolbar 這個方法應該是protected,讓子類可覆寫。

  • 基類不應該直接操作AppBarLayout的背景顏色,就應該像我們寫的列子中一樣,子類只做相關初始化,背景顏色讓子類在xml中定義。

  • NavigationIcon可以讓子類自己設置,在沒有的情況下才使用基類中定義的icon,icon的替換只需要命名為相同的名字,放到module下相同的文件夾中,最終打包將會以module為主。

CandyBaseActivity的代碼量有點多,以下為主要核心代碼:

/**
     * 初始化toolbar<p>
     * 如果子頁面不需要初始化ToolBar,請直接覆寫本方法做空操作即可
     * </p>
     */
    protected void initToolbar() {
        mToolBar = findViewById(R.id.base_toolbar);
        if (null != mToolBar) {
// 設置為透明色
mToolBar.setBackgroundColor(0x00000000);
// 設置全透明
mToolBar.getBackground().setAlpha(0);
// 清除標題
mToolBar.setTitle("");
setSupportActionBar(mToolBar);
// 子類中沒有設置過返回按鈕的情況下
if (mToolBar.getNavigationIcon() == null) {
    //設置返回按鈕
    mToolBar.setNavigationIcon(getNavigationIcon());
}
mToolBar.setNavigationOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        onNavigationOnClickListener();
    }
});
isInitToolbar = true;
//返回文字按鈕
View navText = findViewById(R.id.toolbar_nav_text);
if (null != navText) {
    navText.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
onNavigationOnClickListener();
        }
    });
}
        }
        // appbar
        AppBarLayout mAppBarLayout = findViewById(R.id.base_appbar);
        // 狀態欄高度 getStatusBarHeight只是一個獲取高度的方法
        int statusBarHeight = getStatusBarHeight(mActivity);
        //大于 19  設置沉浸和padding
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (mAppBarLayout != null) {
    ViewGroup.MarginLayoutParams appbarLayoutParam = (ViewGroup.MarginLayoutParams) mAppBarLayout.getLayoutParams();
    // 更改高度 toolbar_height 的高度是可配置的
    appbarLayoutParam.height = (int) (getResources().getDimension(R.dimen.toolbar_height) + statusBarHeight);
    // 設置padding
    mAppBarLayout.setPadding(mAppBarLayout.getPaddingLeft(),
statusBarHeight,
mAppBarLayout.getPaddingRight(),
mAppBarLayout.getPaddingBottom());

    //重新設置回去
    mAppBarLayout.setLayoutParams(appbarLayoutParam);
}
        }
        // 設置沉浸和狀態欄的顏色為透明
        StatusBarUtil.setTranslucentForImageView(this, 0, null);
    }

    /**
     * 返回按鈕
     * 子類通過覆寫本方法返回需要設置的返回按鈕,也可以直接在xml中直接賦值
     * @return
     */
    protected int getNavigationIcon() {
        return R.drawable.ic_chevron_left_write_24dp;
    }

演示一下抽取封裝以后的效果:

圖片描述

結束

總結

總得來說,實現并不是很困難,關鍵點在于實現思路。另外我們此次實現的這個ToolBar是能夠適配異形屏全面屏的,不信的可以試試。


我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(1)
天明向日葵 2019-6-10 09:57
學習了
回復
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

海南特区七星彩