Head First Android ActionBar

Hujiawei Bujidao


     

Head First Android ActionBar


本文介绍Android ActionBar的使用

最近在Android Studio中新建项目时发现Activity还是和以前一样,默认继承自ActionBarActivity,但是ActionBarActivity 却被标示为已经过时的API!对于这个问题,StackOverflow上已经有人回答了,请看ActionBarActivity deprecated,然后你会发现自从Android的兼容支持库升级到21版本以后(appcompat-v7-r21.1.0),ActionBarActivityAppCompatActivity 取代了!还有一个变化是建议使用Toolbar,而不要使用原来的ActionBar 了!所以,这两节的内容我打算总结下ActionBar和Toolbar的基本使用,因为Toolbar实际上是ActionBar的扩展,所以这一节还是介绍复杂的ActionBar,下一节再继续介绍Toolbar。

1.ActionBar的来源

ActionBar是从Android 3.0开始引入的,它是用于取代3.0之前的标题栏,并提供更为丰富的导航效果。

2.添加ActionBar

参考Setting Up the Action Bar

(1)支持Android 3.0以上版本(API level 11)

如果要支持Android 3.0以上版本(API level 11),即android:minSdkVersion="11",那么很简单,只要Activity的Theme是使用了Theme.Holo 系列主题其中一种或者继承自这些主题,那么Activity就默认包含了ActionBar。

(2)支持Android 2.1以上版本(API level 7)

如果要支持Android 2.1以上版本(API level 7),即android:minSdkVersion="7",那么就要使用兼容支持库v7 appcompat。导入AppCompat支持库之后,只要Activity的Theme是使用了Theme.AppCompat 兼容主题其中一种或者继承自这些兼容主题,然后让Activity继承自appcompat中的ActionBarActivity 类即可。

3.设置ActionBar的风格

参考Styling the Action Bar

下图是三种不同的来自Theme.holo 系列的ActionBar的样式,对应于Theme.AppCompat 系列分别是Theme.AppCompatTheme.AppCompat.LightTheme.AppCompat.Light.DarkActionBar

image

那么如何自定义呢?比如修改ActionBar的背景颜色该怎么办呢?和以前一样,我们可以继承默认的主题,然后修改默认主题中的某些样式来实现。

以修改ActionBar的背景颜色为例,如果是支持Android 3.0及以上版本的话可以用下面的方式,需要注意两点:(1)自定义android:actionBarStyle ;(2) 自定义的actionBarStyle 也要继承自某个actionBarStyle 样式。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- the theme applied to the application or activity -->
    <style name="CustomActionBarTheme"
           parent="@android:style/Theme.Holo.Light.DarkActionBar">
        <item name="android:actionBarStyle">@style/MyActionBar</item>
    </style>

    <!-- ActionBar styles -->
    <style name="MyActionBar"
           parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
        <item name="android:background">@drawable/actionbar_background</item>
    </style>
</resources>

如果是支持Android 2.1版本以上的话,可以用下面的方式,注意这里需要设置backgroundandroid:background两个属性的值:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- the theme applied to the application or activity -->
    <style name="CustomActionBarTheme"
           parent="@style/Theme.AppCompat.Light.DarkActionBar">
        <item name="android:actionBarStyle">@style/MyActionBar</item>

        <!-- Support library compatibility -->
        <item name="actionBarStyle">@style/MyActionBar</item>
    </style>

    <!-- ActionBar styles -->
    <style name="MyActionBar"
           parent="@style/Widget.AppCompat.Light.ActionBar.Solid.Inverse">
        <item name="android:background">@drawable/actionbar_background</item>

        <!-- Support library compatibility -->
        <item name="background">@drawable/actionbar_background</item>
    </style>
</resources>

类似的,我们还可以修改其他的样式,例如文本颜色等等。

如果我们想让ActionBar如下图所示悬浮起来的话,可以修改android:windowActionBarOverlay 样式为true

参考Overlaying the Action Bar

image

//**For Android 3.0 and higher only**
<resources>
    <!-- the theme applied to the application or activity -->
    <style name="CustomActionBarTheme"
           parent="@android:style/Theme.Holo">
        <item name="android:windowActionBarOverlay">true</item>
    </style>
</resources>

//**For Android 2.1 and higher**
<resources>
    <!-- the theme applied to the application or activity -->
    <style name="CustomActionBarTheme"
           parent="@android:style/Theme.AppCompat">
        <item name="android:windowActionBarOverlay">true</item>

        <!-- Support library compatibility -->
        <item name="windowActionBarOverlay">true</item>
    </style>
</resources>

在悬浮状态下,如果你又希望你的组件是一直处在ActionBar下面一直可见的,可以设置它的padding 或者 margin属性,值为actionBarSize

//
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?android:attr/actionBarSize">
    ...
</RelativeLayout>

//
<!-- Support library compatibility -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">
    ...
