AppCompat 21实现低版本手机使用Material Design

Android5.0 Lollipop 的sdk发布以后,我就希望兼容包中也包含了新的Material Design主题,幸运的是的确如此。

这个新的主题包含在AppCompat 21中,所以需要注意的是如果你要将Material Design运用到以前的项目中,需要做点额外的工作。

本文演示用最基本的工具创建一个以Material作为主题的应用。我这里并不会详细的介绍如何应用这个主题,而是重点介绍如何向前兼容以及使用Lollipop中的transitions(过度效果)。

注:到目前位置Lollipop中的transitions仍然不能做到兼容非5.0系统的手机。

项目设置:

在gradle项目中,你需要将compile sdk版本设置成21,如下:

android {
    compileSdkVersion 21
    buildToolsVersion "21.0.0"
    defaultConfig {
        applicationId "com.antonioleiva.materialeverywhere"
        minSdkVersion 14
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"
    }
     ...
}
dependencies {
    compile fileTree(dir: 'libs', include: \['*.jar'\])
    compile 'com.android.support:appcompat-v7:21.+'
}

指定Material Theme主题

你需要将自己的主题继承自Theme.AppCompat,新的AppCompat有你所需要的支持Material Design的兼容代码与资源文件。在values-v21中我用自定义的base thmeme替代了原始主题,这是因为我要在里面使用5.0的各种transitions(过度)效果。

values/themes.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="AppTheme.Base"/>
    <style name="AppTheme.Base" parent="Theme.AppCompat">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimary</item>
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>
</resources>

values-v21/themes.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base">
    <item name="android:windowContentTransitions">true</item>
    <item name="android:windowAllowEnterTransitionOverlap">true</item>
    <item name="android:windowAllowReturnTransitionOverlap">true</item>
    <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
    <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
</resources>

在上面的代码中 我们设置了primary colors,同时去掉了actionbar,这是因为我们要使用一种新的工具替代它:ToolBar。后面我们将谈到ToolBar。

设置ToolBar

ToolBar基本上就是我们熟知的ActionBar,他们最主要的区别是ToolBar是我们所能控制的布局的一部分, 所以我们可以随意的实现一些自定义的效果,比如在ToolBar上使用动画、设定其高度之类的。

如下:

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
android:background="?attr/colorPrimaryDark"/>

Toolbar使用的时候就跟一般的控件一样,但是我们得告诉activity,这里的ToolBar是ActionBar的替代者。

@Override
    protectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResource());
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        if(toolbar != null) {
            setSupportActionBar(toolbar);
        }
    }

如上所示当调用了setSupportActionBar(toolbar)之后toolbar就有了特殊的地位,虽然他只是activity布局中的一个元素,但是他能像actionbar那样直接显示menu目录中的菜单资源。 需要注意的是使用setSupportActionBar要求你的activity继承自ActionBarActivity。

Lollipop系统Activity之间的切换效果

上面我们提到了在5.0以下的系统中没法看到Lollipop中的那些生动的切换效果,所以我们得想法解决这个问题。兼容包为我们提供了以下方法:

ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation(
     activity, transitionView, DetailActivity.EXTRA_IMAGE);
ActivityCompat.startActivity(activity, newIntent(activity, DetailActivity.class),
options.toBundle());

ActivityCompat让我们连判断版本的代码都省了。

下面是我实现的一个demo app的效果,代码已经放在了github上。this project in my Github.

纠正:


ActivityOptionsCompat.makeSceneTransitionAnimation只能在5.0上才可以看到效果,在5.0以下只能确保程序不出错,但没有效果,其中的原因估计是这样的:

ActivityOptionsCompat的确支持makeSceneTransitionAnimation方法,但是没法开启Window.FEATURE_CONTENT_TRANSITIONS(不管是代码还是xml中),在本文的demo中开启FEATURE_CONTENT_TRANSITIONS的代码如下:

    <item name="android:windowContentTransitions">true</item>

这是21以上才有的属性。

当然也有可能ActivityOptionsCompat能开启FEATURE_CONTENT_TRANSITIONS,只是我们不知道而已。至少本文的demo是没有能够在5.0以下开启FEATURE_CONTENT_TRANSITIONS的。就差这一步 很无赖。