什么是ToolBar?

作者: 程序员丶星霖 | 来源:发表于2017-06-01 08:27 被阅读4068次

    一、简介

    Android3.0之后,Google引入了ActionBar,想要统一安卓应用的导航栏样式。但是由于ActionBar难以定制,很大程度上限制了开发人员。较为常见的实现是使用普通的ViewGroup来封装自己的APP Bar,或者使用JakeWharton大神的ActionBarSherlock库。

    自2014年Google I/O上Material Design横空出世后,市场上的应用又逐步趋向了样式的风格统一,support library中很快就出来了ToolBar控件,一个定制化的ViewGroup,来完善ActionBar的使用。

    ToolBar是ActionBar的替代品,对于像我这样的菜鸟级Android开发者来说,对怎样使用ToolBar还是感到比较困惑,那今天就来学一下如何使用吧。

    1.1去掉默认的ActionBar

    在styles.xml中新建一个主题AppTheme.Base:

    <style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
            <!-- Customize your theme here. -->
            <item name="colorPrimary">@color/colorPrimary</item>
            <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
            <item name="colorAccent">@color/colorAccent</item>
            <item name="windowActionBar">false</item>
            <item name="windowNoTitle">true</item>
        </style>
    

    并将这个style应用到application中,这样就可以去除掉所有Activity中默认的ActionBar了。

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme.Base">
    </application>
    
    1.2修改ToolBar默认的文字颜色

    在styles.xml中新建相应的style:

    <style name="AppTheme.Toolbar">
            <!--这个是API21以后才有的属性-->
            <item name="android:colorControlNormal">@color/controlNormal</item>
            <item name="android:textColorPrimary">@color/toolbarColor</item>
        </style>
    
        <style name="AppTheme.Toolbar.Popup">
            <item name="android:textColorPrimary">@android:color/black</item>
        </style>
    

    然后将style应用到ToolBar上(注意在builde.gradle文件中添加support.v7包的依赖:compile ‘com.android.support:appcompat-v7:24.2.1’)

    <android.support.v7.widget.Toolbar
            android:id="@+id/tl_bar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            app:theme="@style/AppTheme.Toolbar"
            app:popupTheme="@style/AppTheme.Toolbar.Popup"
            app:elevation="4dp">
        </android.support.v7.widget.Toolbar>
    
    1.3如何加上返回按钮并实现返回:导航返回按钮的图标,还可以通过.setNavigationOnClickListener()方法或者app:navigationIcon属性来修改。
    //设置ToolBar
    private void setupToolBar() {
        setSupportActionBar(mTlBar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);//启动返回按钮
    }
    
       //实现返回功能
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
                case android.R.id.home: //android.R.id.home是Android内置home按钮的id
                    finish();
                    break;
            }
            return super.onOptionsItemSelected(item);
        }
    

    二、Options Menu的用法

    2.1与ActionBar的用法一致在res/menu目录下新建一个search.xml文件,并且添加menu的相应内容:
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <item
            android:id="@+id/search"
            android:title="搜索"
            android:icon="@android:drawable/ic_menu_search"
            app:showAsAction="collapseActionView"
            />
    </menu>
    
    2.2在Activity中添加ToolBar对应的Menu Item,并设置点击事件:
    //为ToolBar添加Menu Item
    Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.search, menu);
        return super.onCreateOptionsMenu(menu);
    }
    
    //实现ToolBar的点击事件
    Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home: //android.R.id.home是Android内置home按钮的id
                finish();
                break;
            case R.id.search://搜索Item的ID
                Toast.makeText(this, "你要搜索啥??", Toast.LENGTH_SHORT).show();
                break;
        }
        return super.onOptionsItemSelected(item);
    }
    
    2.3如果溢出按钮的颜色与主题色不一样,可以通过修改ToolBar的theme和popupTheme属性来改变。
    <android.support.v7.widget.Toolbar
        android:id="@+id/tl_bar"
        app:elevation="4dp"
        app:popupTheme="@style/AppTheme.Toolbar.Popup"
        app:theme="@style/AppTheme.Toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary">
    </android.support.v7.widget.Toolbar>
    

    也可以使用theme中的actionMenuTextColor属性设置Menu Item的字体颜色。

    <item name="android:actionMenuTextColor">@android:color/black</item>
    

    一般情况下,都是将ToolBar相关的属性集中卸载一个style中。

    <style name="AppTheme.Toolbar.Popup" >
        <!--设置menu菜单的背景色-->
        <item name="android:itemBackground">@color/homeTabText</item>
        <!--设置Menu菜单的字体颜色-->
        <item name="android:textColorPrimary">@android:color/black</item>
        <!--设置Menu窗口不覆盖ToolBar视图-->
        <item name="overlapAnchor">false</item>
    </style>
    
    2.4也可以在Java代码中也可以获取Menu Item对象,然后通过如下方法设置Item的显示与隐藏:
     //获取Menu Item
    MenuItem item = menu.findItem(R.id.search);
    //设置Menu Item隐藏
    item.setVisible(false);
    
     //清除所有MenuItem
    menu.clear();
    

    三、ActionMenuView

    ToolBar默认是将Menu内容显示在右边的,那么怎样可以将其显示在左边或者中间呢?不妨试试ActionMenuView。
    ActionMenuView是将原来位于ToolBar中的Menu内容移到自己的名下,将一系列的Menu Item包括在其中,再将其搁置于ToolBar容器中。这样可以更方便的管理和显示Menu内容。所以原本独立的ToolBar控件,就有了一个Child。

    3.1将Menu显示在ToolBar中间
    <android.support.v7.widget.Toolbar
            android:id="@+id/tl_bar"
            app:elevation="4dp"
            app:popupTheme="@style/AppTheme.Toolbar.Popup"
            app:theme="@style/AppTheme.Toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary">
            <android.support.v7.widget.ActionMenuView
                android:id="@+id/amv_search"
                android:gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content">
    
            </android.support.v7.widget.ActionMenuView>
        </android.support.v7.widget.Toolbar>
    
    3.2在Activity中,将Menu资源文件加载到ActionMenuView对象中去:
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.search, mAmvSearch.getMenu());
        return super.onCreateOptionsMenu(menu);
    }
    
    3.3Menu Item的点击事件方法不需要改动,只需要将ActionMenu对象的点击事件设置转移就可以了:
    mAmvSearch.setOnMenuItemClickListener(new ActionMenuView.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    return onOptionsItemSelected(item);
                }
            });
    
    3.4也可以利用getMenu()方法获取到Menu对象,动态添加或删除Menu Item,甚至加载另外一个Menu资源文件:
    mAmvSearch.getMenu().clear();
    getMenuInflater().inflate(R.menu.search, mAmvOther.getMenu());
    
    3.5还可以利用ActionMenuView控制Menu Item的位置。
    • Menu Item间距问题。Item的默认宽度是56dp,可以通过style中的属性进行修改,并将样式设置给Activity主题就可以了。
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:actionButtonStyle">@style/MyActionButtonStyle</item>
    </style>
    
    <style name="MyActionButtonStyle" parent="@android:style/Widget.Holo.ActionBar">
        <!--设置Menu Item的宽度-->
        <item name="android:minWidth">72dip</item>
        <!--设置Menu Item的padding值-->
        <item name="android:padding">0dp</item>
    </style>
    
    • Menu Item图标高亮的问题。可以使用两套图标,在点击时修改图标资源。也可以借助ColorFilter使用一套图标也能做到,还可以减少APK文件大小。
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.option_walk:
                item.getIcon().setColorFilter(ContextCompat.getColor(this,
                        android.R.color.darker_gray), PorterDuff.Mode.MULTIPLY);
                break;
        }
        return super.onOptionsItemSelected(item);
    }
    

    四、actionLayout

    通常情况下,ToolBar中的Menu Item只显示为一个Icon,通过标签定义title和icon属性即可。当然也有一些特殊情况,需要自定义Menu Item的内容,常见的就是搜索页面。

    4.1定义一个layout文件
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
        <EditText
            android:id="@+id/et_search"
            android:hint="搜索你想要的"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
    </RelativeLayout>
    
    4.2通过actionLayout属性引入到标签中
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <item
            android:id="@+id/search"
            android:title="搜索"
            app:actionLayout="@layout/menu_search"
            app:showAsAction="always"
            />
    </menu>
    
    4.3注意事项
    • menu_search布局文件的内容必须以RelativeLayout作为根容器布局,否则,actionLayout对应的视图宽度不足以填充满ToolBar的宽度,显示效果如同layout_width属性为wrap_content一样;
    • actionLayout属性必须使用app作为命名空间,如果使用android的话,会导致menuitem对象通过getActionView()始终获取的对象为null。

    五、ToolBar Shadow

    根据Material Design设计规范,ToolBar是存在于页面Content之上的,有一个类似阴影效果的视觉差。

    但是,无论是android:elevation属性,还是使用APPBarLayout包裹ToolBar,都只能兼容5.0及以上版本的系统。要想兼容一下的版本,就必须要自己实现阴影效果。

    自己实现阴影效果有两种选择:

    • 使用.9背景图;
    • 使用<gradient>标签定制一个阴影渐变效果。
    5.1新建xml阴影形状,res/drawable/shadow.xml文件
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <gradient
            android:startColor="@android:color/transparent"
            android:endColor="#40000000"
            android:angle="90" />
    </shape>
    
    5.2和ToolBar一起使用
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <android.support.v7.widget.Toolbar
            android:id="@+id/tl_bar"
            app:elevation="4dp"
            app:popupTheme="@style/AppTheme.Toolbar.Popup"
            app:theme="@style/AppTheme.Toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"/>
    
        <View
            android:layout_width="match_parent"
            android:layout_height="4dp"
            android:background="@drawable/shadow" />
    
    </LinearLayout>
    

    为了保持不同设备APP体验的一致性,推荐使用这种方式来实现ToolBar阴影效果。

    六、标题居中

    ToolBar就是一个定制化的ViewGroup,所以可以在ToolBar里面放置一个TextView控件作为居中的标题来使用,再将ToolBar的Title隐藏起来即可实现ToolBar标题居中的效果。

     <android.support.v7.widget.Toolbar
            android:id="@+id/tl_bar"
            app:elevation="4dp"
            app:popupTheme="@style/AppTheme.Toolbar.Popup"
            app:theme="@style/AppTheme.Toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary">
            <TextView
                android:id="@+id/amv_search"
                android:layout_gravity="center"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="标题"
                style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
            </TextView>
        </android.support.v7.widget.Toolbar>
    

    TextView设置了style属性,与ActionBar.Title保持一致,然后还要去掉ToolBar中自有的Title,在布局中使用的app:title=""就不会起作用了,会显示ActionBar的标题。隐藏ActionBar的标题的代码如下:

    getSupportActionBar().setDisplayShowTitleEnabled(false);//设置不显示Title
    

    七、Fragment中使用

    有的时候,还需要在Fragment中使用ToolBar,比如Activity中不同的Tab显示不同的Fragment,同时每个Tab的ToolBar标题、Menu均不同,这时在Activity中使用同一个ToolBar就相当不方便了。我们可以在每个Fragment的布局中添加各自的ToolBar,然后在Fragment中单独控制。

    与Activity中使用ToolBar有所不同的是,替换ActionBar时,需要给setSupportActionBar方法添加作用对象:

    ((AppCompatActivity)getActivity()).setSupportActionBar((Toolbar) mContentView.findViewById(R.id.tb_toolbar));
    

    八、仿知乎主界面的实现

    为了加深对ToolBar的理解,来使用ToolBar来实现知乎主页的效果。

    1.xml布局
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:app="http://schemas.android.com/apk/res-auto"
                  android:orientation="vertical"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent">
        <android.support.v7.widget.Toolbar
            android:id="@+id/tl_bar"
            app:elevation="4dp"
            app:popupTheme="@style/AppTheme.Toolbar.Popup"
            app:theme="@style/AppTheme.Toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary">
    
        </android.support.v7.widget.Toolbar>
    
    </LinearLayout>
    
    2.menu菜单
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:app="http://schemas.android.com/apk/res-auto">
        <item
            android:id="@+id/action_search"
            android:icon="@drawable/ic_search_white_24dp"
            android:title="搜索"
            app:showAsAction="ifRoom" />
    
        <item
            android:id="@+id/action_notification"
            android:icon="@drawable/ic_notifications_active_white_24dp"
            android:title="通知"
            app:showAsAction="ifRoom" />
    
        <item
            android:id="@+id/action_settings"
            android:orderInCategory="100"
            android:title="设置"
            app:showAsAction="never" />
    
        <item
            android:id="@+id/action_about"
            android:orderInCategory="101"
            android:title="关于"
            app:showAsAction="never" />
    
    </menu>
    
    3.style
    <style name="AppTheme.Toolbar">
        <!--这个是API21以后才有的属性-->
        <item name="android:colorControlNormal">@color/controlNormal</item>
        <item name="android:textColorPrimary">@color/toolbarColor</item>
    </style>
    
    <style name="AppTheme.Toolbar.Popup" >
        <!--设置menu菜单的背景色-->
        <item name="android:itemBackground">@color/homeTabText</item>
        <!--设置Menu菜单的字体颜色-->
        <item name="android:textColorPrimary">@android:color/black</item>
        <!--设置Menu窗口不覆盖ToolBar视图(true为覆盖ToolBar视图)-->
        <item name="overlapAnchor">false</item>
    </style>
    
    4.Activity
    public class IOSDetailActivity extends BaseActivity {
    
        @BindView(R.id.tl_bar)
        Toolbar mTlBar;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_ios_detail);
            ButterKnife.bind(this);
            mTlBar.inflateMenu(R.menu.ios_menu);
            mTlBar.setNavigationIcon(R.drawable.ic_list_white_24dp);
            mTlBar.setTitle("首页");
        }
    }
    
    5.效果图
    ToolBar.jpg
    好吧,先到这里吧。以后遇到坑再来填!!!感兴趣的朋友关注我的微信公众号,一起学习吧!
    我的微信公众号.jpg

    相关文章

      网友评论

        本文标题:什么是ToolBar?

        本文链接:https://www.haomeiwen.com/subject/rfcjfxtx.html