</RelativeLayout>
//In this case, the ?attr/actionBarSize value without the prefix works on all versions, including Android 3.0 and higher.

4.添加Action Buttons

参考Adding Action Buttons

(4.1) 定义Action Buttons其实就是定义Menu,可以在/res/menu 新建菜单文件即可,如下所示:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- Search, should appear as action button -->
    <item android:id="@+id/action_search"
          android:icon="@drawable/ic_action_search"
          android:title="@string/action_search"
          android:showAsAction="ifRoom" />
    <!-- Settings, should always be in the overflow -->
    <item android:id="@+id/action_settings"
          android:title="@string/action_settings"
          android:showAsAction="never" />
</menu>

当菜单项过多时,Android会分两种情况进行处理: 1、手机有MENU实体键:则按下Menu键后会显示剩余菜单项; 2、手机没有MENU实体键:则会在最左边显示一个Action OverFlow按钮,按下后会显示剩余项菜单。

属性 android:showAsAction 可以用来设置该菜单项的显示方式,共有5中属性值: never:永远不会显示。只会在溢出列表中显示。 ifRoom:会显示在Item中,但是如果已经有4个或者4个以上的Item时会隐藏在溢出列表中。 always:无论是否溢出,总会显示。 withText:Title会显示。 collapseActionView:可拓展的Item。

注意,如果你是为了兼容Android 2.1版本等低版本系统而使用了支持库Support Library 的话,你还需要自定义一个命名空间NameSpace,因为showAsAction 并不在android: 命名空间中,如下所示:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:yourapp="http://schemas.android.com/apk/res-auto" >
    <!-- Search, should appear as action button -->
    <item android:id="@+id/action_search"
          android:icon="@drawable/ic_action_search"
          android:title="@string/action_search"
          yourapp:showAsAction="ifRoom"  />
    ...
</menu>

(4.2) 然后在Activity的onCreateOptionsMenu中将Actions添加到ActionBar中

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu items for use in the action bar
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_activity_actions, menu);
    return super.onCreateOptionsMenu(menu);
}

(4.3) 点击Action之后的处理就是处理onOptionsItemSelected 方法

当用户选择一个Fragment的菜单项时,首先会调用Activity的onOptionsItemSelected()方法,如果该方法返回false,则调用Fragment实现的onOptionsItemSelected()方法。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle presses on the action bar items
    switch (item.getItemId()) {
        case R.id.action_search:
            openSearch();
            return true;
        case R.id.action_settings:
            openSettings();
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

(4.4) 如何利用ActionBar实现应用内的导航呢?

如果是在Anroid 4.1(API level 16)以上版本或者使用支持库中的ActionBarActivity的话,只需要在Manifest文件中指定Activity的父Activity即可,这样系统就知道返回的时候是回到哪个Activity了。(好在使用Android Studio的时候,每次新建Activity的时候都可以选择父Activity然后帮我们在Manifest文件中写好了)

如下所示,Android 4.1以上版本看android:parentActivityName 属性,以下版本看<meta-data> 元素:

<application ... >
    ...
    <!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.myfirstapp.MainActivity" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name="com.example.myfirstapp.DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName="com.example.myfirstapp.MainActivity" >
        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>
</application>

然后在Activity中setDisplayHomeAsUpEnabled(true) 即可

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_displaymessage);

    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    // If your minSdkVersion is 11 or higher, instead use:
    // getActionBar().setDisplayHomeAsUpEnabled(true);
}

如果细想的话,还要考虑当前Activity和父Activity所处的Stack的情况,那么就复杂了,可以参考Providing Up Navigation学习下如何处理不同的launchMode下的导航。

关于Android getActionBar vs getSupportActionBar?

这个一个经常出错的问题,可以看下这里Android getActionBar vs getSupportActionBar?,简言之,如果是支持Android 3.0以上版本(API level 11以上)使用getActionBar 即可,如果需要支持Android 2.1等低版本,那么肯定需要使用兼容支持库,那么就要使用其中的getSupportActionBar 才行。

其他的关于ActionBar的内容参见这篇文章Android UI开发详解之ActionBar,它还详细介绍了如果开发带Tab的ActionBar以及下拉模式的ActionBar等内容。

OK,ActionBar就介绍到这里,下面进入第二节——Toolbar

Hujiawei is a mobile developer Guangdong, China http://javayhu.me/ 本博客所有文章均为原创,请勿随意转载,如需转载请联系我 (hujiawei090807 AT gmail.com) 我在小专栏有个移动开发技术专栏,不定期分享移动开发的核心技术,总结移动开发的实战经验
所有文章皆为原创,内容制作精良,保证干货满满,欢迎订阅 (https://xiaozhuanlan.com/u/javayhu)
>>> 我最近在Android面试指南小专栏里面写了一篇稿子 [Android面试——算法面试心得] ,欢迎阅读!<<<
下面的二维码是我个人维护的微信公众号“潇涧技术专栏”,会不定期分享移动开发的核心技术,欢迎关注!