Toolbar作为ActionBar使用介绍

本文介绍了在Android中将Toolbar作为ActionBar使用的方法.

并且介绍了在Fragment和嵌套Fragment中使用Toolbar作为ActionBar使用时需要注意的事项.

使用support library的Toolbar

Android的ActionBar每个版本都会做一些改变, 所以原生的ActionBar在不同的系统上看起来可能会不一样.

使用support library版本的Toolbar可以让你的应用在多种设备类型上保持一致. support library中总是包含了最新的features.

Android从5.0 (API Level 21)开始提供Material Design, 使用v7版本的Toolbar后, 在任何Android 2.1(API Level 7)以上的机器上都可以看到Material Design风格的Toolbar.

在Activity中使用Toolbar

1.首先项目gradle中添加:

compile 'com.android.support:appcompat-v7:23.4.0'

2.确保Activity继承AppCompatActivity

3.在application设置中使用NoActionBar的主题:

<application
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
/>

4.把Toolbar写在布局中

<android.support.v7.widget.Toolbar
android:id="@+id/my_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

5.在Activity里面把Toolbar设置成为ActionBar

首先把Toolbar find出来, 然后调用setSupportActionBar方法

把Toolbar设置为自己的ActionBar即可.

public class ToolbarDemoActivity extends AppCompatActivity {

    @BindView(R.id.toolbar)
Toolbar toolbar; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toolbar_demo);
ButterKnife.bind(this);
setSupportActionBar(toolbar);
}
}

然后就可以随意使用啦, 用getSupportActionBar可以获取ActionBar类型的对象, 从而使用ActionBar的方法.

添加Action Buttons

定义menu:

<?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/action_android"
android:icon="@drawable/ic_android_black_24dp"
android:title="@string/action_android"
app:showAsAction="always" />
<item
android:id="@+id/action_favourite"
android:icon="@drawable/ic_favorite_black_24dp"
android:title="@string/action_favourite"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_settings"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>

然后在代码中inflate和处理它的点击事件:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
Log.i(TAG, "onCreateOptionsMenu()");
getMenuInflater().inflate(R.menu.menu_activity_main, menu);
return super.onCreateOptionsMenu(menu);
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_android:
Log.i(TAG, "action android selected");
return true;
case R.id.action_favourite:
Log.i(TAG, "action favourite selected");
return true;
case R.id.action_settings:
Log.i(TAG, "action settings selected");
return true;
default:
return super.onOptionsItemSelected(item);
}
}

添加向上返回的action

添加向上返回parent的action:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toolbar_demo);
ButterKnife.bind(this);
setSupportActionBar(toolbar); // add a left arrow to back to parent activity,
// no need to handle action selected event, this is handled by super
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}

然后只需要在manifest中指定parent:

<activity
android:name=".toolbar.ToolbarDemoActivity"
android:parentActivityName=".MainActivity"></activity>

在Fragment中使用Toolbar

在Fragment中使用Toolbar的步骤和Activity差不多.

在Fragment布局中添加一个Toolbar, 然后find它, 然后调用Activity的方法来把它设置成ActionBar:

