ActionBar vs ToolBar
ToolBar是Android 5.0推出的一个新的导航控件用于取代之前的ActionBar,具有可定制性、灵活性、Material Design风格等优点。官方考虑到仍有一部分用户的手机版本号低于5.0,所以,ToolBar也放进了support v7包内,使得低版本的系统也能使用上ToolBar。
使用Android Studio新创建一个项目的话,默认MainActivity是使用的Toolbar,看一下MainActivity的布局文件
看一下manifest里面对MainActivity的声明
MainActivity声明自己的theme是NoActionBar,表示是没有标题栏,而布局文件中又有ToolBar,toolbar就起到了标题栏的作用。
在onCreate的时候设置如下代码,就可以把ActionBar上的所有操作都转移到ToolBar上。
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
在这个新创建的项目中,可以看一下res/values/colors.xml里面的内容,有三个color值,其中colorPrimary
是标题栏的颜色,colorPrimaryDark
是状态栏的颜色。
在5.0及以上是能设置状态栏的颜色的,在5.0以下状态栏的颜色一般都是黑色。
ActionBar与Theme
1.首先要修改app的主题Theme
MaterialDesign的Theme有:
- @android:style/Theme.Material (dark version)
- @android:style/Theme.Material.Light (light version)
- @android:style/Theme.Material.Light.DarkActionBar
与之对应的Compat Theme有:
- Theme.AppCompat
- Theme.AppCompat.Light
- Theme.AppCompat.Light.DarkActionBar
首先看一下这三个主题的区别
主题
Theme.AppCompat.Light.DarkActionBar
在5.x上是这样的
看到colorPrimary
是标题栏的颜色,看到colorPrimaryDark
是状态栏的颜色
主题
Theme.AppCompat.Light
在5.x上是这样的。看到是如下图。标题栏上的文字的颜色变了。
Theme.AppCompat.NoActionBar
在5.x上是这样的。
在一些定制ROM下,颜色就不一定了。比如说我手边有一台华为Honor,5.x,状态栏始终是绿色的,在任何app下都是。让我一开始的时候忙了半天!😂
Toolbar代替ActionBar
先引入v7包,compile 'com.android.support:appcompat-v7:23.1.1'
设置你自己的应用的主题为 Theme.AppCompat.Light.NoActionBar
,如下方所示
1.先找到AndroidManifest.xml里面
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
>
</application>
2.在styles.xml里面设置
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">#23354A</item>
<item name="colorPrimaryDark">#23354A</item>
<item name="colorAccent">#4092F1</item>
</style>
或者设置成这样
<style name="AppTheme" parent="Theme.AppCompat">
<item name="windowActionBar">false</item>
<!-- 使用 API Level 22 编译的話,要拿掉android前綴 -->
<item name="android:windowNoTitle">true</item>
</style>
3.在布局文件里面加上Toolbar,如下方所示
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/id_toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textColor="@color/black"/>
</LinearLayout>
4.在Activity里面设置toolbar代替actionbar
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.id_toolbar);
setSupportActionBar(toolbar);
}
}
如果没有设置为NoActionBar
主题,直接设置setSupportActionBar(toolbar)
的话,会crash,报下面的错:
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.
5.看一下效果,如下图。额……效果和想象的不一样,标题栏怎么不是上面设置colorPrimary颜色?
设置Toolbar的样式
有两个方法可以设置Toolbar的样式,一个是在代码里面,一个是在布局文件里面。
1.先讲在代码里面设置Toolbar的样式。例如设置NavigationIcon、设置logo、设置title、设置subTitle,设置toolbar的背景颜色等。还可以使用setTitleTextColor
和setTitleTextAppearance
设置标题文字颜色或样式,使用setSubtitleTextColor
和setSubtitleTextAppearance
设置副标题的文字颜色或样式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.id_toolbar);
toolbar.setLogo(R.mipmap.ic_launcher);
toolbar.setTitle("Title");
toolbar.setSubtitle("Sub title");
toolbar.setNavigationIcon(R.drawable.icon_titlebar_navi);
toolbar.setBackgroundResource(R.color.colorPrimary);
setSupportActionBar(toolbar);
}
2.给Toolbar添加几个menu。定义一个menu_mainactivity.xml。如果只设置了title而没有设置icon,那么会显示文字。此处设置app:showAsAction命名空间为app而不是android,是因为showAsAction
属性是在Support v7包里面的,不是原生SDK内部的,故不能使用android作为命名空间。always
表示一定要显示在标题栏上,ifRoom
表示有空间就显示在标题栏上,never
表示不显示在标题栏。不显示在标题栏上的menu,会显示在overflow window中。
<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/menu_phone"
android:title="打电话"
android:icon="@drawable/icon_menu_phone"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_add"
android:title="添加"
android:icon="@drawable/icon_menu_add"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_cancel"
android:title="删除"
android:icon="@drawable/icon_menu_cancel"
app:showAsAction="always">
</item>
</menu>
3.在代码里面设置toolbar的menu文件。在Activity里面重写下面这两个方法。
加载菜单
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_mainactivity, menu);
return super.onCreateOptionsMenu(menu);
}
设置对menu选中的监听
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.menu_phone) {
Toast.makeText(MainActivity.this, "按了打电话", Toast.LENGTH_SHORT).show();
return true;
}
if (id == R.id.menu_add) {
Toast.makeText(MainActivity.this, "按了添加", Toast.LENGTH_SHORT).show();
return true;
}
if (id == R.id.menu_cancel) {
Toast.makeText(MainActivity.this, "按了删除", Toast.LENGTH_SHORT).show();
return true;
}
if (id == R.id.menu_search) {
Toast.makeText(MainActivity.this, "按了查找", Toast.LENGTH_SHORT).show();
return true;
}
if (id == R.id.menu_checkbus) {
Toast.makeText(MainActivity.this, "按了公交", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
看上面的图,最左边是我设置的naviIcon,然后绿色机器人是设置的Logo,然后是title,subtitle,然后是三个menu。
如果menu很多的话,就不能都设置app:showAsAction="always"
属性,这个属性表示是否在标题栏上显示。假如说我有五个menu如下,都设置了显示。那么会变成这个样子,menu把标题都挤没了
<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/menu_phone"
android:title="打电话"
android:icon="@drawable/icon_menu_phone"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_add"
android:title="添加"
android:icon="@drawable/icon_menu_add"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_cancel"
android:title="删除"
android:icon="@drawable/icon_menu_cancel"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_search"
android:title="查找"
android:icon="@drawable/icon_menu_search"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_checkbus"
android:title="公交"
android:icon="@drawable/icon_menu_bus"
app:showAsAction="always">
</item>
</menu>
在显示menu的时候,要注意展示方式,建议使用ifRoom
,假如说把后面四个menu都改成ifRoom的展现方式,那么展现的结果是如下图所示。
可以看到,后面的那些放不下的menu都被缩起来了。点进去看一下,发现几个不满的是:
- 希望overflow window的位置挪到标题栏下边,紧贴着标题栏。
- 那个显示overflow window的三个点的颜色是黑色,看着挺违和,想换换。
- overflow window整个的颜色是白的,希望和标题栏颜色一致。
- overflow window里面只显示了文字。希望能文字和图标一起显示
对于第一个问题,即overflow的三个点的颜色,有两个个办法:
- 第一个办法是
Toolbar toolbar = (Toolbar) findViewById(R.id.id_toolbar);
toolbar.setLogo(R.mipmap.ic_launcher);
toolbar.setTitle("Title");
toolbar.setSubtitle("Sub title");
toolbar.setNavigationIcon(R.drawable.icon_titlebar_navi);
toolbar.setBackgroundResource(R.color.colorPrimary);
toolbar.setOverflowIcon(getResources().getDrawable(R.drawable.icon_more, null));
setSupportActionBar(toolbar);
即代码里面toolbar.setOverflowIcon(getResources().getDrawable(R.drawable.icon_more, null));
设置OverflowIcon
,使用一个图标特换系统的图标。如下图,我特意找了个横着的三点,以示区分。
- 第二个办法是
在Theme里面设置<item name="android:textColorSecondary">#FFFFFF</item>
这个能改变那三个点的颜色
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:textColorSecondary">#FFFFFF</item>
</style>
但是在Theme里面设置textColorSecondary,不仅会影响到Toolbar的颜色,还会影响到其他地方的文字颜色。所以不推荐第二种方法。
第二个问题是overflow window的背景色,我希望和标题栏一样。方法如下:
1.定义一个Theme,里面设置背景颜色。这里设置的是android:colorBackground
,如果设置popupBackground
,则没什么效果。
<style name="MyPopupTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:colorBackground">@color/colorPrimary</item>
</style>
2.将刚刚定义的Theme作为的主题
toolbar.setPopupTheme(R.style.MyPopupTheme);
效果如下:
第三个问题是overflow window的位置,希望在标题栏下面。方法如下:
1.在刚刚定义的Theme里面,(其实上面的Theme不继承任何theme也行的),设置overlapAnchor
为false。那么就到下面去了。
<style name="MyPopupTheme">
<item name="android:colorBackground">@color/colorPrimary</item>
<item name="overlapAnchor">false</item>
</style>
2.仍然是在代码中写上面的toolbar.setPopupTheme(R.style.MyPopupTheme);
效果如下:
在api 21以下,overlapAnchor不需要加android前缀。在21及以上需要加前缀
在自定义的这个MyPopupTheme里面还可以设置overflow window的menu的样式,你如说设置颜色、字体大小等。
<style name="MyPopupTheme">
<item name="android:colorBackground">@color/colorPrimary</item>
<item name="overlapAnchor">false</item>
<item name="android:textColor">#FFFFFF</item>
<item name="android:textSize">20sp</item>
</style>
对于第四个问题,在overflow里面也同时显示图片和文字
在网上找了找,大部分建议的解决办法是,menu里面套menu。注意:套在里面一层menu里的item,不能写成
假如说menu是这样的形式,那么效果如下图:
<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/menu_phone"
android:title="打电话"
android:icon="@drawable/icon_menu_phone"
app:showAsAction="always">
</item>
<item android:id="@+id/menu_add"
android:title="添加"
android:icon="@drawable/icon_menu_add"
app:showAsAction="ifRoom">
</item>
<item android:id="@+id/menu_cancel"
android:title="删除"
android:icon="@drawable/icon_menu_cancel"
app:showAsAction="ifRoom">
</item>
<item
android:id="@+id/menu_test"
android:title="test"
app:showAsAction="ifRoom">
<menu>
<item android:id="@+id/menu_search"
android:title="查找"
android:icon="@drawable/icon_menu_search"
app:showAsAction="ifRoom"/>
<item android:id="@+id/menu_checkbus"
android:title="公交"
android:icon="@drawable/icon_menu_bus"
app:showAsAction="ifRoom"/>
</menu>
</item>
</menu>
点开那个“test”menu之后是这样的。可以看到下一层的menu有icon展现
如果不给“test”这个menu添加title和icon的话,是不是子项就会挪上来呢?然而并不会。。。只留下一个空空的带有展开三角形的menu。展开后的情形在没有父title和icon的情况下,倒是不展示了。
那么加入把所有的menu都包含在一个item里面,那么显示overflow menu的icon的愿望是不是可以实现了呢?试一下。
最外面的壳是一个menu,图标采用的是上面的横着的三点。里面是各个menu子项。
<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/menu_test"
android:title="test"
android:icon="@drawable/icon_more"
app:showAsAction="ifRoom">
<menu>
<item android:id="@+id/menu_phone"
android:title="打电话"
android:icon="@drawable/icon_menu_phone"
app:showAsAction="always"/>
<item android:id="@+id/menu_add"
android:title="添加"
android:icon="@drawable/icon_menu_add"
app:showAsAction="ifRoom"/>
<item android:id="@+id/menu_cancel"
android:title="删除"
android:icon="@drawable/icon_menu_cancel"
app:showAsAction="ifRoom"/>
<item android:id="@+id/menu_search"
android:title="查找"
android:icon="@drawable/icon_menu_search"
app:showAsAction="ifRoom"/>
<item android:id="@+id/menu_checkbus"
android:title="公交"
android:icon="@drawable/icon_menu_bus"
app:showAsAction="ifRoom"/>
</menu>
</item>
</menu>
效果如下。可以看到每个icon都显示出来了。
这样虽然overflow里面的menu都有icon了,可是和我的初衷不符。我希望能在标题栏上显示的就在标题栏显示,在overflow上显示的也能展示icon。这个以后再研究。
Toolbar的标题居中显示
看上面几个图,现在的标题都是靠左的,想要标题居中,除了不使用Toolbar/actionbar自定义标题栏之外,还可以这样:
Toolbar其实是个ViewGroup,在里面是可以放入子视图的。放一个TextView,让它居中。
<android.support.v7.widget.Toolbar
android:id="@+id/id_toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="我是标题"
android:textColor="@color/white"/>
</android.support.v7.widget.Toolbar>
看到原来的title和subtitle还是显示着,此处需要将它隐藏,那么就真正实现了标题居中。
在代码里面,setSupportActionBar
之后加入setDisplayShowTitleEnabled
,就ok了。title和subtitle就都不会显示。
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
AppBarLayout 、Toolbar、TabLayout
AppBarLayout
和TabLayout
都是design这个包里面的,所以使用的时候先要在gradle里面引入 compile 'com.android.support:design:24.1.0'
。否则会报找不到AppBarLayout和TabLayout.
之前写过一篇选项卡视图TabLayout,这里再回忆一下
-
1.首先在gradle里面引入
compile 'com.android.support:design:24.1.0'
-
2.此时定义这样的布局文件。先不把TabLayout放到AppBarLayout里面。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/gray"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
>
<android.support.v7.widget.Toolbar
android:id="@+id/id_toolbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="我是标题"
android:textColor="@color/white"/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.TabLayout
android:id="@+id/id_tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"/>
</LinearLayout>
- 3.在代码里面定义5个tab。
TabLayout tabLayout = (TabLayout) findViewById(R.id.id_tablayout);
tabLayout.addTab(tabLayout.newTab().setText("我是Tab1"));
tabLayout.addTab(tabLayout.newTab().setText("我是Tab2"));
tabLayout.addTab(tabLayout.newTab().setText("我是Tab3"));
tabLayout.addTab(tabLayout.newTab().setText("我是Tab4"));
tabLayout.addTab(tabLayout.newTab().setText("我是Tab5"));
设置tab的文字颜色、指示条的颜色、指示条的高度,将tab扩展成9个tab,看看效果如下:
tabLayout.setSelectedTabIndicatorColor(Color.WHITE);
tabLayout.setSelectedTabIndicatorHeight(20);
// 被选中是是白色,未被选中是是黑色
tabLayout.setTabTextColors(Color.BLACK, Color.WHITE);
看到tab多了之后,tab挤得很小,此时可以设置tabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
,那么tab就可以滚动。效果如下: