首页 > 代码库 > Android Studio精彩案例(七)《ToolBar使用详解<一>》

Android Studio精彩案例(七)《ToolBar使用详解<一>》

转载本专栏文章,请注明出处,尊重原创 。文章博客地址:道龙的博客

本文参考博客:http://blog.csdn.net/h_zhang/article/details/51232773

        http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1118/2006.html



Android5.x以后谷歌大力推崇Material Design设计,有意统一之前Android style风格乱象的情况。上一篇博客我们学习了ActionBar的使用,因为以前很多方式都会对ActionBar做深度定制,使用起来不是很方便,toolbar 作为 android 5.x 引入的一个新控件,可以理解为是ActionBar的升级版,大大扩展了Actionbar,使用更灵活,不像actionbar那么固定,所以单纯使用ActionBar已经稍显过时了,它的一些方法已被标注过时。Toolbar更像是一般的View元素,可以被放置在view树体系的任意位置,可以应用动画,可以跟着scrollView滚动,可以与布局中的其他view交互,等总之很强大。。这篇文章来介绍Android5.x新特性之 Toolbar和Theme的使用,参考了许多博文,和书籍,在此对其做一个总结,从零开始,教您学会使用ToolBar。

应用程序中使用app bar可有如下优点: 
1. 可以显示出用户所处的当前位置; 
2. 可以提供一些重要的交互操作,比如搜索(search)操作; 
3. 可以实现导航功能,让用户快速回到Home Activity;

本文就主要介绍一下Android Toolbar的使用方法。

我们先来看一张图片,因为在下面你会不断地遇到这个图片中的内容

技术分享

简单解释一下属性意义:

colorPrimaryDark状态栏的颜色(可用来实现沉浸效果)

colorPrimary:Toolbar的背景颜色 (xml中用android:background=”?attr/colorPrimary”指定)

android:textColorPrimaryToolbar中文字的颜色,设置后Menu Item的字体颜色也会跟随

colorAccentEditText正在输入时,RadioButton选中时的颜色

windowBackground:底部导航栏的颜色

app:title=”App Title”Toolbar中的App Title

app:subtitle=”Sub Title” Toobar中的小标题

app:navigationIcon=”@android:drawable/ic_menu_sort_by_size” : 导航图标(注意和Logo的区别)


我们从以下几个点了解Toolbar的使用

  1. Toolbar的基础使用
  2. Toolbar配置主题Theme
  3. Toolbar中常用的控件设置
  4. Toolbar的自定义

Toolbar的基础使用

我们从以下几点来一步一步的学习Toolbar的使用

  1. Style(风格)
  2. Layout(布局)
  3. Activity(代码)

Style(风格)

为了能在你的Activity中使用Toolbar,你必须在工程里修改styles.xml文件里的主题风格,系统默认如下

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">

这种Theme表示使用系统之前的ActionBar,那么我们想要使用Toolbar怎么办呢?
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">

我们还需要隐藏默认的ActionBar,否则会报如下错误:

Caused by: java.lang.IllegalStateException: This Activity already has an action bar 
supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set 
windowActionBar to false in your theme to use a Toolbar instead.

这个主题表示不使用系统的Actionbar了,这是第一步。

Layout布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        >
    </android.support.v7.widget.Toolbar>

</RelativeLayout>

为了在你的UI中使用Toolbar,你得为每个activity布局添加Toolbar,并且给Toolbar设置一个id android:id=”@+id/toolbar”。这是第二部。其中高度指定为了ActionBar大小

Activity(代码)

 Toolbar toolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = findView(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

代码中通过findView找到Toolbar,然后通过setSupportActionBar(toolbar);将Toolbar设置为Activity的导航栏。

通过上面的三个步骤,你就已经使用了Support v7提供的Toolbar了。看看那效果图。

技术分享

是不是感觉很丑?没有一点MD设计的风格,而且还有一个问题,为什么跟Action有这么大的差距?那么先来穿插的解决这个问题。还要注意点,默认的title是项目名称。然后加入Menu:

步骤如下:

打开Android studio会发现如图所示,没有Menu文件:

技术分享

这时我们需要Menu文件,怎么办呢?

做法如下:

技术分享

点击进去后会出现如下界面:

技术分享

点击OK,就创建成功,如图

技术分享

修改文件名为main_menu.xml。加入如下代码:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <!--添加一条item-->
    <item android:id="@+id/Setting"
          android:title="设置"
          />
</menu>

然后再主活动引入menu:

@Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main_menu,menu);
        return true;
    }

