本课程讨论如何创建一个镜像更新的 API 但支持旧版设备的实现。
决定替代解决方案
以向后兼容的方式使用更新的 UI 功能最具挑战性的任务是决定并实施针对旧版平台版本的旧版(回退)解决方案。在许多情况下,可以使用旧版 UI 框架功能来实现这些更新的 UI 组件的目的。例如
-
操作栏可以使用包含图像按钮的水平
LinearLayout
来实现,无论是作为自定义标题栏还是作为您活动布局中的视图。溢出操作可以在设备的菜单按钮下显示。 -
操作栏选项卡可以使用包含按钮的水平
LinearLayout
来实现,或者使用TabWidget
UI 元素来实现。 -
NumberPicker
和Switch
小部件可以使用Spinner
和ToggleButton
小部件分别实现。 -
ListPopupWindow
和PopupMenu
小部件可以使用PopupWindow
小部件实现。
通常没有适用于将更新的 UI 组件移植到旧版设备的通用解决方案。请注意用户体验:在旧版设备上,用户可能不熟悉更新的设计模式和 UI 组件。请考虑如何使用熟悉的元素来提供相同的功能。在许多情况下,这并不那么令人担忧 - 如果更新的 UI 组件在应用程序生态系统中很突出(例如操作栏),或者交互模型非常简单直观(例如使用 ViewPager
的滑动视图)。
使用旧版 API 实现选项卡
要创建操作栏选项卡的旧版实现,可以使用 TabWidget
和 TabHost
(尽管可以使用水平排列的 Button
小部件)。在名为 TabHelperEclair
和 CompatTabEclair
的类中实现此功能,因为此实现使用的是在 Android 2.0(Eclair)或更高版本中引入的 API。
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
小部件上的方法来创建 TabHost.TabSpec
对象和选项卡指示器。
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。下一课将讨论如何在您的应用程序中使用这些实现。