写在前面

•前言

  这两天,学完了 Fragment 的基础知识,正准备跟着《第一行代码》学习制作一个简易版的新闻应用;

  嘀嘀嘀~~~

  一声消息传来,像往常一样,打开 QQ,当我看到 QQ 界面的时候:

    

  突发奇想,我是不是可以尝试制作一下这个界面,以及完成一些点击跳转的效果;

  说干就干,先大致画了个草图,明确该如何分配空间:

    

  忍不住叨叨两句,画这种嵌套的方形框, Notability 真香;

  大体理了理思路:

  • 将 ipad 界面一分为二,左边是一个权重为 1 的 LinearLayout
  • 右边是一个权重为 2 的 LinearLayout

  当点击左边消息列表时,右边动态添加一个 Fragment,思路是不是还蛮清晰的~~~

  左右分工好后,接着开始细究左边内部的分工了;

  我将左边的 LinearLayout 分成了三块,就暂且叫他们 a,b,c;

  在设计 a 的时候,也就是这一块:

    

  最左边的头像我用 ImageView 控件体现,中间的,暂且用 TextView 控件实现;

  最右边的 有一个弹出菜单,当然选择 menu 来实现喽;

  当开始敲 menu 控件的时候,突然发现,我好像没怎么深入的学习过,so,一场恶补开始了;

  翻阅了各种各样的博客,终于,完成了这篇惊世之作——在活动中使用 menu

  可是,我却翻车了,怎么也实现不了QQ里的这种效果;

  不放弃的我又去找度娘聊天去了,还好找到了一篇,快点我

  ToolBar 是什么玩意????

  没办法,接着肝;

  苦熬一上午,终于肝明白了,以此记录;

  接下来要步入正题喽~~~~~

•简介

  Toolbar 是在 Android 5.0 开始推出的一个 Material Design 风格的导航控件 ;

  Google 非常推荐大家使用 Toolbar 来作为Android客户端的导航栏,以此来取代之前的 Actionbar 。

  与 Actionbar 相比,Toolbar 明显要灵活的多。

  它不像 Actionbar 一样,一定要固定在Activity的顶部,而是可以放到界面的任意位置。

  除此之外,在设计 Toolbar 的时候,Google也留给了开发者很多可定制修改的余地;

  这些可定制修改的属性在API文档中都有详细介绍,如:

  • 设置导航栏图标;
  • 设置App的logo;
  • 支持设置标题和子标题;
  • 支持添加一个或多个的自定义控件;
  • 支持Action Menu;

•准备工作

  首先,新建一个项目,选择 Empty Activity 这个选项,并命名为 Tool Bar;

  进入 Project 模式,点击 app/src/main/,找到 AndroidManifest.xml 文件;

  找到这句话  android:theme="@style/Theme.ToolBar"> ;

  可以看到,这里使用  android:theme  属性指定了一个 Theme.TestToolBar 的主提。

  那么,这个 Theme.TestToolBar 又是在哪里定义的呢?

  按住 ctrl,鼠标点击  "@style/Theme.ToolBar">  这句话:

    

  通过快捷键 ctrl,Android Studio 引领我们找到了这句话的出处;

  在我这里,这个文件在 themes.xml 中:

    

  而并不是在 res/values/styles.xml 中,《第一行代码》以及好多优质博客都声明在 styles.xml 文件中;

  这是为什么呢?

  来看这句话  <style name="Theme.ToolBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> ;

  这里定义了一个叫 Theme.TestToolBar 的主题;

  然后指定它的 parent 主题是  "Theme.MaterialComponents.DayNight.DarkActionBar" 。

  这个 DarkActionBar 是一个深色的 ActionBar 主题;

  而我们现在准备使用 ToolBar 来替代 ActionBar,因此需要指定一个不带 ActionBar 的主题;

  通常有  "Theme.AppCompat.NoActionBar"  和  "Theme.AppCompat.Light.NoActionBar"  这两种主题可选。

  其中前者表示深色主题,它会将界面的主题颜色设成深色,陪衬颜色设成淡色;

  而后者表示淡色主题,它会将界面的主题颜色设成淡色,陪衬颜色设成深色;

  具体效果,上手便知,这里我们选择后者;

  更改 parent 属性为后者:

     <style name="Theme.ToolBar" parent="Theme.AppCompat.Light.NoActionBar">

  至于其他的:

    

  暂且不管它们,你可以留着,或者删了也行,这不是本次的重点!!!

  如果你嫌上边的配置过于繁琐,那么恭喜你,接下来本博主将带着你用一行代码简单粗暴的实现上述效果;

  是不是挺期待的;

  在 MainActivity.java 中加入这一行代码  supportRequestWindowFeature(Window.FEATURE_NO_TITLE); ;

  注意,一定要放在  setContentView()  之前,不然,会出错;

  