现在再来运行程序:

技术分享

好了介绍搜玩了如何引入menu,点击指示图标会显示设置。再回到toolBar上来,虽然还是很丑,不过别失望,这仅仅是为了让Toolbar正常工作而已,为了让Toolbar有Material Design风格,我们必须去设置Toolbar的主题风格。

Toolbar配置主题Theme

我们重新配置系统主题Theme,修改styles.xml代码如下:

<!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <!--导航栏底色-->
        <item name="colorPrimary">#f61d1f1f</item>
        <!--状态栏底色-->
        <item name="colorPrimaryDark">#0a0909</item>
        <!--导航栏上的标题颜色,这里的颜色还可以自己定义喜欢的类型-->
        <item name="android:textColorPrimary">#fff</item>
        <!--Activity窗口的颜色,注意:这个颜色值要通过color属性引进来-->
        <item name="android:windowBackground">@color/windowBackground</item>
        <!--按钮选中或者点击获得焦点后的颜色-->
        <item name="colorAccent">#00ff00</item>
        <!--和 colorAccent相反,正常状态下按钮的颜色,如果我们的colorPrimary是深色,一般设置这里为白色-->
        <item name="colorControlNormal">#fff</item>
        <!--Button按钮正常状态颜色,根据项目来定义-->
        <item name="colorButtonNormal">@color/accent_material_light</item>
        <!--EditText 输入框中字体的颜色,colorPrimary如果设置深色,一般字体设置为白色-->
        <item name="editTextColor">@android:color/white</item>
    </style>


Toolbar中常用的控件设置

各个属性就不解释了,注释都很清楚。你可以对着文章开头的那张图片理解一下上边都对应了手机屏幕的哪个位置的。我们来看看Toolbar怎么使用这些主题吧?

配置activity_main.xml中的Toolbar改成为如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
>

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:background="?attr/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
        >
    </android.support.v7.widget.Toolbar>
</RelativeLayout>


相比上面的Toolbar配置,这里添加了 不少代码

首先。app定义了命名空间,主要目的是为了兼容低版本也是用MD效果的。

然后:

android:background="?attr/colorPrimary"
它表示我这个ToolBar的整个样式。使用?attr表示全引用,整个自定义样式里面的内容都对我的tooBar生效。表示根据屏幕的分辨率采用系统默认的高度。

为了在你的UI中使用Toolbar,你得为每个activity布局添加Toolbar,并且给Toolbar设置一个id android:id=”@+id/toolbar”。这是第二。

代码添加toobar

       
        getSupportActionBar().setDisplayShowTitleEnabled(false);
       toolbar.setTitle("主标题");
        toolbar.setSubtitle("副标题");
        //还可以代码设置标题颜色
        toolbar.setSubtitleTextColor(Color.WHITE);
        //设置logo。您要注意logo与导航位置图标的区别
        toolbar.setLogo(R.mipmap.ic_action_select_all);
        //添加导航位置图标
        toolbar.setNavigationIcon(R.mipmap.img_menu);


注释写的很详细了吧。

Toolbar可以设置 Title(主标题),Subtitle(副标题),Logo(logo图标),NavigationIcon(导航按钮)。

注意 如果你想要通过toolbar.setTitle(“主标题”);设置Toolbar的标题,你必须在调用它之前调用如下代码:

getSupportActionBar().setDisplayShowTitleEnabled(false);
上面代码用来隐藏系统默认的Title,不指定这行代码,代码设置Title是没有任何效果的。

经过如上配置再来看看效果图吧!

技术分享

当然,你也可以通过布局文件来添加同样的效果。个人喜欢使用代码添加。对于布局文件添加,可参考如下:通过app:title属性设置Toolbar的标题,通过app:logo属性设置Toolbar的图标。还可以通过app:titleTextColor属性设置标题文字颜色等等。

那么Toolbar能不能使用Menu菜单功能呢?答案是肯定的了。来看看加载如下menu菜单的Toolbar吧

修改刚才的main_menu.xml中的代码:

<menu 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"
    tools:context=".MainActivity">
    <!--添加一条item-->
    <item
        android:id="@+id/action_edit"
        android:icon="@drawable/ic_action_search"
        android:orderInCategory="80"
        android:title="查找"
        app:showAsAction="always"/>

    <item
        android:id="@+id/action_share"
        android:icon="@drawable/abc_ic_menu_share_mtrl_alpha"
        android:orderInCategory="90"
        android:title="分享"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="设置"
        app:showAsAction="never"/>
</menu>

