第二个 Android 11 开发者预览版现已推出,快来测试并分享您的反馈吧

向初次使用的用户介绍您的应用

要向初次使用的用户展示如何充分利用您的应用,可以在应用启动时显示新手入门信息。如下是新手入门信息的一些示例:

  • 当用户第一次访问频道应用时,展示有关提供哪些频道的详细信息。
  • 提醒用户关注您的应用中值得注意的功能。
  • 说明用户在第一次使用应用时应当要执行的必要或建议步骤。

Leanback androidx 库提供用于展示初次使用的用户信息的 OnboardingFragment 类。本课介绍如何使用 OnboardingFragment 类来展示应用第一次启动时所显示的介绍信息。OnboardingFragment 利用电视界面最佳做法来展示信息,这种方式不仅适合电视界面风格,也方便在电视设备上导航。

图 1 OnboardingFragment 示例。

您的 OnboardingFragment 不应包含需要用户输入的界面元素,如按钮和字段。同样,它也不应用作用户将定期执行的任务的界面元素。如果需要显示需要用户输入的多页界面,请考虑使用 GuidedStepFragment

添加 OnboardingFragment

要在您的应用中添加 OnboardingFragment,请实现一个用于扩展 OnboardingFragment 类的类。通过 Activity 的布局 XML 或以编程方式将这个 Fragment 添加到 Activity 中。确保 Activity 或 Fragment 采用派生自 Theme_Leanback_Onboarding 的主题背景,如自定义主题背景中所述。

在应用的主 Activity 的 onCreate() 方法中,通过指向 OnboardingFragment's 父 Activity 的 Intent 调用 startActivity()。这可确保您的 OnboardingFragment 在应用启动后立即显示。

要确保 OnboardingFragment 仅在用户首次启动您的应用时显示,请使用 SharedPreferences 对象来跟踪用户是否已查看过 OnboardingFragment。定义一个在用户查看完 OnboardingFragment 时变为 true 的布尔值。在您的主 Activity 的 onCreate() 中检查这个值,并且仅当值为 false 时启动 OnboardingFragment 父 Activity。以下示例展示了如何替换用于检查 SharedPreferencesonCreate(),如果没有设为 true,则调用 startActivity() 来显示 OnboardingFragment

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        PreferenceManager.getDefaultSharedPreferences(this).apply {
            // Check if we need to display our OnboardingFragment
            if (!getBoolean(MyOnboardingFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
                // The user hasn't seen the OnboardingFragment yet, so show it
                startActivity(Intent(this@OnboardingActivity, OnboardingActivity::class.java))
            }
        }
    }
    

Java

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SharedPreferences sharedPreferences =
                PreferenceManager.getDefaultSharedPreferences(this);
        // Check if we need to display our OnboardingFragment
        if (!sharedPreferences.getBoolean(
                MyOnboardingFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
            // The user hasn't seen the OnboardingFragment yet, so show it
            startActivity(new Intent(this, OnboardingActivity.class));
        }
    }
    

当用户查看 OnboardingFragment 后,利用 SharedPreferences 对象将它标记为已查看。为此,请在您的 OnboardingFragment 中替换 onFinishFragment() 并将 SharedPreferences 值设为 true,如以下示例所示:

Kotlin

    override fun onFinishFragment() {
        super.onFinishFragment()
        // User has seen OnboardingFragment, so mark our SharedPreferences
        // flag as completed so that we don't show our OnboardingFragment
        // the next time the user launches the app.
        PreferenceManager.getDefaultSharedPreferences(context).edit().apply {
            putBoolean(COMPLETED_ONBOARDING_PREF_NAME, true)
            apply()
        }
    }
    

Java

    @Override
    protected void onFinishFragment() {
        super.onFinishFragment();
        // User has seen OnboardingFragment, so mark our SharedPreferences
        // flag as completed so that we don't show our OnboardingFragment
        // the next time the user launches the app.
        SharedPreferences.Editor sharedPreferencesEditor =
                PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
        sharedPreferencesEditor.putBoolean(
                COMPLETED_ONBOARDING_PREF_NAME, true);
        sharedPreferencesEditor.apply();
    }
    

添加 OnboardingFragment 页面

在添加 OnboardingFragment 之后,您需要定义新手入门信息页。OnboardingFragment 可在一系列有序页面中显示内容。每个页面可以包含标题、说明,以及含有图像或动画的若干子视图。

图 2. OnboardingFragment 页面元素。

图 2 中展示了一个示例页面,并通过标注标出您的 OnboardingFragment 可以提供的可自定义页面元素。页面元素有:

  1. 页面标题。
  2. 页面说明。
  3. 页面内容视图,本例中是一个简单的绿色勾号显示在灰色方框中。此视图是可选的。此视图可用于展示页面详细信息,例如突出显示页面所介绍应用功能的屏幕截图。
  4. 页面背景视图,本例中为一个简单的蓝色渐变背景。此视图始终呈现在页面上其他视图的后面。此视图是可选的。
  5. 页面前景视图,本例中为一个徽标。此视图始终呈现在页面上所有其他视图的前面。此视图是可选的。

当首次创建 OnboardingFragment 或将其附加到父 Activity 时初始化页面信息,因为系统会在创建该 Fragment 的视图时请求页面信息。您可以在类构造函数或 onAttach() 替换中初始化页面信息。

替换以下各种向系统提供页面信息的方法:

替换以下各种方法,以提供用于显示图像或动画的可选子视图:

系统会将您创建的 View 添加到页面布局中。以下示例替换 onCreateContentView() 并返回 ImageView

Kotlin

    private lateinit var contentView: ImageView
    ...
    override fun onCreateContentView(inflater: LayoutInflater?, container: ViewGroup?): View? {
        return ImageView(context).apply {
            scaleType = ImageView.ScaleType.CENTER_INSIDE
            setImageResource(R.drawable.onboarding_content_view)
            setPadding(0, 32, 0, 32)
            contentView = this
        }
    }
    

Java

    private ImageView contentView;
    ...
    @Override
    protected View onCreateContentView(LayoutInflater inflater, ViewGroup container) {
        contentView = new ImageView(getContext());
        contentView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        contentView.setImageResource(R.drawable.onboarding_content_view);
        contentView.setPadding(0, 32, 0, 32);
        return contentView;
    }
    

添加初始徽标屏幕

您的 OnboardingFragment 可以在启动后显示一个可选的徽标屏幕,用来介绍您的应用。如果希望将 Drawable 显示为徽标屏幕,请在 OnboardingFragment'sonCreate() 方法中通过 Drawable 的 ID 调用 setLogoResourceId()。系统将淡入并简要显示此 Drawable,再淡出 Drawable,然后显示 OnboardingFragment 的第一个页面。

如果要为您的徽标屏幕提供自定义动画,则不要调用 setLogoResourceId(),而是替换 onCreateLogoAnimation() 并返回一个呈现自定义动画的 Animator 对象,如以下示例所示:

Kotlin

    public override fun onCreateLogoAnimation(): Animator =
            AnimatorInflater.loadAnimator(context, R.animator.onboarding_logo_screen_animation)
    

Java

    @Override
    public Animator onCreateLogoAnimation() {
        return AnimatorInflater.loadAnimator(getContext(),
                R.animator.onboarding_logo_screen_animation);
    }
    

自定义页面动画

在显示 OnboardingFragment 的第一个页面时,以及当用户导航到另一个页面时,系统会使用默认的动画。您可以通过替换 OnboardingFragment 中的方法来自定义这些动画。

要自定义在第一个页面上显示的动画,请替换 onCreateEnterAnimation() 并返回 Animator。以下示例将创建一个 Animator,它将在水平方向上缩放内容视图:

Kotlin

    override fun onCreateEnterAnimation(): Animator =
        ObjectAnimator.ofFloat(contentView, View.SCALE_X, 0.2f, 1.0f)
                .setDuration(ANIMATION_DURATION)
    

