Android扩展知识 - Toolbar

借鉴了以下两篇博文

https://www.jianshu.com/p/b3a40a55826e
https://blog.csdn.net/da_caoyuan/article/details/79557704

Toolbar与ActionBar

  • 在看本篇博文之前,建议写阅读下有关ActionBar的文章,可以加深对Toolbar的理解,如博主的这篇博文Toolbar
  • 从Android3.0(API level 11)开始,所有使用默认主题的activity都自带一个ActionBar,但是随着Android版本的迭代,ActionBar的特性不断增加,从而导致了在不同Android系统的设备上,ActionBar的显示不一致。
  • 从Android5.0(API level 21)开始,引进了Toolbar,它包含了ActionBar最近添加的大多数特性(这也是我为什么建议先了解ActionBar的原因),同时添加到了支持库中,使得在低版本设备上也可以使用Toolbar。
  • Toolbar与ActionBar的区别:
    • ToolBar就是一个View,跟其他View一样包含在布局中。
    • 像常规View一样,Toolbar很容易来放置、实现动画以及控制效果。
    • 一个Activity中可以有多个Toolbar。

Android 向 AndroidX的迁移

  • 背景知识:Google 2018 IO 大会推出了 Android新的扩展库 AndroidX,用于替换原来的 Android扩展库,将原来的 android.* 替换成 androidx.* ;只有包名和Maven工件名受到影响,原来的类名、方法名和字段名不会更改。
  • 而Toolbar也由原来的android.support.v7.widget.Toolbar支持库,迁移到
    androidx.appcompat.widget.Toolbar支持库。
  • 为保证项目中版本的一致,出现的各种类库都要使用androidx库。

Toolbar的基本用法

准备工作

  • 在应用的build.gradle中添加androidx支持库
dependencies {
    implementation 'androidx.appcompat:appcompat:1.2.0'
    ...
}
  • 让Activity继承自AppCompatActivity
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
}
  • 在AndroidManifest.xml文件中,设置<application>标签中使用appcompat中的某个NoActionBar主题,从而去除使用ActionBar来提供操作栏。
    <application
        ...
        android:theme="@style/Theme.AppCompat.NoActionBar">
  • 在activity的布局中添加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:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.Toolbar
	    android:id="@+id/my_toolbar"
	    android:layout_width="match_parent"
	    android:layout_height="?attr/actionBarSize"
	    android:background="?attr/colorAccent"
	    android:elevation="4dp"
	    app:navigationIcon="@drawable/back"
	    app:title="TitleXml"
	    app:titleTextColor="@color/black"
	    app:subtitle="SubTitleXml"
	    app:subtitleTextColor="@color/white">
    </androidx.appcompat.widget.Toolbar>

</LinearLayout>
  • 在activity中的onCreate()方法中,调用setSupportActionBar() 方法,传入Toolbar,这样就会将Toolbar设置为activity的操作栏了
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 将ToolBar设置成activity的操作栏
    Toolbar toolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(toolbar);
}

常用的方法

xml中的设置

<androidx.appcompat.widget.Toolbar
    android:id="@+id/my_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorAccent"
    android:elevation="4dp"
    app:logo="@mipmap/launcher"
    app:navigationIcon="@drawable/back"
    app:title="TitleXml"
    app:titleTextColor="@color/black"
    app:subtitle="SubTitleXml"
    app:subtitleTextColor="@color/white"
    app:titleMarginStart="90dp">
</androidx.appcompat.widget.Toolbar>

解释xml中参数的意义

<!-- 
1.android:layout_height="?attr/actionBarSize"
查阅博文:https://blog.csdn.net/songzi1228/article/details/103857503
得到,这里的actionBarSize系统默认为56dp
2.android:background="?attr/colorAccent"
代表Toolbar的背景颜色
此外还有android:background="?attr/colorAccent"
3.android:elevation="4dp"
查阅博文:https://blog.csdn.net/u010356768/article/details/100896669
自己理解,elevation起到了权重的作用,已知后写的View会覆盖之前的写的View上面,
而每一个View的默认值权重都是0dp,如果设置成>0的权重,则会显示在最上面,不会被后面的View覆盖。
4.app:logo="@mipmap/launcher"
设置Toolbar的图标,非应用图标,应用图标还是得从AndroidManifest.xml注册文件中修改(icon)。
5.app:navigationIcon="@drawable/back"
设置导航按钮图标,即左边点击返回图标,通常我们要设置专门设置的监听事件
,或者对于onOptionsItemSelected函数,在android.R.id.home中做出反应。
6.app:title="TitleXml"
设置Toolbar的标题,非应用程序名字,应用程序名字还是得从AndroidManifest.xml注册文件中修改(label)。
注意:如果在xml中不对app:title属性进行设置,则默认使用AndroidManifest.xml文件中的\<application\>标签中的android:label属性值。
因此即使我们想在java代码中设置title,也要在xml文件中令app:title=" "重置掉系统的默认值。
7.app:subtitle="SubTitleXml"
设置Toolbar的子标题,位置在标题的下面
8.app:titleTextColor="@color/black"
设置标题的颜色,建议在java中设置,颜色种类更多一些,xml文件中只有black/white,还有一些其他不知名的颜色。
9.app:titleMarginStart="90dp"
标题栏距离左边的距离
-->
  • 效果图
    在这里插入图片描述

如果不在xml中设置,在java中设置

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // 将ToolBar设置成activity的操作栏
    Toolbar toolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(toolbar);

    // 显示应用的Logo
    /*
    // 博客里提供的,测试你下不用写上也能实现
    getSupportActionBar().setDisplayShowHomeEnabled(true);// 启动导航按钮(返回按钮)
    getSupportActionBar().setDisplayUseLogoEnabled(true);// 启动Logo*/
    getSupportActionBar().setLogo(R.mipmap.launcher);

    // 显示导航按钮
    toolbar.setNavigationIcon(R.drawable.back);

    // 显示标题和子标题及相关颜色
    // 博客里提供的,测试你下不用写上也能实现
    //getSupportActionBar().setDisplayShowTitleEnabled(true);
    toolbar.setTitle("TitleJava");
    toolbar.setTitleTextColor(Color.BLUE);
    toolbar.setSubtitle("SubtitleJava");
    toolbar.setSubtitleTextColor(Color.GREEN);


    // 导航按钮(左边返回按钮)的监听事件
    toolbar.setNavigationOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            finish();
        }
    });
}
  • 此时xml文件中的属性设置为:
<androidx.appcompat.widget.Toolbar
    android:id="@+id/my_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorAccent"
    android:elevation="4dp"
    app:title=" "
    app:titleMarginStart="90dp">
 <!-- app:title=" "这样写在前面已经解释过了 -->
</androidx.appcompat.widget.Toolbar>
  • 导航按钮的监听事件除了上面的写法,还可以在 onOptionsItemSelected() 方法中设置,如下所示:
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch(item.getItemId()){
            case android.R.id.home:// 导航按钮,即左边返回按钮
                finish();
                break;
            default:
                break;
    	}
    }
- 但是这部分要结合menu知识点,只写上面这部分并不会有反应。下面介绍menu资源的时候会再次提到此处。
  • 注意1:你如果添加了setSupportActionBar(toolbar),那么toolbar.setNavigationOnClickListener监听方法,要放到其后面,否则点击事件,监听不到的。

设置标题的字体大小

  • 看上面的属性,没有设置标题字体大小的属性
  • 因此通过标题样式进行更改
  • 首先定义一个style:
<!-- 主标题 -->
<style name="ToolbarTitle" parent="@style/TextAppearance.AppCompat.Widget.ActionBar.Title">
    <item name="android:textColor">#f0f0</item>
    <item name="android:textSize">20sp</item>
</style>
<!-- 子标题 -->
<style name="ToolbarSubtitle" parent="TextAppearance.AppCompat.Widget.ActionBar.Subtitle">
   <item name="android:textColor">#f0f0</item>
    <item name="android:textSize">15sp</item>
</style>
  • 然后通过app:titleTextAppearance 属性进行调用。如下所示:
<androidx.appcompat.widget.Toolbar
    android:id="@+id/my_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorAccent"
    android:elevation="4dp"
    app:title=" "
    app:titleMarginStart="90dp"
    app:titleTextAppearance="@style/ToolbarTitle"
    app:subtitleTextAppearance="@style/ToolbarSubtitle">
  • 这里是既能修改标题(子标题)字体大小,也能修改字体颜色
  • 如果在前面java代码中增加修改字体颜色的代码,最终呈现的是java代码中的效果。

自定义View

  • 这里,如果想要标题居中怎么办呢?查看Toolbar并没有居中的办法,也就是提供了使其距左右,上下边距大小的方法。
  • 因此引入自定义View
  • 因为Toolbar是ViewGroup的子类,因此可以向其内部添加View进行显示。这里我们添加一个TextView,显示一个居中的文本。
<androidx.appcompat.widget.Toolbar
    android:id="@+id/my_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorAccent"
    android:elevation="4dp"
    app:title=" "
    app:titleMarginStart="0dp"
    app:titleTextAppearance="@style/ToolbarTitle"
    app:subtitleTextAppearance="@style/ToolbarSubtitle">
    
    <TextView
        android:id="@+id/toolbar_textview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="TextView"
        android:textColor="@color/white"
        android:textSize="22sp"/>
        
</androidx.appcompat.widget.Toolbar>

在这里插入图片描述

  • 注意:此时TextView的控件的宽和高都是自适应大小,java中此行代码setSupportActionBar(toolbar)就不要添加了,否则就会显示不正常了。如果你非要添加setSupportActionBar(toolbar)这行代码的话,TextView控件的宽要用match_parent属性。这里再次建议不要添加这行代码。(但其实自己测试的时候,添加这句代码,并没有显示不正常,不过仍然记录下来,以防不测。)
  • 上面是引用的博客里提到的,按要求删掉setSupportActionBar(toolbar)这行代码,发现getSupportActionBar().setLogo(R.mipmap.launcher)代码出错了,出错信息是java.lang.NullPointerException
  • 即getSupportActionBar()方法找不到ActionBar
  • 那么这里就要理解setSupportActionBar(toolbar)这句代码的作用:
    • 在Toolbar这个控件出现之前,其实我们可以通过ActionBar actionBar = getSupportActionBar()方法获取到ActionBar。(前提是你的主题theme,是采用的带ActionBar的主题,如果你采用的是主题是NoActionBar,则拿到的ActionBar是null。)之后你就可以采用如下方法来操作ActionBar了:
ActionBar actionbar = getSupportActionBar();
if(actionbar != null){
	actionbar .setDisplayShowHomeEnabled(true);
    actionbar .setDisplayUseLogoEnabled(true);*/
    actionbar .setTitle("主标题");
}else{
	Log.d("fhy","onCreate: ActionBar is null!");
}
  • 但是,原生自带的ActionBar设置的灵活性,还是有限,因此Toolbar这个控件,也就应运而生了!
  • 此时,如果使用Toolbar代替了ActionBar,但是自己还是想用ActionBar的一些特性怎么办呢?
  • 这个时候setSupportActionBar(toolbar)就发挥其作用了,添加这行代码,你的toolbar可以说也就是具有了ActionBar的相关属性了。
  • 因此也可以理解,为什么删除了setSupportActionBar(toolbar)这句代码,getSupportActionBar().setLogo(R.mipmap.launcher)代码就出错了。
  • 建议: 如果用不到ActionBar的一些特性的话,建议setSupportActionBar(toolbar)这句代码就不要添加了。但是这里因为添加Logo需要ActionBar特性,这里还是加上了。
  • 注意: 下面的介绍的menu菜单(Action按钮和overflow按钮),是属于ActionBar特性的,因此需要加上setSupportActionBar(toolbar)这句代码。

结合menu菜单

  • 首先在res/menu目录下新建一个main.xml文件,添加几个Action,如下所示:
<?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/user"
        android:icon="@drawable/user"
        android:title="用户"
        app:showAsAction="ifRoom"/>

    <item
        android:id="@+id/write"
        android:icon="@drawable/write"
        android:title="发布"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/favo"
        android:icon="@drawable/favo"
        android:title="收藏"
        app:showAsAction="never"/>

</menu>
  • menu文件中的设置这里就不再介绍了,ActionBar博文中讲得很清楚了。
  • activity活动中加载menu菜单
    // 加载菜单
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }
  • 给每个Action添加点击事件,包括上文提到的导航按钮(android.R.id.home):
@Override
 public boolean onOptionsItemSelected(@NonNull MenuItem item) {
     switch(item.getItemId()){
         case android.R.id.home:// 导航按钮,即左边返回按钮
             finish();
             break;
         case R.id.user:
             Toast.makeText(this,"You clicked 用户",Toast.LENGTH_SHORT).show();
             break;
         case R.id.write:
             Toast.makeText(this,"You clicked 发布",Toast.LENGTH_SHORT).show();
             break;
         case R.id.favo:
             Toast.makeText(this,"You clicked 收藏",Toast.LENGTH_SHORT).show();
             break;
         default:
             break;
     }
     return true;
 }

在这里插入图片描述

  • 注意到点击overflow按钮(溢出列表)时,弹出的菜单位置太靠上了,可以设置吗?还有菜单的背景和文字颜色也可以设置。
    在这里插入图片描述
  • 首先设置好样式
 <!--    overflow按钮,弹出的菜单样式-->
 <style name="ToolbarPopupTheme" parent="@style/ThemeOverlay.AppCompat.Dark">
     <!--        这里可以改变菜单的背景色        -->
     <item name="android:colorBackground">#00EE00</item>
     <!--        新增一个item,用于控制menu的位置     -->
     <item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
 </style>

 <style name="OverflowMenuStyle" parent="Widget.AppCompat.Light.PopupMenu.Overflow">
     <!--        该属性改为false即可使Menu位置位于toolbar之下       -->
     <item name="overlapAnchor">false</item>
 </style>
  • 直接引用app:popupTheme="@style/ToolbarPopupTheme"
<androidx.appcompat.widget.Toolbar
    android:id="@+id/my_toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="?attr/colorAccent"
    android:elevation="4dp"
    app:title=" "
    app:titleMarginStart="0dp"
    app:titleTextAppearance="@style/ToolbarTitle"
    app:subtitleTextAppearance="@style/ToolbarSubtitle"
    app:popupTheme="@style/ToolbarPopupTheme">
  • 效果图
    在这里插入图片描述

与AppBarLayout结合的使用

  • 博主自己对AppBarLayout还不了解,这部分挖个坑,留着以后再来填补。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值