怎么给menu的各个Item添加点击事件呢?Toolbar给我们提供如下方法

        //事件
        //实现接口(也可以重写onOptionItemSelected()方法实现同样的功能,个人喜欢添加监听器效果)
        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_edit:
                        Toast.makeText(MainActivity.this, "查找按钮", Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.action_share:
                        Toast.makeText(MainActivity.this, "分享按钮", Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.action_settings:
                        Toast.makeText(MainActivity.this, "设置按钮", Toast.LENGTH_SHORT).show();
                        break;
                }
                return false;
            }
        });

至此,Toolbar添加控件就基本完结了,来看看效果如下

技术分享

效果还可以,接下来让我们紧跟脚步。再来修改一下ToolBar的样式:

在style文件中,修改成如下形式的样式:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" 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="android:textColorPrimary">#fafbfb</item>

        <!--Activity窗口的颜色,注意:这个颜色值要通过color属性引进来,否则会报错-->
        <item name="android:windowBackground">@color/windowBackground</item>

        <!--和 colorAccent相反,正常状态下按钮的颜色,如果我们的colorPrimary是深色,一般设置这里为白色-->
        <item name="colorControlNormal">#e1fe05</item>
        <!--Button按钮正常状态颜色,根据项目来定义-->
        <item name="colorButtonNormal">@color/accent_material_light</item>
        <!--EditText 输入框中字体的颜色,colorPrimary如果设置深色,一般字体设置为白色-->
        <item name="editTextColor">@android:color/white</item>
    </style>
</resources>

通过上边修改,样式改为下面的状态:;

技术分享


使用默认导航,返回上一个活动。

导航按钮可以让用户很容易的返回app的主界面,这就能够产生非常好的用户体验。给Toolbar添加导航按钮功能也是非常简单的,通过如下两步即可:
1. 在manifest文件中通过android:parentActivityName属性为Activity配置parent activity
2. 在代码中通过ActionBar.setDisplayHomeAsUpEnabled(true)方法使能导航按钮

下面我们就来实现一下,先做一些准备工作。在首页增加一个按钮;
activity_main.xml :

 <Button
        android:onClick="next"
        android:text="进入下一个活动"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

相当简单,就是增加了一个Button按钮,点击button执行start()方法。
MainActivity.java :

public void next(View view)
{
    Intent i = new Intent(this, ChildActivity.class);
    startActivity(i);
}
方法启动了一个Nextactivity。
Nextactivity.java :

public class NextActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_next);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ActionBar ab = getSupportActionBar();

        //使能app bar的导航功能
        ab.setDisplayHomeAsUpEnabled(true);

    }
}


通过getSupportActionBar()方法得到ActionBar实例;调用ActionBar的setDisplayHomeAsUpEnabled()使能导航功能。

接下来看一下child activity的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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:id="@+id/activity_next"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.itydl.toolbarforcsdn.NextActivity">

    <android.support.v7.widget.Toolbar
        app:title="另一个更活动"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    <TextView
        android:text="这是另一个活动"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

没什么可说的,相信讲过上边的介绍,看起来很简单。

最后,在manifest文件中为ChildActivity指定parent Activity。

<activity
    android:name=".NextActivity"
    android:label="@string/title_activity_child"
    android:parentActivityName=".MainActivity">

    <meta-data
        android:name="android.support.PARENT_ACTIVITY"
        android:value=http://www.mamicode.com/".MainActivity"/>>

通过android:parentActivityName属性指定ChildActivity的parent Activity。注意:meta-data标签是为了兼容android 4.0或者更小的版本。

程序运行效果图:

技术分享

添加ToolBar的子按钮并对所有空间添加点击事件:

在主布局中添加如下代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
        <!--添加Toolbar的子控件-->

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:gravity="center"
            android:text="首页"
            android:textColor="@android:color/holo_red_light"
            android:textSize="20sp" />
    </android.support.v7.widget.Toolbar>

    <!--app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"能够让toobar上边的文字为浅色主题(例如默认白色)
    如果不指定的话,由于我们之前在style中制定了toolbar为浅色主题,那么toobar的文字就是深色主题(例如黑色)-->

    <Button
        android:onClick="next"
        android:text="进入下一个活动"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

