版权声明:本文为博主原创翻译文章,转载请注明出处。
推荐:
欢迎关注我创建的Android TV 简书专题,会定期给大家分享一些AndroidTv相关的内容:
http://www.jianshu.com/c/37efc6e9799b
FullWidthDetailsOverviewRowPresenter1
本章目的 - DetailsActivity的实现
实现了以下功能:
- 在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示例应用程序的图片。
DetailsFragment_combined_picture_explain在Android示例应用程序中,我们在VideoDetailsFragment中设置2行。 第一行是DetailsOverviewRow,第二行是ListRow(已在MainFragment中解释)。 DetailsOverviewRow显示内容详细信息,其中包括图片中的图片,描述和一些操作设置在左下角。
我们可以准备我们自己的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以与第1篇中介绍的MainActivity和MainFragment相同的方式完成。
DetailsActivity
创建:New → Activity → BlankActivity
VideoDetailsFragment
创建:New -> Java Class -> Name: VideoDetailsFragment
首先,修改activity_details.xml,如下所示,只显示VideoDetailsFragment。
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/details_fragment"
android:name="com.corochann.androidtvapptutorial.ui.VideoDetailsFragment"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context=".DetailsActivity" tools:deviceIds="tv" />
修改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<Movie, Integer, DetailsOverviewRow> {
@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);
}
}
}
编译后运行
FullWidthDetailsOverviewRowPresenter1当用户再次按“下”键时,将出现下一行(此示例中的ListRow)。
FullWidthDetailsOverviewRowPresenter3源码在github.
编译运行2
detailsoverviewrowpresente fullwidthdetailsoverviewrowpresenter如果您对(已经不推荐使用)DetailsOverviewRowPresenter实现感兴趣,请检查github上的更新源代码。 下一篇:ErrorFragmet--Android TV 应用开发教程六
关注微信公众号,定期为你推荐移动开发相关文章。
songwenju
网友评论