Cómo presentar tu app a los usuarios que acceden por primera vez

Compila mejor con Compose
Crea IU atractivas con muy poco código usando Jetpack Compose para el SO Android TV.

Para mostrarle a un usuario nuevo cómo aprovechar al máximo tu app, muéstrale la información de integración cuando se inicia la app. Estos son algunos ejemplos de información de integración:

  • Presenta información detallada sobre qué canales están disponibles la primera vez que un usuario accede a una app de canales.
  • Destaca las funciones notables de tu app.
  • Explica los pasos obligatorios o recomendados que deben seguir los usuarios cuando usen la app por primera vez.

La biblioteca de androidx.Lean proporciona la clase OnboardingSupportFragment para presentar información al usuario que ingresa por primera vez. En esta guía, se describe cómo usar la clase OnboardingSupportFragment para presentar información introductoria que se muestra cuando la app se inicia por primera vez.

OnboardingSupportFragment usa las prácticas recomendadas de la IU de TV para presentar información de una manera que coincida con los estilos de la IU de TV y que sea fácil navegar en ella en dispositivos de TV.

Figura 1: Un OnboardingSupportFragment de ejemplo.

OnboardingSupportFragment no es adecuado para todos los casos de uso. No uses OnboardingSupportFragment cuando necesites incluir elementos de la IU que requieren entradas del usuario, como botones y campos. Tampoco uses OnboardingSupportFragment para las tareas que el usuario hará con regularidad. Por último, si necesitas presentar una IU de varias páginas que requiera la entrada del usuario, considera usar un GuidedStepSupportFragment.

Cómo agregar un elemento OnboardingSupportFragment

Para agregar un OnboardingSupportFragment a tu app, implementa una clase que extienda la clase OnboardingSupportFragment. Agrega este fragmento a una actividad, ya sea mediante el XML de diseño de la actividad o de manera programática. Asegúrate de que la actividad o el fragmento usen un tema derivado de Theme_Leanback_Onboarding, como se describe en la sección Cómo personalizar temas.

En el método onCreate() de la actividad principal de tu app, llama a startActivity() con un Intent que apunte a la actividad superior de tu OnboardingSupportFragment. De esta manera, te aseguras de que tu OnboardingSupportFragment aparezca tan pronto como se inicie la app.

Para asegurarte de que el objeto OnboardingSupportFragment solo aparezca la primera vez que el usuario inicie tu app, usa un objeto SharedPreferences para realizar un seguimiento si el usuario ya vio el elemento OnboardingSupportFragment. Define un valor booleano que cambie a "verdadero" cuando el usuario termine de ver el elemento OnboardingSupportFragment. Verifica este valor en el método onCreate() de tu actividad principal y solo inicia la actividad superior OnboardingSupportFragment si el valor es falso.

En el siguiente ejemplo, se muestra una anulación de onCreate() que comprueba si hay un valor SharedPreferences y, si no se establece en verdadero, se llama a startActivity() para mostrar el OnboardingSupportFragment:

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 OnboardingSupportFragment
        if (!getBoolean(MyOnboardingSupportFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
            // The user hasn't seen the OnboardingSupportFragment 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 OnboardingSupportFragment
    if (!sharedPreferences.getBoolean(
            MyOnboardingSupportFragment.COMPLETED_ONBOARDING_PREF_NAME, false)) {
        // The user hasn't seen the OnboardingSupportFragment yet, so show it
        startActivity(new Intent(this, OnboardingActivity.class));
    }
}

Después de que el usuario vea la OnboardingSupportFragment, márcala como vista con el objeto SharedPreferences. Para ello, anula onFinishFragment() en tu OnboardingSupportFragment y establece el valor SharedPreferences en verdadero, como se muestra en el siguiente ejemplo:

Kotlin

override fun onFinishFragment() {
    super.onFinishFragment()
    // User has seen OnboardingSupportFragment, so mark our SharedPreferences
    // flag as completed so that we don't show our OnboardingSupportFragment
    // 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 OnboardingSupportFragment, so mark our SharedPreferences
    // flag as completed so that we don't show our OnboardingSupportFragment
    // the next time the user launches the app
    SharedPreferences.Editor sharedPreferencesEditor =
            PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
    sharedPreferencesEditor.putBoolean(
            COMPLETED_ONBOARDING_PREF_NAME, true);
    sharedPreferencesEditor.apply();
}

Cómo agregar páginas OnboardingSupportFragment

Un elemento OnboardingSupportFragment muestra contenido en una serie de páginas ordenadas. Después de agregar tu OnboardingSupportFragment, debes definir las páginas de integración. Cada página puede tener un título, una descripción y varias subvistas que pueden contener imágenes o animaciones.

Figura 2: OnboardingSupportFragment.

En la Figura 2, se muestra una página de ejemplo con texto destacado que marca elementos de página personalizables que tu OnboardingSupportFragment puede proporcionar. Los elementos de la página son los siguientes:

  1. El título de la página
  2. La descripción de la página
  3. La vista de contenido de la página, en este caso, una simple marca de verificación verde en un cuadro gris (esta vista es opcional Usa esta vista para ilustrar los detalles de la página. Por ejemplo, puedes incluir una captura de pantalla que destaque la función de la app que se describe en la página.
  4. La vista del segundo plano de la página, en este caso, un simple gradiente azul Esta vista siempre se renderiza detrás de otras vistas de la página. (esta vista es opcional
  5. La vista de primer plano de la página, en este caso, un logotipo Esta vista siempre se renderiza frente a todas las demás vistas de la página. (esta vista es opcional

Inicializa la información de la página cuando OnboardingSupportFragment se cree por primera vez o se adjunte a la actividad superior, como la información de la página de solicitud del sistema cuando crea la vista del fragmento. Puedes inicializar la información de la página en tu constructor de clases o en una anulación de onAttach().

Anula cada uno de los siguientes métodos, que proporcionan información de la página al sistema:

Anula cada uno de los siguientes métodos para proporcionar subvistas opcionales que muestren imágenes o animaciones:

  • onCreateBackgroundView() muestra un objeto View que creas para que actúe como vista en segundo plano o un valor nulo si no se necesita una vista en segundo plano.
  • onCreateContentView() muestra un objeto View que creas para que actúe como vista de contenido o un valor nulo si no se necesita una vista de contenido.
  • onCreateForegroundView() muestra un objeto View que creas para que actúe como vista en primer plano o un valor nulo si no se necesita una vista en primer plano.

El sistema agrega el objeto View que crees al diseño de la página. En el siguiente ejemplo, se anula onCreateContentView() y se muestra un 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;
}

Cómo agregar una pantalla de logotipo inicial

Tu OnboardingSupportFragment puede comenzar con una pantalla de logotipo opcional que presenta a tu app. Si deseas mostrar una Drawable como la pantalla de tu logotipo, llama a setLogoResourceId() con el ID de tu Drawable en el método onCreate() de tu OnboardingSupportFragment. El sistema aplica un fundido de entrada y muestra brevemente el Drawable; luego, aplica un fundido de salida para el Drawable antes de mostrar la primera página de tu OnboardingSupportFragment.

Si deseas proporcionar una animación personalizada para la pantalla de tu logotipo, en lugar de llamar a setLogoResourceId(), anula onCreateLogoAnimation() y muestra un objeto Animator que renderice tu animación personalizada, como se muestra en el siguiente ejemplo:

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);
}

Cómo personalizar animaciones de página

El sistema usa animaciones predeterminadas cuando muestra la primera página de tu OnboardingSupportFragment y cuando el usuario navega a otra página. Para personalizar estas animaciones, puedes anular métodos en tu OnboardingSupportFragment.

Para personalizar la animación que aparece en tu primera página, anula onCreateEnterAnimation() y muestra un Animator. En el siguiente ejemplo, se crea un Animator que escala la vista de contenido de forma horizontal:

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;
}

