Android中的工具栏(ActionBar和ToolBar)

ActionBar和ToolBar

Action Bar是Android 3.0引入的导航栏功能,然而到5.0的时候,又推出了ToolBar,实际上这两个可以理解为同一个东西,ToolBar是对ActionBar的升级,使用起来也基本是一样的。只是因为ActionBar在实际使用过程中的各种问题,才推出了ToolBar来接替ActionBar。ActionBar通常翻译为操作栏,而到了ToolBar则翻译为工具栏,这里我们统称为工具栏。

添加和隐藏工具栏

在Toolbar引入之前,添加ActionBar是通过Theme来实现的,在Manifest文件中指定Application或者Activity的Theme为Theme.Holo或者它的子类,运行以后ActionBar会自动添加进来。移除ActionBar也可以通过指定theme的方式,设置为Theme.Holo.NoActionBar。或者使用动态方式,先获取到ActionBar,然后设置隐藏

ActionBar actionBar = getActionBar();  
actionBar.hide(); 

ToolBar的引入之后,Android已经不推荐我们这么操作了。应该采用ToolBar的方式来管理工具栏

为了能更好的向下兼容,官方推荐我们使用 v7 appcompat 来添加和管理ToolBar。添加ToolBar的步骤如下:

  1. 按照支持库设置中所述向您的项目添加 v7 appcompat 支持库。

  2. 确保 Activity 可以扩展 AppCompatActivity:

public class MyActivity extends AppCompatActivity {
  // ...
}

注:请为您应用中每个使用 Toolbar 作为应用栏的 Activity 进行此更改。

  1. 在应用清单中,将 <application> 元素设置为使用 appcompat 的其中一个 NoActionBar 主题。使用这些主题中的一个可以防止应用使用原生 ActionBar 类提供应用栏。例如:
<application
    android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    />

到这里为止,所做的工作是确保Activity中不包含默认的ActionBar,否则会引起崩溃。如果想保留theme,而这个theme又是包含ActionBar的,可以在Activity中调用requestWindowFeature(Window.FEATURE_NO_TITLE);,如果是继承在AppCompatActivity,调用supportRequestWindowFeature(Window.FEATURE_NO_TITLE),这样就可以去掉theme中自带的ActionBar了

  1. 向 Activity 的布局添加一个 Toolbar。例如,以下布局代码可以添加一个 Toolbar 并赋予其浮动在 Activity 之上的外观:
< 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"/>

Material Design 规范建议应用栏具有 4 dp 的仰角。

将工具栏定位在 Activity 布局的顶部,因为您要使用它作为应用栏。

  1. 在 Activity 的 onCreate() 方法中,调用 Activity 的 setSupportActionBar() 方法,然后传递 Activity 的工具栏。该方法会将工具栏设置为 Activity 的应用栏。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(myToolbar);
    ActionBar actionBar = getSupportActionBar();
    actionBar.hide();
    }

设置好ToolBar之后,如果想对他进行操作,再使用getSupportActionBar获取到ActionBar对象,就可以按照ActionBar的操作方式来管理工具栏了

可以看出来,ToolBar可以作为一个UI单元,可以很方便的对每个Activity进行单独设定管理,不再像ActionBar一样,只能通过主题来管理。当然,如果对工具栏要求不高,仍然可以使用主题来指定ActionBar,但是要注意,如果你的Activity继承自AppCompatActivity,使用的主题应该是Theme.AppCompat.,如果直接继承自Activity,用Theme.AppCompat.是不起作用的!

管理工具栏

一个完整的工具栏主要组成部分如下:


ActionBar

现在我们来依次看一下各个部分是怎样设置的

  • Navigation

    这是工具栏的层级导航功能,类似于按下Back键,但是,与Back键不同,这里需要我们指定返回的Activity。在Manifest文件里设置:

<activity
            android:name=".model.fragment.LandViewActivity"//包含ToolBar的当前Activity
            android:parentActivityName=".SplashActivity"//按下导航键返回的目标Activity
            >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value=".SplashActivity" />
        </activity>

这样,层级导航的功能设置就完成了。当然还需要设置Navigation,如果不想使用默认的导航图标,也可以自己在layout文件中指定:

