「译」Android 总览画面(Overview Screen)详解

你在寻找在 Lolipop 上优化总览画面的方法吗?大多数开发者的选择是阅读官方文档

如文档所述:

总览画面(返回最近的屏幕,最近的任务(task)列表,或者最近的应用程序)是用来给最近的 Activities 和 tasks 提供入口的系统级 UI. 用户可以从这个列表中选择一个 task 并恢复它,当然用户也可以通过滑动来移除这个任务。

在 Lollipop 之前,总览画面是不可设置的。它所显示的内容包含应用程序的标签(label),launcher icon,还有用户在应用程序中最后操作的页面的截图。

从 Lollipop 起,我们有了更精致的总览画面。更重要的是,新的 API 可以让我们自定义总览画面”卡片”的 icon,title 和 顶部栏(top bar)的颜色。

通过简单的设置,你就可以让你程序纵览画面卡片在众多应用中脱颖而出。

默认的总览画面(Overview Card)样式和 XML

让我们先了解下,如果你使用默认的 Lollipop 样式时将会发生什么。

系统将会根据程序的 manifest 给总览画面卡片的图标(icon),标签(label)和顶部栏(top bar)。

  • Icon - android:icon
  • Label text - android:label
  • Top Bar Color - colorPrimary value of android:theme

这些参数值会从 Manifest 文件的 base activity 中读取。在大多数情况下,总览画面是基于应用程序的 launcher 或 main activity 来显示内容。如果当前的 Activity 中没有定义指定的参数,系统将会使用 application 的参数。

有趣的事情是,标签(lable)文字的颜色是不能直接设置的。系统会根据顶部栏的颜色自动设置标签文字的颜色。如果顶部栏是暗色,标签文字将为白色。否则,标签文字颜色将为黑色。

向下兼容和 colorPrimary

从 Lollipop 才开始引入 colorPrimary 参数。然而,我们可以通过v7 appcompat 设置这个参数。同时请确保你应用的主题为Lollipop-compatible.更简单的方式就是 include v7 appcompat 资源库同时让主题继承自 AppCompat. 比如 Theme.AppCompat.Light.

默认样式:使用 XML 的限制

在什么情况下默认的样式就不够好了呢?这取决于你程序的设计。

更改总览画面最简单粗暴的方法,就是提供一个尺寸较小并且背景色跟 primaryColor 相同的,单独的总览图标(overview icon)。遗憾的是,通过 XML 文件并不能达到这样的效果。

Demo 程序获取:LollipopOverviewStylingDemo

AndroidManifest.xml 文件的代码片段:

...
<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher_bnr"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >

    <activity
        android:name="com.bignerdranch.android.bignerdranch.WelcomeActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
...  

sytles.xml 文件代码:

<resources>
    <style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">#747501</item>
        <item name="colorPrimaryDark">#595a02</item>
        <item name="colorAccent">#e7ad10</item>
    </style>
</resources>  

如果你运行了程序你可以看到,总览画面的 icon 根据 applicaation android:icon 显示,标签(label)根据 WelcomeActivity 的 android:label 显示,top bar 的颜色根据 AppTheme 的 colorPrimary 显示。

Kar Loong Wong,一个超厉害的设计师,看了我的总览画面的卡片效果后,直接指出了我用 launcher icon 在总览页面很丑。他说图片显示小了导致上面的螺旋桨形状的 Logo 很难辨认。

于是我给 launcher 界面设置了独立的图标。问题来了,manifest 不提供根据 activity 的图标来自定义总览图标的方法。在 WelcomeActivity 设置 android:icon 会被 launcher 图标所覆盖。这意味着我们需要用其他方式来重写总览页的卡片样式。算你运气好,还真有一种方式来实现…

通过代码重写总览界面卡片样式

Lollipop 可以在程序运行时设置 TaskDescription .这将会覆盖总览卡片的图片,背景色和标签。

TaskDescription 默认基于任务的 activity 栈的 activity。其他的 Activity 不会影响样式,除非这些 Activity 在运行(run time)时明确的设置了 TaskDescription. 任务栈中最顶端的设置了 TaskDescription 的 Activity 将会生效(覆盖了 manifest 或者其他设置了 TaskDescription Activity 的效果)

下面的代码段来自 WelcomeActivity.java,演示了如何创建及设置一个 task description :

public class WelcomeActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

            TypedValue typedValue = new TypedValue();
            Resources.Theme theme = getTheme();
            theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
            int color = typedValue.data;

            Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_activity_welcome);
            ActivityManager.TaskDescription td = new ActivityManager.TaskDescription(null, bm, color);

            setTaskDescription(td);
            bm.recycle();

        }
    }
    ...
}

Activity.setTaskDescription() 只在 API 21(Lollipop)及以上版本可用。为了在适配旧设备的同时在新设备上有较好的展示效果,我们需要在使用 TaskDescription 前进行 API 版本的判断。

我们使用 TaskDescription 的需要三个参数的构造函数 ActivityManager.TaskDescription(String label, Bitmap icon, int colorPrimary)) 来创建一个 TaskDescription 实例。不要使用 TaskDescription 的其他构造函数;他们都忽略的 colorPrimary 的设置。

如果你没有给标签(label)赋值或者传了一个空值,系统将会读取 manifest 中的值。

colorPrimary 直接根据主题获取。这种情况下,你不需要在许多地方修改色板的值。我建议你直接使用 colorPrimary 的值,除非你有很好的理由。注意,primary color 一定要设置成不透明的。否则,系统将会抛出 runtime exception.

最后,调用 setTaskDescription() 方法使 TaskDescription 实例与 Activity 实例关联。

最后的效果如下(一个独立的 launcher 和 总览图标):

当心不标准的 Toolbar

总览卡片实际上是将一个 top bar 覆盖到程序截图上。默认情况下 Toolbar 跟 top bar 的尺寸是相同的。如果 Toolbar 的高度大于默认高度,那么 Toolbar 将会在 top bar 底部出现一部分内容。如果应用程序没有 Toolbar 或者你的 Toolbar 不是标准的,或者你的 Toolbar 比默认的尺寸小,我们将会看到一个被裁剪的截图。

原文地址:https://www.bignerdranch.com/blog/polishing-your-Android-overview-screen-entry/#fnref:1