Android TV — Noções básicas sobre BrowseSupportFragment — Parte 1

Dec 12 2022
Se você já começou com o desenvolvimento do Android TV, deve conhecer o BrowseSupportFragment. Para os iniciantes absolutos, para começar rapidamente com o desenvolvimento da Android TV, o BrowseSupportFragment é a primeira coisa que você encontrará.

Se você já começou com o desenvolvimento do Android TV , você deve conhecer o BrowseSupportFragment . Para os iniciantes absolutos, para começar rapidamente com o desenvolvimento da Android TV, o BrowseSupportFragment é a primeira coisa que você encontrará. Aqui está um trecho da documentação,

Um fragmento para criar telas de navegação Leanback. Ele é composto por um RowsSupportFragment e um HeadersSupportFragment.

É um pouco técnico demais, eu diria. Francamente, não entendi muito na primeira leitura. E como esse é o ponto de partida de qualquer maneira, eu queria entender o que exatamente esse fragmento especial está fazendo?

Visualmente, o fragmento faz isso….

Sim, este fragmento faz muitas coisas. Vamos ver um vídeo.

Toda a rolagem, navegação entre a barra lateral e o painel de conteúdo à direita, animações etc. acontecem dentro do BrowseSupportFragment. Bem, na verdade, existem outras classes envolvidas, mas tudo começa a partir deste fragmento realmente especial.

Quando você cria um projeto Android TV, ele fornece essa implementação por padrão, para que você possa começar a usar seu aplicativo. Eu queria personalizar o HeaderSupportFragment, mas não estava muito claro por onde começar. Então, eu tive que cavar um pouco mais fundo.

Ele contém 2 fragmentos, HeadersSupportFragment e RowsSuportFragment .

2 Fragmentos — BrowseSupportFragment

OK. Agora está bem claro como proceder. Se você deseja personalizar a barra lateral esquerda, precisa lidar com HeadersSupportFragment. Vamos cavar um pouco mais fundo como isso pode ser feito.

HeadersSupportFragment consiste em cabeçalhos de linha de lista. Você precisa oferecer suporte a 3 tipos de itens de linha.

  • Linha do divisor — Renderiza um divisor
  • Linha — Renderiza um item focalizável que destaca os dados relacionados no lado direito
  • Linha de seção — Renderiza uma vista de seção que ajuda a organizar as opções em várias seções
  • Divisor, Linhas e Seções
    Tipos de itens no HeadersSupportFragment

Implementações padrão

  1. DividerRow — Uma subclasse ou linha
  2. RowHeaderPresenter — Uma subclasse de Presenter
  3. RowPresenter — Uma subclasse de Presenter

Os apresentadores estão intimamente relacionados ao conceito de RecyclerView.Adapter. Eles são usados ​​para gerar visualizações e vincular objetos/dados a eles. A implementação também seria muito semelhante a RecyclerView.Adapter e aos padrões ViewHolder que você já deve conhecer.

class QTVRowViewHolder(view: View) : RowHeaderPresenter.ViewHolder(view) {
    val tvTitle: TextView
    init {
        tvTitle = view.findViewById(R.id.tvTitle)
    }
}

class QTVRowPresenter : Presenter() {
    override fun onCreateViewHolder(parent: ViewGroup?): QTVRowViewHolder {
        val root: View = LayoutInflater.from(parent!!.context)
            .inflate(R.layout.presenter_row, parent, false)

        val viewHolder = QTVRowViewHolder(root)
        return viewHolder
    }

    override fun onBindViewHolder(viewHolder: ViewHolder?, item: Any?) {
        val headerItem = if (item == null) null else (item as Row).headerItem
        val vh = viewHolder as QTVRowViewHolder
        vh.tvTitle.text = headerItem?.name
    }

    override fun onUnbindViewHolder(viewHolder: ViewHolder?) {
        val vh = viewHolder as QTVRowViewHolder
        vh.tvTitle.text = null
    }
}

No método onBindViewHolder, você receberá o view holder e o item. Atualmente, por padrão, o tipo deste “item” é um HeaderItem , que possui as propriedades “id: Long” e “name: String”. Para este exemplo, vinculei o nome do item ao TextView que tenho no “R.layout.presenter_row”. Mais adiante, veremos como podemos personalizar o HeaderItem para adicionar outros dados como ícones, descrições etc.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView android:id="@+id/tvTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

  1. Lançar nossa própria implementação de HeadersSupportFragment
  2. Modifique o HeadersSupportFragment padrão

private fun setupUIElements() {
    title = getString(R.string.browse_title)
    // over title
    headersState = BrowseSupportFragment.HEADERS_ENABLED
    isHeadersTransitionOnBackEnabled = true

    // set fastLane (or headers) background color
    brandColor = ContextCompat.getColor(context!!, R.color.color_primary)
    // set search icon color
    searchAffordanceColor = ContextCompat.getColor(context!!, R.color.search_opaque)

    // Lines of code to be added
    val sHeaderPresenter: PresenterSelector = ClassPresenterSelector()
        .addClassPresenter(DividerRow::class.java, DividerPresenter())
        .addClassPresenter(
            SectionRow::class.java,
            RowHeaderPresenter()
        )
        .addClassPresenter(Row::class.java, QTVRowPresenter())

    setHeaderPresenterSelector(sHeaderPresenter)
}

  1. DividerPresenter — Para divisores
  2. RowHeaderPresenter — Para seções
  3. RowPresenter — Para itens de dados

É isso. Se você executar o aplicativo agora, não verá as seções ou os divisores. O projeto padrão que o Android Studio cria para você não adiciona nenhum dado para divisores e seções. Vamos ver como você pode adicionar dados para eles.

private fun loadRows() {
    val list = MovieList.list

    val rowsAdapter = ArrayObjectAdapter(ListRowPresenter())
    val cardPresenter = CardPresenter()

    // Add a section
    rowsAdapter.add(SectionRow(100, "Section 1"))
    // Add a divider
    rowsAdapter.add(DividerRow())

    for (i in 0 until NUM_ROWS) {
        if (i != 0) {
            Collections.shuffle(list)
        }
        val listRowAdapter = ArrayObjectAdapter(cardPresenter)
        for (j in 0 until NUM_COLS) {
            listRowAdapter.add(list[j % 5])
        }
        val header = HeaderItem(i.toLong(), MovieList.MOVIE_CATEGORY[i])
        rowsAdapter.add(ListRow(header, listRowAdapter))
    }

    // One more divider
    rowsAdapter.add(DividerRow())
    // One more section 
    rowsAdapter.add(SectionRow(100, "Section 2"))

    val gridHeader = HeaderItem(NUM_ROWS.toLong(), "PREFERENCES")

    val mGridPresenter = GridItemPresenter()
    val gridRowAdapter = ArrayObjectAdapter(mGridPresenter)
    gridRowAdapter.add(resources.getString(R.string.grid_view))
    gridRowAdapter.add(getString(R.string.error_fragment))
    gridRowAdapter.add(resources.getString(R.string.personal_settings))
    rowsAdapter.add(ListRow(gridHeader, gridRowAdapter))

    adapter = rowsAdapter
}

Em postagens subsequentes, abordarei mais sobre o BrowseSupportFragment. Fique ligado!!!