Cómo proporcionar una vista de tarjetas

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

En la lección anterior, creaste un navegador de catálogos, implementado en un fragmento de navegación, que muestra una lista de elementos multimedia. En esta lección, crearás las vistas de tarjetas para tus elementos multimedia y presentarlos en el fragmento de navegación.

El BaseCardView la clase y las subclases muestran los metadatos asociados a un elemento multimedia. El ImageCardView que se usa en esta lección muestra una imagen para el contenido junto con el título del elemento multimedia.

Consulta también la implementación de muestra en la App de ejemplo de Leanback de Google Cloud.

Vista de tarjetas de la app

Figura 1: Vista de tarjetas de imágenes de la app de muestra de Leanback cuando se la selecciona

Cómo crear un presentador de tarjetas

Un Presenter genera vistas y vincula objetos a ellas según demanda. En el fragmento del navegador en el que tu app presenta su contenido al usuario, creas un Presenter para las tarjetas de contenido y pasarlo al adaptador que agrega el contenido a la pantalla. En el siguiente código, se crea CardPresenter. por la onLoadFinished() devolución de llamada de LoaderManager:

Kotlin

override fun onLoadFinished(loader: Loader<HashMap<String, List<Movie>>>, data: HashMap<String, List<Movie>>) {
    rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
    val cardPresenter = CardPresenter()

    var i = 0L

    data.entries.forEach { entry ->
        val listRowAdapter = ArrayObjectAdapter(cardPresenter).apply {
            entry.value.forEach { movie ->
                add(movie)
            }
        }

        val header = HeaderItem(i, entry.key)
        i++
        rowsAdapter.add(ListRow(header, listRowAdapter))
    }

    val gridHeader = HeaderItem(i, getString(R.string.more_samples))

    val gridRowAdapter = ArrayObjectAdapter(GridItemPresenter()).apply {
        add(getString(R.string.grid_view))
        add(getString(R.string.error_fragment))
        add(getString(R.string.personal_settings))
    }
    rowsAdapter.add(ListRow(gridHeader, gridRowAdapter))

    adapter = rowsAdapter

    updateRecommendations()
}

Java

@Override
public void onLoadFinished(Loader<HashMap<String, List<Movie>>> arg0,
                           HashMap<String, List<Movie>> data) {

    rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
    CardPresenter cardPresenter = new CardPresenter();

    int i = 0;

    for (Map.Entry<String, List<Movie>> entry : data.entrySet()) {
        ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(cardPresenter);
        List<Movie> list = entry.getValue();

        for (int j = 0; j < list.size(); j++) {
            listRowAdapter.add(list.get(j));
        }
        HeaderItem header = new HeaderItem(i, entry.getKey());
        i++;
        rowsAdapter.add(new ListRow(header, listRowAdapter));
    }

    HeaderItem gridHeader = new HeaderItem(i, getString(R.string.more_samples));

    GridItemPresenter gridPresenter = new GridItemPresenter();
    ArrayObjectAdapter gridRowAdapter = new ArrayObjectAdapter(gridPresenter);
    gridRowAdapter.add(getString(R.string.grid_view));
    gridRowAdapter.add(getString(R.string.error_fragment));
    gridRowAdapter.add(getString(R.string.personal_settings));
    rowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));

    setAdapter(rowsAdapter);

    updateRecommendations();
}

Cómo crear una vista de tarjetas

En este paso, crearás el presentador de tarjetas con un contenedor de vistas para la vista de tarjetas que los elementos de tu contenido multimedia. Ten en cuenta que cada presentador debe crear solo un tipo de vista. Si tienes dos tipos de vistas de tarjetas, necesitas dos presentadores de tarjetas.

En el Presenter, implementa un onCreateViewHolder() devolución de llamada que crea un contenedor de vistas que se puede usar para mostrar un elemento de contenido:

Kotlin

private const val CARD_WIDTH = 313
private const val CARD_HEIGHT = 176

class CardPresenter : Presenter() {

    private lateinit var mContext: Context
    private lateinit var defaultCardImage: Drawable

    override fun onCreateViewHolder(parent: ViewGroup): Presenter.ViewHolder {
        mContext = parent.context
        defaultCardImage = mContext.resources.getDrawable(R.drawable.movie)
        ...

Java

@Override
public class CardPresenter extends Presenter {

    private Context context;
    private static int CARD_WIDTH = 313;
    private static int CARD_HEIGHT = 176;
    private Drawable defaultCardImage;

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent) {
        context = parent.getContext();
        defaultCardImage = context.getResources().getDrawable(R.drawable.movie);
...

En el método onCreateViewHolder(), crear una vista de tarjetas para los elementos de contenido. En el siguiente ejemplo, se usa un ImageCardView

Cuando se selecciona una tarjeta, el comportamiento predeterminado la expande a un tamaño mayor. Si deseas designar un color diferente para la tarjeta seleccionada, llama al setSelected() como se muestra aquí:

Kotlin

    ...
    val cardView = object : ImageCardView(context) {
        override fun setSelected(selected: Boolean) {
            val selected_background = context.resources.getColor(R.color.detail_background)
            val default_background = context.resources.getColor(R.color.default_background)
            val color = if (selected) selected_background else default_background
            findViewById<View>(R.id.info_field).setBackgroundColor(color)
            super.setSelected(selected)
        }
    }
    ...

Java

...
    ImageCardView cardView = new ImageCardView(context) {
        @Override
        public void setSelected(boolean selected) {
            int selected_background = context.getResources().getColor(R.color.detail_background);
            int default_background = context.getResources().getColor(R.color.default_background);
            int color = selected ? selected_background : default_background;
            findViewById(R.id.info_field).setBackgroundColor(color);
            super.setSelected(selected);
        }
    };
...

Cuando el usuario abre tu app, la Presenter.ViewHolder muestra los objetos CardView de tus elementos de contenido. Debes configurarlos para recibir el enfoque desde el control del pad direccional llamando a setFocusable(true). y setFocusableInTouchMode(true), como se muestra en el siguiente código:

Kotlin

    ...
    cardView.isFocusable = true
    cardView.isFocusableInTouchMode = true
    return ViewHolder(cardView)
}

Java

...
    cardView.setFocusable(true);
    cardView.setFocusableInTouchMode(true);
    return new ViewHolder(cardView);
}

Cuando el usuario selecciona el elemento ImageCardView, se expande para revelar su área de texto con el color de fondo que especifiques, como se muestra en la figura 1.