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

Para mostrar a un usuario nuevo cómo aprovechar tu app, presenta información integrada cuando esta se inicie. A continuación, puedes ver algunos ejemplos:

  • 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 los usuarios deberían seguir al usar la app por primera vez.

La Biblioteca Leanback de AndroidX proporciona la clase OnboardingFragment para presentar información al usuario que ingresa por primera vez. En esta lección, se describe cómo usar la clase OnboardingFragment para presentar información introductoria que se muestra cuando la app se inicia por primera vez. OnboardingFragment usa las prácticas recomendadas de la IU de TV a fin de presentar la información de manera tal que coincida con los estilos de IU de TV y que sea fácil navegar en ella en dispositivos de TV.

Figura 1: Ejemplo de OnboardingFragment

Tu OnboardingFragment no debería contener elementos de IU que requieran entradas por parte del usuario, como botones y campos. Tampoco debería usarse como elemento de IU para una tarea que el usuario realizará con frecuencia. Si necesitas presentar una IU de varias páginas que requiere entradas por parte del usuario, considera usar un elemento GuidedStepFragment.

Cómo agregar un elemento OnboardingFragment

Para agregar un elemento OnboardingFragment a tu app, implementa una clase que extienda la clase OnboardingFragment. 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 Cómo personalizar temas.

En el método onCreate() de la actividad principal de tu app, llama a startActivity() con un elemento Intent que apunte a tu actividad principal de OnboardingFragment's. Esta acción garantiza que el elemento OnboardingFragment aparezca tan pronto como se inicie tu app.

Para asegurarte de que OnboardingFragment solo aparezca la primera vez que el usuario inicia tu app, usa un objeto SharedPreferences, que registrará si el usuario ya visualizó el elemento OnboardingFragment. Define un valor booleano que cambie a "verdadero" cuando el usuario termine de visualizar el elemento OnboardingFragment. Comprueba este valor en el elemento onCreate() de tu actividad principal y solo inicia la actividad principal de OnboardingFragment si el valor es "falso". En el siguiente ejemplo, se muestra cómo anular onCreate() que comprueba si existe el valor SharedPreferences y, si no está configurado como "verdadero", llama a startActivity() para mostrar 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));
        }
    }
    

Después de que el usuario vea el elemento OnboardingFragment, márcalo como visto con el objeto SharedPreferences. Para ello, en tu OnboardingFragment, anula onFinishFragment() y configura SharedPreferences en "verdadero", como se muestra en el siguiente ejemplo:

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

Cómo agregar páginas de OnboardingFragment

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

Figura 2: Elementos de página de OnboardingFragment

En la figura 2, se muestra una página de ejemplo con texto destacado que marca elementos de página personalizables que tu OnboardingFragment 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 y puedes usarla para mostrar detalles de la página, como una captura de pantalla que destaque la función de la app que se describe)
  4. La vista del segundo plano de la página, en este caso, un simple gradiente azul (esta vista siempre se procesa detrás de otras vistas de la página y es opcional)
  5. La vista de primer plano de la página, en este caso, un logotipo (esta vista siempre se procesa en primer plano, delante de las demás vistas de la página, y es opcional)

Inicializa información de la página cuando OnboardingFragment se cree por primera vez o esté adjuntado a una actividad principal, como la información de la página de solicitud del sistema cuando crea la vista del fragmento. Puedes inicializar 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 proporcionen información de la página al sistema:

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

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

El sistema agrega el objeto View creado al diseño de la página. En el siguiente ejemplo, se anula onCreateContentView() y se muestra un objeto 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 objeto OnboardingFragment puede iniciar con una pantalla de logotipo opcional que presenta a tu app. Si quieres mostrar un objeto Drawable como pantalla de logotipo, en tu método onCreate() de OnboardingFragment's, llama a setLogoResourceId() con el ID de tu Drawable. El sistema aplicará un fundido de entrada y mostrará el objeto Drawable brevemente. Luego, aplicará un fundido de salida para el objeto Drawable antes de mostrar la primera página de tu OnboardingFragment.

Si quieres ofrecer una animación personalizada para tu pantalla de logotipo, en lugar de llamar a setLogoResourceId(), anula onCreateLogoAnimation() y muestra un objeto Animator que procese 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 OnboardingFragment y cuando el usuario navega a una página diferente. Para personalizar estas animaciones, puedes anular métodos de tu OnboardingFragment.

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 ajusta la vista de contenido horizontalmente:

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 hacia una página diferente, anula onPageChanged(). En tu método onPageChanged(), crea objetos Animators que quiten la página anterior y muestren la siguiente página, agrégalos a un AnimatorSet y reproduce el conjunto. En el siguiente ejemplo, se usa una animación con fundido de salida para quitar la página anterior, se actualiza la imagen de 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 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();
    }
    

Para obtener más información sobre cómo crear Animators y AnimatorSets, consulta Animación de propiedades.

Cómo personalizar temas

Cualquier implementación de OnboardingFragment debe usar el tema Theme_Leanback_Onboarding o uno heredado de Theme_Leanback_Onboarding. Realiza una de las siguientes tareas para configurar el tema de tu OnboardingFragment:

  • Configura la actividad principal de OnboardingFragment's 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 de una actividad principal. Para ello, usa el atributo LeanbackOnboardingTheme_onboardingTheme en un tema de actividad personalizado. Apunta este atributo a otro tema personalizado que solo usen los objetos OnboardingFragment de tu actividad. Usa este enfoque si tu actividad ya usa un tema personalizado y no quieres aplicar estilos de OnboardingFragment a otras vistas de la actividad.
  • Anula onProvideTheme() y muestra el tema deseado. Usa este enfoque si varias actividades usan tu OnboardingFragment o si la actividad principal 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;
        }