یک نمای کارت ارائه دهید

با Compose بهتر بسازید
با استفاده از Jetpack Compose برای سیستم عامل Android TV، رابط‌های کاربری زیبایی با حداقل کد ایجاد کنید.

این راهنما بر ایجاد نماهای کارت برای آیتم‌های رسانه‌ای شما و ارائه آنها در قطعه مرور با استفاده از ابزار منسوخ‌شده Leanback UI تمرکز دارد. پیاده‌سازی مرورگر کاتالوگ در یک قطعه مرور در راهنمای قطعه مرور به تفصیل شرح داده شده است.

کلاس BaseCardView و زیرکلاس‌های آن، متادیتای مرتبط با یک آیتم رسانه‌ای را نمایش می‌دهند. کلاس ImageCardView که در این درس استفاده شده است، تصویری را برای محتوا به همراه عنوان آیتم رسانه‌ای نمایش می‌دهد.

همچنین پیاده‌سازی نمونه را در برنامه نمونه منسوخ‌شده Leanback ببینید.

نمای کارت برنامه

شکل ۱. نمای کارت تصویر برنامه نمونه Leanback هنگام انتخاب.

یک ارائه دهنده کارت ایجاد کنید

یک Presenter نماها (views) را تولید می‌کند و اشیاء را بر اساس تقاضا به آنها متصل می‌کند. در بخش مرور (browse fragment) که برنامه شما محتوای خود را به کاربر ارائه می‌دهد، شما یک Presenter برای کارت‌های محتوا ایجاد می‌کنید و آن را به آداپتوری که محتوا را به صفحه اضافه می‌کند، منتقل می‌کنید. در کد زیر، CardPresenter در فراخوانی onLoadFinished() از LoaderManager ایجاد می‌شود:

کاتلین

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

جاوا

@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() پیاده‌سازی کنید که یک view holder ایجاد می‌کند که می‌تواند برای نمایش یک آیتم محتوا استفاده شود:

کاتلین

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

جاوا

@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() را همانطور که در اینجا نشان داده شده است، فراخوانی کنید:

کاتلین

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

جاوا

...
    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-pad دریافت کنند:

کاتلین

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

جاوا

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

وقتی کاربر ImageCardView انتخاب می‌کند، همانطور که در شکل ۱ نشان داده شده است، باز می‌شود تا ناحیه متنی خود را با رنگ پس‌زمینه‌ای که شما مشخص می‌کنید، نشان دهد.