注意

  我的 MainActivity 是继承了 AppCompatActivity的;

  如果是继承 Activity 就应该调用  requestWindowFeature(Window.FEATURE_NO_TITLE); ;

  是不是只通过一行代码就简单粗暴的实现了上述繁琐的配置。

  现在,我们已经将 ActionBar 隐藏起来了,那么,接下来看一看如何使用 ToolBar 来替代 ActionBar。


Toolbar的简单用法

•初次使用 Toolbar

  介绍步骤之前,请允许我把本次内容将要使用的图标一一列举出来;

        

  至于这些图标的命名问题,我相信,屏幕前聪明的你会从代码中找到蛛丝马迹的,哈哈哈~~~~

  修改 activity_main.xml 中的代码;

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"> <!-- 设置成黄色的背景色-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/yello"
/> </LinearLayout>

  有关这个 Toolbar 的使用,《第一行代码》以及一些优质博客,用的都是  <android.support.v7.widget.Toolbar ;

  我也尝试着用,然后又是一顿瞎捣鼓,也没捣鼓出啥花来;

  万般无奈,搜了搜包方面的博客,找到了这篇,Android AndroidX的迁移

  

  大概是说,过年的时候,Android 也会换身新衣服穿;

  所以,我们安心用 androidx 中的 Toolbar 就行,没必要非得去实现  <android.support.v7.widget.Toolbar ;

——来自萌新的见解,大佬轻点喷

  好了,这里的废话暂且说这么多,下面步入正题;

  接着修改 MainActivity.java 中的代码;

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main); toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); }

  这里需要注意一点,再导入 Toolbar 包的时候,有两个选择:

    

  我选择了第一个  import androidx.appcompat.widget.Toolbar; ;

  因为如果选择第二个的话,语句  setSupportActionBar(toolbar);  就会报错,我也不知道为什么;

运行效果

  

•Title and SubTitle

  接下来,我们为 Toolbar 设置标题、子标题,并设置标题子标题颜色;

  修改 activity_main.xml 中的代码;

<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"> <!-- 设置成黄色的背景色-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/yello"
app:title="title"
app:titleTextColor="@color/black"
app:subtitle="sub title"
app:subtitleTextColor="@color/white"
/> </LinearLayout>

  乍一看,仅仅是在 Toolbar 中加入了  app:title , app:titleTextColor , app:subtitle , app:subtitleTextColor  这四句话;

  其实,还额外加入了  xmlns:app="http://schemas.android.com/apk/res-auto" ,也就是第 3 行语句;

  这里使用  xmlns:app  指定了一个自定义属性的命名空间,当然,你也可以将  app  换成你想要的其他命名。

  思考一下,正是由于每个布局文件都会使用  xmlns:android 来指定一个命名空间;

  因此,我们才一只能用  android:id , android:layout_width 等写法;

  那么,这里指定了  xmlns:app ,也就是说,现在可以使用  app:attribute  这样的写法了。

  但是为什么这里要指定一个新的命名空间呢?

  目的是为了能够兼容之前的老系统,具体详情自行百度,这里不再赘述。

运行效果

  

•左侧导航栏

  修改 MainActivity.java 代码;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main); toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); getSupportActionBar().setHomeButtonEnabled(true); //设置导航栏可用
getSupportActionBar().setDisplayHomeAsUpEnabled(true); //为导航栏设置点击事件
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"back",Toast.LENGTH_SHORT).show();
}
});
}
}

  并通过  toolbar.setNavigationOnClickListener() 为其设置点击事件;

运行效果

  

•右侧溢出菜单

  接下来,我们把右侧溢出菜单搞出来;

  首先在 res 的 menu 目录下创建一个 main 资源文件,具体做法参考我的这篇博客

