本节课讨论如何创建镜像新 API 但仍支持旧设备的实现。
确定替代解决方案
要以向后兼容的方式使用新界面功能,最具挑战性的任务就是为旧平台版本决定并实现旧版(回退)解决方案。在许多情况下,使用旧界面框架功能可以实现这些新界面组件的用途。例如:
-
可以使用包含图片按钮的水平
LinearLayout
、作为自定义标题栏或 Activity 布局中的视图实现操作栏。可以在设备“菜单”按钮下显示溢出操作。 -
可以使用包含按钮的水平
LinearLayout
或使用TabWidget
界面元素实现操作栏标签页。 -
可以分别使用
Spinner
和ToggleButton
微件实现NumberPicker
和Switch
微件。 -
可以使用
PopupWindow
微件实现ListPopupWindow
和PopupMenu
微件。
通常,没有一个通用的解决方案可以将新界面组件向后移植到旧设备。注意用户体验:在旧设备上,用户可能不熟悉新的设计模式和界面组件。适当考虑如何使用熟悉的元素提供相同的功能。在许多情况下,如果应用生态系统中的新界面组件比较显眼(例如操作栏),或互动模型非常简单直观(例如使用 ViewPager
滑动视图),则问题不大。
使用旧 API 实现标签页
如需创建操作栏标签页的旧实现,可以使用 TabWidget
和 TabHost
(虽然也可以选择使用水平布局的 Button
微件)。在名为 TabHelperEclair
和 CompatTabEclair
的类中实现此步骤,因为该实现使用不高于 Android 2.0 (Eclair) 的版本中引入的 API。
![Eclair 标签页实现的类图。](https://developer.android.google.cn/static/images/training/backward-compatible-ui-classes-eclair.png?authuser=3&hl=nb)
图 1. Eclair 标签页实现的类图。
CompatTabEclair
实现会存储标签页属性,例如实例变量中的标签页文本和图标,这是因为没有 ActionBar.Tab
对象可用于处理此存储:
Kotlin
class CompatTabEclair internal constructor(val activity: FragmentActivity, tag: String) : CompatTab(tag) { // Store these properties in the instance, // as there is no ActionBar.Tab object. private var text: CharSequence? = null ... override fun setText(resId: Int): CompatTab { // Our older implementation simply stores this // information in the object instance. text = activity.resources.getText(resId) return this } ... // Do the same for other properties (icon, callback, etc.) }
Java
public class CompatTabEclair extends CompatTab { // Store these properties in the instance, // as there is no ActionBar.Tab object. private CharSequence text; ... public CompatTab setText(int resId) { // Our older implementation simply stores this // information in the object instance. text = activity.getResources().getText(resId); return this; } ... // Do the same for other properties (icon, callback, etc.) }
TabHelperEclair
实现使用
用于创建 TabHost.TabSpec
的 TabHost
widget
对象和标签页指示器:
Kotlin
class TabHelperEclair internal constructor(activity: FragmentActivity) : TabHelper(activity) { private var tabHost: TabHost? = null ... override fun setUp() { // Our activity layout for pre-Honeycomb devices // must contain a TabHost. tabHost = tabHost ?: mActivity.findViewById<TabHost>(android.R.id.tabhost).apply { setup() } } override fun addTab(tab: CompatTab) { ... tabHost?.newTabSpec(tab.tag)?.run { setIndicator(tab.getText()) // And optional icon ... tabHost?.addTab(this) } } // The other important method, newTab() is part of // the base implementation. }
Java
public class TabHelperEclair extends TabHelper { private TabHost tabHost; ... protected void setUp() { if (tabHost == null) { // Our activity layout for pre-Honeycomb devices // must contain a TabHost. tabHost = (TabHost) mActivity.findViewById( android.R.id.tabhost); tabHost.setup(); } } public void addTab(CompatTab tab) { ... TabSpec spec = tabHost .newTabSpec(tag) .setIndicator(tab.getText()); // And optional icon ... tabHost.addTab(spec); } // The other important method, newTab() is part of // the base implementation. }
您现在有 CompatTab
和 TabHelper
两个实现:一个适用于搭载 Android 3.0 或更高版本的设备并使用新 API,另一个适用于搭载 Android 2.0 或更高版本的设备并使用旧 API。下一课将讨论如何在您的应用中使用这些实现。