本文参考博客:
Android5.x 以后谷歌大力推崇 Material Design 设计,有意统一之前 style 风格乱象的情况。上一篇博客我们学习了 ActionBar 的使用,因为以前很多方式都会对 ActionBar 做深度定制,使用起来不是很方便,toolbar 作为 android 5.x 引入的一个新控件,可以理解为是 ActionBar 的升级版,大大扩展了 Actionbar,使用更灵活,不像 actionbar 那么固定,所以单纯使用 ActionBar 已经稍显过时了,它的一些方法已被标注过时。Toolbar 更像是一般的 View 元素,可以被放置在 view 树体系的任意位置,可以应用动画,可以跟着 scrollView 滚动,可以与布局中的其他 view 交互,等总之很强大。。这篇文章来介绍 Android5.x 新特性之 Toolbar 和 Theme 的使用,参考了许多博文,和书籍,在此对其做一个总结,从零开始,教您学会使用 ToolBar。
应用程序中使用 app bar 可有如下优点:
1. 可以显示出用户所处的当前位置;
2. 可以提供一些重要的交互操作,比如搜索 (search) 操作;
3. 可以实现导航功能,让用户快速回到 Home Activity;
本文就主要介绍一下 Android Toolbar 的使用方法。
我们先来看一张图片,因为在下面你会不断地遇到这个图片中的内容
简单解释一下属性意义:
colorPrimaryDark:状态栏的颜色(可用来实现沉浸效果)
colorPrimary:Toolbar 的背景颜色 (xml 中用 android:background="?attr/colorPrimary" 指定)
android:textColorPrimary:Toolbar 中文字的颜色,设置后 Menu Item 的字体颜色也会跟随
colorAccent:EditText 正在输入时,RadioButton 选中时的颜色
windowBackground: 底部导航栏的颜色
app:title="App Title":Toolbar 中的 App Title
app:subtitle="Sub Title" :Toobar 中的小标题
app::drawable/ic_menu_sort_by_size" : 导航图标(注意和 Logo 的区别)
我们从以下几个点了解 Toolbar 的使用
我们从以下几点来一步一步的学习 Toolbar 的使用
Style(风格)
为了能在你的 Activity 中使用 Toolbar,你必须在工程里修改 styles.xml 文件里的主题风格,系统默认如下
- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
- <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
我们还需要隐藏默认的 ActionBar, 否则会报如下错误:
这个主题表示不使用系统的 Actionbar 了,这是第一步。
- Caused by: java.lang.IllegalStateException: 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.
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- >
- </android.support.v7.widget.Toolbar>
- </RelativeLayout>
Activity(代码)
- Toolbar toolbar;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- toolbar = findView(R.id.toolbar);
- setSupportActionBar(toolbar);
- }
代码中通过 findView 找到 Toolbar,然后通过 setSupportActionBar(toolbar); 将 Toolbar 设置为 Activity 的导航栏。
通过上面的三个步骤,你就已经使用了 Support v7 提供的 Toolbar 了。看看那效果图。
是不是感觉很丑?没有一点 MD 设计的风格,而且还有一个问题,为什么跟 Action 有这么大的差距?那么先来穿插的解决这个问题。还要注意点,默认的 title 是项目名称。然后加入 Menu:
步骤如下:
打开 studio 会发现如图所示,没有 Menu 文件:
这时我们需要 Menu 文件,怎么办呢?
做法如下:
点击进去后会出现如下界面:
点击 OK,就创建成功,如图
修改文件名为 main_menu.xml。加入如下代码:
- <?xml version="1.0" encoding="utf-8"?>
- <menu xmlns:android="http://schemas.android.com/apk/res/android">
- <!--添加一条item-->
- <item android:id="@+id/Setting"
- android:title="设置"
- />
- </menu>
然后再主活动引入 menu:
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main_menu,menu);
- return true;
- }
现在再来运行程序:
好了介绍搜玩了如何引入 menu,点击指示图标会显示设置。再回到 toolBar 上来,虽然还是很丑,不过别失望,这仅仅是为了让 Toolbar 正常工作而已,为了让 Toolbar 有 Material Design 风格,我们必须去设置 Toolbar 的主题风格。
我们重新配置系统主题 Theme,修改 styles.xml 代码如下:
- <!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
- <!-- Customize your theme here. -->
- <!--导航栏底色-->
- <item name="colorPrimary">
- #f61d1f1f
- </item>
- <!--状态栏底色-->
- <item name="colorPrimaryDark">
- #0a0909
- </item>
- <!--导航栏上的标题颜色,这里的颜色还可以自己定义喜欢的类型-->
- <item name="android:textColorPrimary">
- #fff
- </item>
- <!--Activity窗口的颜色,注意:这个颜色值要通过color属性引进来-->
- <item name="android:windowBackground">
- @color/windowBackground
- </item>
- <!--按钮选中或者点击获得焦点后的颜色-->
- <item name="colorAccent">
- #00ff00
- </item>
- <!--和 colorAccent相反,正常状态下按钮的颜色,如果我们的colorPrimary是深色,一般设置这里为白色-->
- <item name="colorControlNormal">
- #fff
- </item>
- <!--Button按钮正常状态颜色,根据项目来定义-->
- <item name="colorButtonNormal">
- @color/accent_material_light
- </item>
- <!--EditText 输入框中字体的颜色,colorPrimary如果设置深色,一般字体设置为白色-->
- <item name="editTextColor">
- @android:color/white
- </item>
- </style>
各个属性就不解释了,注释都很清楚。你可以对着文章开头的那张图片理解一下上边都对应了手机屏幕的哪个位置的。我们来看看 Toolbar 怎么使用这些主题吧?
配置 activity_main.xml 中的 Toolbar 改成为如下:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:background="?attr/colorPrimary"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- app:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
- >
- </android.support.v7.widget.Toolbar>
- </RelativeLayout>
- 首先。app定义了命名空间,主要目的是为了兼容低版本也是用MD效果的。
- 然后:
它表示我这个 ToolBar 的整个样式。使用? attr 表示全引用,整个自定义样式里面的内容都对我的 tooBar 生效。表示根据屏幕的分辨率采用系统默认的高度。
- android:background="?attr/colorPrimary"
- 为了在你的UI中使用Toolbar,你得为每个activity布局添加Toolbar,并且给Toolbar设置一个id android:id="@+id/toolbar"。这是第二。
- 代码添加toobar
注释写的很详细了吧。
- getSupportActionBar().setDisplayShowTitleEnabled(false);
- toolbar.setTitle("主标题");
- toolbar.setSubtitle("副标题");
- //还可以代码设置标题颜色
- toolbar.setSubtitleTextColor(Color.WHITE);
- //设置logo。您要注意logo与导航位置图标的区别
- toolbar.setLogo(R.mipmap.ic_action_select_all);
- //添加导航位置图标
- toolbar.setNavigationIcon(R.mipmap.img_menu);
Toolbar 可以设置 Title(主标题),Subtitle(副标题),Logo(logo 图标),NavigationIcon(导航按钮)。
注意 如果你想要通过 toolbar.setTitle("主标题"); 设置 Toolbar 的标题,你必须在调用它之前调用如下代码:
上面代码用来隐藏系统默认的 Title,不指定这行代码,代码设置 Title 是没有任何效果的。
- getSupportActionBar().setDisplayShowTitleEnabled(false);
经过如上配置再来看看效果图吧!
当然,你也可以通过布局文件来添加同样的效果。个人喜欢使用代码添加。对于布局文件添加,可参考如下:通过 app:title 属性设置 Toolbar 的标题,通过 app:logo 属性设置 Toolbar 的图标。还可以通过 app:titleTextColor 属性设置标题文字颜色等等。
那么 Toolbar 能不能使用 Menu 菜单功能呢?答案是肯定的了。来看看加载如下 menu 菜单的 Toolbar 吧
修改刚才的 main_menu.xml 中的代码:
怎么给 menu 的各个 Item 添加点击事件呢?Toolbar 给我们提供如下方法
- <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-->
- <item
- android:id="@+id/action_edit"
- android:icon="@drawable/ic_action_search"
- android:orderInCategory="80"
- android:title="查找"
- app:showAsAction="always"/>
- <item
- android:id="@+id/action_share"
- android:icon="@drawable/abc_ic_menu_share_mtrl_alpha"
- android:orderInCategory="90"
- android:title="分享"
- app:showAsAction="ifRoom"/>
- <item
- android:id="@+id/action_settings"
- android:orderInCategory="100"
- android:title="设置"
- app:showAsAction="never"/>
- </menu>
- //事件
- //实现接口(也可以重写onOptionItemSelected()方法实现同样的功能,个人喜欢添加监听器效果)
- toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_edit:
- Toast.makeText(MainActivity.this, "查找按钮", Toast.LENGTH_SHORT).show();
- break;
- case R.id.action_share:
- Toast.makeText(MainActivity.this, "分享按钮", Toast.LENGTH_SHORT).show();
- break;
- case R.id.action_settings:
- Toast.makeText(MainActivity.this, "设置按钮", Toast.LENGTH_SHORT).show();
- break;
- }
- return false;
- }
- });
效果还可以,接下来让我们紧跟脚步。再来修改一下 ToolBar 的样式:
在 style 文件中,修改成如下形式的样式:
- <resources>
- <!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
- <!-- Customize your theme here. -->
- <!--导航栏底色-->
- <item name="colorPrimary">
- @color/colorPrimary
- </item>
- <!--状态栏底色-->
- <item name="colorPrimaryDark">
- @color/colorPrimaryDark
- </item>
- <!--按钮选中或者点击获得焦点后的颜色-->
- <item name="colorAccent">
- @color/colorAccent
- </item>
- <!--导航栏上的标题颜色,这里的颜色还可以自己定义喜欢的类型-->
- <item name="android:textColorPrimary">
- #fafbfb
- </item>
- <!--Activity窗口的颜色,注意:这个颜色值要通过color属性引进来,否则会报错-->
- <item name="android:windowBackground">
- @color/windowBackground
- </item>
- <!--和 colorAccent相反,正常状态下按钮的颜色,如果我们的colorPrimary是深色,一般设置这里为白色-->
- <item name="colorControlNormal">
- #e1fe05
- </item>
- <!--Button按钮正常状态颜色,根据项目来定义-->
- <item name="colorButtonNormal">
- @color/accent_material_light
- </item>
- <!--EditText 输入框中字体的颜色,colorPrimary如果设置深色,一般字体设置为白色-->
- <item name="editTextColor">
- @android:color/white
- </item>
- </style>
- </resources>
通过上边修改,样式改为下面的状态:;
导航按钮可以让用户很容易的返回 app 的主界面,这就能够产生非常好的用户体验。给 Toolbar 添加导航按钮功能也是非常简单的,通过如下两步即可:
1. 在 manifest 文件中通过 android:parentActivityName 属性为 Activity 配置 parent activity
2. 在代码中通过 ActionBar.setDisplayHomeAsUpEnabled(true) 方法使能导航按钮
下面我们就来实现一下,先做一些准备工作。在首页增加一个按钮;
activity_main.xml :
- <Button
- android:onClick="next"
- android:text="进入下一个活动"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
相当简单,就是增加了一个 Button 按钮,点击 button 执行 start() 方法。
MainActivity.java :
- public void next(View view)
- {
- Intent i = new Intent(this, ChildActivity.class);
- startActivity(i);
- }
方法启动了一个 Nextactivity。
Nextactivity.java :
- public class NextActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_next);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- ActionBar ab = getSupportActionBar();
- //使能app bar的导航功能
- ab.setDisplayHomeAsUpEnabled(true);
- }
- }
通过 getSupportActionBar() 方法得到 ActionBar 实例;调用 ActionBar 的 setDisplayHomeAsUpEnabled() 使能导航功能。
接下来看一下 child activity 的布局文件
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- 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"
- android:id="@+id/activity_next"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.itydl.toolbarforcsdn.NextActivity">
- <android.support.v7.widget.Toolbar
- app:title="另一个更活动"
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
- app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
- <TextView
- android:text="这是另一个活动"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
- </LinearLayout>
没什么可说的,相信讲过上边的介绍,看起来很简单。
最后,在 manifest 文件中为 ChildActivity 指定 parent Activity。
- <activity
- android:name=".NextActivity"
- android:label="@string/title_activity_child"
- android:parentActivityName=".MainActivity">
- <meta-data
- android:name="android.support.PARENT_ACTIVITY"
- android:value=".MainActivity"/>
- </activity>
通过 android:parentActivityName 属性指定 ChildActivity 的 parent Activity。注意:meta-data 标签是为了兼容 android 4.0 或者更小的版本。
程序运行效果图:
添加 ToolBar 的子按钮并对所有空间添加点击事件:
在主布局中添加如下代码:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:orientation="vertical"
- android:id="@+id/activity_main"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
- <android.support.v7.widget.Toolbar
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
- app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
- app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
- <!--添加Toolbar的子控件-->
- <TextView
- android:id="@+id/tv_title"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:gravity="center"
- android:text="首页"
- android:textColor="@android:color/holo_red_light"
- android:textSize="20sp" />
- </android.support.v7.widget.Toolbar>
- <!--app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"能够让toobar上边的文字为浅色主题(例如默认白色)
- 如果不指定的话,由于我们之前在style中制定了toolbar为浅色主题,那么toobar的文字就是深色主题(例如黑色)-->
- <Button
- android:onClick="next"
- android:text="进入下一个活动"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- </LinearLayout>
最后把主活动中的代码贴一下,相当于对上边知识点做一个汇总
- public class MainActivity extends AppCompatActivity implements View.OnClickListener {
- private Toolbar mToolbar;
- private PopupWindow mPopupWindow;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mToolbar = (Toolbar) findViewById(R.id.toolbar);
- //表示ToolBar取代ActionBar
- setSupportActionBar(mToolbar);
- getSupportActionBar().setDisplayShowTitleEnabled(false);
- //设置主标题和颜色
- mToolbar.setTitle("title");
- mToolbar.setTitleTextColor(Color.YELLOW);
- //设置副标题和颜色
- mToolbar.setSubtitle("sub");
- mToolbar.setSubtitleTextColor(Color.parseColor("#80ff0000"));
- //添加导航位置图标,这个图片一般用于点击打开侧边栏,或者点击返回上一个活动。
- mToolbar.setNavigationIcon(R.mipmap.img_menu);
- //事件
- //1、设置NavigationIcon的点击事件,需要放在setSupportActionBar之后设置才会生效,
- //因为setSupportActionBar里面也会setNavigationOnClickListener
- mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Toast.makeText(getApplicationContext(), "click NavigationIcon", Toast.LENGTH_SHORT).show();
- }
- });
- //2、Menu控件的点击事件。实现接口(也可以重写onOptionItemSelected()方法实现同样的功能,个人喜欢添加监听器效果)
- mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_edit:
- Toast.makeText(MainActivity.this, "查找按钮", Toast.LENGTH_SHORT).show();
- break;
- case R.id.action_share:
- Toast.makeText(MainActivity.this, "分享按钮", Toast.LENGTH_SHORT).show();
- break;
- case R.id.action_settings:
- popUpMyOverflow();
- break;
- }
- return true;
- }
- });
- //3、ToolBar里面还可以包含子控件
- mToolbar.findViewById(R.id.tv_title).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Toast.makeText(getApplicationContext(), "点击自定义标题", Toast.LENGTH_SHORT).show();
- }
- });
- }
- /**
- * 弹出自定义的popWindow
- */
- public void popUpMyOverflow() {
- //获取状态栏高度
- Rect frame = new Rect();
- getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
- //状态栏高度+toolbar的高度
- int yOffset = frame.top + mToolbar.getHeight();
- if (null == mPopupWindow) {
- //初始化PopupWindow的布局
- View popView = getLayoutInflater().inflate(R.layout.action_overflow_popwindow, null);
- //popView即popupWindow的布局,ture设置focusAble.
- mPopupWindow = new PopupWindow(popView,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT, true);
- //必须设置BackgroundDrawable后setOutsideTouchable(true)才会有效
- mPopupWindow.setBackgroundDrawable(new ColorDrawable());
- //点击外部关闭。
- mPopupWindow.setOutsideTouchable(true);
- //设置一个动画。
- mPopupWindow.setAnimationStyle(android.R.style.Animation_Dialog);
- //设置Gravity,让它显示在右上角。
- mPopupWindow.showAtLocation(mToolbar, Gravity.RIGHT | Gravity.TOP, 0, yOffset);
- //设置popupWindow上边控件item的点击监听
- popView.findViewById(R.id.ll_item1).setOnClickListener(this);
- popView.findViewById(R.id.ll_item2).setOnClickListener(this);
- popView.findViewById(R.id.ll_item3).setOnClickListener(this);
- } else {
- mPopupWindow.showAtLocation(mToolbar, Gravity.RIGHT | Gravity.TOP, 0, yOffset);
- }
- }
- //PopupWindow的监听回调事件
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.ll_item1:
- Toast.makeText(getApplicationContext(), "添加好友", Toast.LENGTH_SHORT).show();
- break;
- case R.id.ll_item2:
- Toast.makeText(getApplicationContext(), "发现", Toast.LENGTH_SHORT).show();
- break;
- case R.id.ll_item3:
- Toast.makeText(getApplicationContext(), "发起群聊", Toast.LENGTH_SHORT).show();
- break;
- }
- //点击PopWindow的item后,关闭此PopWindow
- if (null != mPopupWindow && mPopupWindow.isShowing()) {
- mPopupWindow.dismiss();
- }
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- //让toolbar的menu显示出来
- getMenuInflater().inflate(R.menu.main_menu, menu);
- return true;
- }
- public void next(View view) {
- Intent intent = new Intent(this, NextActivity.class);
- startActivity(intent);
- }
- }
然后是 popupwindow 的布局:然后咱再运行看看效果怎么样:
来源: