版权声明:本文为博主原创翻译文章,转载请注明出处。
推荐: 欢迎关注我创建的Android TV 简书专题,会定期给大家分享一些AndroidTv相关的内容:
- 在MainFragment中setOnItemViewClickedListener - onItemClicked回调函数。 实现之后,我们可以点击card去详情页。 我们将在本章中显示每个电影项目的内容详细信息。
- 编写DetailsActivity,VideoDetailsFragment和DetailsDescriptionPresenter DetailsActivity通过在MainActivity中card来调用。它显示VideoDetailsFragment,它是显示card内容的布局。
###在MainFragment 中实现点击监听 当用户点击某个card时跳转到下一个动作,使用BrowseFragment类中定义的setOnItemViewClickedListener方法(MainFragment类是一个BrowseFragment的子类)。
示例实现如下。 这与上一章中介绍的setOnItemViewSelectedListener几乎相同。 MainFragment.java
@Override public void onActivityCreated(Bundle savedInstanceState) { ... setupEventListeners(); picassoBackgroundManager = new PicassoBackgroundManager(getActivity()); } private void setupEventListeners() { setOnItemViewSelectedListener(new ItemViewSelectedListener()); setOnItemViewClickedListener(new ItemViewClickedListener()); } private final class ItemViewClickedListener implements OnItemViewClickedListener { @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { // each time the item is clicked, code inside here will be executed. } } }复制代码
###DetailsActivity和VideoDetailsFragment - 说明 以下是AOSP示例应用程序的图片。
我们可以准备我们自己的Presenter来指定DetailsOverviewRow的设计布局。 我们可以在Leanback支持库中使用2个预先实施的presenters。 1.DetailsOverviewRowPresenter:在上图中显示,但它已经在版本22.2.0中被弃用。 2.FullWidthDetailsOverviewRowPresenter:用于替换DetailsOverviewRowPresenter,在AOSP文档中建议使用此presenter。
接下来,我将尝试介绍这个新的FullWidthDetailsOverviewRowPresenter(你还可以查看DetailsOverviewRowPresenter,请参阅此帖的底部)。 它将指定DetailsOverviewRow的设计布局,通常在你的DetailFragment的第一行中使用它来显示项目详细信息。 FullWidthDetailsOverviewRowPresenter包含三部分,即: 1.Logo view:可定制(可选),通过实现DetailsOverViewLogoPresenter 2.Action list view:通过点击可以查看不同的信息,如视频简介,演员表等。 3.详细的说明view:可定制(必须),是 AbstractDetailsDescriptionPresenter 的子类
我们定义了“DetailsDescriptionPresenter”,它继承了Leanback libarary中定义的AbstractDetailsDescriptionPresenter。 AbstractDetailsDescriptionPresenter决定描述视图的设计布局。
###DetailsActivity 和 VideoDetailsFragment – 实现 我们继续创建DetailsActivity来显示内容详细信息的UI。 该设计在VideoDetailsFragment中指定,它是DetailFragment的子类。
创建DetailsActivity和VideoDetailsFragment以与中介绍的MainActivity和MainFragment相同的方式完成。
####DetailsActivity 创建:New → Activity → BlankActivity
####VideoDetailsFragment 创建:New -> Java Class -> Name: VideoDetailsFragment
首先,修改activity_details.xml,如下所示,只显示VideoDetailsFragment。
复制代码
修改VideoDetailsFragment。 我们将这个VideoDetailsFragment作为DetailFragment的子类。 DetailsFragment类是在 leanback support library中用于内容详细信息的UI。在VideoDetailsFragment中,声明的私有成员mFwdorPresenter是FullWidthDetailsOverviewRowPresenter的实例。
请注意,AsyncTask用于在后台线程(“doInBackground”)中执行一些任务,然后在UI线程(“onPostExecute”)中执行一些任务。在这里,我们在后台加载图片图像,并在UI线程中更新UI。
import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.AsyncTask;import android.os.Bundle;import android.support.v17.leanback.app.DetailsFragment;import android.support.v17.leanback.widget.Action;import android.support.v17.leanback.widget.ArrayObjectAdapter;import android.support.v17.leanback.widget.ClassPresenterSelector;import android.support.v17.leanback.widget.DetailsOverviewRow;import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;import android.support.v17.leanback.widget.HeaderItem;import android.support.v17.leanback.widget.ListRow;import android.support.v17.leanback.widget.ListRowPresenter;import android.support.v17.leanback.widget.SparseArrayObjectAdapter;import android.util.Log;import com.squareup.picasso.Picasso;import java.io.IOException;public class VideoDetailsFragment extends DetailsFragment { private static final String TAG = VideoDetailsFragment.class.getSimpleName(); private static final int DETAIL_THUMB_WIDTH = 274; private static final int DETAIL_THUMB_HEIGHT = 274; private static final String MOVIE = "Movie"; private CustomFullWidthDetailsOverviewRowPresenter mFwdorPresenter; private PicassoBackgroundManager mPicassoBackgroundManager; private Movie mSelectedMovie; private DetailsRowBuilderTask mDetailsRowBuilderTask; @Override public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "onCreate"); super.onCreate(savedInstanceState); mFwdorPresenter = new CustomFullWidthDetailsOverviewRowPresenter(new DetailsDescriptionPresenter()); mPicassoBackgroundManager = new PicassoBackgroundManager(getActivity()); mSelectedMovie = (Movie)getActivity().getIntent().getSerializableExtra(MOVIE); mDetailsRowBuilderTask = (DetailsRowBuilderTask) new DetailsRowBuilderTask().execute(mSelectedMovie); mPicassoBackgroundManager.updateBackgroundWithDelay(mSelectedMovie.getCardImageUrl());; } @Override public void onStop() { mDetailsRowBuilderTask.cancel(true); super.onStop(); } private class DetailsRowBuilderTask extends AsyncTask{ @Override protected DetailsOverviewRow doInBackground(Movie... params) { DetailsOverviewRow row = new DetailsOverviewRow(mSelectedMovie); try { Bitmap poster = Picasso.with(getActivity()) .load(mSelectedMovie.getCardImageUrl()) .resize(Utils.convertDpToPixel(getActivity().getApplicationContext(), DETAIL_THUMB_WIDTH), Utils.convertDpToPixel(getActivity().getApplicationContext(), DETAIL_THUMB_HEIGHT)) .centerCrop() .get(); row.setImageBitmap(getActivity(), poster); } catch (IOException e) { Log.w(TAG, e.toString()); } return row; } @Override protected void onPostExecute(DetailsOverviewRow row) { /* 1st row: DetailsOverviewRow */ SparseArrayObjectAdapter sparseArrayObjectAdapter = new SparseArrayObjectAdapter(); for (int i = 0; i<10; i++){ sparseArrayObjectAdapter.set(i, new Action(i, "label1", "label2")); } row.setActionsAdapter(sparseArrayObjectAdapter); /* 2nd row: ListRow */ ArrayObjectAdapter listRowAdapter = new ArrayObjectAdapter(new CardPresenter()); for(int i = 0; i < 10; i++){ Movie movie = new Movie(); if(i%3 == 0) { movie.setCardImageUrl("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/08/DSC02580.jpg"); } else if (i%3 == 1) { movie.setCardImageUrl("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/08/DSC02630.jpg"); } else { movie.setCardImageUrl("http://heimkehrend.raindrop.jp/kl-hacker/wp-content/uploads/2014/08/DSC02529.jpg"); } movie.setTitle("title" + i); movie.setStudio("studio" + i); listRowAdapter.add(movie); } HeaderItem headerItem = new HeaderItem(0, "Related Videos"); ClassPresenterSelector classPresenterSelector = new ClassPresenterSelector(); mFwdorPresenter.setInitialState(FullWidthDetailsOverviewRowPresenter.STATE_SMALL); Log.e(TAG, "mFwdorPresenter.getInitialState: " +mFwdorPresenter.getInitialState()); classPresenterSelector.addClassPresenter(DetailsOverviewRow.class, mFwdorPresenter); classPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter()); ArrayObjectAdapter adapter = new ArrayObjectAdapter(classPresenterSelector); /* 1st row */ adapter.add(row); /* 2nd row */ adapter.add(new ListRow(headerItem, listRowAdapter)); /* 3rd row */ //adapter.add(new ListRow(headerItem, listRowAdapter)); setAdapter(adapter); } }}复制代码
请注意,适配器的构造函数在MainFragment和VideoDetailsFragment之间是不同的。 我们只在MainFragment中使用ListRow - ListRowPresenter。 在这种情况下,我们可以通过设置Presenter本身来实例化适配器。 MainFragment.java
adapter = new ArrayObjectAdapter(new ListRowPresenter());复制代码
我们正在使用VideoDetails Fragment中的DetailsOverviewRow - FullWidthDetailsOverviewRowPresenter和ListRow - ListRowPresenter。 ClassPresenterSelector定义了这个对应关系,我们可以在适配器的构造函数的参数中使用它。 VideoDetailsFragment.java
ClassPresenterSelector classPresenterSelector = new ClassPresenterSelector();classPresenterSelector.addClassPresenter(DetailsOverviewRow.class, mFwdorPresenter);classPresenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());adapter = new ArrayObjectAdapter(classPresenterSelector);复制代码
接下来,在Movie类中添加描述成员,可以在Android studio中通过[Alt] + [Insert]实现Getter和Setter方法。 此外,使Movie Serializable可以通过意图传递此对象。 因为我们通过意图将Movie对象从MainActivity传递给DetailsActivity。
public class Movie implements Serializable { private static final String TAG = Movie.class.getSimpleName(); static final long serialVersionUID = 727566175075960653L; private long id; private String title; private String studio; private String description; private String cardImageUrl; ... public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } ...}复制代码
从AOSP样本源代码复制DetailsDescriptionPresenter如下。 再次,DetailsDescriptionPresenter扩展了AbstractDetailsDescriptionPresenter,它决定了描述视图的设计布局。
/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */package com.corochann.androidtvapptutorial;import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;public class DetailsDescriptionPresenter extends AbstractDetailsDescriptionPresenter { @Override protected void onBindDescription(ViewHolder viewHolder, Object item) { Movie movie = (Movie) item; if (movie != null) { viewHolder.getTitle().setText(movie.getTitle()); viewHolder.getSubtitle().setText(movie.getStudio()); viewHolder.getBody().setText(movie.getDescription()); } }}复制代码
CustomFullWidthDetailsOverviewRowPresenter.java
import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;import android.support.v17.leanback.widget.Presenter;import android.support.v17.leanback.widget.RowPresenter;public class CustomFullWidthDetailsOverviewRowPresenter extends FullWidthDetailsOverviewRowPresenter { CustomFullWidthDetailsOverviewRowPresenter(Presenter presenter) { super(presenter); } @Override protected void onBindRowViewHolder(RowPresenter.ViewHolder holder, Object item) { super.onBindRowViewHolder(holder, item); this.setState((ViewHolder) holder, FullWidthDetailsOverviewRowPresenter.STATE_SMALL); }}复制代码
最后,修改MainFragment以发送intent来启动DetailsActivity。
private void setupEventListeners() { setOnItemViewSelectedListener(new ItemViewSelectedListener()); setOnItemViewClickedListener(new ItemViewClickedListener()); } private final class ItemViewClickedListener implements OnItemViewClickedListener { @Override public void onItemClicked(Presenter.ViewHolder itemViewHolder, Object item, RowPresenter.ViewHolder rowViewHolder, Row row) { // each time the item is clicked, code inside here will be executed. if (item instanceof Movie) { Movie movie = (Movie) item; Log.d(TAG, "Item: " + item.toString()); Intent intent = new Intent(getActivity(), DetailsActivity.class); intent.putExtra(DetailsActivity.MOVIE, movie); getActivity().startActivity(intent); } } }复制代码
###编译后运行
源码在. ###编译运行2