前言:本文的重头戏在第4部分,主要讲解新手接触Toolbar时遇到的困惑和如何随心所欲地定制Toolbar,例如,
. 如何正确地使用Toolbar
. xml中设置属性无效
. 导航按钮的间距问题
. 自定义标题文字的大小和颜色
. 自定义ActoinView的文字大小和颜色
. 自定义溢出菜单的弹出窗口的背景、弹出位置
. 标题居中
...
Toolbar是Android5.0(API 21)引入的,取代之前的ActionBar,它的本质是一个View,使用起来更加灵活,功能也更加强大。Toolbar的组成如下:
①为Toolbar,继承ViewGroup,是个普通的容器。
②为导航按钮,类型为ImageButton,可设置点击事件,用于返回上个页面或者滑出侧滑菜单。
xml属性:app:navigationIcon 对应方法:setNavigationIcon(Drawable d) ,setNavigationIcon(int resId)
③为Logo展示图,类型为ImageView,不响应事件,仅仅作为展示。
xml属性:app:logo 对应方法:setLogo(Drawable d) ,setLogo(int resId)
④为主标题,类型为TextView
xml属性:app:title 对应方法:setTitle(CharSequence title),setTitle(int resId)
⑤为副标题,类型为TextView
xml属性:app:subtitle 对应方法:setSubtitle(CharSequence title),setSubtitle(int resId)
⑥为普通子View,标题和ActionMenuView之间是留给我们添加子View的区域
⑦为ActionMenuView,负责管理选项菜单
Toolbar的高度我们使用当前主题下ActionBar的高度,Toolbar默认没有背景,通常使用@color/colorPrimary
//像获取普通控件那样获取Toolbar
mToolbar = (Toolbar) findViewById(R.id.toolbar);
//以下四个方法分别用来设置导航按钮、Logo、主标题和副标题
//如果xml文件中没有设置这些属性或者想覆盖xml文件中设置的值可调用这些方法
mToolbar.setNavigationIcon(R.drawable.nav_icon);
mToolbar.setLogo(R.drawable.logo_icon);
mToolbar.setTitle("主标题");
mToolbar.setSubtitle("副标题");
//设置导航按钮的点击事件
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击了导航按钮!", Toast.LENGTH_SHORT).show();
}
});
//生成选项菜单
mToolbar.inflateMenu(R.menu.action_menu_main);
//设置选项菜单的菜单项的点击事件
mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(MainActivity.this, "点击了菜单项" + item.getTitle(), Toast.LENGTH_SHORT).show();
return true;
}
});
//获取选项菜单,可增加,减少菜单项
Menu menu = mToolbar.getMenu();
menu.add("测试菜单项");
menu.removeItem(R.id.item_04);
//设置溢出菜单的icon,显示、隐藏溢出菜单弹出的窗口
mToolbar.setOverflowIcon(ContextCompat.getDrawable(this,android.R.drawable.ic_menu_more));
mToolbar.showOverflowMenu();
mToolbar.dismissPopupMenus();
选项菜单如下:
看一下运行效果:
①如何正确地使用Toolbar
Toolbar是Android5.0(API 21)引入的,为了兼容低版本,我们不要使用android.widget.Toolbar,而是android.support.v7.widget.Toolbar。v7库最低兼容API 7,咱们一般的应用兼容到API 15足够,即便是开发第三方SDK,一般也只兼容到API 10,所以我们完全不用担心低版本的兼容问题。
Toolbar也可以如此使用,转化成ActionBar
setSupportActionBar(mToolbar);
这样一来,选项菜单就得按照之前ActionBar的方式设置,在Activity中重写下列方法,
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_menu_main,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText(MainActivity.this, "点击了菜单项" + item.getTitle(), Toast.LENGTH_SHORT).show();
return true;
}
Toolbar的出现就是为了取代ActionBar,所以我们强烈建议不要按上述方式使用Toolbar,将其与ActionBar纠缠在一起。Toolbar无论在灵活上、功能上都把AcionBar甩好几条街。交织在一起,使用不当的话,反而引入稀奇古怪的Bug,真是得不偿失。
②.xml中设置属性无效
上面的设置中,id,layout_width,layout_height,background有效,而后四个属性无效。解决办法是将后四个属性的命名空间改成app。
这是为什么?
前四个属性是非兼容库中SDK本身就有的属性,他们的命名空间是android,而后四个属性是Toolbar的专有属性,我们使用的是支持库中的Toolbar,所以要用自定义命名空间,所以需要使用app。
Toolbar的布局规则:默认状况下,上下左右的内边距皆为0,导航按钮和选项菜单分别紧靠Toolbar的左右两端,其他内容插入他们二者之间。
我们去主题中看一下导航按钮的默认样式,
显示导航图标的ImageButton本身是紧靠Toolbar左边缘,无外边距的,不过它的最小宽度是56dp,缩放类型为只居中不缩放,所以在视觉效果上,跟Toolbar边缘有一定距离。有的时候这种距离并不合适,我们可以这样改变它。
第一步,自定义一个样式
我们把ImageButton的最小宽度设为0。如果美工切给你的图本身周边有空白的透明区域,你可以把左右内边距设置为0或其他合适的值进行调整。如果没有,设置为16dp即可。
不要通过给ImageButton设置外边距的方式形成间距,虽然视觉效果一样,但是导航按钮是响应用户点击的,内边距依然是View的一部分,依然在响应触碰的范围内,这样用户的体验较好,避免图标过小时,用户“不易”触发点击事件。
其他内容插入导航按钮和选项菜单之间时,受四个xml属性的影响:contentInsetStart、contentInsetStartWithNavigation、contentInsetEnd、contentInsetEndWithActions;
contentInsetStart默认值为16dp,contentInsetStartWithNavigation默认值为72dp,其他两个属性的默认值为0。
导航按钮存在,内容插入的左间距取contentInsetStart和contentInsetStartWithNavigation的最大值,否则取contentInsetStart的值。
也就是说contentInsetStartWithNavigation只在导航按钮存在时有效,contentInsetStart无论是否存在都有效。
同理,选项菜单存在,内容插入的右间距取contentInsetEnd和contentInsetEndWithActions的最大值,否则取contentInsetEnd的值。
也就是说,contentInsetEndWithActions只在选项菜单存在时有效,contentInsetEnd无论是否存在都有效。
所以,如果改变导航按钮右间距,只需如此设置,
因为前面我们已经给导航按钮设置了16dp的右内边距,所以这里设为0dp就可以了。
④.标题文字的大小和颜色
以主标题为例,如果仅需改变字体颜色,可以通过app:titleTextColor="#ffffff"设置。如果需要改变大小,自定义一个样式,
⑤.定制Toolbar选项菜单项
选项菜单项在Toolbar上显示时,有可能是图标,也有可能是文字,我们可以自定义他们的字体大小,颜色以及他们之间的间距。先看看它的默认样式,
values-v21
自定义一个样式,
注意,在API 21以下,资源文件定义了paddingLeft和paddingRight,API 21及以上定义了paddingStart和paddingEnd,这里为了适配同时指定了四个属性。字体颜色在这里指定是无效的,需在主题中指定android:actionMenuTextColor的值。
在主题中使用该样式,并指定android:actionMenuTextColor的值,
⑥.溢出按钮的样式
溢出按钮的样式,通过在主题中设置android:actionOverflowButtonStyle来指定,不过一般我们不会自定义它的样式,另外,通过代码可以替换溢出按钮的图标,setOverflowIcon(Drawable d)
看看默认样式,
自定义样式,
在主题中指定使用该样式,
⑧标题居中问题
很少有产品经理设计标题居中的了,但如果有,可以如此解决,
效果如下,
package coder.zzq.toolbardemo;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import programmer.zzq.toolbardemo.R;
public class MainActivity extends AppCompatActivity {
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//像获取普通控件那样获取Toolbar
mToolbar = (Toolbar) findViewById(R.id.toolbar);
//以下四个方法分别用来设置导航按钮、Logo、主标题和副标题
//如果xml文件中没有设置这些属性或者想覆盖xml文件中设置的值可调用这些方法
mToolbar.setNavigationIcon(R.drawable.nav_icon);
mToolbar.setLogo(R.drawable.logo_icon);
mToolbar.setTitle("主标题");
mToolbar.setSubtitle("副标题");
//设置导航按钮的点击事件
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "点击了导航按钮!", Toast.LENGTH_SHORT).show();
}
});
//生成选项菜单
mToolbar.inflateMenu(R.menu.action_menu_main);
//设置选项菜单的菜单项的点击事件
mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(MainActivity.this, "点击了菜单项" + item.getTitle(), Toast.LENGTH_SHORT).show();
return true;
}
});
//获取选项菜单,可增加,减少菜单项
Menu menu = mToolbar.getMenu();
menu.add("测试菜单项");
menu.removeItem(R.id.item_04);
//设置溢出菜单的icon,显示、隐藏溢出菜单弹出的窗口
mToolbar.setOverflowIcon(ContextCompat.getDrawable(this,android.R.drawable.ic_menu_more));
mToolbar.showOverflowMenu();
mToolbar.dismissPopupMenus();
}
}
布局文件
样式资源
最终的运行效果:
后期追加:
有的时候,我们想要显示溢出菜单项的图标,就像微信这样:
通过一行代码即可实现:
((MenuBuilder) mToolbar.getMenu()).setOptionalIconsVisible(true);
布局文件:
菜单资源:
主题设置: