세부정보 뷰 빌드

Leanback AndroidX 라이브러리에서 제공하는 미디어 탐색 인터페이스 클래스에는 설명 또는 리뷰와 같은 미디어 항목에 관한 추가 정보를 표시하는 클래스가 포함되어 있습니다. 또한 구매 또는 콘텐츠 재생과 같이 항목에 대한 작업을 수행하기 위한 클래스도 포함됩니다.

이 가이드에서는 미디어 항목 세부정보에 관한 프레젠터 클래스를 만드는 방법과 사용자가 미디어 항목을 선택할 때 DetailsSupportFragment 클래스를 확장하여 미디어 항목의 세부정보 뷰를 구현하는 방법을 설명합니다.

참고: 여기서 보여주는 구현 예에서는 추가 활동을 사용하여 DetailsSupportFragment를 포함합니다. 그러나 프래그먼트 트랜잭션을 사용하여 동일한 활동 내에서 BrowseSupportFragmentDetailsSupportFragment로 대체하면 두 번째 활동이 생성되는 것을 방지할 수 있습니다. 프래그먼트 트랜잭션 사용에 관한 자세한 내용은 프래그먼트 만들기를 참조하세요.

세부정보 프레젠터 빌드

Leanback 라이브러리에서 제공되는 미디어 탐색 프레임워크에서는 프레젠터 객체를 사용하여 미디어 항목 세부정보를 비롯한 화면의 데이터 표시를 제어합니다. 이를 위해 프레임워크는 미디어 항목 세부정보에 관한 프레젠터를 거의 완전하게 구현한 AbstractDetailsDescriptionPresenter 클래스를 제공합니다. 다음 코드 샘플과 같이 onBindDescription() 메서드를 구현하여 뷰 필드를 데이터 객체에 결합하기만 하면 됩니다.

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

세부정보 프래그먼트 확장

미디어 항목 세부정보를 표시하는 데 DetailsSupportFragment 클래스를 사용할 때는 이 클래스를 확장하여 미디어 항목의 미리보기 이미지 및 작업과 같은 추가 콘텐츠를 제공합니다. 관련 미디어 항목 목록 등의 추가 콘텐츠를 제공할 수도 있습니다.

다음 코드 예는 이전 섹션에 표시된 프레젠터 클래스를 사용하여 보고 있는 미디어 항목의 미리보기 이미지와 작업을 추가하는 방법을 보여줍니다. 이 예는 관련 미디어 항목 행을 추가하는 과정도 보여줍니다. 이 행은 세부정보 목록 아래에 표시됩니다.

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

세부정보 활동 만들기

DetailsSupportFragment와 같은 프래그먼트는 표시에 사용할 활동 내에 포함되어야 합니다. 탐색 활동과는 별개로 세부정보 뷰에 관한 활동을 만들면 Intent를 사용하여 세부정보 뷰를 호출할 수 있습니다. 이 섹션에서는 미디어 항목의 세부정보 뷰 구현을 포함하는 활동을 빌드하는 방법을 설명합니다.

DetailsSupportFragment 구현을 참조하는 레이아웃을 빌드하여 세부정보 활동을 만듭니다.

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

그다음에는 이전 코드 예시에서 보여준 레이아웃을 사용하는 액티비티 클래스를 생성합니다.

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

마지막으로 이 새로운 액티비티를 매니페스트에 추가합니다. 사용자 인터페이스가 미디어 탐색 활동과 일치되도록 Leanback 테마를 적용해야 합니다.

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

</application>

클릭된 항목의 리스너 정의

DetailsSupportFragment를 구현한 후에는 사용자가 미디어 항목을 클릭할 때 세부정보 뷰로 이동하도록 기본 미디어 탐색 뷰를 수정합니다. 이 동작을 사용 설정하려면 인텐트를 실행하여 항목 세부정보 활동을 시작하는 BrowseSupportFragmentOnItemViewClickedListener 객체를 추가합니다.

다음 예에서는 사용자가 기본 미디어 탐색 활동에서 미디어 항목을 클릭할 때 세부정보 뷰를 시작하는 리스너를 구현하는 방법을 보여줍니다.

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