Material Design 实战 之第一弹——Toolbar详解
本模块共有六篇文章,参考郭神的《第一行代码》,对Material Design的学习做一个详细的笔记,大家可以一起交流一下:
- Material Design 实战 之第一弹——Toolbar(即本文)
- Material Design 实战 之第二弹——滑动菜单详解&实战
- Material Design 实战 之第三弹—— 悬浮按钮和可交互提示(FloatingActionButton & Snackbar & CoordinatorLayout)
- Material Design 实战 之第四弹 —— 卡片布局以及灵动的标题栏(CardView & AppBarLayout)
- Material Design 实战 之第五弹 —— 下拉刷新(SwipeRefreshLayout)
- Material Design 实战 之 第六弹 —— 可折叠式标题栏(CollapsingToolbarLayout) & 系统差异型的功能实现(充分利用系统状态栏空间)
写在文首,什么是Material Design?这里参考一下郭神的说法:
文章提要与总结
1. 关于android:theme的详细理解(附图); (运用:使用Toolbar代替ActionBar时,须将Theme.AppCompat.Light.DarkActionBar改成Theme.AppCompat.Light.NoActionBar) 2. 在activity_main.xml中使用Toolbar代替ActionBar; 关于命名空间:android app; 关于Toolbar控件的属性; 尤其android:theme以及app:popupTheme的用法理解; 3. 关于activity.android:label; 4. 通过Menu resource file菜单文件式(同时为xml格式)来为Toolbar添加action按钮; 文件中: <item>标签来定义action按钮, android:id用于指定按钮的id, android:icon用于指定按钮的图标, android:title用于指定按钮的文字; 使用app:showAsAction来指定按钮的显示位置,再次使用了app命名空间,同样是为了能够兼容低版本的系统; showAsAction的几种选值:always ifRoom never 注意, Toolbar中的action按钮只会显示图标, 菜单中的action按钮只会显示文字; 5. onCreateOptionsMenu()加载描述Toolbar的action按钮的Menu resource file; onOptionsItemSelected()方法中处理各个按钮的点击事件;
正文
关于Toolbar
Toolbar相关于ActionBar;
不过ActionBar由于其设计原因,被限定只能位于活动的顶部,从而不能实现一些Material Design的效果,因此官方现在已经不建议
使用ActionBar了。
首先要知道,任何一个新建的项目默认都是会显示ActionBar的。
ActionBar是根据项目中指定的主题来显示,
打开AndroidManifest.xml文件:
可以看到这里用android:theme指定了一个AppTheme的主题。
打开res/values/styles.xml文件可以查看其定义出处:
这里定义了一个叫AppTheme的主题并指定它的parent主题是Theme.AppCompat.Light.DarkActionBar。
DarkActionBar是一个深色的ActionBar主题,所有的新建项目中自带的ActionBar就是因为指定了这个主题才出现的。
要使用TooIbar来替代ActionBar时需要指定一个不带ActionBar的主题,
对应的通常有Theme.AppCompat.NoActionBar和Theme.AppCompat.Light.NoActionBar这两种主题可选;
其中:
- Theme.AppCompat.NoActionBar表示深色主题,它会将界面的主体颜色设成深色,陪衬颜色设成淡色;
- Theme.AppCompat.Light.NoActionBar表示淡色主题,它会将界面的主体颜色设成淡色,陪衬颜色设成深色。
具体可以根据情况去设置,这里主要选用淡色主题,如下所示:
观察代码中AppTheme中的属性重写:
可见这里重写了colorPrimary、colorPrimaryDark和colorAccent这3个属性的颜色。
属性指定颜色名称对应的位置,如图:
可见除了上述3个属性之外,我们还可以通过textColorPrimary、windowBackground和navigationBarCotor等属性来控制更多位置的颜色。
不过colorAccent这个属性比较特殊,它不只是用来指定这样一个按钮的颜色,而是更多表达了一个强调的意思,比如一些控件的选中状态也会使用colorAccent的颜色。
至此已将ActionBar隐藏,接下来使用Toolbar来替代ActionBar。
修改activity_main.xml:
<FrameLayout 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.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </FrameLayout>
下面解析一下这段代码:
- 首先看一下第2行,这里使用xmlns:app指定了一个新的命名空间。
正是由于每个布局文件都会使用xmlns:android来指定一个命名空间,因此我们才能一直使用android:id、android:layoutwidth等写法,
这里指定了xmlns:app,现在便可以使用app:attribute这样的写法了。
但是为什么这里要指定一个xmlns:app的命名空间呢?
这是由于MaterialDesign是在Android5.0系统中才出现的,而很多的Material属性在5.0之前的系统中并不存在,那么为了能够兼容之前的老系统,我们就不能使用android:attribute这样的写法了,而是应该使用app:attribute
接下来
定义了一个Toolbar控件
,这个控件是由appcompat-v7库提供的。
这里我们给Toolbar指定了一个id,将它的
宽度设置为matchparent,
高度设置为actionBar的高度,
背景色设置为colorPrimary。-
接下来,关于主题:
由于我们刚才在styles.xml中将程序的主题指定成了淡色主题
,因此Toolbar现在也是淡色主题
(“蓝底(黑字)”),而TooIbar上面的各种元素就会自动使用深色主题
(“(黑底)X字”),这是为了和主体颜色区别开(具体可以看文章开头对于深色浅色主题的解释)。
但是这个效果看起来就会很差
,之前
使用ActionBar时文字都是白色
的,现在变成黑色
的会很难看
。那么为了能让Toolbar单独(全局是用由APPTheme制定的浅色主题的,故相对而言这里用“单独”)使用深色主题
,这里我们使用android:theme
属性,将Toolbar的主题指定成了ThemeOverlay.AppCompat.Dark.ActionBar。
但是这样指定完了之后又会出现新的问题,如果Toolbar中有菜单按钮,那么弹出的菜单项也会变成深色主题,这样就
再次变得十分难看
,于是这里使用了app:popupTheme属性单独将弹出的菜单项指定成了淡色主题。
之所以使用app:popupTheme,是因为popupTheme这个属性是在Android5.0系统中新增的,我们使用app:popupTheme的话就可以兼容Android5.0以下的系统了。
小结:
- 为了能够兼容之前的老系统,使用
app:attribute
,而不是android:attribute
;- 在styles.xml中将程序的主题指定成了淡色主题;
- 使用
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
让Toolbar单独使用深色主题;- 使用
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
单独将弹出的菜单项指定成了淡色主题;- 之所以使用app:popupTheme,是因为popupTheme这个属性是在Android5.0系统中新增的,我们使用app:popupTheme的话就可以兼容Android5.0以下的系统了。
接下来修改MainActivity:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); }
这里,
首先用findViewByid()得到Toolbar的实例,
然后调用setSupportActionBar()方法同时传入Toolbar的实例,
至此便实现了既使用Toolbar,又让它的外观与功能都同ActionBar一致。
现在运行一下程序,效果如图:
这个标题栏虽然看上去和之前的没什么两样,但其实它已经是Toolbar而不是ActionBar了,它现在也具备了实现MaterialDesign效果的能力。
接着实战一些Toolbar比较常用的功能,比如修改标题栏上显示的文字内容,
这段文字是在AndroidManifest.xml中指定的,如下所示:
这里给activity增加了一个android:label属性,用于指定在Toolbar中显示的文字内容,
如果没有指定的话,会默认使用application中指定的label内容,也就是我们的应用名称。
接下来再添加一些action按钮来丰富Toolbar:
先准备了几张图片来作为按钮的图标,将它们放在了drawable-xxhdpi目录下;
右击res目录→New→Directory,创建一个menu文件夹;
右击menu文件夹→New→Menuresourcefile,创建一个toolbar.xml文件并编写:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/backup" android:icon="@drawable/ic_backup" android:title="Backup" app:showAsAction="always"/> <item android:id="@+id/delete" android:icon="@drawable/ic_delete" android:title="Delete" app:showAsAction="ifRoom"/> <item android:id="@+id/settings" android:icon="@drawable/ic_settings" android:title="Settings" app:showAsAction="never"/> </menu>
可以看到,我们通过
<item>标签来定义action按钮,
android:id用于指定按钮的id,
android:icon用于指定按钮的图标,
android:title用于指定按钮的文字。接着使用app:showAsAction来指定按钮的显示位置,
之所以这里再次使用了app命名空间,同样是为了能够兼容低版本的系统。showAsAction主要有以下几种值可选:
always表示永远显示在Toolbar中,如果屏幕空间不够则不显示;
ifRoom表示屏幕空间足够的情况下显示在Toolbar中,不够的话就显示在菜单当中;
never则表示永远显示在菜单当中。注意,
Toolbar中的action按钮只会显示图标,
菜单中的action按钮只会显示文字。
接下来就是创建菜单的套路了,修改MainActivity中的代码,如下所示:
package com.example.materialtest; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; 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.toolbar); setSupportActionBar(toolbar); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.toolbar,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.backup: Toast.makeText(this,"You clicked Backup" , Toast.LENGTH_SHORT).show(); break; case R.id.delete: Toast.makeText(this,"You clicked Delete" , Toast.LENGTH_SHORT).show(); break; case R.id.settings: Toast.makeText(this,"You clicked Settings" , Toast.LENGTH_SHORT).show(); break; default: } return true; } }
上述代码:
在onCreate0ptionsMenu()中加载toolbar.xml这个菜单文件,
在onOptionsItemSelected()中处理各个按钮的点击事件。
重新运行一下程序,效果如图:
可见Toolbar上面现在显示了两个action按钮,这是因为
Backup按钮指定的显示位置是alway,
Delete按钮指定的显示位置是ifRoom,而现在屏幕空间充足。因此两个按钮都会显示在Toolbar中。
Settings按钮则由于指定的显示位置是never,所以显示在菜单中(点击最右边的三个小点即知)。
同时注意这些action按钮都是可以响应点击事件的!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Android 开发中的代码片段(3)地图操作相关
前言 收集常用的代码块,留存记录。此次代码块包含:唤起高德地图导航、唤起百度地图导航 代码 判断手机内安装的地图 /**判断是否安装目标应用*/ private boolean isInstallByread(String packageName) { return new File("/data/data/" + packageName) .exists(); } /** * 判断和打开地图 */ public void navigationMap() { //1.两个地图都安装了,让用户选择 boolean installBaidu = isInstallByread("com.baidu.BaiduMap"); boolean installAmap = isInstallByread("com.autonavi.minimap"); if (installBaidu && installAmap) {//两个地图都安装了 让用户进行选择 showSelectMap(); } else if (installBaidu) {//安装了百度地图 startBaidu...
- 下一篇
我要做 Android 之要点总结
Q:开启一个线程的方法有哪些?销毁一个线程的方法呢? 直接使用Thread类。 使用Runnable和Thread。 使用Runnable和线程池。 使用AsyncTask。 使用HandlerThread。 使用IntentService。 直接使用Thread类开启子线程 这是最简单开启子线程的方法,也是最本质的方法,其他开启子线程的方法都是在此方法基础上的扩展。 一,使用示例如下: new Thread(){ @Override public void run() { super.run(); } }.start(); 使用Thread类开启子线程一共分为三步: 创建Thread的子类对象。 重写run方法。 调用start方法开启子线程。 此时就开启了子线程,run方法执行在子线程中。 使用Runnable接口和Thread类开启子线程 此种方法使用的是Thread类的有参构造创建线程对象。 先实例实现了 Runnable 接口的类,之后在实例化一个 Thread,把接口类作为参数传递进去。之后调用 start 方法即可开启。 使用Runnable和线程池开启子线程 线程池中维...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS8安装Docker,最新的服务器搭配容器使用