Criar uma visualização detalhada

Criar da melhor forma com o Compose
Crie interfaces incríveis com o mínimo de código usando o Jetpack Compose para o SO do Android TV.

As classes de interface de navegação de mídia oferecidas pela biblioteca androidx.androidx incluem classes para exibir mais informações sobre um item de mídia, como uma descrição ou avaliações. Eles também incluem classes para realizar uma ação em relação a esse item, como comprar o item ou abrir o conteúdo dele.

Este guia discute como criar uma classe de apresentador para detalhes do item de mídia e como estender a classe DetailsSupportFragment para implementar uma visualização detalhada de um item de mídia quando o usuário o seleciona.

Observação:o exemplo de implementação mostrado aqui usa uma atividade extra para conter o DetailsSupportFragment. No entanto, é possível evitar a criação de uma segunda atividade substituindo o BrowseSupportFragment por um DetailsSupportFragment dentro da mesma atividade usando transações de fragmento. Para mais informações sobre o uso de transações de fragmentos, consulte Criar um fragmento.

Criar uma apresentação de detalhes

No framework de navegação de mídia oferecido pelo kit de ferramentas de interface do Leanback, você usa objetos de apresentador para controlar a exibição de dados na tela, incluindo detalhes do item de mídia. Para essa finalidade, o framework fornece a classe AbstractDetailsDescriptionPresenter, que é uma implementação quase completa do apresentador para detalhes do item de mídia. Basta implementar o método onBindDescription() para vincular os campos de visualização aos objetos de dados, conforme mostrado no exemplo 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 DetailsSupportFragment para exibir detalhes do item de mídia, estenda essa classe para oferecer mais conteúdo, como uma imagem de prévia e ações para o item de mídia. Você também pode oferecer mais conteúdo, 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 visualização e ações para o item de mídia que está sendo visualizado. Esse 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 : DetailsSupportFragment() {
    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 DetailsSupportFragment {
    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 DetailsSupportFragment precisam ser contidos em uma atividade a ser usada para exibição. Criar uma atividade para a visualização detalhada, separada da atividade de navegação, permite que você invoque 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 seus itens de mídia.

Crie a atividade de detalhes criando um layout que referencie a implementação do DetailsSupportFragment:

<!-- 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 : FragmentActivity() {

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

Java

public class DetailsActivity extends FragmentActivity
{
    @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

Depois de implementar o DetailsSupportFragment, modifique a visualização de navegação de mídia principal para ir para a visualização detalhada quando um usuário clicar em um item de mídia. Para ativar esse comportamento, adicione um objeto OnItemViewClickedListener ao BrowseSupportFragment que acione um intent para iniciar a atividade de detalhes do item.

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 : FragmentActivity() {
    ...
    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 FragmentActivity {
    ...
    @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);
                }
            });
    }
}