google推荐使用ToolBar代替ActionBar,同时还设计了Meterial Design的控件能跟他进行交互,但是由于ToolBar需要较高的版本支持,所以如果需要兼容的话,需要使用兼容包appcompat-v7兼容包,而Activity需要继承自AppCompatActivity,然后style需要继承自parent=“Theme.AppCompat.Light.NoActionBar”的风格,这里这种风格会去掉就版本的ActionBar,当然和可以继承Theme.AppCompat的风格,然后再<item name="windowActionBar">false</item>里面去掉。
ToolBar的使用有两种方式,一种是直接作为控件使用,一种是作为ActionBar进行使用。
对于直接使用ToolBar的,就是将ToolBar作为普通控件那样放在布局里面就可以了,但是需要注意的是,如果直接作为控件使用而不进行任何设置,那么ToolBar将是什么都没有的,这点跟将ToolBar作为ActionBar,将ToolBar作为ActionBar使用即使不进行任何设置也会有图标,标题。
对于将ToolBar作为ActionBar使用的情况,需要使用setSupportActionBar(ToolBar),这样ToolBar就可以作为ActionBar使用了,同时注意,ActionBar的menu也就植入ToolBar了,我们对ActionBar的操作也就可以在ToolBar上使用了。
另外,原本的ActionBar的tab模式,这里建议使用Meterial Design的TabLayout进行,这个优化的更好!
另外,这里涉及到一个AppBarLayout控件,这个控件往往包裹着ToolBar,之所以使用他,从google将标题栏统称为app bar可以看出,AppBarLayout可以包裹ToolBar和TabLayout这些控件,而ToolBar仅仅代表标题栏。例如xml如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/third_activity_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
<android.support.design.widget.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlways"
app:tabIndicatorColor="@color/medium_blue"
app:tabSelectedTextColor="@color/medium_blue"
app:tabTextAppearance="@style/TabText"
app:tabTextColor="@color/gray_text"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</android.support.design.widget.CoordinatorLayout>
使用Meterial Design的控件跟ToolBar进行交互已经在之前http://blog.csdn.net/hangeqq685042/article/details/47954429中讲过了,这里不再讲。
下面讲讲使用ToolBar代替ActionBar的过程。
在ToolBar的style设计中,可以使用如下代码进行:
<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>
colorPrimary设置设置标题栏颜色;
colorPrimaryDark设置状态栏颜色;
android:windowBackground设置布局背景;
android:navigationBarColor对导航栏设置背景颜色;
textColorPrimary设置标题颜色
常见的ToolBar使用方式代码一般如下:
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(mToolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true);//返回箭头 mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } });这里
setDisplayHomeAsUpEnabled(true)将使用系统的返回按钮,setNavigationOnClickListener设置返回按钮监听;
setNavigationViewIcon设置返回按钮左边的按钮,同时,这个方法需要在调用过setSupportActionBar(ToolBar)之后调用才有效;
setLogo设置图标;
setDisplayUseLogoEnabled设置图标是否显示。
setTitle设置标题,setSubTitle设置副标题;
setOnMenuItemListener设置最右边的选项按钮监听。
这里注意,最右边按钮是onCreateOptionsMenu中返回的menu。也就是下面代码中item描述的按钮:
<menu xmlns:android=
"http://schemas.android.com/apk/res/android"
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"
/>
这样,app bar常见的menu,tab,title等就实现了。
对于app bar,还有一个需要注意的地方,那就是overflow,当app bar空间不够用的时候,会将原本的控件放在最右边三个点的按钮里面。说到overflow就需要从ActionBar说起,在ActionBar里面,当app bar控件不够的时候会将多出的按钮放在最右边的三个点的按钮里面,这个按钮就是overflow了,但是如果手机有menu按钮,那么overflow就不会显示,所以如果需要overflow一直显示,那么就需要自定义一个Application如下:
public class UIApplication extends Applications{
public void onCreate() { try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if (menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
}
catch (Exception ex) {
// Ignore
}
super.onCreate();
}
可以使用下面的方法让overflow一直显示:
官方做法:
private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class
.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
或者
其他做法:
private void getOverflowMenu() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class
.getDeclaredField("sHasPermanentMenuKey");
if (menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
重写这个方法可以改变OverFlow按钮只显示文字的特性,这里还涉及到一个MenuBuilder类,但是这个类是内部类,这个类可以设置很多特性,如OverFlow的item项的属性,这里应该注意,MenuBuilder.setOptionalIconsVisible就是用于设置图标是否显示的,但是我们不可以直接设置,因为这个类是内部类,所以用的是回调显示,也就是说,可以在onCreateOptionsMenu方法中进行回调,
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {
if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
try {
Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
m.setAccessible(true);
//MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
m.invoke(menu, true);
} catch (Exception e) {
}
}
}
return super.onMenuOpened(featureId, menu);
}
需要特别注意,在使用ActionBar时,如果版本不能高于11,那么需要使用v7兼容包,然后继承ActionBarActivity,然后调用getSupportActionBar方法而不是getActionBar方法,但是使用了ActionBarActivity就意味着需要使用兼容包的theme作为风格,否则就会报错,这点需要特别注意!
最后,需要注意,Activity中的onCreateOptionsMenu与onOptionsItemSelected方法是对应的app bar的item项的,同时由于item项太多而使用overflow的话,那么overflow里面的item项也算是app bar的item项的。这是我容易混淆的地方。
回到ToolBar,使用ToolBar代替ActionBar可知,ToolBar有SearchView,下面是SearchView作为app bar的item项代码:
<
item
android:id
=
"@+id/action_search"
android:icon
=
"@drawable/ic_search"
app:actionViewClass
=
"android.support.v7.widget.SearchView"
app:showAsAction
=
"ifRoom|collapseActionView"
android:inputType
=
"textCapWords"
android:imeOptions
=
"actionSearch"
android:title
=
"search"
/>
下面是代码部分:
public
boolean
onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
MenuItem menuItem = menu.findItem(R.id.action_search);
//在菜单中找到对应控件的item
SearchView searchView = (SearchView) MenuItemCompat.getActionView(menuItem);
Log.d(
"Tag"
,
"menu create"
);
MenuItemCompat.setOnActionExpandListener(menuItem,
new
MenuItemCompat.OnActionExpandListener() {
//设置打开关闭动作监听
@Override
public
boolean
onMenuItemActionExpand(MenuItem item) {
Toast.makeText(MainActivity.
this
,
"onExpand"
, Toast.LENGTH_LONG).show();
return
true
;
}
@Override
public
boolean
onMenuItemActionCollapse(MenuItem item) {
Toast.makeText(MainActivity.
this
,
"Collapse"
, Toast.LENGTH_LONG).show();
return
true
;
}
});
return
super
.onCreateOptionsMenu(menu);
}
另外,ToolBar不作为ActionBar使用时,item项的点击监听使用setOnMenuItemListener方法监听。这点注意!
ToolBar的overflow使用方式跟ActionBar是一样的。目前还没有发现ToolBar的overflow有什么问题。
在Theme.Appcompat.Light风格中,style里面的item项如果添加一个colorAccent,那么所有的控件的强调颜色都可以变成指定的颜色,例如RadioButton的checked状态,EditText的输入状态。另外,在该风格中RadioButton的checked状态是绿色的。另外需要注意的是,backgroundTint这个属性实际上限制非常大,可以不用使用了,因为需要高版本,而且高版本中不同版本支持程度不一样,所以最好不要使用。
在ToolBar的style中,colorPrimary是高版本才能使用的,但是在低版本中,我们可以直接在ToolBar控件下使用android:background="?attr/colorPrimary"引用android内部特征,而这个特征正是style中定义的colorPrimary!
如果想要掌握好ToolBar,其实很大程度上需要参照旧版本的ActionBar,因为google开发出ToolBar很多都是参照ActionBar的。
ToolBar自己的控件风格时可以修改的,这里以修改navigationIcon的图片的缩放方式为例,首先需要在ToolBar的style中添加一项
<item name="toolbarNavigationButtonStyle">@style/myToolbarNavigationButtonStyle</item>这里引用的风格时自定义风格,如下所示:
<style name="myToolbarNavigationButtonStyle" parent="@style/Widget.AppCompat.Toolbar.Button.Navigation"> <item name="android:scaleType">fitCenter</item> </style>这样就能修改navigationIcon的图片的缩放方式了。另外,可以直接在SDK->Extras->android->support-v7->res->values的attrs.xml和styles.xml文件中查看用到的属性。
需要注意,在Toolbar的使用中,控制Toolbar本身的按钮一般都是通过属性以及风格实现的,这里按钮的点击变色需要非常注意,因为ToolBar本身的按钮其实是一个ImageButton,所以其实点击的时候背景使用的是android系统本身的点击变色,也就是背景会有蓝色出现,对于这一点,如果需要更改颜色,那么就需要使用风格控制相应的按钮。
这里返回按钮部分对应的是toolbarNavigationButtonStyle,而overflow按钮对应的是actionOverflowButtonStyle,所有的按钮可以使用actionButtonStyle。在我们的style中添加项:
<item name="toolbarNavigationButtonStyle">@style/NavigationButton</item> <item name="actionButtonStyle">@style/actionButton</item> <item name="actionOverflowButtonStyle">@style/overflowButton</item>然后这里对应的style为:
<style name="actionButton" parent="@style/Widget.AppCompat.ActionButton"> </style> <style name="overflowButton" parent="@style/Widget.AppCompat.ActionButton.Overflow"> </style> <!--修改ToolBar中navigationIcon的风格--> <!--在ToolBar的风格中添加<item name="toolbarNavigationButtonStyle">@style/myToolbarNavigationButtonStyle</item> 可以修改控件风格,这里修改了navigationIcon的图片的对齐方式--> <style name="NavigationButton" parent="@style/Widget.AppCompat.Toolbar.Button.Navigation"> <!--<item name="android:scaleType">fitCenter</item>--> <item name="android:width">50dp</item> <item name="android:height">50dp</item> <item name="android:background">@null</item> </style>
这里需要注意,在NavigationButton中,android:background对应的是按钮的背景,这里设置为null之后,按钮点击就不会变色了!
总的来说就是针对ToolBar中不同的按钮,我们使用不同的item使用不同的style对按钮进行控制。
ps:对于ToolBar如果仅仅作为一个控件在XML中使用时,最左边的控件是无法对其最左边的,也就是说最左边的控件离ToolBar最左边有一定的空隙。我们需要设置app:contentInsetStart="0dp"才可以消除这个间隙,这点需要特别注意!
ps:在AndroidManifest中添加android:parentActivityName可以让ToolBar的返回按钮自动有点击返回上一个Activity的功能。但是如果需要监听这个按钮,需要使用setNavigationOnClickListener()方法。
ps:使用app:maxButtonHeight可以设置ToolBar所有的按钮的高度,但是并没有提供宽度设置,同时这个属性设置高度仅仅是截取,并不能实现像ImageVIew一样的缩放效果,这点需要注意,另外,在在ToolBar高度wrap_content时,app:maxButtonHeight大于56dp时,ToolBar高度会随之变大,但是如果ToolBar指定了高度,那么那么app:maxButtonHeight设置的再大也没用,所以其实这个属性并没有什么用。
ps:ToolBar里面的NavigationIcon等控件如果修改了图片,那么效果并不能像ImageView那样有自动缩放效果,如果尺寸没定好,会出现截取的现象,这点需要注意!
ps:对于ToolBar的高度需要注意,默认是56dp,也就是?attr/actionBarSize的高度。ToolBar添加的控件在ToolBar中是居中对齐的。ToolBar的高度为wrap_content表示高度值大于等于56dp,也就是说添加到ToolBar的控件大于56dp则ToolBar的高度为添加的控件中最高的控件的高度,否则为56dp。ToolBar的高度设置为除56dp之外的值,则无论app:maxButtonHeight怎么设置,ToolBar自身的控件跟ToolBar之间之中都会有间隙,例如NavigationIcon控件。总的来说就是,在ToolBar中添加控件基本可以正常使用,但是如果要使用ToolBar自身的控件则会受到高度56dp的影响!如果需要设置app bar的高度,正确的做法应该是在style里面的item中设置actionBarSize数值,这才是最正确的做法!高度引用?attr/ActionBarSize中?意思是使用android内部特征,从ToolBar使用这个属性作为高度可以看出,我们在style中定义actionBarSize是最正规的做法。
ps:在ToolBar中添加控件,给ToolBar添加android:gravity属性中,bottom属性起作用,而top属性不起作用。
ps:在旧版本的ActionBar里面,在设置getSupportActionBar().setDisplayHomeAsUpEnabled(true)之后,需要在Activity里面设置android:parentActivity之后,然后返回按钮才会生效,但是需要在android 4.0之后才会生效。而在oolBar里面根本就不需要配置android:parentActivity这个属性就可以生效。
ps:对于ToolBar,如果没有在Activity里面设置setSupportActionBar(ToolBar)这个属性,那么ToolBar的点击时不会生效的,控件的点击也就不会变色了,因为这个时候ToolBar就仅仅是一个控件而已!如果需要点击变色以及返回按钮,overflow按钮就必须要加上setSupportActionBar(ToolBar)这个属性,如果返回按钮需要可以返回上一个Activity的话,还需要在AndroidManifest中声明android:parentActivity才行,不然不会返回。