美文网首页Android TV
VerticalGridView第一行获取焦点后,再次按向上键,

VerticalGridView第一行获取焦点后,再次按向上键,

作者: dongdengke | 来源:发表于2017-09-18 16:56 被阅读300次

    最近在做项目中,有这么一个需求。点击电视剧某一集进入详情页,并可以点击选集按钮进行选集。于是乎,想到了使用VerticalGridView来实现(VerticalGridView是V17新推出的控件,不熟悉的朋友可以查找资料学习下)。使用VerticalGridView很容易实现了基本的功能,但是遇到一个很棘手的问题。就是当第一行获取焦点后,再次按向上键,上方的控件获取不到焦点。在网上找了好多解决方案,最终也没有解决问题。最后,使用setOnKeyListner方法来实现。虽说解决了问题,带来了新的问题:在第二行按向上键后,第一行先获取到焦点,接着第一行有失去焦点,上方控件获取到焦点了。尼玛,我也是醉了。最终发现onKey方法执行了两次,知道了原因,问题就好解决了。下面,就介绍下实现方案。
    本Demo还实现了,获取焦点高亮显示的效果。VerticalGridView的使用不在介绍,不熟悉的可以参考
    android leanback使用详解以及获取焦点高亮

    首先,布局页面编写:
    (1)主布局页面

    <?xml version="1.0" encoding="utf-8"?>  
    <LinearLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"  
        xmlns:lb="http://schemas.android.com/apk/res-auto"  
        xmlns:tools="http://schemas.android.com/tools"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent"  
        android:background="@drawable/index_bg"  
        android:orientation="vertical">  
      
        <LinearLayout  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_marginTop="@dimen/h_56"  
            android:orientation="horizontal">  
      
            <View  
                android:id="@+id/btn_pd_play"  
                style="@style/pd_btn"  
                android:background="@drawable/pd_play_selector"  
                android:visibility="visible" />  
      
            <View  
                android:id="@+id/btn_pd_collect"  
                style="@style/pd_btn.non_starter"  
                android:background="@drawable/pd_collect_selector"  
                android:visibility="visible" />  
      
            <View  
                android:id="@+id/btn_pd_xuanji"  
                style="@style/pd_btn.non_starter"  
                android:visibility="visible" />  
        </LinearLayout>  
      
        <android.support.v17.leanback.widget.HorizontalGridView  
            android:id="@+id/hv_tuijian"  
            android:layout_width="match_parent"  
            android:layout_height="@dimen/h_400"  
            android:layout_marginLeft="@dimen/w_145"  
            android:layout_marginRight="@dimen/w_115"  
            android:focusable="true"  
            android:focusableInTouchMode="true"  
            lb:horizontalMargin="@dimen/w_15"  
            lb:numberOfRows="1"></android.support.v17.leanback.widget.HorizontalGridView>  
      
        <android.support.v17.leanback.widget.VerticalGridView  
            android:id="@+id/hv_suanji"  
            android:layout_width="match_parent"  
            android:layout_height="@dimen/h_480"  
            android:layout_marginLeft="@dimen/w_145"  
            android:layout_marginRight="@dimen/w_115"  
            android:focusable="true"  
            android:focusableInTouchMode="true"  
            android:paddingTop="@dimen/h_10"  
            lb:horizontalMargin="@dimen/w_15"  
            lb:numberOfColumns="10"  
            lb:numberOfRows="2"></android.support.v17.leanback.widget.VerticalGridView>  
    </LinearLayout> 
    

    (2)item布局页面

    <?xml version="1.0" encoding="utf-8"?>  
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:id="@+id/ll_item_search"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:clipChildren="false"  
        android:clipToPadding="false"  
        android:focusable="true"  
        android:focusableInTouchMode="true"  
        android:orientation="vertical" >  
      
        <RelativeLayout  
            android:id="@+id/rl_scale"  
            android:layout_width="@dimen/w_220"  
            android:layout_height="@dimen/h_260"  
            android:background="@drawable/bg_pic_n" >  
      
            <ImageView  
                android:id="@+id/iv_pic"  
                android:layout_width="match_parent"  
                android:layout_height="match_parent"  
                android:background="@drawable/mid_bottom"  
                android:scaleType="fitXY" />  
      
            <TextView  
                android:id="@+id/tv_target"  
                android:layout_width="match_parent"  
                android:layout_height="wrap_content"  
                android:layout_alignBottom="@id/iv_pic"  
                android:textColor="@color/search_text"  
                android:gravity="center"  
                android:padding="@dimen/w_10"  
                android:text="更新至"  
                android:textSize="@dimen/w_30"  
                android:visibility="gone" />  
        </RelativeLayout>  
      
        <FrameLayout  
            android:layout_width="@dimen/w_220"  
            android:layout_height="wrap_content"  
            android:layout_below="@id/rl_scale"  
            android:layout_centerHorizontal="true"  
            android:layout_marginTop="@dimen/h_2" >  
      
            <TextView  
                android:id="@+id/tv_name"  
                android:layout_width="wrap_content"  
                android:layout_height="wrap_content"  
                android:layout_gravity="center"  
                android:singleLine="true"  
                android:textColor="@color/search_text"  
                android:textSize="@dimen/w_32" />  
        </FrameLayout>  
      
    </RelativeLayout>  
    

    接着,编写通用的适配器:

    package cn.chinaiptv.foucedemo.adapter;  
      
    import android.support.v7.widget.RecyclerView;  
    import android.view.LayoutInflater;  
    import android.view.View;  
    import android.view.ViewGroup;  
      
    import java.util.Collections;  
    import java.util.Comparator;  
    import java.util.List;  
      
    /** 
     * @author zeng_yong_chang@163.com 
     */  
    public abstract class RvAdapter<T, VH extends RecyclerView.ViewHolder> extends  
            RecyclerView.Adapter<VH> {  
        protected List<T> mList;  
      
        public RvAdapter(List<T> data) {  
            setData(data);  
        }  
      
        public List<T> getData() {  
            return mList;  
        }  
      
        public void setData(List<T> data) {  
            mList = data;  
            notifyDataSetChanged();  
        }  
      
        public void sort(Comparator<T> comparator) {  
            Collections.sort(mList, comparator);  
            notifyDataSetChanged();  
        }  
      
        protected View inflateView(int itemViewLayoutId, ViewGroup parent) {  
            return LayoutInflater.from(parent.getContext()).inflate(  
                    itemViewLayoutId, parent, false);  
        }  
      
        @Override  
        public int getItemCount() {  
            return mList.size();  
        }  
    }  
    

    其次,VerticalGridView适配器的编写,具体代码如下:

    package cn.chinaiptv.foucedemo.adapter;  
      
    import android.annotation.SuppressLint;  
    import android.content.Context;  
    import android.support.v17.leanback.widget.VerticalGridView;  
    import android.support.v7.widget.RecyclerView.Adapter;  
    import android.view.KeyEvent;  
    import android.view.LayoutInflater;  
    import android.view.View;  
    import android.view.ViewGroup;  
      
    import java.util.List;  
      
    import cn.chinaiptv.foucedemo.R;  
    import cn.chinaiptv.foucedemo.bean.Content;  
    import cn.chinaiptv.foucedemo.cn.chinaiptv.foucedemo.holder.SearchListViewHolder;  
    import cn.chinaiptv.foucedemo.utils.FocusUtisl;  
      
    @SuppressLint("InflateParams")  
    public class XuanJiAdapter extends  
            Adapter<SearchListViewHolder> {  
      
        private List<Content> contentList;  
      
        private Context context;  
      
        private VerticalGridView hv_suanji;  
        private View btn_pd_xuanji;  
      
        public XuanJiAdapter(List<Content> recommenList, VerticalGridView hv_suanji, View btn_pd_xuanji) {  
            contentList = recommenList;  
            this.hv_suanji = hv_suanji;  
            this.btn_pd_xuanji = btn_pd_xuanji;  
        }  
      
        @Override  
        public int getItemCount() {  
            return contentList.size();  
      
        }  
      
        @Override  
        public void onBindViewHolder(final SearchListViewHolder holder, final int position) {  
            holder.itemView.setOnClickListener(new FocusUtisl.MyClick(position));  
            holder.itemView.setOnFocusChangeListener(new FocusUtisl.MyFocuchange(holder.rl_scale, holder.tv_name,  
                    position));  
            String name = "";  
            String miniPicURI = "";  
            Content content = contentList.get(position);  
            name = content.getName();  
            miniPicURI = content.getMiniPicURI();  
            holder.tv_name.setText(name);  
        }  
      
        @Override  
        public SearchListViewHolder onCreateViewHolder(ViewGroup parent, int arg1) {  
            View inflate = LayoutInflater.from(parent.getContext()).inflate(  
                    R.layout.item_serialdetail_recomm, null);  
            SearchListViewHolder holder = new SearchListViewHolder(inflate);  
            context = parent.getContext();  
            return holder;  
        }  
      
    }  
    

    接下来就要在Activity中设置数据了,代码如下:

    package cn.chinaiptv.foucedemo;  
      
    import android.app.Activity;  
    import android.os.Bundle;  
    import android.support.v17.leanback.widget.HorizontalGridView;  
    import android.support.v17.leanback.widget.VerticalGridView;  
    import android.view.View;  
      
    import java.util.ArrayList;  
      
    import cn.chinaiptv.foucedemo.adapter.SerialDetailRecommAdapter;  
    import cn.chinaiptv.foucedemo.adapter.XuanJiAdapter;  
    import cn.chinaiptv.foucedemo.bean.Content;  
      
    /** 
     * 连续剧详情页 
     */  
    public class MainActivity extends Activity {  
      
        private  HorizontalGridView hv_tuijian;  
        private VerticalGridView hv_suanji;  
        private  XuanJiAdapter xuanjiAdapter;  
        private View btn_pd_xuanji;  
        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.activity_series_detail);  
            btn_pd_xuanji=findViewById(R.id.btn_pd_xuanji);  
            initView();  
        }  
      
        private void initView() {  
            hv_tuijian=(HorizontalGridView)findViewById(R.id.hv_tuijian);  
            hv_suanji=(VerticalGridView)findViewById(R.id.hv_suanji);  
            getListRecommen();  
            getXuanJi();  
      
        }  
        private  ArrayList<Content> recommenList;  
        private  ArrayList<Content> xuanJiList;  
        private SerialDetailRecommAdapter recommenResultAdapter;  
        /** 
         * 获取可能要找的内容 
         */  
        private void getListRecommen() {  
            recommenList=new ArrayList<Content>();  
            for(int i=0;i<10;i++){  
                Content content=new Content();  
                content.setName("十月风暴"+i);  
                content.setType("ddd");  
                recommenList.add(content);  
            }  
            recommenResultAdapter = new SerialDetailRecommAdapter(recommenList);  
            hv_tuijian.setAdapter(recommenResultAdapter);  
        }  
        /** 
         * 获取可能要找的内容 
         */  
        private void getXuanJi() {  
            xuanJiList=new ArrayList<Content>();  
            for(int i=0;i<20;i++){  
                Content content=new Content();  
                content.setName("测试"+i);  
                content.setType("ddd");  
                xuanJiList.add(content);  
            }  
            xuanjiAdapter = new XuanJiAdapter(xuanJiList,hv_suanji,btn_pd_xuanji);  
            hv_suanji.setAdapter(xuanjiAdapter);  
        }  
    }  
    

    如果只这样去实现,第一行获取焦点后,再按向上键,上方的控件是获取不到代码的。解决方案如下:

    @Override  
      public void onBindViewHolder(final SearchListViewHolder holder, final int position) {  
          holder.itemView.setOnClickListener(new FocusUtisl.MyClick(position));  
          holder.itemView.setOnFocusChangeListener(new FocusUtisl.MyFocuchange(holder.rl_scale, holder.tv_name,  
                  position));  
          String name = "";  
          String miniPicURI = "";  
          Content content = contentList.get(position);  
          name = content.getName();  
          miniPicURI = content.getMiniPicURI();  
          holder.tv_name.setText(name);  
          holder.itemView.setOnKeyListener(new View.OnKeyListener() {  
              @Override  
              public boolean onKey(View v, int keyCode, KeyEvent event) {  
                  if (event.getAction() == KeyEvent.ACTION_UP) {  
                      return true;  
                  } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {  
                      if (position < 10) {  
                          hv_suanji.setFocusable(false);  
                          btn_pd_xuanji.requestFocus();  
                      }  
                  }  
                  return false;  
              }  
          });  
      
      }  
    
    

    这样上方的控件就可以获取到焦点了。
    最后,还有一些获取焦点时,高亮显示的方法,代码如下:

    package cn.chinaiptv.foucedemo.utils;  
      
    import android.view.View;  
      
    import cn.chinaiptv.foucedemo.R;  
      
    /** 
     * Created by ddklsy163com on 17/1/13. 
     */  
      
    public class FocusUtisl {  
        private static OnItemCallBack onItemCallBack;  
      
        public static class MyFocuchange implements View.OnFocusChangeListener {  
      
            int position;  
            View rl_scale;  
            View tv_name;  
      
            /** 
             * 图片,文字都放缩 
             * 
             * @param position 
             * @param rl_scale 
             */  
            public MyFocuchange(View rl_scale, View tv_name, int position) {  
                this.position = position;  
                this.rl_scale = rl_scale;  
                this.tv_name = tv_name;  
    //            Log.e("111111",position);  
            }  
      
            /** 
             * 仅仅放缩图片 
             * 
             * @param position 
             * @param rl_scale 
             */  
            public MyFocuchange(int position, View rl_scale) {  
                this.position = position;  
                this.rl_scale = rl_scale;  
            }  
      
            @Override  
            public void onFocusChange(View v, boolean hasFocus) {  
                if (hasFocus) {  
                    if (rl_scale != null) {  
                        rl_scale.animate().scaleX(1.1f).scaleY(1.1f).start();  
                        rl_scale.setBackgroundResource(R.drawable.bg_pic_s);  
                    }  
                    if (tv_name != null)  
                        tv_name.animate().scaleX(1.1f).scaleY(1.1f).start();  
                } else {  
                    if (rl_scale != null) {  
                        rl_scale.animate().scaleX(1.f).scaleY(1.f).start();  
                        rl_scale.setBackgroundResource(R.drawable.bg_pic_n);  
                    }  
                    if (tv_name != null)  
                        tv_name.animate().scaleX(1f).scaleY(1f).start();  
      
                }  
                if (onItemCallBack != null) {  
                    onItemCallBack.onFocusChange(v, hasFocus, position);  
                }  
            }  
      
        }  
      
        public static class MyClick implements View.OnClickListener {  
      
            int position;  
      
            public MyClick(int position) {  
                this.position = position;  
            }  
      
            @Override  
            public void onClick(View v) {  
                if (onItemCallBack != null) {  
                    onItemCallBack.onItemClick(v, position);  
                }  
            }  
        }  
      
        public void setOnItemCallBack(OnItemCallBack onItemCallBack) {  
            this.onItemCallBack = onItemCallBack;  
        }  
      
        public interface OnItemCallBack {  
            public void onFocusChange(View v, boolean hasFocus, int posiotion);  
      
            public void onItemClick(View v, int position);  
        }  
    }  
    

    到此,已经完美实现了获取焦点时高亮显示,并且解决了上方控件获取不到焦点的bug,Demo截图如下:

    20170114161500728.png

    相关文章

      网友评论

        本文标题:VerticalGridView第一行获取焦点后,再次按向上键,

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