main.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/option_normal_1"
android:icon="@mipmap/icon_one"
android:title="普通菜单1"
app:showAsAction="ifRoom"/> <item android:id="@+id/option_normal_2"
android:icon="@mipmap/icon_two"
android:title="普通菜单2"
app:showAsAction="always"/> <item android:id="@+id/option_normal_3"
android:icon="@mipmap/icon_three"
android:title="普通菜单3"
app:showAsAction="withText|always"/> <item android:id="@+id/option_normal_4"
android:title="普通菜单4"
android:icon="@mipmap/icon_four"
app:showAsAction="never"/>
</menu>

  修改 MainActivity.java 中的代码;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main); toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); getSupportActionBar().setHomeButtonEnabled(true); //设置导航栏可用
getSupportActionBar().setDisplayHomeAsUpEnabled(true); //为导航栏设置点击事件
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"back",Toast.LENGTH_SHORT).show();
}
}); toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
Toast toast = null;
switch(item.getItemId()){
case R.id.option_normal_1:
toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
break;
case R.id.option_normal_2:
toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
break;
case R.id.option_normal_3:
toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
break;
case R.id.option_normal_4:
toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
break;
default:
}
toast.show();
return true;
}
});
} @Override
public boolean onCreateOptionsMenu(Menu menu) {//为toolbar设置溢出菜单
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main,menu);
return true;
}
}

  通过  onCreateOptionsMenu() 方法为 toolbar 设置溢出菜单;

  并通过  setOnMenuItemClickListener() 设置溢出菜单的点击效果;

运行效果

  

注意

  Toolbar中的 action 按钮只会显示图标,菜单中的 action 按钮只会显示文字。

  那如果设置了 ifRoom 属性之后,既然只显示图标不显示文字,那还设置  android:title=””  文字干嘛呢?

  如果你设置了之后,虽然不显示,但是你长按相应按钮后,就会吐司相应文字内容的。

  不信的话,你自己试试;

  还有,有关 app:showAsAction 属性,已经在 menu 中做过详细讲解,这里就不在赘述;

•Logo

  我们在 activity_main.xml 中通过  app:logo 属性为 Toolbar 设置 Logo;

activity_main.xml

<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"> <!-- 设置成黄色的背景色-->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/yello"
app:title="title"
app:titleTextColor="@color/black"
app:subtitle="sub title"
app:subtitleTextColor="@color/white"
app:logo="@mipmap/icon_one"
/> </LinearLayout>

  这里我直接使用了 icon_one,懒得在下载其他图标了,哈哈哈;

运行效果

  

注意

  NavigationIcon 和 Logo 不建议同时使用,不然 logo 和 title,subtitle的 间距会显得比较小;

  到此,Toolbar 的所有元素组件都搞出来了,接下来我们接着说如何自定义 Toolbar;


自定义Toolbar

•声明

  因为接下来的内容并没有 Logo 参与,所以我将这个属性去掉了;

•自定义导航栏的icon

  只需要在 activity_main.xml 中设置  app:navigationIcon="@mipmap/icon_two" 即可。

  这里我直接使用了 inon_two 图标;

运行效果

  

•设置溢出菜单icon的颜色

  还记得我们在前面繁琐配置中的  <style name="Theme.ToolBar" 吗?

  一定要找到这个文件,因为,一会还会用到,哈哈哈~~~

  将下面这个代码添加到  <style name="Theme.ToolBar" 中;

<!--设置溢出菜单图片颜色为红色-->
<item name="colorControlNormal">@color/red</item>

  注意,这里用的是 @color/red,是我在 res/values 下的 color.xml 文件夹中自定义的颜色;

  不要使用  @android:color/red ,编译报错;

运行效果

  

•设置标题和子标题的字体大小

  点击 app/src/main/res/,找到 values 文件夹,右击 New->Values Resource File;

  

  新建一个名为 styles 的 xml 文件;

styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources> <!-- toolbar标题文字大小 -->
<style name="ToolbarTitleSize" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textSize">25sp</item>
</style>
<!-- toolbar子标题文字大小 -->
<style name="ToolbarSubTitleSize" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
<item name="android:textSize">12sp</item>
</style> </resources>

  并在 activity_main.xml 设置:

