android tv 开发布局,Android TV开发总结(七)构建一个TV app中的剧集列表控件
前言:劇集類控件,在TV app中非常常見,今天將介紹構建一個TV app中的劇集列表控件,此控件上傳到我的Github:https://github.com/hejunlin2013/EpisodeListView,點擊【閱讀原文】,可看對應的github, 喜歡可以star。Agenda如下:效果圖
效果圖gif
實現思路
代碼分析
效果圖
效果圖gif:
實現思路:1、用兩個RecycleView作為控件橫向布局
2、PopupWindow作為該集劇情簡介
3、當焦點到達Parent時,對Child進行監聽,并發生變化,同理,如果Child超過10個時,通知Parent
代碼分析:
EpisodeListView.java 作用:負責組配兩個RecycleView填充對應的數據
焦點監聽及獲焦情況
public?class?EpisodeListView?extends?RelativeLayout?implements?View.OnFocusChangeListener?{????public?static?final?String?TAG?=?EpisodeListView.class.getSimpleName();????private?Context?mContext;????private?RelativeLayout?mContentPanel;????private?RecyclerView?mChildrenView;????private?RecyclerView?mParentView;????private?LinearLayoutManager?mEpisodesLayoutManager;????private?LinearLayoutManager?mGroupLayoutManager;????private?EpisodeListViewAdapter?mEpisodeListAdapter;????private?ChildrenAdapter?mChildrenAdapter;????private?ParentAdapter?mParentAdapter;????private?Handler?mHandler?=?new?Handler(Looper.getMainLooper());????public?EpisodeListView(Context?context)?{????????this(context,?null);????}????public?EpisodeListView(Context?context,?AttributeSet?attrs)?{????????this(context,?attrs,?0);????}????public?EpisodeListView(Context?context,?AttributeSet?attrs,?int?defStyleAttr)?{????????super(context,?attrs,?defStyleAttr);????????if?(!isInEditMode())?{????????????mContext?=?context;????????????init();????????}????}????private?void?init()?{????????LayoutInflater?inflater?=?LayoutInflater.from(mContext);????????inflater.inflate(R.layout.episodelist_layout,?this,?true);????????mChildrenView?=?(RecyclerView)?findViewById(R.id.episodes);????????mParentView?=?(RecyclerView)?findViewById(R.id.groups);????????mEpisodesLayoutManager?=?new?LinearLayoutManager(mContext,?LinearLayout.HORIZONTAL,?false);????????mGroupLayoutManager?=?new?LinearLayoutManager(mContext,?LinearLayout.HORIZONTAL,?false);????????mChildrenView.setLayoutManager(mEpisodesLayoutManager);????????mParentView.setLayoutManager(mGroupLayoutManager);????????mChildrenView.setItemAnimator(new?DefaultItemAnimator());????????mParentView.setItemAnimator(new?DefaultItemAnimator());????????mChildrenView.setOnFocusChangeListener(this);????????mParentView.setOnFocusChangeListener(this);????????this.setOnFocusChangeListener(this);????}????public?void?setAdapter(final?EpisodeListViewAdapter?adapter)?{????????mEpisodeListAdapter?=?adapter;????????mChildrenAdapter?=?adapter.getEpisodesAdapter();????????mParentAdapter?=?adapter.getGroupAdapter();????????mChildrenView.setAdapter(mChildrenAdapter);????????mParentView.setAdapter(mParentAdapter);????????mParentAdapter.setOnItemClickListener(new?ParentAdapter.OnItemClickListener()?{????????????@Override????????????public?void?onGroupItemClick(View?view,?int?position)?{????????????????mEpisodesLayoutManager.scrollToPositionWithOffset(adapter.getChildrenPosition(position),?0);????????????}????????});????????mParentAdapter.setOnItemFocusListener(new?ParentAdapter.OnItemFocusListener()?{????????????@Override????????????public?void?onGroupItemFocus(View?view,?int?position,?boolean?hasFocus)?{????????????????int?episodePosition?=?adapter.getChildrenPosition(position);????????????????mChildrenAdapter.setCurrentPosition(episodePosition);????????????????mEpisodesLayoutManager.scrollToPositionWithOffset(adapter.getChildrenPosition(position),?0);????????????}????????});????????mChildrenAdapter.setOnItemFocusListener(new?ChildrenAdapter.OnItemFocusListener()?{????????????@Override????????????public?void?onEpisodesItemFocus(View?view,?int?position,?boolean?hasFocus)?{????????????????if?(hasFocus)?{????????????????????int?groupPosition?=?adapter.getParentPosition(position);????????????????????mGroupLayoutManager.scrollToPositionWithOffset(groupPosition,?0);????????????????????mParentAdapter.setCurrentPosition(adapter.getParentPosition(groupPosition));????????????????}????????????}????????});????????mChildrenAdapter.setOnItemClickListener(new?ChildrenAdapter.OnItemClickListener()?{????????????@Override????????????public?void?onEpisodesItemClick(View?view,?int?position)?{????????????}????????});????}????public?void?setLongFocusListener(ChildrenAdapter.OnItemLongFocusListener?listener)?{????????mChildrenAdapter.setOnItemLongFocusListener(listener);????}????@Override????public?boolean?dispatchKeyEvent(KeyEvent?event)?{????????if?(event.getAction()?==?KeyEvent.ACTION_DOWN)?{????????????switch?(event.getKeyCode())?{????????????????case?KeyEvent.KEYCODE_DPAD_UP:????????????????????if?(mParentView.hasFocus())?{????????????????????????mChildrenView.requestFocus();????????????????????????return?true;????????????????????}????????????????????break;????????????????case?KeyEvent.KEYCODE_DPAD_DOWN:????????????????????if?(mChildrenView.hasFocus())?{????????????????????????mParentView.requestFocus();????????????????????????return?true;????????????????????}????????????????????break;????????????????case?KeyEvent.KEYCODE_DPAD_RIGHT:????????????????????if?(mChildrenView.hasFocus()????????????????????????????&&?mChildrenAdapter.getCurrentPosition()?>=?mChildrenAdapter.getData().size()?-?1)?{????????????????????????return?true;????????????????????}????????????????????if?(mParentView.hasFocus()????????????????????????????&&?mParentAdapter.getCurrentPosition()?>=?mParentAdapter.getDatas().size()?-?1)?{????????????????????????return?true;????????????????????}????????????}????????}????????return?super.dispatchKeyEvent(event);????}????@Override????public?void?onFocusChange(View?v,?boolean?hasFocus)?{????????if?(v?==?this?&&?hasFocus)?{????????????mChildrenView.requestFocus();????????}?else?if?(v?==?mChildrenView?&&?hasFocus)?{????????????View?child?=?mChildrenView.getLayoutManager().findViewByPosition(mChildrenAdapter.getCurrentPosition());????????????if?(child?!=?null)?{????????????????child.requestFocus();????????????}?else?{????????????????int?lastPosition?=?mEpisodesLayoutManager.findLastVisibleItemPosition();????????????????child?=?mEpisodesLayoutManager.findViewByPosition(lastPosition);????????????????if?(child?!=?null)????????????????????child.requestFocus();????????????}????????}?else?if?(v?==?mParentView?&&?hasFocus)?{????????????View?child?=?mParentView.getLayoutManager().findViewByPosition(mParentAdapter.getCurrentPosition());????????????if?(child?!=?null)?{????????????????child.requestFocus();????????????}????????}????}}
EpisodeListViewAdapter 作用:抽象類,在實例化時負責將外部數據轉成list傳入
實例化ParentAdapter及ChildrenAdapter
public?abstract?class?EpisodeListViewAdapter{????private?ChildrenAdapter?mChildrenAdapter;????private?ParentAdapter?mParentAdapter;????public?EpisodeListViewAdapter()?{????????mChildrenAdapter?=?new?ChildrenAdapter(getChildrenList());????????mParentAdapter?=?new?ParentAdapter(getParentList());????}????public?ChildrenAdapter?getEpisodesAdapter()?{????????return?mChildrenAdapter;????}????public?ParentAdapter?getGroupAdapter()?{????????return?mParentAdapter;????}????public?void?setSelectedPositions(List?positions)?{????????mChildrenAdapter.setSelectedPositions(positions);????}????public?abstract?List?getChildrenList();????public?abstract?List?getParentList();????public?abstract?int?getChildrenPosition(int?childPosition);????public?abstract?int?getParentPosition(int?parentPosition);}
ParentAdapter?作用:每10集為一組,進行控制
public?class?ParentAdapter?extends?RecyclerView.Adapter?{????private?static?final?int?GROUPS_COLUMN_COUNT?=?10;????private?OnItemClickListener?mItemClickListener;????private?OnItemFocusListener?mItemFocusListener;????private?List?mDatas;????private?int?parentWidth;????private?int?itemWidth;????private?int?mCurrentPosition;????public?ParentAdapter(List?datas)?{????????mDatas?=?datas;????}????@Override????public?MyViewHolder?onCreateViewHolder(ViewGroup?parent,?int?viewType)?{????????View?view?=?LayoutInflater.from(parent.getContext())????????????????.inflate(R.layout.parent_item,?parent,?false);????????MyViewHolder?holder?=?new?MyViewHolder(view);????????parentWidth?=?parent.getMeasuredWidth();????????itemWidth?=?(parentWidth?-????????????????(holder.textView.getPaddingLeft()?+?holder.textView.getPaddingRight())?*?(GROUPS_COLUMN_COUNT))????????????????/?GROUPS_COLUMN_COUNT?+?1;????????return?holder;????}????@Override????public?void?onBindViewHolder(MyViewHolder?holder,?final?int?position)?{????????holder.textView.setText(mDatas.get(position));????????holder.textView.setWidth(itemWidth);????????holder.textView.setFocusable(true);????????holder.textView.setOnClickListener(new?View.OnClickListener()?{????????????@Override????????????public?void?onClick(View?v)?{????????????????mItemClickListener.onGroupItemClick(v,?position);????????????}????????});????????holder.textView.setOnFocusChangeListener(new?View.OnFocusChangeListener()?{????????????@Override????????????public?void?onFocusChange(View?v,?boolean?hasFocus)?{????????????????if?(hasFocus)?{????????????????????mItemFocusListener.onGroupItemFocus(v,?position,?hasFocus);????????????????????mCurrentPosition?=?position;????????????????}????????????}????????});????}????@Override????public?int?getItemCount()?{????????return?mDatas.size();????}????public?List?getDatas()?{????????return?mDatas;????}????public?int?getCurrentPosition()?{????????return?mCurrentPosition;????}????public?void?setCurrentPosition(int?position)?{????????mCurrentPosition?=?position;????}????public?void?setOnItemFocusListener(OnItemFocusListener?listener)?{????????mItemFocusListener?=?listener;????}????public?void?setOnItemClickListener(OnItemClickListener?listener)?{????????mItemClickListener?=?listener;????}????class?MyViewHolder?extends?RecyclerView.ViewHolder?{????????TextView?textView;????????public?MyViewHolder(View?view)?{????????????super(view);????????????textView?=?(TextView)?view.findViewById(R.id.item);????????}????}????public?interface?OnItemClickListener?{????????void?onGroupItemClick(View?view,?int?position);????}????public?interface?OnItemFocusListener?{????????void?onGroupItemFocus(View?view,?int?position,?boolean?hasFocus);????}}
ChildrenAdapter?作用:每行最多顯示10個,大于10可以左右變換
parent之間焦點變換時,children可立即響應。字數限制,不貼代碼,可直接對應github看。
總結
以上是生活随笔為你收集整理的android tv 开发布局,Android TV开发总结(七)构建一个TV app中的剧集列表控件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么把win10系统装在U盘里怎么把wi
- 下一篇: android 支付宝沙箱测试环境,An