Java

    @Override
    protected Animator onCreateEnterAnimation() {
        Animator startAnimator = ObjectAnimator.ofFloat(contentView,
                View.SCALE_X, 0.2f, 1.0f).setDuration(ANIMATION_DURATION);
        return startAnimator;
    }
    

要自定义用户导航到另一个页面时使用的动画,请替换 onPageChanged()。在 onPageChanged() 方法中,创建 Animators 来移除上一页并显示下一页,将它们添加到 AnimatorSet 中,再播放这个集合。以下示例使用一个淡出动画来移除上一页,更新内容视图图像,然后使用淡入动画来显示下一页:

Kotlin

    override fun onPageChanged(newPage: Int, previousPage: Int) {
        // Create a fade-out animation used to fade out previousPage and, once
        // done, swaps the contentView image with the next page's image.
        val fadeOut = ObjectAnimator.ofFloat(mContentView, View.ALPHA, 1.0f, 0.0f)
                .setDuration(ANIMATION_DURATION)
                .apply {
                    addListener(object : AnimatorListenerAdapter() {

                        override fun onAnimationEnd(animation: Animator) {
                            mContentView.setImageResource(pageImages[newPage])
                        }
                    })
                }
        // Create a fade-in animation used to fade in nextPage
        val fadeIn = ObjectAnimator.ofFloat(mContentView, View.ALPHA, 0.0f, 1.0f)
                .setDuration(ANIMATION_DURATION)
        // Create AnimatorSet with our fade-out and fade-in animators, and start it
        AnimatorSet().apply {
            playSequentially(fadeOut, fadeIn)
            start()
        }
    }
    

Java

    @Override
    protected void onPageChanged(final int newPage, int previousPage) {
        // Create a fade-out animation used to fade out previousPage and, once
        // done, swaps the contentView image with the next page's image.
        Animator fadeOut = ObjectAnimator.ofFloat(mContentView,
                View.ALPHA, 1.0f, 0.0f).setDuration(ANIMATION_DURATION);
        fadeOut.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mContentView.setImageResource(pageImages[newPage]);
            }
        });
        // Create a fade-in animation used to fade in nextPage
        Animator fadeIn = ObjectAnimator.ofFloat(mContentView,
                View.ALPHA, 0.0f, 1.0f).setDuration(ANIMATION_DURATION);
        // Create AnimatorSet with our fade-out and fade-in animators, and start it
        AnimatorSet set = new AnimatorSet();
        set.playSequentially(fadeOut, fadeIn);
        set.start();
    }
    

要详细了解如何创建 AnimatorsAnimatorSets,请参阅属性动画

自定义主题背景

任何 OnboardingFragment 实现都必须使用 Theme_Leanback_Onboarding 主题背景,或继承自 Theme_Leanback_Onboarding 的主题背景。通过执行以下操作之一,为您的 OnboardingFragment 设置主题背景:

  • 设置 OnboardingFragment's 父 Activity 以使用所需的主题背景。以下示例展示了如何设置一个 Activity 来使用应用清单中的 Theme_Leanback_Onboarding
        <activity
           android:name=".OnboardingActivity"
           android:enabled="true"
           android:exported="true"
           android:theme="@style/Theme.Leanback.Onboarding">
        </activity>
        
  • 使用自定义 Activity 主题背景中的 LeanbackOnboardingTheme_onboardingTheme 属性,在父 Activity 中设置主题背景。将这个属性指向只有您的 Activity 中的 OnboardingFragment 对象使用的另一个自定义主题背景。如果您的 Activity 已使用了一个自定义主题背景,并且您不想将 OnboardingFragment 样式应用到 Activity 中的其他视图,请采用这种方法。
  • 替换 onProvideTheme() 并返回所需的主题背景。如果有多个 Activity 使用您的 OnboardingFragment,或者父 Activity 无法使用所需的主题背景,请采用这种方法。以下示例替换 onProvideTheme() 并返回 Theme_Leanback_Onboarding

    Kotlin

        override fun onProvideTheme(): Int = R.style.Theme_Leanback_Onboarding
        

    Java

        @Override
        public int onProvideTheme() {
           return R.style.Theme_Leanback_Onboarding;
        }