42

Android 之路 (11) - 对Toolbar的封装-实现渐变标题栏与沉浸适配

 4 years ago
source link: https://www.tuicool.com/articles/ABRfAnQ
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

引言

看过上篇文章的演示,就应该能看到我们在滑动返回的时候,顶部的状态栏其实是没和我们的页面一起滑动的,本篇就此问题进行适配,让标题栏沉浸到状态栏中,而且还是能够适配现在市面上所见的异形屏。

正文

我们要实现下面这样的一个标题栏,支持沉浸图片或者纯色,还需要提供 helper,为以后需求变更做准备。

ryqqQfR.gif

分析

首先来分析一下我们的布局,在默认的情况下,我们的整个屏幕分为三部分(没有考虑虚拟状态栏):状态栏、标题栏、内容区域。对于状态栏来说我们只能设置颜色,而像我们上面的需求他应该是一个 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>

运行效果

ERbmEbN.png!web

然后在我们的 Activity的onCreate 中加上这段代码:

// 设置沉浸和状态栏的颜色为透明
StatusBarUtil.setTranslucentForImageView(this, 0, null);

看一下效果吧:

JbiQjuZ.gif

从上图可以看出,我们的 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);
    }

运行起来看看效果吧。

U73mY3U.gif

看上去我们已经完美,接下来我们就尝试直接将背景颜色更改为 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 看上去颜色有点失真,但是实际上是很圆滑的)。

ryqqQfR.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;
    }

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

JRnU3aq.gif

结束

总结

总得来说,实现并不是很困难,关键点在于实现思路。另外我们此次实现的这个ToolBar是能够适配 异形屏全面屏 的,不信的可以试试。

如果我的文章和代码对你有了帮助,请给我一个star和关注~~

源码

软广

来都来了,就给个关注吧,时不时会悄悄的推送一些小技巧的文章~~!

mqUrme2.jpg!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK