12.2--Toolbar

Toolbar 将会是我们本章接触的第一个控件,是由AndroidX 库提供的。虽说对于 Toolbar 你暂时应该还是比较陌生的,但是对于它的另一个相关控件 ActionBar ,你就应该有点熟悉了。

回忆一下,我们曾经在 4.4.1 小节为了使用一个自定义的标题栏,而隐藏了系统原生的 ActionBar。没错,每个Activity 最顶部的那个标题栏其实就是 ActionBar,之前我们编写的所有程序里直都有它的身影。

不过ActionBar 由于其设计的原因,被限定只能位于 Activity 的顶部,从而不能实现一些 Material Design 的效果,因此官方现在已经不再建议使用ActionBar 了。那么本书中我也就不准备再介绍ActionBar 的用法了,而是直接讲解现在更加推荐使用的Toolbar。

首先你要知道,任何一个新建的项目,默认都会显示ActionBar 的,这个想必你已经见识过太多次了。那么这个ActionBar 到底是从哪里来的呢?其实这事根据项目中指定的主题来显示的。打开Androidmanifest.xml 文件看一下,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.materialtest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

可以看到,这里使用 android: theme 属性指定了一个 AppTheme 的主题。那么这个 AppTheme 又是在哪里定义的呢?打开 res/values/styles.xml 文件,代码如下所示:

<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

这里定义了一个叫 AppTheme 的主题,然后指定它的 parent 主题是 Theme. AppCompat.Light.DarkActionbar。这个 DarkActionbar 是一个深色的 Actionbar 主题,我们之前所有的项目中自带的 Actionbar 就是因为指定了这个主题才出现的。

而现在我们准备使用 lobar 来替代 Actionbar,因此需要指定一个不带 Actionbar 的主题通常有 Theme. AppCompat.Noaction Bar 和 Theme. AppCompat. Light.NoactionBar这两种主题可选。其中 Theme.App Compat.NoactionBar 表示深色主题,它会将界面的主体颜色设成深色,陪衬颜色设成淡色。而 Theme.AppCompat. Light.NoactionBar 表示淡色主题,它会将界面的主体颜色设成淡色,陪衬颜色设成深色。具体的效果你可以自己动手试一试,这里由于我们之前的程序一直都是以淡色为主的,那么我就选用淡色主题了,如下所示:

<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>
    </style>

</resources>

然后观察一下 Apptheme 中的属性重写,这里重写了 colorPrimary、colorPrimarydark 和 colorAccent 这 3 个属性的颜色。那么这 3 个属性分别代表着什么位置的颜色呢?我用语言比较难描述清楚,还是通过一张图来理解一下吧,如图 12.2 所示。

可以看到,每个属性所指定颜色的位置直接一目了然了。

除了上述 3 个属性之外,我们还可以通过 textcolorPrimary、windowBackground 和 navigationBarColor 等属性来控制更多位置的颜色。不过唯独 colorAccent 这个属性比较难理解,它不只是用来指定这样一个按钮的颜色,而是更多表达了一个强调的意思,比如一些控件的选中状态也会使用 colorAccent 的颜色。

现在我们已经将 ActionBar 隐藏起来了,那么接下来看一看如何使用 Toolbar 来替代 ActionBar,。修改 activity_main.xml 中的代码,如下所示:

<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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        />

</LinearLayout>

虽然这段代码不长,但是里面着实有不少技术点是需要我们仔细琢磨一下的。首先看一下第2行,这里使用xmlns:app 指定了一个新的命名空间。思考一下,正是由于每个布局文件都会使用xmlns:android 来指定一个命名空间,我们才能一直使用android:id、android:layout_width 等写法。这里指定了xmlns:app ,也就是说现在可以使用app:attribute 这样的写法了。但是为什么这里要一个xmlns:app 的命名空间呢?这是由于许多Material 属性是在新系统中新增的,老系统中并不存在,那么为了能够兼容老系统,我们就不能使用android:attribute 这样的写法了,而是应该使用app:attribute。

接下来定义了一个Toolbar 控件,这个控件是由 appcompat 库提供的。这里我们给Toolbar 指定了一个id,将它的宽度设置为match_parent,高度设置为actionBar 的高度,背景色设置为colorPrimary。 不过下面的部分就稍稍有点难理解了,由于我们刚才在style.xml 中将程序的主题指的成了浅色主题,因此Toolbar 现在也是浅色主题,那么Toolbar 上面的各种元素就会自动使用深色系,从而和主题颜色区别开。但是之前使用ActionBar 时文字都是白色的,现在变成黑色的会很难看。那么为了能让Toolbar 单独使用深色主题,这里我们使用了android:theme 属性,将Toolbar 的主题指定成了 ThemeOverlay.AppCompat.Dark.ActionBar 。但是这样指定之后又会出现新的问题,如果Toolbar 中有菜单按钮(我们在3.2.5 小节中学过),那么弹出的菜单项也会变成深色主题,这样就再次变得十分难看了,于是这里又使用了app:popupTheme 属性,单独将弹出的菜单指定成了浅色主题。

如果你觉得上面的描素很绕的话,可以自己动手做一做实验,看看不指定上诉主题会是什么样的效果,这样你会理解得更加深刻。

写完了布局,接下来我们修改MainActivity,代码如下所示:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
    }
}

 这里关键的代码只有一句,调用setSupportActionBar() 方法并将Toolbar 的实例传入,这样我们就做到既使用了Toolbar,又让它的外观与功能都和ActionBar 一致了。

现在运行一下程序,效果如图:

这个标题栏我们再熟悉不过了,虽然看上去和之前的标题栏没什么两样,但其实它已经是Toolbar 而不是ActionBar 了。因此它现在也具备了实现Material Design 效果的能力,这个我们在后面就会学到。

接下来我们再学习一些 Toolbar 比较常用的功能吧,比如修改标题栏上显示的文字内容。这段文字内容是在 AndroidManifest.xml 中指定的,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.materialtest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity 
            android:name=".MainActivity"
            android:label="Fruits"      
            >
            ...
        </activity>
    </application>

</manifest>

这里给 activity 増加了一个 android: label 属性,用于指定在 Toolbar 中显示的文字内容,如果没有指定的话,会默认使用 application 中指定的 label 内容,也就是我们的应用名称。

不过只有一个标题的 polar 看起来太单调了,我们还可以再添加一些 action 按钮来让Toolbar 更加丰富一些,这里我提前准备了几张图片来作为按钮的图标,将它们放在了 drawable--xxhdpi 目录下。现在右击 res 目录→New → Directory,创建一个 menu 文件夹。然后右击 menu 文件夹→ New-Menu resource file, 创建一个 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 用于指定按钮的图标,and roid:title 用于指定按钮的文字。

接着使用 app: showAsAction 来指定按钮的显示位置,之所以这里再次使用了 app 命名空间,同样是为了能够兼容低版本的系统。showAsAction 主要有以下几种值可选:

always 表示永远显示在 Toolbar 中,如果屏幕空间不够则不显示;

ifRoom 表示屏幕空间足够的情况下显示在 Toolbar 中,不够的话就显示在菜单当中;

never 则表示永远显示在菜单当中。

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

接下来的做法就和 3.2.5 小节中的完全一致了,修改 MainActivity 中的代码,如下所示:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)

    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.toolbar,menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.backup -> Toast.makeText(this,"You clicked Backup",Toast.LENGTH_SHORT).show()
            R.id.delete -> Toast.makeText(this,"You clicked Delete",Toast.LENGTH_SHORT).show()
            R.id.settings -> Toast.makeText(this,"You clicked Settings",Toast.LENGTH_SHORT).show()
        }
        return true
    }
}

非常简单,我们在onCreateOptionsMenu() 方法中加载了 toolbar.xml 这个菜单文件,然后在onOptionsItemSelected() 方法中处理各个按钮的点击事件。现在重新运行一下程序,效果如图:

可以看到,Toolbar 上面现在显示了两个 action 按钮,这是因为 Backup 按钮指定的显示位置是 always, Delete 按钮指定的显示位置是 ifRoom,而现在屏幕空间很充足,因此两个按钮都会显示在 Toolbar 中。另外一个 Settings 按钮由于指定的显示位置是 never,所以不会显示在 Toolbar 中,点击一下最右边的菜单按钮来展开菜单项,你就能找到 Settings 按钮了。另外这些 action 按钮都是可以响应点击事件的,你可以自己去试一试。

好了,关于 Toolbar 的内容就先讲这么多吧。当然 Toolbar 的功能还远远不只这些,不过我们显然无法在一节当中就把所有的用法全部学完,后面会结合其他控件来挖掘 Toolbar 的更多功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值