美文网首页AndroidAndroid TVAndroidTV开发
[译]DetailsOverviewRowPresenter和F

[译]DetailsOverviewRowPresenter和F

作者: wenju_song | 来源:发表于2017-04-24 10:03 被阅读1074次

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

    推荐:
    欢迎关注我创建的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 的子类

    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

    相关文章

      网友评论

      • 1699eef9a3fc:那请问一下楼主 点击事件使用setOnItemViewClickedListener - onItemClicked实现 那么长按事件怎么实现呢

      本文标题:[译]DetailsOverviewRowPresenter和F

      本文链接:https://www.haomeiwen.com/subject/wygbattx.html