AndroidAndroid TVAndroidTV开发

[译]DetailsOverviewRowPresenter和F

2017-04-24  本文已影响1074人  wenju_song

版权声明:本文为博主原创翻译文章,转载请注明出处。

推荐:
欢迎关注我创建的Android TV 简书专题,会定期给大家分享一些AndroidTv相关的内容:
http://www.jianshu.com/c/37efc6e9799b


FullWidthDetailsOverviewRowPresenter1

本章目的 - DetailsActivity的实现
实现了以下功能:

在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 的子类

FullWidthDetailsOverviewRowPresenter

我们定义了“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
上一篇下一篇

猜你喜欢

热点阅读