Criar uma visualização detalhada

As classes de interface de navegação de mídia oferecidas pela biblioteca de suporte v17 leanback incluem classes para a exibição de informações adicionais sobre um item de mídia, como uma descrição ou avaliações, e para agir sobre esse item, como para comprá-lo ou reproduzir o conteúdo dele.

Esta lição discute como criar uma classe de apresentador para detalhes de item de mídia e como estender a classe DetailsFragment para implementar uma visualização detalhada para um item de mídia quando ele é selecionado pelo usuário.

Observação: o exemplo de implementação mostrado aqui usa uma atividade adicional para conter o DetailsFragment. No entanto, é possível evitar a criação de uma segunda atividade substituindo o BrowseFragment atual por DetailsFragment dentro da mesma atividade usando transações de fragmento. Para mais informações sobre como usar transações de fragmento, veja o treinamento Criar uma interface de usuário dinâmica com fragmentos.

Construção de um apresentador de detalhes

Na estrutura de trabalho de navegação de mídia fornecida pela biblioteca leanback, são usados objetos de apresentador para controlar a exibição de dados na tela, incluindo detalhes do item de mídia. A estrutura de trabalho fornece a classe AbstractDetailsDescriptionPresenter para essa finalidade, o que é quase uma implementação completa do apresentador para detalhes do item de mídia. Basta implementar o método onBindDescription() para ligar os campos de visualização aos objetos de dado, como mostrado na amostra de código a seguir:

Kotlin

    class DetailsDescriptionPresenter : AbstractDetailsDescriptionPresenter() {

        override fun onBindDescription(viewHolder: AbstractDetailsDescriptionPresenter.ViewHolder, itemData: Any) {
            val details = itemData as MyMediaItemDetails
            // In a production app, the itemData object contains the information
            // needed to display details for the media item:
            // viewHolder.title.text = details.shortTitle

            // Here we provide static data for testing purposes:
            viewHolder.apply {
                title.text = itemData.toString()
                subtitle.text = "2014   Drama   TV-14"
                body.text = ("Lorem ipsum dolor sit amet, consectetur "
                        + "adipisicing elit, sed do eiusmod tempor incididunt ut labore "
                        + " et dolore magna aliqua. Ut enim ad minim veniam, quis "
                        + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
                        + "commodo consequat.")
            }
        }
    }
    

Java

    public class DetailsDescriptionPresenter
            extends AbstractDetailsDescriptionPresenter {

        @Override
        protected void onBindDescription(ViewHolder viewHolder, Object itemData) {
            MyMediaItemDetails details = (MyMediaItemDetails) itemData;
            // In a production app, the itemData object contains the information
            // needed to display details for the media item:
            // viewHolder.getTitle().setText(details.getShortTitle());

            // Here we provide static data for testing purposes:
            viewHolder.getTitle().setText(itemData.toString());
            viewHolder.getSubtitle().setText("2014   Drama   TV-14");
            viewHolder.getBody().setText("Lorem ipsum dolor sit amet, consectetur "
                    + "adipisicing elit, sed do eiusmod tempor incididunt ut labore "
                    + " et dolore magna aliqua. Ut enim ad minim veniam, quis "
                    + "nostrud exercitation ullamco laboris nisi ut aliquip ex ea "
                    + "commodo consequat.");
        }
    }
    

Estender o fragmento de detalhes

Ao usar a classe DetailsFragment para exibir os detalhes do item de mídia, estenda essa classe para oferecer conteúdo adicional, como uma imagem de pré-visualização e ações para o item de mídia. Você também pode oferecer conteúdo adicional, como uma lista de itens de mídia relacionados.

O código de exemplo a seguir demonstra como usar a classe de apresentador mostrada na seção anterior para adicionar uma imagem de pré-visualização e ações para o item de mídia sendo visualizado. Este exemplo também mostra a adição de uma linha de itens de mídia relacionados, que aparece abaixo da listagem de detalhes.

Kotlin

    private const val TAG = "MediaItemDetailsFragment"

    class MediaItemDetailsFragment : DetailsFragment() {
        private lateinit var rowsAdapter: ArrayObjectAdapter

        override fun onCreate(savedInstanceState: Bundle?) {
            Log.i(TAG, "onCreate")
            super.onCreate(savedInstanceState)

            buildDetails()
        }

        private fun buildDetails() {
            val selector = ClassPresenterSelector().apply {
                // Attach your media item details presenter to the row presenter:
                FullWidthDetailsOverviewRowPresenter(DetailsDescriptionPresenter()).also {
                    addClassPresenter(DetailsOverviewRow::class.java, it)
                }
                addClassPresenter(ListRow::class.java, ListRowPresenter())
            }
            rowsAdapter = ArrayObjectAdapter(selector)

            val res = activity.resources
            val detailsOverview = DetailsOverviewRow("Media Item Details").apply {

                // Add images and action buttons to the details view
                imageDrawable = res.getDrawable(R.drawable.jelly_beans)
                addAction(Action(1, "Buy $9.99"))
                addAction(Action(2, "Rent $2.99"))
            }
            rowsAdapter.add(detailsOverview)

            // Add a Related items row
            val listRowAdapter = ArrayObjectAdapter(StringPresenter()).apply {
                add("Media Item 1")
                add("Media Item 2")
                add("Media Item 3")
            }
            val header = HeaderItem(0, "Related Items")
            rowsAdapter.add(ListRow(header, listRowAdapter))

            adapter = rowsAdapter
        }
    }
    