app:subtitleTextAppearance="@style/ToolbarSubTitleSize"
app:titleTextAppearance="@style/ToolbarTitleSize"

运行效果

  

•溢出菜单自定义

  首先,将下面这些代码添加到 styles.xml 中;

    <!-- toolbar溢出菜单图标自定义 -->
<style name="OverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow">
<item name="android:src">@mipmap/icon_add</item>
<item name="android:scaleType">centerInside</item>
</style>

  注意,溢出菜单图标自定义  <style name="OverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow"> ;

  parent 是  "Widget.AppCompat.ActionButton.Overflow" 而不是  "android:Widget.ActionButton.Overflow"

  如果 parent 属性设置为后者,那么,Toolbar 并不会成功显示你定义的图标;

  因为这个原因,可苦了我了,搜了是好几个博客,都没有解决;

  最后还是在 Stack Overflow 的评论中找到了答案;

  接着,将下面的代码添加到  <style name="Theme.ToolBar" 中;

        <!-- 溢出菜单图标自定义-->
<item name="actionOverflowButtonStyle">@style/OverflowButtonStyle</item>

运行结果

  

  溢出菜单的图标是不是变成 了,神奇吧。

•设置溢出菜单弹出位置以及背景颜色,文字颜色

  上边的效果图看着很别扭,溢出菜单弹出的位置遮住了 Toolbar;

  所以,我们将溢出菜单弹出位置设置到Toolbar下面;

  在 styles.xml 中添加如下代码;

    <!--设置溢出菜单弹出位置-->
<style name="OverflowMenuStyle" parent="@style/Widget.AppCompat.PopupMenu.Overflow">
<!-- 是否覆盖锚点,默认为true,即盖住Toolbar -->
<item name="overlapAnchor">false</item>
<!-- 设置弹出菜单文字颜色 -->
<item name="android:textColor">@color/white</item>
<!-- 弹出层背景颜色 -->
<item name="android:colorBackground">@color/green</item>
</style>

  并将  <style name="OverflowMenuStyle" parent="@style/Widget.AppCompat.PopupMenu.Overflow"> 属性引用到 activity_main.xml 中的 Toolbar 中:

     app:popupTheme="@style/OverflowMenuStyle"

运行结果

  

  说好的绿色背景呢???

  经过我一番瞎捣鼓,终于整出来了;

  还是得将  <style name="Theme.ToolBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar">  中的 parent 改为:

     parent="Theme.AppCompat.Light.NoActionBar" ;

  那我直接用这个方法不就好了吗,何必添加  supportRequestWindowFeature(Window.FEATURE_NO_TITLE); 。

运行结果

  

  最后再叨叨几句,当前这个版本,是我改版后的;

  其实一开始我写这篇博客的时候,并不知道  supportRequestWindowFeature(Window.FEATURE_NO_TITLE) ;

  是我在今天(2021.2.8)随意翻阅博客的时候看到的;

  本着追根究底的态度,我试了试,实现了和修改 themes 同样的效果;

  最主要的是,添加这个语句,可以使用   toolbar.inflateMenu(R.menu.main); 语句。


写在最后

•结语

  至此,Toolbar 的学习就告一段落了,带着满满的疲惫结束了 Toolbar 的学习;

  最后,奉上我在学习 Toolbar 过程中翻阅过的资料;

  【Android Toolbar详解——简书】

  【Android ToolBar详解——CSDN】

  【Toolbar的详细介绍和自定义Toolbar

  【Android开发:最详细的 Toolbar 开发实践总结

  在此感谢!

