카드 뷰 제공

Compose를 사용하여 더 효과적으로 빌드
Android TV OS용 Jetpack Compose를 사용하여 최소한의 코드로 멋진 UI를 만드세요.

이전 과정에서는 탐색 프래그먼트에서 구현되고 미디어 항목 목록을 표시하는 카탈로그 브라우저를 만들었습니다. 이 과정에서는 미디어 항목의 카드 뷰를 만들어 탐색 프래그먼트에 표시합니다.

BaseCardView 클래스 및 서브클래스는 미디어 항목과 연결된 메타데이터를 표시합니다. 이 과정에 사용된 ImageCardView 클래스는 미디어 항목의 제목과 함께 콘텐츠 이미지를 표시합니다.

Leanback 샘플 앱의 샘플 구현도 참고하세요.

앱 카드 보기

그림 1. 선택할 때 표시되는 Leanback 샘플 앱 이미지 카드 보기

카드 프레젠터 만들기

Presenter는 뷰를 생성하고 필요에 따라 객체를 뷰에 결합합니다. 앱에서 사용자에게 콘텐츠를 표시하는 탐색 프래그먼트에서 콘텐츠 카드의 Presenter를 만들어 화면에 콘텐츠를 추가하는 어댑터에 전달합니다. 다음 코드에서 CardPresenterLoaderManageronLoadFinished() 콜백에 생성됩니다.

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

카드 보기 만들기

이 단계에서는 미디어 콘텐츠 항목을 설명하는 카드 뷰용 뷰 홀더가 있는 카드 프레젠터를 빌드합니다. 각 프레젠터는 하나의 뷰 유형만 만들어야 합니다. 카드 뷰 유형이 두 개인 경우 카드 프레젠터도 두 개가 필요합니다.

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 객체가 표시됩니다. 다음 코드와 같이 setFocusable(true)setFocusableInTouchMode(true)를 호출하여 D패드 컨트롤러에서 포커스를 받도록 이 API를 설정해야 합니다.

Kotlin

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

Java

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

사용자가 ImageCardView를 선택하면 확장되어 그림 1과 같이 지정된 배경 색상으로 텍스트 영역을 표시합니다.