appcompat v21: 让 Android 5.0 前的设备支持 Material Design

今天Android 5.0 SDK正式出炉,随之而来的是许多的升级,其中包括新的UI控件以及卡片式主题设计。为了使您能够在旧的平台上使用升级后的设计模式,我们同时升级了支持库( support libraries),其中包括AppCompat。在这篇文章中我会简要的介绍AppCompat的新特性以及如何在您的应用中使用它。

AppCompat (aka ActionBarCompat)最初是作为android4.0  ActionBar 的API的补丁,为那些运行在Gingerbread环境中的设备提供一个通用的API层。新的v21的appcompat提供了与android5.0相一致的API及新特性。

Android 5.0 引入了一个新的 Toolbar控件,该控件是Action Bar设计模式的一个一般化实现,但是却给予了您更多的控制以及更灵活的使用能力。在您的视图结构中toolbar就是一个与其他控件一样的view,从而使得它能够更好的与其他的view以及动画相交互,并且能够对滚动事件作出响应。

配置

如果你现在用的是 Gradle , 那首先要做的是把 appcompat 做为 dependency 加到 build.gradle 中:

dependencies {  
    ...
    compile "com.android.support:appcompat-v7:21.0.0"}

新的整合

如果你没有过 AppCompat, 那就通过下列步骤配置:

Action Bar API 指南 是一部很全面的 AppCompat 使用手册. 需要升级到 v21 版本. 底下那个教你每个 Action Bar Style 属性都要做两个版本的 ‘Example theme’ 部分可以无视.

将以前的配置移植过来

如果你已经配置过 AppCompat, 下面教你如何更新 theme, 以便能够使用新的特性:

我们现在, 可以在所有平台上使用 Toolbar/ActionBar 的支持实现(Support Implementation), 也就是说, 我们不用再去读取跟 ActionBar 有关的 android:属性(android: attributes ).

对于那些已经配置过 appcompat 的应用, 你得把 v14 或以上版本的 theme 移除.  因为这些版本有些值的设置, 在 android 命名空间(namespace) 中, 会跟新版本发生冲突. 请注意, 本方法只对影响 ActionBar 的 styles/widgets 适用.

对于大部分应用来说, 只要在 values/: 中, 放置一个theme 声明就可以了,

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">  
    <!-- Here we setting appcompat’s actionBarStyle -->
    <item name="actionBarStyle">@style/MyActionBarStyle</item>

    <!-- ...and here we setting appcompat’s color theming attrs -->
    <item name="colorPrimary">@color/my_awesome_red</item>
    <item name="colorPrimaryDark">@color/my_awesome_darker_red</item>

    <!-- The rest of your attributes -->
</style>

主题

AppCompat已经支持最新的调色板主题,该主题能够使你更容易的通过使用主色调和强调色(primary and accent colour)来适配你的主题。下面是一个简单的示例:

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat.Light">  
    <!-- colorPrimary is used for the default action bar background -->
    <item name="colorPrimary">@color/my_awesome_color</item>

    <!-- colorPrimaryDark is used for the status bar -->
    <item name="colorPrimaryDark">@color/my_awesome_darker_color</item>

    <!-- colorAccent is used as the default value for colorControlActivated
         which is used to tint widgets -->
    <item name="colorAccent">@color/accent</item>

    <!-- You can also set colorControlNormal, colorControlActivated
         colorControlHighlight & colorSwitchThumbNormal. -->
</style>

通过这些设置,AppCompat将会自动的将这些值应用到API21+的框架属性中,从而自动的为状态栏以及最近的任务着色。

在老的平台上,AppCompat将会尽可能的模拟这些颜色主题。目前仅限于对actionbar以及一些控件的着色。

Widget 着色

在 Android 5.0 设备上运行,所有的 widgets 将使用我们刚谈论到颜色主题属性着色。有两个主要的特点,在棒棒糖上允许这个:绘制着色,在画板上引用主题属性(形式?attr/foo)。

Appcompat 提供了对 UIwidgets 的一个子集的旧设备的类似行为:

你不需要做任何特别的做这些工作,只是像往常一样在你的布局中使用这些控件与Appcompat将完成剩下的(有一些注意事项;请参阅下面的FAQ)。

首先,工具栏完全依靠Appcompat支持,有特色和使用框架widget的API同等。一旦使用它,你需要使用class android.support.v7.widget.工具栏。有两种方法使用工具栏:

Action Bar

为了像action bar一样使用toolbar,首先要停用decor提供action bar的功能。最简单的方式就是让你的主题继承Theme.AppCompat.NoActionBar (或者 light variant).

然后,你需要创建一个toolbar实例,通常都是通过xml布局的方式:

<android.support.v7.widget.Toolbar  
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/my_awesome_toolbar"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    android:background="?attr/colorPrimary" />

至于宽高以及背景完全取决与你,上面只是一个示例。由于toolbar只是一个ViewGroup所以你可以给它任何你想要的样式,并且放置的位置有你定。

然后在Activityh或Fragment中,将Toolbar设置成为你的action bar:

@Overridepublic void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_layout);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
    setSupportActionBar(toolbar);
}

到目前为止,你所有的菜单都将在Toolbar中显示出来,通过options menu的回调来弹出。

独立式

与上面的很类似,但是在这种模式下你并不需要将Toolbar作为你的action bar。正应为如此,你可以在使用AppCompat主题的时候,不需要停用decor提供的action bar的功能。

当独立使用的时候,你需要手动的为其配置content/actions。例如,如果你想要显示actions,那么你首先要向其中inflate一个menu:

@Overridepublic void onCreate(Bundle savedInstanceState) {  
    super.onCreate(savedInstanceState);
    setContentView(R.layout.my_layout);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);    // Set an OnMenuItemClickListener to handle menu item clicks
    toolbar.setOnMenuItemClickListener(            new Toolbar.OnMenuItemClickListener() {                @Override
                public boolean onMenuItemClick(MenuItem item) {                    // Handle the menu item
                    return true;
                }
    });    // Inflate a menu to be displayed in the toolbar
    toolbar.inflateMenu(R.menu.your_toolbar_menu);
}

使用Toolbar你还可以做一些其他的事情,详见 javadoc

样式

Toolbar的样式随标准的action bar的不同而不同,并且它是直接在view上设置的。

以下是你将Toolbar作为acton bar使用时将会用到的一个最基本的样式:

<android.support.v7.widget.Toolbar  
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="?attr/actionBarSize"
    app:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

app:theme 的声明保证你的文本和items使用的是实色(也就是100%的不透明的白色)

DarkActionBar

在开发过程中通常会问到我的一个问题就是,如何获得一个类似与'DarkActionBar'(深色的内容和浅色的菜单)的Toolbar。这里可以通过theme和popupTheme属性来实现:

<android.support.v7.widget.Toolbar  
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:minHeight="@dimen/triple_height_toolbar"
    app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

很显然的是背景和高度等属性你都可以自定义,以上的只是一些建议。

SearchView

AppCompat所提供的棒棒糖最新的SearchView的API具有很高的自我定制能力(欢呼声)。正应为如此,我们将使用L的样式而非以前的searchView*主题的属性。

以下就是你要使用SearchView的方法:

values/themes.xml:

<style name="Theme.MyTheme" parent="Theme.AppCompat">  
    <item name="searchViewStyle">@style/MySearchViewStyle</item>
</style>

<style name="MySearchViewStyle" parent="Widget.AppCompat.SearchView">  
    <!-- The layout for the search view. Be careful. -->
    <item name="layout">...</item>
    <!-- Background for the search query section (e.g. EditText) -->
    <item name="queryBackground">...</item>
    <!-- Background for the actions section (e.g. voice, submit) -->
    <item name="submitBackground">...</item>
    <!-- Close button icon -->
    <item name="closeIcon">...</item>
    <!-- Search button icon -->
    <item name="searchIcon">...</item>
    <!-- Go/commit button icon -->
    <item name="goIcon">...</item>
    <!-- Voice search button icon -->
    <item name="voiceIcon">...</item>
    <!-- Commit icon shown in the query suggestion row -->
    <item name="commitIcon">...</item>
    <!-- Layout for query suggestion rows -->
    <item name="suggestionRowLayout">...</item>
</style>

显然你并不需要设置所有(或任何一个)的属性值,默认的设置将会在大部分app中可用。

Toolbar is coming

希望这则博客能够帮助你使用AppCompat并且能够创造出一些很棒的、卡片化设计的app,如果有任何的关于AppCompat、支持库或更多的文档的需求,请在/G+/Twitter的评论中提出。

FAQ

为什么在我的预览版棒棒糖设备上,EditText(或上面列出的其他控件)无法被正确的着色?

appcompat中的控件着色是通过拦截布局的inflation并在这个地方插入一个特别的可感知着色操作的版本的控件来是实现的。对于大部分用户来说都是可以正常的工作的,但这里也可以列出一些无法正常工作的场景:

那些特殊的可感知着色的控件(tint aware widgets)目前仍未公开,因为他们有一些细节尚未完成。