((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

注意此处有一个强转, 必须是AppCompatActivity才有这个方法.

但是此时运行到Fragment之后, 发现Toolbar上的文字和按钮全是Activity传过来的, 这是因为只有Activity的onCreateOptionsMenu()被调用了, 但是Fragment的并没有被调用.

在Fragment中加上这句:

setHasOptionsMenu(true);

此时Fragment的onCreateOptionsMenu()回调会被调到了, 但是inflate出的按钮和Activity中的actions加在一起显示出来了.

因为Activity的onCreateOptionsMenu()会在之前调用到.

于是Fragment中的写成这样:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.e(TAG, "onCreateOptionsMenu()");
menu.clear();
inflater.inflate(R.menu.menu_parent_fragment, menu);
}

即先clear()一下, 这样按钮就只有Fragment中设置的自己的了, 不会有Activity中的按钮.

在嵌套的子Fragment中使用Toolbar

前面已经介绍过, Fragment可以嵌套使用: Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误.

那么在前面的Fragment中再显示一个子Fragment, 并且又带有一个不一样的Toolbar, 还需要哪些处理呢?

首先, java代码中还是需要有:

setHasOptionsMenu(true)
((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

然后根据是否需要菜单按钮, 覆写onCreateOptionsMenu()方法来inflate自己的menu文件即可.

感觉和在普通的Fragment中使用Toolbar作为ActionBar并没有什么区别.

但是如果你的多个Fragment有不同的Toolbar菜单选项, 如果你没有懂得其中的原理, 可能就会出现一些混乱.

下面来解说一下相关的方法.

onCreateOptionsMenu()方法的调用

一旦调用

((AppCompatActivity) getActivity()).setSupportActionBar(toolbar);

就会导致ActivityonCreateOptionsMenu()方法的调用, 而Activity会根据其中Fragment是否设置了setHasOptionsMenu(true)来调用Fragment的

onCreateOptionsMenu()方法, 调用顺序是树形的, 按层级调用, 中间如果有false则跳过.

假设当前Activity, Parent Fragment和Child Fragment中都设置了自己的Toolbar为ActionBar.

在打开Child fragment的时候, onCreateOptionsMenu()的调用顺序是.

Activity -> Parent -> Child. 此时parent和child fragment都设置了setHasOptionsMenu(true).

关于这个, 还有以下几种情况:


- 如果Parent的`setHasOptionsMenu(false)`, Child为true, 则Parent的`onCreateOptionsMenu()`不会调用, 打开Child的时候Activity -> Child.
- 如果Child的`setHasOptionsMenu(false)`, Parent为true, 则打开Child的时候仍然会调用Activity和Parent的onCreateOptionsMenu()方法.
- 如果Parent和Child都置为false, 打开Parent和Child Fragment的时候都会调用Activity的onCreateOptionsMenu()方法.

仅仅是child Fragment的show() hide()的切换, activity和parent Fragment的onCreateOptionsMenu()也会重新进入.

这一点我还没有想明白, 是项目中遇到的, 初步推测可能是menu的显隐变化invalidate了menu, 改天有空再试试.

上面的机制常常是导致Toolbar上面的按钮混淆错乱的原因.

举个例子:

如果我们现在Activity和Parent Fragment有不同的Toolbar按钮, 但是Child只有文字, 没有按钮.

很显然我们不需要给child写menu文件, 也不需要覆写child里的onCreateOptionsMenu()方法.

但是此时不管怎样, parent的onCreateOptionsMenu()方法都会被调用, 这样我们打开child的时候, toolbar上就神奇地出现了parent里的按钮.

这种情况如何解决呢?

可以在parent中加一个条件, 当没有child fragment的时候才做inflate的工作:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Log.e(TAG, "onCreateOptionsMenu()");
menu.clear();
if (getChildFragmentManager().getBackStackEntryCount() == 0) {
inflater.inflate(R.menu.menu_parent_fragment, menu);
}
}

另外, 除了setSupportActionBar()之外, 如果我们想主动触发 onCreateOptionsMenu()方法的调用, 可以用

invalidateOptionsMenu()方法.

onOptionsItemSelected()方法的调用

在Activity和其中的Fragment都有options menu的时候, 需要注意menu item的id不要重复.

以为点击事件的分发也是从Activity开始分发下去的, 如果child fragment中有个选项的id和Activity中一个选项的id重复了, 则在Activity中就会将其处理, 不会继续分发.

有嵌套Fragment时 Back键处理

之前没有嵌套Fragment的情况下, 只要将Fragment加入到Back Stack中, 那么按下Back键的时候pop动作是系统自动做好的.

虽然在添加child fragment的时候将其加入到back stack中, 但是按back键的时候仍然是将parent fragment弹出, 只剩下Activity.

这是因为back键只检查第一层Fragment的back stack, 对于child fragment, 需要在其parent中自己处理.

比如这样处理:

在Activity中

@Override
public void onBackPressed() {
Fragment fragment = getSupportFragmentManager().findFragmentById(android.R.id.content);
if (fragment instanceof ToolbarFragment) {
if (((ToolbarFragment) fragment).onBackPressed()) {
return;
}
}
super.onBackPressed();
}

其中ToolbarFragment是直接加在Activity中作为parent fragment的.

在parent fragment中(即ToolbarFragment中):

public boolean onBackPressed() {
return getChildFragmentManager().popBackStackImmediate();
}

本文Demo地址: Demo on github

其中的: ToolbarDemoActivity即为Toolbar Demo.

本文地址: Android Fragment使用(四) Toolbar使用及Fragment中的Toolbar处理

参考资料

Developer Android:

Training AppBar

v7.widget.Toolbar Reference

v7.app.ActionBar

Guides: action bar menu items and fragments

Android Fragment使用(四) Toolbar使用及Fragment中的Toolbar处理的更多相关文章

  1. 四、Android学习第四天——JAVA基础回顾(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的 ...

  2. Android Toolbar使用及Fragment中的Toolbar处理

    Toolbar作为ActionBar使用介绍 本文介绍了在Android中将Toolbar作为ActionBar使用的方法.并且介绍了在Fragment和嵌套Fragment中使用Toolbar作为A ...

  3. Android系列之Fragment(四)----ListFragment的使用

    ​[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...

  4. 【转】 Pro Android学习笔记(四三):Fragment(8):再谈Transaction和管理器

    目录(?)[-] Transaction的一些操作 再谈FragmentManager 调用其他fragment的方法 唤起activity 唤起fragment和相互通信 一些其它 Transact ...

  5. 【转】 Pro Android学习笔记(四二):Fragment(7):切换效果

    目录(?)[-] 利用setTransition 利用setCustomAnimations 通过ObjectAnimator自定义动态效果 程序代码的编写 利用fragment transactio ...

  6. Android手机平板两不误,使用Fragment实现兼容手机和平板的程序

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/8744943 记得我之前参与开发过一个华为的项目,要求程序可以支持好几种终端设备,其 ...

  7. 【Android 界面效果17】Android手机平板两不误,使用Fragment实现兼容手机和平板的程序

    记得我之前参与开发过一个华为的项目,要求程序可以支持好几种终端设备,其中就包括Android手机和Android Pad.然后为了节省人力,公司无节操地让Android手机和Android Pad都由 ...

  8. Fragment(四)Fragment生命周期分析(转)

    Fragment(四)Fragment生命周期分析 转载请注明:http://blog.csdn.net/liaoqianchuan00/article/details/24271607   例子一 ...

  9. Android典型界面设计(4)——使用ActionBar+Fragment实现tab切换

    一.问题描述 之前我们使用ViewPager+Fragment区域内头部导航,在Android 3.0之后Google增加了新的ActionBar,可方便的实现屏幕Head部区域的 设计如返回键.标题 ...

随机推荐

  1. Hawk 3.1 动态页面,ajax,瀑布流

    不少朋友反映,Hawk的手气不错,好像没法处理动态页面.其实很容易,比其他软件都容易,让我慢慢道来. 1. 什么是动态页面 很多网站,在刷新的时候会返回页面的全部内容,但实际上只需要更新一部分,这样可 ...

  2. php+phpStorm+xdebug配置方法

    1.下载xdebug文件 http://xdebug.org/wizard.php 将phpinfo()的源代码复制到文本框中,xdebug会提示如何配置和下载哪个版本的xdebug. 全部下载地址: ...

  3. Spire.Pdf 的各种操作总结

     Spire.Pdf 的各种操作总结 简介 试验新产品总是给我带来许多挑战,当然这也是一个引进创新技术的好方法.在这里我要跟大家分享的是使用Spire.Pdf的过程,它是来自E-iceblue公司的轻 ...

  4. Thinking in React

    本文翻译自React的官方博客,详情请阅读原文. React非常适合构建组件化的应用,它注重高性能,因此组建的重用,项目的扩展都十分灵活,Facebook和instagram的不少商业项目使用了此框架 ...

  5. 【NET MVC】View

    通过阅读一些书籍,结合源代码,稍微深入的学习了Asp.Net MVC中的视图View 任何类型的响应都可以利用当前HttpResponse来响应,MVC可以通过Controller的Response属 ...

  6. [python]CentOS 6下安装Python2.7

    安装方法 如果在CentOS上自己编译安装过python2.7,使用过程中会发现有些标准库没有安装之类的问题. 逛别人博客的时候发现,一个便捷的方法:使用RHSCL的全称是Red Hat Softwa ...

  7. 在Mac上开发使用yeoman构建Asp.net core项目并且实现分层引用

    1.Yeoman? yeoman是一个自动化脚手架工具.它提供很多generator,generator相当于VisualStudio的模板,用来初始化项目.更多的就不多说了,写一遍都写不完,自己看吧 ...

  8. 关系数据库SQL之可编程性事务

    前言 前面关系数据库SQL之可编程性函数(用户自定义函数)一文提到关系型数据库提供了可编程性的函数.存储过程.事务.触发器及游标,前文已介绍了函数.存储过程,本文来介绍一下事务的使用.(还是以前面的银 ...

  9. clr enabled Server Configuration Option

    在SQL Server中启用CLR,可以执行下面SQL语句: EXEC sp_configure 'clr enabled'; '; RECONFIGURE; Source Code

  10. PHP5各个版本的新功能和新特性总结

    因为 PHP 那“集百家之长”的蛋疼语法,加上社区氛围不好,很多人对新版本,新特征并无兴趣.本文将会介绍自 PHP5.2 起,直至 PHP5.6 中增加的新特征 本文目录:PHP5.2 以前:auto ...