Java

    public class MediaItemDetailsFragment extends DetailsFragment {
        private static final String TAG = "MediaItemDetailsFragment";
        private ArrayObjectAdapter rowsAdapter;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            Log.i(TAG, "onCreate");
            super.onCreate(savedInstanceState);

            buildDetails();
        }

        private void buildDetails() {
            ClassPresenterSelector selector = new ClassPresenterSelector();
            // Attach your media item details presenter to the row presenter:
            FullWidthDetailsOverviewRowPresenter rowPresenter =
                new FullWidthDetailsOverviewRowPresenter(
                    new DetailsDescriptionPresenter());

            selector.addClassPresenter(DetailsOverviewRow.class, rowPresenter);
            selector.addClassPresenter(ListRow.class,
                    new ListRowPresenter());
            rowsAdapter = new ArrayObjectAdapter(selector);

            Resources res = getActivity().getResources();
            DetailsOverviewRow detailsOverview = new DetailsOverviewRow(
                    "Media Item Details");

            // Add images and action buttons to the details view
            detailsOverview.setImageDrawable(res.getDrawable(R.drawable.jelly_beans));
            detailsOverview.addAction(new Action(1, "Buy $9.99"));
            detailsOverview.addAction(new Action(2, "Rent $2.99"));
            rowsAdapter.add(detailsOverview);

            // Add a Related items row
            ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(
                    new StringPresenter());
            listRowAdapter.add("Media Item 1");
            listRowAdapter.add("Media Item 2");
            listRowAdapter.add("Media Item 3");
            HeaderItem header = new HeaderItem(0, "Related Items", null);
            rowsAdapter.add(new ListRow(header, listRowAdapter));

            setAdapter(rowsAdapter);
        }
    }
    

Criar uma atividade de detalhes

Fragmentos como o DetailsFragment precisam ser contidos dentro de uma atividade para serem usados para exibição. A criação de uma atividade para visualização detalhada, separada da atividade de navegação, permite chamar a visualização detalhada usando um Intent. Esta seção explica como criar uma atividade para conter a implementação da visualização detalhada para os itens de mídia.

Comece criando a atividade de detalhes ao construir um layout que referencie a implementação do DetailsFragment:

    <!-- file: res/layout/details.xml -->

    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        android:name="com.example.android.mediabrowser.MediaItemDetailsFragment"
        android:id="@+id/details_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
    />
    

Em seguida, crie uma classe de atividade que use o layout mostrado no exemplo de código anterior:

Kotlin

    class DetailsActivity : Activity() {

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.details)
        }
    }
    

Java

    public class DetailsActivity extends Activity
    {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.details);
        }
    }
    

Por fim, adicione essa nova atividade ao manifesto. Lembre-se de aplicar o tema Leanback para garantir que a interface do usuário seja consistente com a atividade de navegação de mídia:

    <application>
      ...

      <activity android:name=".DetailsActivity"
        android:exported="true"
        android:theme="@style/Theme.Leanback"/>

    </application>
    

Definir um listener para itens clicados

Após a implementação de DetailsFragment, modifique a visualização de navegação de mídia principal para que alterne para a visualização detalhada quando um usuário clicar em um item de mídia. Para permitir esse comportamento, adicione um objeto OnItemViewClickedListener ao BrowseFragment que acione um intent para iniciar o item da atividade de detalhes.

O exemplo a seguir mostra como implementar um listener para iniciar a visualização detalhada quando um usuário clica em um item de mídia na atividade de navegação de mídia principal:

Kotlin

    class BrowseMediaActivity : AppCompatActivity() {
        ...

        override fun onCreate(savedInstanceState: Bundle?) {
            ...

            // create the media item rows
            buildRowsAdapter()

            // add a listener for selected items
            browseFragment.onItemViewClickedListener = OnItemViewClickedListener { _, item, _, _ ->
                println("Media Item clicked: ${item}")
                val intent = Intent(this@BrowseMediaActivity, DetailsActivity::class.java).apply {
                    // pass the item information
                    extras.putLong("id", item.getId())
                }
                startActivity(intent)
            }
        }
    }
    

Java

    public class BrowseMediaActivity extends Activity {
        ...

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...

            // create the media item rows
            buildRowsAdapter();

            // add a listener for selected items
            browseFragment.OnItemViewClickedListener(
                new OnItemViewClickedListener() {
                    @Override
                    public void onItemClicked(Object item, Row row) {
                        System.out.println("Media Item clicked: " + item.toString());
                        Intent intent = new Intent(BrowseMediaActivity.this,
                                DetailsActivity.class);
                        // pass the item information
                        intent.getExtras().putLong("id", item.getId());
                        startActivity(intent);
                    }
                });
        }
    }