最后把主活动中的代码贴一下,相当于对上边知识点做一个汇总

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Toolbar mToolbar;
    private PopupWindow mPopupWindow;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mToolbar = (Toolbar) findViewById(R.id.toolbar);
        //表示ToolBar取代ActionBar
        setSupportActionBar(mToolbar);
        getSupportActionBar().setDisplayShowTitleEnabled(false);
        //设置主标题和颜色
        mToolbar.setTitle("title");
        mToolbar.setTitleTextColor(Color.YELLOW);

        //设置副标题和颜色
        mToolbar.setSubtitle("sub");
        mToolbar.setSubtitleTextColor(Color.parseColor("#80ff0000"));


        //添加导航位置图标,这个图片一般用于点击打开侧边栏,或者点击返回上一个活动。
        mToolbar.setNavigationIcon(R.mipmap.img_menu);


        //事件

        //1、设置NavigationIcon的点击事件,需要放在setSupportActionBar之后设置才会生效,
        //因为setSupportActionBar里面也会setNavigationOnClickListener
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "click NavigationIcon", Toast.LENGTH_SHORT).show();
            }
        });


        //2、Menu控件的点击事件。实现接口(也可以重写onOptionItemSelected()方法实现同样的功能,个人喜欢添加监听器效果)
        mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.action_edit:
                        Toast.makeText(MainActivity.this, "查找按钮", Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.action_share:
                        Toast.makeText(MainActivity.this, "分享按钮", Toast.LENGTH_SHORT).show();
                        break;
                    case R.id.action_settings:
                        popUpMyOverflow();
                        break;
                }
                return true;
            }
        });

        //3、ToolBar里面还可以包含子控件
        mToolbar.findViewById(R.id.tv_title).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(), "点击自定义标题", Toast.LENGTH_SHORT).show();
            }
        });


    }

    /**
     * 弹出自定义的popWindow
     */
    public void popUpMyOverflow() {

        //获取状态栏高度
        Rect frame = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);

        //状态栏高度+toolbar的高度
        int yOffset = frame.top + mToolbar.getHeight();

        if (null == mPopupWindow) {
            //初始化PopupWindow的布局
            View popView = getLayoutInflater().inflate(R.layout.action_overflow_popwindow, null);
            //popView即popupWindow的布局,ture设置focusAble.
            mPopupWindow = new PopupWindow(popView,
                    ViewGroup.LayoutParams.WRAP_CONTENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT, true);
            //必须设置BackgroundDrawable后setOutsideTouchable(true)才会有效
            mPopupWindow.setBackgroundDrawable(new ColorDrawable());
            //点击外部关闭。
            mPopupWindow.setOutsideTouchable(true);
            //设置一个动画。
            mPopupWindow.setAnimationStyle(android.R.style.Animation_Dialog);
            //设置Gravity,让它显示在右上角。
            mPopupWindow.showAtLocation(mToolbar, Gravity.RIGHT | Gravity.TOP, 0, yOffset);
            //设置popupWindow上边控件item的点击监听
            popView.findViewById(R.id.ll_item1).setOnClickListener(this);
            popView.findViewById(R.id.ll_item2).setOnClickListener(this);
            popView.findViewById(R.id.ll_item3).setOnClickListener(this);
        } else {
            mPopupWindow.showAtLocation(mToolbar, Gravity.RIGHT | Gravity.TOP, 0, yOffset);
        }

    }

    //PopupWindow的监听回调事件
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_item1:
                Toast.makeText(getApplicationContext(), "添加好友", Toast.LENGTH_SHORT).show();
                break;
            case R.id.ll_item2:
                Toast.makeText(getApplicationContext(), "发现", Toast.LENGTH_SHORT).show();
                break;
            case R.id.ll_item3:
                Toast.makeText(getApplicationContext(), "发起群聊", Toast.LENGTH_SHORT).show();
                break;
        }
        //点击PopWindow的item后,关闭此PopWindow
        if (null != mPopupWindow && mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //让toolbar的menu显示出来
        getMenuInflater().inflate(R.menu.main_menu, menu);
        return true;
    }

    public void next(View view) {
        Intent intent = new Intent(this, NextActivity.class);
        startActivity(intent);
    }
}

然后是popupwindow的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:background="#000000"
              android:orientation="vertical"
              android:padding="10dp">

    <LinearLayout
        android:id="@+id/ll_item1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center">

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src=http://www.mamicode.com/"@mipmap/icon_user" />>

然后咱再运行看看效果怎么样:

技术分享


下一篇文章会介绍ToolBar更高级的用法,比如添加ActionViiew、添加Action Provider、自定义ToolBar等。

喜欢的朋友点个赞或者关注下博客,支持下楼主~


加群聊技术,Android开发交流群:  497646615


Android Studio精彩案例(七)《ToolBar使用详解<一>》