Android:Material系列:ActionBar-->Toolbar
去年(2014) 的 google i/o 发表令多数人为之一亮的 material design,而 google 也从「google i/o 2014」 开始,大家也陆陆续续地看到其更新的 android app 皆套用了这个设计介面。当然,这个设计介面著实让大家感到惊艳外,更让 android 开发者开始担心未来 app 的界面处理了。
不过,所幸有着之前 actionbar 的经验后,android 也很快地在 support library 里面提供了相对应的 api 给开发者使用,本篇就为各位介绍 – toolbar,这是用来取代过去 actionbar 的控件,而现在于 material design 中也对之有一个统一名称:app bar,在未来的 android app 中,就以 toolbar 这个元件来实作之。
Toolbar之所以灵活,是因为它其实就是一个ViewGroup,我们在使用的时候和普通的组件一样,在布局文件中声明。
概述
Android 3.0 Android 推了 ActionBar 这个控件,而到了2013 年 Google 开始大力地推动所谓的 android style,想要逐渐改善过去 android 纷乱的界面设计,希望让终端使用者尽可能在 android 手机有个一致的操作体验。ActionBar 过去最多人使用的两大套件就是 ActionBarSherlock 以及官方提供在 support library v 7 里的 AppCompat。
既然会有本篇介绍 Toolbar,也意味着官方在某些程度上认为 ActionBar 限制了 android app 的开发与设计的弹性,而在 material design 也对之做了名称的定义:App bar。接下来将为各位分成几个阶段进行说明,如何在 android app 中用 toolbar 这个控件来做出一个基本的 app bar 喽。
主题使用
使用Toolbar时,如果单纯的当作控件来使用,主题是不需要单独设置的。
但是如果想用他来替代ActionBar,
那么需要配置为Theme.AppCompat.NoActionBar主题,
或者在主题中加入
<item name="windowActionBar">false</item><item name="windowNoTitle">true</item>
(两个都必须有,上一篇已经提到没有windowNoTitle时会报错)
这里推荐使用第一种方式。
常用的配置
Toolbar因为经常被用来替代ActionBar,所以一般项目里都会抽取出来,以便include。
可能有人会说,既然还是用来替换ActionBar,那我项目里直接不动ActionBar不就完了?
对,一般情况下是没有问题的,但是有些界面需要借助Toolbar灵活性的时候,你就被迫要换成Toolbar了。
先来看Toolbar常用代码:
include_toolbar.xml
<?xml version="1.0" encoding="utf-8"?><android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:minHeight="?attr/actionBarSize" />
配置中需要注意的是theme和popupTheme,我们来仔细看下,先从View的theme说起。
View的theme
Android 5.0引入一个全新的特性,允许你对view设置theme,这种设置会影响控件及其包含的子控件。
使用AppCompat v22.1.x 后,也可以给你 layout 里的任意视图设置主题。
只要使用 android:theme 这个属性就好,新版本的兼容库可以在 compat 和 framework 之间无缝地切换功能。
实现原理
这是因为有ContextThemeWrapper类,这个类API v1的时候就有了。
他包裹(wrap)一个存在的Context(这里指你的Activity),之后覆盖(overlay)一个新的主题在当前Context的主题之上,这也是为什么叫ThemeOverlay。
Toolbar常用的ThemeOverlay
- ThemeOverlay.AppCompat.Light.ActionBar
- ThemeOverlay.AppCompat.Dark.ActionBar
android:theme 与 app:theme
在AppCompat v21里,提供了一个快速方便的方法设置Toolbar的主题,使用app:theme。
而新版本22.1.x中,AppCompat 允许对 Toolbar 使用android:theme代替app:theme。
最好的一点是:它会自动继承父视图的theme ,并且兼容所有APIv11以上的设备。
示例:
<Toolbar android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <!-- This TextView inherits its theme from the parent Toolbar --> <TextView android:text="I'm light!" /></Toolbar>
对于运行 API v10 甚至更老的设备来说,你也可以使用android:theme属性, 不过它不会继承父视图theme。
这就意味着你要么重新考虑你的布局,要么为每一个子视图都设置上 android:theme 属性。(这样做效率真的很低)
总结一下:
- 兼容 API 11 以上,推荐使用android:theme
- 如果兼容更老的版本,推荐继续使用app:theme
app:popupTheme
有时候我们有需求:
ActionBar文字是白的,ActionBar Overflow弹出的是白底黑字
让ActionBar文字是白的,那么对应的theme肯定是Dark。
可是让ActionBar弹出的是白底黑字,那么需要Light主题。
这时候popupTheme就派上用场了。
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" android:minHeight="?attr/actionBarSize" />
注意:
使用app:popupTheme=”@style/ThemeOverlay.AppCompat.Light”而不是android:popupTheme
作为ActionBar使用
@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.blah); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar);}
独立使用
@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.blah); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); // Set an OnMenuItemClickListener to handle menu item clicks toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { // Handle the menu item return true; } }); // Inflate a menu to be displayed in the toolbar toolbar.inflateMenu(R.menu.your_toolbar_menu);}
一般使用疑问
1.没有了splitActionBarWhenNarrow,用两个Toolbar模拟是否可以?
不可以,这种方式是有问题的。
两个Toolbar放在布局中后,下面的Toolbar不能顶到最左边。
stackoverflow : How to center action menu on toolbar 中有详细的描述。
问题中给出了SplitToolbar的解决方案,但我尝试后发现这种解决方案仍然有轻微的偏移。
2.使用Toolbar后,NavigationIcon不垂直居中?
NavigationIcon
Toolbar的layout_height属性,要用“?attr/actionBarSize”而不是“?android:attr/actionBarSize”,替换后可解决NavigationIcon不垂直居中的问题。
原因是系统的actionBarSize比AppCompat中的要小。使用“?android:attr/actionBarSize”调用了较小的那个。
ActionMode配置
使用AppCompatActivity启动
需要声明的是,这种方法更加简便一些,有无Toolbar都适合使用。直接在AppCompatActivity或者ActionBarActivity中调用startSupportActionMode启动即可。
注意这里的ActionMode是support包里的ActionMode。
这时如果你运行程序触发ActionMode,可能会看到ActionMode和ActionBar分立成两栏,并没有浮在ActionBar上面。
解决的办法很简单,在主题中加入
<item name="windowActionModeOverlay">true</item>
即可。
给ActionMode配置主题
有些同学使用了Dark主题下的Toolbar,并且主题使用了Theme.AppCompat.Light.NoActionBar,这时候会发现ActionMode是Light主题,很难看。
那么怎么能配置成Dark主题呢?
<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
弹出菜单自定义主题
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
ActionMode背景色替换
<!--action Mode背景--><item name="actionModeBackground">@color/theme_color_action_mode</item>
使用Toolbar启动
代码示例:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);toolbar.startActionMode(mActionModeCallback)
注意这里的ActionMode是view包下的,不是support v7下的。
保证ActionMode浮在ActionBar上及ActionMode背景色替换与上面方式一致,这里不再赘述,请参考上文。
如何实现和Inbox一样的ActionMode
Toolbar_第1张图片" title="" width="650" height="129" style="border:1px solid black;">
可以看到,ActionMode开启时,顶部的Status Bar颜色也跟着改变了
这种功能Theme中并没有提供属性来修改。
但是联想到入门篇提到的代码设置status bar颜色,这里就不难实现了。
代码共享下:
private int mOldStatusBarColor = -1;private void setActionModeStatusBarColor(int colorResId) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mOldStatusBarColor = mActivity.getWindow().getStatusBarColor(); setStatusBarColorCore(mActivity.getResources().getColor(colorResId)); }}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void setStatusBarColorCore(int color) { mActivity.getWindow().setStatusBarColor(color);}private void resetStatusBarColor() { if (mOldStatusBarColor != -1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ setStatusBarColorCore(mOldStatusBarColor); mOldStatusBarColor = -1; }}
开启时调用set,销毁时调用reset即可。
P.S. : 上面的计数可以通过setTitle来完成。
自定义颜色(Customization color)
先看一张图
上图是将本阶段要完成的结果画面做了标示,结合下面的描述希望大家能明白。
colorPrimaryDark(状态栏底色):在风格 (styles) 或是主题 (themes) 里进行设定。
App bar 底色
这个设定分为二,若你的 android app 仍是使用 actionbar ,则直接在风格 (styles) 或是主题 (themes) 里进行设定 colorPrimary 参数即可;
可若是采用 toolbar 的话,则要在界面 (layout) 里面设定 toolbar 控件的 background 属性。
navigationBarColor(导航栏底色):
仅能在 API v21 也就是 Android 5 以后的版本中使用, 因此要将之设定在 res/values-v21/styles.xml 里面。
主视窗底色:windowBackground
也因此在这个阶段,我们需要设定的地方有三,一是 style中(res/values/styles.xml)
<style name="AppTheme.Base" parent="Theme.AppCompat"> <item name="windowActionBar">false</item> <item name="android:windowNoTitle">true</item> <!-- Actionbar color --> <item name="colorPrimary">@color/accent_material_dark</item> <!--Status bar color--> <item name="colorPrimaryDark">@color/accent_material_light</item> <!--Window color--> <item name="android:windowBackground">@color/dim_foreground_material_dark</item></style>
再来是 v21 的style中 (res/values-v21/styles.xml)
<style name="AppTheme" parent="AppTheme.Base"> <!--Navigation bar color--> <item name="android:navigationBarColor">@color/accent_material_light</item> </style>
最后,就是为了本篇的主角 – Toolbar 的 background 进行设定。
<android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_height="?attr/actionBarSize" android:layout_width="match_parent" android:background="?attr/colorPrimary" ></android.support.v7.widget.Toolbar>
在本范例中,toolbar 是设定来在 activity_main.xml,对其设定 background 属性: android:background=”?attr/colorPrimary” ,这样就可以使之延用 Actionbar 的颜色设定喽。
控件 (component)
Toolbar_第2张图片" title="" width="300" height="160" style="border:1px solid black;">
大抵来说,预设常用的几个元素就如图中所示,接着就依序来说明之:
- setNavigationIcon 即设定 up button 的图标,因为 Material 的介面,在 Toolbar这里的 up
button样式也就有別于过去的 ActionBar 哦。 - setLogo APP 的图标。
- setTitle 主标题。
- setSubtitle 副标题。
- setOnMenuItemClickListener 设定菜单各按鈕的动作。
先来看看菜单外的代码,在 MainActivity.java 中:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); // App Logotoolbar.setLogo(R.drawable.ic_launcher);// Titletoolbar.setTitle("My Title");// Sub Titletoolbar.setSubtitle("Sub title"); setSupportActionBar(toolbar); // Navigation Icon 要设定在 setSupoortActionBar 才有作用// 否则会出现 back buttontoolbar.setNavigationIcon(R.drawable.ab_android);
这边要留意的是setNavigationIcon需要放在 setSupportActionBar之后才会生效。
菜单部分,需要先在res/menu/menu_main.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 android:id="@+id/action_edit" android:title="@string/action_edit" android:orderInCategory="80" android:icon="@drawable/ab_edit" app:showAsAction="ifRoom" /> <item android:id="@+id/action_share" android:title="@string/action_edit" android:orderInCategory="90" android:icon="@drawable/ab_share" app:showAsAction="ifRoom" /> <item android:id="@+id/action_settings" android:title="@string/action_settings" android:orderInCategory="100" app:showAsAction="never"/></menu>
再回到MainActivity.java 中加入OnMenuItemClickListener 的监听者:
private Toolbar.OnMenuItemClickListener onMenuItemClick = new Toolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { String msg = ""; switch (menuItem.getItemId()) { case R.id.action_edit: msg += "Click edit"; break; case R.id.action_share: msg += "Click share"; break; case R.id.action_settings: msg += "Click setting"; break; } if(!msg.equals("")) { Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show(); } return true; }};
将onMenuItemClick监听者设置给toolbar
setSupportActionBar(toolbar);...// Menu item click 的监听事件一定要设定在 setSupportActionBar 才有作用toolbar.setOnMenuItemClickListener(onMenuItemClick);
和 setNavigationIcon 一样,需要將之设定在 setSupportActionBar 之后才有作用。
总结
在这样的架构设计下,ToolBar直接成了Layout中可以控制的东西,相对于过去的actionbar来说,设计与可操控性大幅提升。
最后再附上一个界面上常用的属性说明图:
Toolbar_第3张图片" title="" width="168" height="300" style="border:1px solid black;">
这里按照图中从上到下的顺序做个简单的说明:
colorPrimaryDark
状态栏背景色。在 style 的属性中设置。
textColorPrimary
App bar 上的标题与更多菜单中的文字颜色。在 style 的属性中设置。
App bar 的背景色
Actionbar 的背景色设定在 style 中的 colorPrimary。
Toolbar 的背景色在layout文件中设置background属性。
colorAccent
各控制元件(如:check box、switch 或是 radoi) 被勾选 (checked) 或是选定 (selected) 的颜色。
在 style 的属性中设置。colorControlNormal
各控制元件的预设颜色
在 style 的属性中设置
windowBackground
App 的背景色。在 style 的属性中设置
navigationBarColor
导航栏的背景色,但只能用在 API Level 21 (Android 5) 以上的版本
在 style 的属性中设置
最后需要注意的是:使用material主题的时候,必须设定targetSdkVersion = 21,否则界面看起来是模糊的
其他Material适配必备贴
常用效果及实现
How do I use DrawerLayout to display over the ActionBar/Toolbar and under the status bar?
A basic sample which shows how to use SlidingTabLayout to display a custom ViewPager title strip which gives continuous feedback to the user when scrolling.
[Material Design]使用Toolbar + DrawerLayout快速实现高大上菜单侧滑
官方参考App及示例
philm
android-UniversalMusicPlayer
iosched
New Code Samples for Lollipop
参考资料
AppCompat v21 — Material Design for Pre-Lollipop Devices!
Material Design on Android Checklist
Material Design Everywhere: Using AppCompat 21
AppCompat 21实现低版本手机使用Material Design
Theme vs Style
Android 5.x Theme 与 ToolBar 实战
http://www.cnblogs.com/ct2011/p/4493439.html
http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1028/1856.html
http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1118/2006.html
更多相关文章
- Android事件总线之EventBus3.0基本使用
- Android使用第三方字体
- Android实战技巧:使用原始资源文件
- 在Android(安卓)library中不能使用switch-case语句访问资源ID
- 【Android(安卓)4.0】Android(安卓)Icon Set的使用
- Android系列教程之六:TextView小组件的使用--附带超链接和跑马灯
- 箭头函数的基础使用
- NPM 和webpack 的基础使用
- Python list sort方法的具体使用