Para personalizar la animación que se usa cuando el usuario navega a una página diferente, anula onPageChanged(). En tu método onPageChanged(), crea objetos Animator que quiten la página anterior y muestren la siguiente, agrégalos a un AnimatorSet y reproduce el conjunto. En el siguiente ejemplo, se usa una animación de fundido de salida para quitar la página anterior, se actualiza la imagen de la vista de contenido y se usa una animación con fundido de entrada para mostrar la página siguiente:

Kotlin

override fun onPageChanged(newPage: Int, previousPage: Int) {
    // Create a fade-out animation for previousPage and, once
    // done, swap 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 for nextPage
    val fadeIn = ObjectAnimator.ofFloat(mContentView, View.ALPHA, 0.0f, 1.0f)
            .setDuration(ANIMATION_DURATION)
    // Create AnimatorSet with 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 for previousPage and, once
    // done, swap 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 for nextPage
    Animator fadeIn = ObjectAnimator.ofFloat(mContentView,
            View.ALPHA, 0.0f, 1.0f).setDuration(ANIMATION_DURATION);
    // Create AnimatorSet with fade-out and fade-in animators and start it
    AnimatorSet set = new AnimatorSet();
    set.playSequentially(fadeOut, fadeIn);
    set.start();
}

Para obtener más detalles sobre cómo crear objetos Animator y objetos AnimatorSet, consulta Descripción general de la animación de propiedades.

Cómo personalizar temas

Cualquier implementación de OnboardingSupportFragment debe usar el tema Theme_Leanback_Onboarding o un tema heredado de Theme_Leanback_Onboarding. Realiza una de las siguientes acciones para configurar el tema de tu OnboardingSupportFragment:

  • Configura la actividad superior de OnboardingSupportFragment para que use el tema deseado. En el siguiente ejemplo, se muestra cómo configurar una actividad para que use Theme_Leanback_Onboarding en el manifiesto de la app:
    <activity
       android:name=".OnboardingActivity"
       android:enabled="true"
       android:exported="true"
       android:theme="@style/Theme.Leanback.Onboarding">
    </activity>
    
  • Configura el tema en la actividad principal mediante el atributo LeanbackOnboardingTheme_onboardingTheme en un tema de actividad personalizado. Apunta este atributo a otro tema personalizado que solo usen los objetos OnboardingSupportFragment de tu actividad. Usa este enfoque si tu actividad ya usa un tema personalizado y no quieres aplicar estilos de OnboardingSupportFragment a otras vistas de la actividad.
  • Anula onProvideTheme() y muestra el tema deseado. Usa este enfoque si varias actividades usan tu OnboardingSupportFragment o si la actividad superior no puede usar el tema deseado. En el siguiente ejemplo, se anula onProvideTheme() y se muestra Theme_Leanback_Onboarding:

    Kotlin

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

    Java

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