来源: http://blog.csdn.net/wangyanguiyiyang
目录(?)[+]
去年(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">falseitem>
<item name="windowNoTitle">trueitem>
(两个都必须有,上一篇已经提到没有windowNoTitle时会报错)
这里推荐使用第一种方式。
Toolbar因为经常被用来替代ActionBar,所以一般项目里都会抽取出来,以便include。
可能有人会说,既然还是用来替换ActionBar,那我项目里直接不动ActionBar不就完了?
对,一般情况下是没有问题的,但是有些界面需要借助Toolbar灵活性的时候,你就被迫要换成Toolbar了。
先来看Toolbar常用代码:
include_toolbar.xml
<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说起。
Android 5.0引入一个全新的特性,允许你对view设置theme,这种设置会影响控件及其包含的子控件。
使用AppCompat v22.1.x 后,也可以给你 layout 里的任意视图设置主题。
只要使用 android:theme 这个属性就好,新版本的兼容库可以在 compat 和 framework 之间无缝地切换功能。
这是因为有ContextThemeWrapper类,这个类API v1的时候就有了。
他包裹(wrap)一个存在的Context(这里指你的Activity),之后覆盖(overlay)一个新的主题在当前Context的主题之上,这也是为什么叫ThemeOverlay。
在AppCompat v21里,提供了一个快速方便的方法设置Toolbar的主题,使用app:theme。
而新版本22.1.x中,AppCompat 允许对 Toolbar 使用android:theme代替app:theme。
最好的一点是:它会自动继承父视图的theme ,并且兼容所有APIv11以上的设备。
示例:
<Toolbar
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<TextView android:text="I'm light!" />
Toolbar>
对于运行 API v10 甚至更老的设备来说,你也可以使用android:theme属性, 不过它不会继承父视图theme。
这就意味着你要么重新考虑你的布局,要么为每一个子视图都设置上 android:theme 属性。(这样做效率真的很低)
总结一下:
有时候我们有需求:
ActionBar文字是白的,ActionBar Overflow弹出的是白底黑字
让ActionBar文字是白的,那么对应的theme肯定是Dark。
可是让ActionBar弹出的是白底黑字,那么需要Light主题。
这时候popupTheme就派上用场了。
.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
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.blah);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
@Override
public 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);
}
不可以,这种方式是有问题的。
两个Toolbar放在布局中后,下面的Toolbar不能顶到最左边。
stackoverflow : How to center action menu on toolbar 中有详细的描述。
问题中给出了SplitToolbar的解决方案,但我尝试后发现这种解决方案仍然有轻微的偏移。
NavigationIcon
Toolbar的layout_height属性,要用“?attr/actionBarSize”而不是“?android:attr/actionBarSize”,替换后可解决NavigationIcon不垂直居中的问题。
原因是系统的actionBarSize比AppCompat中的要小。使用“?android:attr/actionBarSize”调用了较小的那个。
需要声明的是,这种方法更加简便一些,有无Toolbar都适合使用。直接在AppCompatActivity或者ActionBarActivity中调用startSupportActionMode启动即可。
注意这里的ActionMode是support包里的ActionMode。
这时如果你运行程序触发ActionMode,可能会看到ActionMode和ActionBar分立成两栏,并没有浮在ActionBar上面。
解决的办法很简单,在主题中加入
<item name="windowActionModeOverlay">trueitem>
即可。
有些同学使用了Dark主题下的Toolbar,并且主题使用了Theme.AppCompat.Light.NoActionBar,这时候会发现ActionMode是Light主题,很难看。
那么怎么能配置成Dark主题呢?
- "actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar
<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Lightitem>
<item name="actionModeBackground">@color/theme_color_action_modeitem>
代码示例:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.startActionMode(mActionModeCallback)
注意这里的ActionMode是view包下的,不是support v7下的。
保证ActionMode浮在ActionBar上及ActionMode背景色替换与上面方式一致,这里不再赘述,请参考上文。
可以看到,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来完成。
先看一张图
上图是将本阶段要完成的结果画面做了标示,结合下面的描述希望大家能明白。
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)
再来是 v21 的style中 (res/values-v21/styles.xml)
<style name="AppTheme" parent="AppTheme.Base">
--Navigation bar color-->
<item name="android:navigationBarColor">@color/accent_material_light
style>
最后,就是为了本篇的主角 – Toolbar 的 background 进行设定。
.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:background="?attr/colorPrimary" >
.support.v7.widget.Toolbar>
在本范例中,toolbar 是设定来在 activity_main.xml,对其设定 background 属性: android:background=”?attr/colorPrimary” ,这样就可以使之延用 Actionbar 的颜色设定喽。
大抵来说,预设常用的几个元素就如图中所示,接着就依序来说明之:
先来看看菜单外的代码,在 MainActivity.java 中:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
// App Logo
toolbar.setLogo(R.drawable.ic_launcher);
// Title
toolbar.setTitle("My Title");
// Sub Title
toolbar.setSubtitle("Sub title");
setSupportActionBar(toolbar);
// Navigation Icon 要设定在 setSupoortActionBar 才有作用
// 否则会出现 back button
toolbar.setNavigationIcon(R.drawable.ab_android);
这边要留意的是setNavigationIcon需要放在 setSupportActionBar之后才会生效。
菜单部分,需要先在res/menu/menu_main.xml左定义:
再回到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来说,设计与可操控性大幅提升。
最后再附上一个界面上常用的属性说明图:
这里按照图中从上到下的顺序做个简单的说明:
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,否则界面看起来是模糊的
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快速实现高大上菜单侧滑
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