Tạo chế độ xem chi tiết

Tạo dựng ứng dụng hiệu quả hơn với Compose
Tạo giao diện người dùng đẹp mắt mà không cần nhiều mã nguồn bằng Jetpack Compose cho hệ điều hành Android TV.

Các lớp giao diện duyệt nội dung đa phương tiện do thư viện androidx.leanback cung cấp bao gồm các lớp để hiển thị thêm thông tin về một mục nội dung đa phương tiện, chẳng hạn như nội dung mô tả hoặc bài đánh giá. Nội dung trong đó cũng bao gồm các lớp về cách thao tác đối với mặt hàng đó, chẳng hạn như mua hoặc phát nội dung.

Hướng dẫn này thảo luận cách tạo một lớp trình bày cho thông tin chi tiết về mục nội dung đa phương tiện và cách mở rộng lớp DetailsSupportFragment để triển khai khung hiển thị chi tiết cho một mục nội dung đa phương tiện khi người dùng chọn mục đó.

Lưu ý: Ví dụ triển khai hiển thị ở đây sử dụng một hoạt động bổ sung để chứa DetailsSupportFragment. Tuy nhiên, bạn có thể tránh việc tạo hoạt động thứ hai bằng cách thay thế BrowseSupportFragment bằng DetailsSupportFragment trong cùng một hoạt động sử dụng các giao dịch mảnh. Để biết thêm thông tin về cách sử dụng giao dịch mảnh, hãy xem phần Tạo mảnh.

Tạo người trình bày chi tiết

Trong khung duyệt nội dung đa phương tiện do bộ công cụ Leanback UI cung cấp, bạn sử dụng các đối tượng của người trình bày để kiểm soát việc hiển thị dữ liệu trên màn hình, bao gồm cả thông tin chi tiết về các mục nội dung đa phương tiện. Vì mục đích này, khung này cung cấp lớp AbstractDetailsDescriptionPresenter. Lớp này là phương thức triển khai gần như hoàn chỉnh của trình trình bày cho thông tin chi tiết về mục nội dung đa phương tiện. Bạn chỉ cần triển khai phương thức onBindDescription() để liên kết các trường khung hiển thị với đối tượng dữ liệu, như minh hoạ trong đoạn mã mẫu sau:

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

Mở rộng mảnh chi tiết

Khi sử dụng lớp DetailsSupportFragment để hiện thông tin về mục nội dung đa phương tiện, hãy mở rộng lớp đó để cung cấp thêm nội dung, chẳng hạn như hình ảnh xem trước và các thao tác cho mục nội dung đa phương tiện. Bạn cũng có thể cung cấp thêm nội dung, chẳng hạn như danh sách các mục nội dung nghe nhìn có liên quan.

Mã ví dụ sau đây minh hoạ cách dùng lớp của người trình bày trong phần trước để thêm hình ảnh xem trước và các thao tác cho mục nội dung đa phương tiện đang được xem. Ví dụ này cũng cho thấy việc thêm một hàng mục nội dung đa phương tiện có liên quan, xuất hiện bên dưới trang thông tin chi tiết.

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

Tạo một hoạt động Chi tiết

Các mảnh như DetailsSupportFragment phải được chứa trong một hoạt động thì mới dùng được cho mục đích hiển thị. Việc tạo một hoạt động cho chế độ xem chi tiết (tách biệt với hoạt động duyệt web) cho phép bạn gọi chế độ xem chi tiết bằng Intent. Phần này giải thích cách tạo một hoạt động để chứa cách triển khai khung hiển thị chi tiết cho các mục nội dung đa phương tiện của bạn.

Tạo hoạt động chi tiết bằng cách xây dựng một bố cục tham chiếu đến hoạt động triển khai DetailsSupportFragment của bạn:

<!-- 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"
/>

Tiếp theo, hãy tạo một lớp hoạt động sử dụng bố cục như trong ví dụ về mã trước:

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

Cuối cùng, hãy thêm hoạt động mới này vào tệp kê khai. Hãy nhớ áp dụng giao diện Leanback để đảm bảo rằng giao diện người dùng nhất quán với hoạt động duyệt nội dung đa phương tiện.

<application>
  ...
  <activity android:name=".DetailsActivity"
    android:exported="true"
    android:theme="@style/Theme.Leanback"/>

</application>

Xác định trình nghe cho các mục được nhấp vào

Sau khi bạn triển khai DetailsSupportFragment, hãy sửa đổi khung hiển thị duyệt nội dung nghe nhìn chính để chuyển sang khung hiển thị chi tiết khi người dùng nhấp vào một mục nội dung nghe nhìn. Để bật hành vi này, hãy thêm một đối tượng OnItemViewClickedListener vào BrowseSupportFragment để kích hoạt ý định bắt đầu hoạt động chi tiết về mặt hàng.

Ví dụ sau đây cho biết cách triển khai trình nghe để bắt đầu khung hiển thị chi tiết khi người dùng nhấp vào một mục nội dung đa phương tiện trong hoạt động duyệt nội dung nghe nhìn chính:

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