[Android TV] Phần 6: Tạo một Card View
Ở phần trước chúng ta đã tạo được một catalog browser, thực hiện trên một browse fragment, hiển thị chúng thành 1 danh sách các media items. Trong phần này, chúng ta sẽ tạo và tuỳ biến dánh sách các media items đó theo dạng card view. Lớp BaseCardView và lớp con hiển thị các meta data liên kết với ...
Ở phần trước chúng ta đã tạo được một catalog browser, thực hiện trên một browse fragment, hiển thị chúng thành 1 danh sách các media items. Trong phần này, chúng ta sẽ tạo và tuỳ biến dánh sách các media items đó theo dạng card view. Lớp BaseCardView và lớp con hiển thị các meta data liên kết với một media item. Lớp ImageCardView được tìm hiểu trong phần này sẽ đảm nhiệm việc tuỳ biến hiển thị một hình anh với nội dung chính kèm theo tiêu đề của từng item. Phần này sẽ mô tả code từ một ví dụ Android Leanback sample app, ví dụ này có trên Github, chúng ta có thể lấy phần code ví dụ về để trực quan trải nghiệm.
Figure 1. Leanback sample app thẻ ảnh khi được chọnTạo một Card Presenter
Một Presenter tạo ra views và liên kết các objects đó theo yêu cầu đặt ra. Trên một browse framgent nơi mà ứng dụng của chúng ta hiển thị các nội dung chính đến người dùng, chúng ta sẽ tạo một presenter cho phần nội dung dạng cards và truyền nó thông qua một adapter và thêm nó phần nội dung chính trên màn hình. Phần code sau, CardPresenter được tạo ra trong hàm [onLoadFinished](https://developer.android.com/reference/android/support/v4/app/LoaderManager.LoaderCallbacks.html#onLoadFinished(android.support.v4.content.Loader<D>, D)) và được gọi lại ở LoaderManager.
@Override public void onLoadFinished(Loader<HashMap<String, List<Movie>>> arg0, HashMap<String, List<Movie>> data) { mRowsAdapter = 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(), null); i++; mRowsAdapter.add(new ListRow(header, listRowAdapter)); } HeaderItem gridHeader = new HeaderItem(i, getString(R.string.more_samples), null); 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)); mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter)); setAdapter(mRowsAdapter); updateRecommendations(); }
Tạo một Card View
Ở bước này, chúng ta xây dựng một card presenter với một view holder cho card view để mô tả phần hiển thị nội dung của các items. Chúng ta cần lưu ý rằng mỗi một presenter chỉ tạo ra một kiểu view. Nếu chúng ta có hai kiểu card views khác nhau thì chúng ta cần phải tạo ra 2 card presenters khác nhau.
Ở trong Presenter, thực hiện gọi lại phương thức onCreateViewHolder() để tạo một view holder có thể sử dụng để hiển thị nội dung của một item.
@Override public class CardPresenter extends Presenter { private Context mContext; private static int CARD_WIDTH = 313; private static int CARD_HEIGHT = 176; private Drawable mDefaultCardImage; @Override public ViewHolder onCreateViewHolder(ViewGroup parent) { mContext = parent.getContext(); mDefaultCardImage = mContext.getResources().getDrawable(R.drawable.movie); ...
Trong phương thức onCreateViewHolder(), tạo một card view cho nội dung của items. Ví dụ dưới đây sử dụng một ImageCardView. Khi một card được chọn, mặc định nó sẽ được mở ra với một kích thước lớn hơn. Nếu chúng ta muốn chỉ định một màu khác cho card được chọn, chúng ta sẽ gọi phương thức setSelected()
... ImageCardView cardView = new ImageCardView(mContext) { @Override public void setSelected(boolean selected) { int selected_background = mContext.getResources().getColor(R.color.detail_background); int default_background = mContext.getResources().getColor(R.color.default_background); int color = selected ? selected_background : default_background; findViewById(R.id.info_field).setBackgroundColor(color); super.setSelected(selected); } }; ...
Khi người dùng chọn một ImageCardView, nó se mở đến một phần vùng text với màu nền do chúng ta chỉ định, giống như ảnh Figure 1.
Xây dụng một View chi tiết(Details View)
Các lớp media browsing interface được cung cấp bởi [v17 leanback support library] bao gồm các lớp hiển thị thêm phần thông tin của một media item, chẳng hạn như mô tả hoặc đánh giá, và các hành động trên mục đó, chẳng hạn như mua hay sử dụng nội dung của nó.
Phần này sẽ cho chúng ta hiểu làm thế nào để tạo một lớp presenter card cho media item details, và làm thế nào để sử dụng các lớp trong DetailsFramgent để thực hiện một detail view cho một media item khi nó được chọn bởi người dùng.
Chú ý : Ví dụ thực hiện ở đây sử dụng một activity bổ sung để chứa các DetailsFramgent. Tuy nhiên nó có thể để tránh tạo ra một activity thứ hai bằng cách thay thế BrowseFragment hiện tại với một DetailsFramgent trong cùng một activity khi chúng ta sử dụng fragment transaction. Để có thêm thông tin về việc sử dụng các fragment transaction. xem thêm ở Building a Dynamic UI with Framgnets
Xây dựng một Details Presenter
Trong media browsing framework cung cấp bởi thư viện leanback, chúng ta sử dụng presenter objects để điều khiển các dữ liệu hiển thị trên màn hình, bao gồm cả các media item details. Framework cung cấp lớp AbstractDetailsDescriptionPresenter cho mục đích này, nó là một thực hiện gần như hoàn chỉnh của một presenter cho media item details. Thực hiện phương thức onBindDescription() để bind dữ liệu lên các trường trên view, đoạn code dưới sẽ giống như một ví dụ:
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."); } }
Extend the Details Fragment
Khi sử dụng lớp DetailsFragment để hiển thị các media item details của chúng ta, sử dụng các phương thức được cung cấp giống như việc xem trước ảnh và hoạt động của media item. Chúng ta cũng có thể cung cấp thêm nội dụng bổ sung chẳng hạn như một danh sách các media items có liên quan.
Đoạn code sau trình bày cách sử dụng lớp presenter trong phần trước, để thêm một hình ảnh hiển thị và hành động cho media item đang được xem. Ví dụ này cũng cho thấy việc bổ sung các media item có liên quan, được hiển thị ở bên dưới danh sách.
public class MediaItemDetailsFragment extends DetailsFragment { private static final String TAG = "MediaItemDetailsFragment"; private ArrayObjectAdapter mRowsAdapter; @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()); mRowsAdapter = 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")); mRowsAdapter.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); mRowsAdapter.add(new ListRow(header, listRowAdapter)); setAdapter(mRowsAdapter); } }
Tạo một Deatils Activity
Fragment chẳng hạn như DetailsFragment phải được chạy trên nền một activity để có thể hiển thị. Tạo một activity cho details view của chúng ta, riêng biệt cho các browse activity, cho phép chúng ta gọi details view sử dụng Intent. Phần này giải thích làm thế nào để xây dựng một activity cho phần details view. Bắt đầu tạo một details activity bằng cách xây dụng một layout tham chiếu đến DeatilsFragment:
<!-- 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_awidth="match_parent" android:layout_height="match_parent" />
Tiếp theo, tạo một lớp activity để điều khiển layout chúng ta vừa tạo phía trên:
public class DetailsActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.details); } }
Cuối cùng, thêm phần khai báo activity vừa tạo vào manifest.
<application> ... <activity android:name=".DetailsActivity" android:exported="true" android:theme="@style/Theme.Leanback"/> </application>
Khai báo lắng nghe sự kiện khi clicked vào items
Sau khi chúng ta thực hiện các DetailsFramgent, sửa đổi phần main media browsing view để di chuyển đến các details view khi ngưới dùng click . Để khai báo hành vi này, chúng ta dùng phương thức OnItemViewClickedListener đến BrowseFragment để khởi tạo activity của từng details item.
Ví dụ sau đây cho thấy làm thế nào để thực hiện một lắng nghe để bắt đầu xem chi tiết khi người dùng nhấp vào một mục media item trong main media browsing activity:
public class BrowseMediaActivity extends Activity { ... @Override protected void onCreate(Bundle savedInstanceState) { ... // create the media item rows buildRowsAdapter(); // add a listener for selected items mBrowseFragment.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); } }); } }
Phần tiếp theo chúng ta thảo luận về Displaying a Now Playing Card.
Thank in advande for your reading.