app:navigationIcon="@drawable/ic_action_nav"

注意:使用ToolBar的时候,如果在Layout文件中没有设置NavigationIcon,工具栏是不会显示Navigation按键的。如果不想自定义图标,可以在获取到ActionBar对象之后,设置actionBar.setDisplayHomeAsUpEnabled(true)来启用Navigation功能,这样就可以使用系统自带的图标了。如果我们使用是ActionBar主题,Navigation功能默认是启用的,设置parentActivity就可以了
Navigation返回的Activity并不是返回栈里存在的实例,而是重新创建的Activity,也就是说,之前Activity存在的状态,从Navigation返回之后,并不会保存下来

  • Logo和Title

    这两项的设置非常简单,可以在layout文件中设置,也可以在代码中对ActionBar对象进行设置,就不再介绍了。

  • Menu

    在工具栏上可以设置多个按钮,Menu就是由这些按钮组成的。
    要在工具栏上添加按键,需要先指定Menu文件,menu文件需要定义在res/menu文件夹下(toolbar_menu.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/add_item"
        android:icon="@drawable/ic_action_new"
        android:title="Add"
        app:showAsAction="ifRoom|withText"
        />
    <item
        android:id="@+id/remo_item"
        android:icon="@drawable/ic_action_remove"
        android:title="Remove"
        app:showAsAction="ifRoom|withText"
        />
    <item
        android:id="@+id/more_item"
        android:icon="@drawable/ic_action_more"
        android:title="Remove"
        app:showAsAction="never"
        />
</menu>

注意,因为例子中使用是v7支持库,需要使用app命名空间。如果不使用支持库可以直接使用android。app:showAsAction指定了按键的显示方式。因为工具栏空间相对有限,我们可指定按键的显示方式,never表示总在overflow menu中显示,always表示总在工具栏显示,ifRoom表示空间足够则显示在工具栏上,withText表示空间足够的时候显示Title,也可以用组合的方式:ifRoom|withTitle

Menu定义好之后,在Activity中添加并引用它:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.toobar_menu,menu);
        return super.onCreateOptionsMenu(menu);
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
                break;
            case R.id.remo_item:
                Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
                break;
            case R.id.more_item:
                Toast.makeText(this,"Add button clicked",Toast.LENGTH_SHORT).show();
                break;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

这里是在Activity中直接加载menu,如果是Fragment中使用,会有所不同。Fragment中必须设置setHasOptionsMenu(true),它用来通知FragmentManager,当前Fragment需要调用onCreateOptionsMenu方法。

  • Navigation和Menu的关系

    实际上Navigation也属于menu,它的id是android.R.id.home,可以在onOptionsItemSelected中对它进行监听

public boolean onOptionsItemSelected(MenuItem item) {  
    switch (item.getItemId()) {  
    case android.R.id.home:  
        Intent upIntent = NavUtils.getParentActivityIntent(this);  
        if (NavUtils.shouldUpRecreateTask(this, upIntent)) {  
            TaskStackBuilder.create(this)  
                    .addNextIntentWithParentStack(upIntent)  
                    .startActivities();  
        } else {  
            upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
            NavUtils.navigateUpTo(this, upIntent);  
        }  
        return true;  
        ......  
    }  
}  

调用NavUtils.getParentActivityIntent()方法可以获取到跳转至父Activity的Intent,然后如果父Activity和当前Activity是在同一个Task中的,则直接调用navigateUpTo()方法进行跳转,如果不是在同一个Task中的,则需要借助TaskStackBuilder来创建一个新的Task。

OverFlow按钮显示图标

overflow中的按钮默认是不显示图标的,它由MenuBuilder这个类的setOptionalIconsVisible方法来决定,如果我们在overflow被展开的时候给这个方法传入true,那么里面的每一个Action按钮对应的图标就都会显示出来了。

@Override  
public boolean onMenuOpened(int featureId, Menu menu) {  
    if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {  
        if (menu.getClass().getSimpleName().equals("MenuBuilder")) {  
            try {  
                Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);  
                m.setAccessible(true);  
                m.invoke(menu, true);  
            } catch (Exception e) {  
            }  
        }  
    }  
    return super.onMenuOpened(featureId, menu);  
}  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容