Cómo proporcionar una vista de tarjetas

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

La clase BaseCardView y las subclases muestran los metadatos asociados a un elemento multimedia. La clase ImageCardView que se usa en esta lección muestra una imagen para el contenido, además del título del elemento multimedia.

En esta lección, se describe el código de la app de ejemplo de Android Leanback en el repositorio de GitHub de Android TV. Usa este código de muestra para crear tu propia app.

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 a pedido. En el fragmento del navegador en el que tu app presenta su contenido al usuario, crea un Presenter para las tarjetas de contenido y pásalo al adaptador que agrega el contenido a la pantalla. En el siguiente código, se crea el CardPresenter en la devolución de llamada onLoadFinished() 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, aprenderás a crear el presentador de tarjetas con un contenedor de vistas que describe tus elementos de contenido multimedia. Ten en cuenta que cada presentador solo debe crear un tipo de vista. Si tienes dos tipos de vistas de tarjetas diferentes, deberás crear dos presentadores de tarjetas.

En el Presenter, implementa una devolución de llamada de onCreateViewHolder(), 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(), crea una vista de tarjetas para los elementos de contenido. En el ejemplo siguiente, se usa una clase ImageCardView.

Cuando se selecciona una tarjeta, el comportamiento predeterminado la expande a un tamaño mayor. Si quieres asignar un color diferente a la tarjeta seleccionada, llama a 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, Presenter.ViewHolder muestra los objetos CardView de tus elementos de contenido. Debes llamar a setFocusable(true) y setFocusableInTouchMode(true) a fin de configurarlos para que el pad direccional actúe sobre estos elementos.

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 la clase ImageCardView, esta se expande para mostrar su área de texto con el color de fondo que especifiques, como se muestra en la figura 1.