カードビューを提供する

Compose を利用して魅力的なアプリを作成する
Android TV OS 向け Jetpack Compose を使用して、最小限のコードで美しい UI を作成します。

このガイドでは、非推奨の Leanback UI ツールキットを使用して、メディア アイテムのカードビューを作成し、ブラウズ フラグメント内に表示する方法について説明します。ブラウズ フラグメントでのカタログ ブラウザの実装については、ブラウズ フラグメント ガイドで詳しく説明しています。

BaseCardView クラスとそのサブクラスは、メディア アイテムに関連付けられているメタデータを表示します。このレッスンで使用する ImageCardView クラスは、コンテンツの画像をメディア アイテムのタイトルとともに表示します。

非推奨の Leanback サンプルアプリのサンプル実装もご覧ください。

アプリのカードビュー

図 1. Leanback サンプルアプリの画像カードビュー(選択時)

カード プレゼンターを作成する

Presenter はビューを生成して、オブジェクトをそのビューにオンデマンドでバインドします。アプリがそのコンテンツをユーザーに表示するブラウズ フラグメントで、コンテンツ カードの Presenter を作成し、コンテンツを画面に追加するアダプターに渡します。次のコードでは、LoaderManageronLoadFinished() コールバックで CardPresenter が作成されています。

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();
}

カードビューを作成する

ここでは、メディア コンテンツのアイテムについて説明するカードビューのビューホルダーを含むカード プレゼンターを作成します。プレゼンターごとに 1 つのビュータイプだけを作成する必要があります。カードビューのタイプが 2 つある場合は、カード プレゼンターが 2 つ必要になります。

Presenter に、コンテンツ アイテムの表示に使用可能なビューホルダーを作成する onCreateViewHolder() コールバックを実装します。

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);
...

onCreateViewHolder() メソッドで、コンテンツ アイテム用のカードビューを作成します。次のサンプルでは ImageCardView を使用しています。

カードが選択されると、デフォルトの動作により、カードの元のサイズよりも拡大されます。選択したカードに別の色を指定したい場合は、次のように setSelected() を呼び出します。

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);
        }
    };
...

ユーザーがアプリを開くと、Presenter.ViewHolder にコンテンツ アイテムの CardView オブジェクトが表示されます。D-pad コントローラからフォーカスを受け取るには、次のコードに示すように、setFocusable(true)setFocusableInTouchMode(true) を呼び出して、以下のように設定する必要があります。

Kotlin

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

Java

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

ユーザーが ImageCardView を選択すると、図 1 に示すようにビューが拡大され、指定した背景色でテキスト領域が表示されます。