Android 之 ToolBar 踩坑笔记的更多相关文章

  1. [置顶] xamarin android toolbar(踩坑完全入门详解)

    网上关于toolbar的教程有很多,很多新手,在使用toolbar的时候踩坑实在太多了,不好好总结一下,实在浪费.如果你想学习toolbar,你肯定会去去搜索androd toolbar,既然你能看到 ...

  2. Android Studio安装踩坑

    title: Android Studio安装踩坑 date: 2018-09-07 19:31:32 updated: tags: [Android,Android Studio,坑] descri ...

  3. EntityFramework CodeFirst SQLServer转Oracle踩坑笔记

    接着在Oracle中使用Entity Framework 6 CodeFirst这篇博文,正在将项目从SQLServer 2012转至Oracle 11g,目前为止遇到的问题在此记录下. SQL Se ...

  4. CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记

    CAS5.3服务器搭建与客户端整合SpringBoot以及踩坑笔记 cas服务器的搭建 导出证书(1和2步骤是找了课程,随便写了一下存记录,不过对于自己测试不投入使用应该不影响) C:\Users\D ...

  5. React Native Android配置部署踩坑日记

    万事开头难 作为一只进入ECMAScript世界不久的菜鸟,已经被React Native的名气惊到了,开源一周数万星勾起了我浓烈的兴趣.新年新气象,来个HellWorld压压惊吧^_^(故意少打个' ...

  6. ES踩坑笔记

    现在开始在业务上使用ES,记录一些踩坑经历,做点笔记. 2018-11-13 source不返回问题 使用了角色校验,客户端插入成功之后获取数据没有source,和查询参数无关. 检查mapping, ...

  7. Android 图片裁剪踩坑

      今天做图库图片的裁剪遇到了不少坑,今天记录一下,以下坑位供各位看官参考: 如果有不对之处,欢迎各位看官留言评论! 图片裁剪踩坑锦囊: 问题一:相册裁剪权限问题 解:这个简单,对于Android6. ...

  8. 微信小程序使用pako.js的踩坑笔记

    问题 今天组长跟我们讨论了个问题,说是文章存储占用有点大,消耗宽带流量费,让我看看能不能找个方法解决一下(文章存储的是html字符串).第一反应是没什么头绪,能想到的就是将相同的字符串替换成一个标识之 ...

  9. Vue3.x+element-plus+ts踩坑笔记

    闲聊 前段时间小颖在B站找了个学习vue3+TS的视频,自己尝试着搭建了一些基础代码,在实现功能的过程中遇到了一些问题,为了防止自己遗忘,写个随笔记录一下嘻嘻 项目代码 git地址:vue3.x-ts ...

随机推荐

  1. HTML5 动效

    HTML5 动效 motion graphics toolbelt for the web https://github.com/xgqfrms/mojs A collection of loadin ...

  2. How to enable HTTPS for local development in macOS using Chrome

    How to enable HTTPS for local development in macOS using Chrome HTTPS, macOS, Chrome local HTTPS htt ...

  3. flutter & dart & vs code & bug

    flutter & dart & vs code & bug Waiting for another flutter command to release the startu ...

  4. macOS & Nginx

    macOS & Nginx ngnix # 使用 brew 安装(如果没有 brew 命令,需要自行安装 brew) $ brew install nginx $ nginx -h # 查看 ...

  5. 万链互联时代,NGK DeFi项目如何在牛市中崭露头角!

    众所周知,中心化交易所存在技术风险.道德风险与法律风险.去中心化交易所像是NGK以其匿名性.安全性.私钥独立掌控的特点,弥补了中心化交易所的不足,我们看到Uniswap日成交量均超过1亿美元,甚至接近 ...

  6. 从HashMap面试聊聊互联网内卷

    微信公众号:大黄奔跑 关注我,可了解更多有趣的面试相关问题. 写在之前 毫无疑问,回想2020年有什么词出现在眼前最多的,无疑是"996"和"内卷",从马老师的 ...

  7. 元类、orm

    目录 一.内置函数exec 二.元类 1. 什么是元类 2. 元类的作用 3. 创建类的两种方法 4. 怎么自定义创建元类 三.ORM 1. ORM中可能会遇到的问题 2. ORM中元类需要解决的问题 ...

  8. Virtual DOM 简直就是挥霍

    彻底澄清"Virtual DOM 飞快"的神话. 注意:原文发表于2018-12-27,随着框架不断演进,部分内容可能已不适用. 近年来,如果你有使用过 JavaScript 框架 ...

  9. EFCodeFirst Migrations数据库迁移

    EFCodeFirst Migrations数据库迁移 数据库迁移 1.生成数据库 修改类文件PortalContext.cs的静态构造函数,取消当数据库模型发生改变时删除当前数据库重建新数据库的设置 ...

  10. 微信小程序3D轮播图

    <!-- 轮播图 --> <swiper previous-margin='50px' next-margin='50px' bindchange="swiperChang ...