RecyclerView焦點循環切換的方法

                                 RecyclerView焦點循環切換的方法

       RecyclerView我們使用的很多了,做TV開發的時候,當焦點在第一項時按上鍵希望能跳到最後一項,焦點在最後一項時按下鍵跳到第一項,recyclerView沒有這個功能的,現在就介紹如何實現這個功能。

       1,在recyclerView的adapter的onBindViewHolder裏對viewHolder設置按鍵監聽。

public class ManagerFavoritesRecycleViewAdapter extends  RecyclerView.Adapter<ManagerFavoritesRecycleViewAdapter.ViewHolder> {
    private OnRecycleViewItemSelectListener mOnItemSelectLister;
    private OnRecycleViewItemClickListener mOnItemClickLister;
    private OnRecyclerViewItemKeyListener mOnKeyListener;

    private Context mContext;
    private ArrayList<ManagerServiceEntity> mServiceList;

    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView mChannelIndex;
        private TextView mChannelName;
        private ImageView mChannelFavStatus;

        public ViewHolder(View view) {
            super(view);
            mChannelIndex = (TextView) view.findViewById(R.id.tv_channel_index);
            mChannelName = (TextView) view.findViewById(R.id.tv_channel_name);
            mChannelFavStatus = (ImageView) view.findViewById(R.id.im_fav_status);
        }
    }

    public ManagerFavoritesRecycleViewAdapter(Context context, ArrayList<ManagerServiceEntity> service_list) {
        this.mContext = context;
        this.mServiceList = service_list;
    }

    public void setOnItemSelectListener(OnRecycleViewItemSelectListener listener) {
        mOnItemSelectLister = listener;
    }

    public void setOnItemClickLister(OnRecycleViewItemClickListener listener) {
        mOnItemClickLister = listener;
    }

    public void setOnKeyListener(OnRecyclerViewItemKeyListener listener) {
        mOnKeyListener = listener;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.manager_favorites_recycleview_holder, viewGroup, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int position) {
        ManagerServiceEntity serviceInfoEntity = mServiceList.get(position);
        viewHolder.mChannelIndex.setText(String.valueOf(serviceInfoEntity.getServiceLcn()));
        viewHolder.mChannelName.setText(DVBPlayerUtil.filterSpecialChar(serviceInfoEntity.getServiceName()));

        if (serviceInfoEntity.getServiceIndex() == 1) {
            viewHolder.mChannelFavStatus.setBackgroundResource(R.drawable.icon_fave);
        } else {
            viewHolder.mChannelFavStatus.setBackgroundResource(R.drawable.translucent_background);
        }

        if(mOnItemSelectLister != null) {
            viewHolder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View view, boolean hasFocus) {
                    mOnItemSelectLister.onItemSelected(view, position, hasFocus);
                }
            });
        }

        if (mOnItemClickLister != null) {
            viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mOnItemClickLister.onItemClick(view, position);
                }
            });
        }

        if (mOnKeyListener != null) {
            viewHolder.itemView.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    return mOnKeyListener.recyclerViewItemOnKey(v, keyCode, event, position);
                }
            });
        }
    }

    @Override
    public int getItemCount() {
        return this.mServiceList.size();
    }

    public ManagerServiceEntity getItemDataByPosition(int position) {
        if (mServiceList != null && mServiceList.size() > 0) {
            return mServiceList.get(position);
        }

        return null;
    }

    public ArrayList<ManagerServiceEntity> getServiceList() {
        return mServiceList;
    }

    public void setServiceList(ArrayList<ManagerServiceEntity> service_list) {
        this.mServiceList = service_list;
    }

    public interface OnRecycleViewItemSelectListener {
        void onItemSelected(View view, int position, boolean hasFocus);
    }

    public interface OnRecycleViewItemClickListener {
        void onItemClick(View view,int position);
    }

    public interface OnRecyclerViewItemKeyListener {
        boolean recyclerViewItemOnKey(View view, int keyCode, KeyEvent event, int position);
    }
}

2、監聽後的實現

private ManagerFavoritesRecycleViewAdapter mChannelAdapter;

mChannelAdapter = new ManagerFavoritesRecycleViewAdapter(getContext(), new ArrayList<ManagerServiceEntity>());

mChannelAdapter.setOnItemSelectListener(new OnRecycleViewItemSelectListener() {
            private View mLastView = null;

            @Override
            public void onItemSelected(View view, int position, boolean hasFocus) {
                ObjectAnimator animator1;
                ObjectAnimator animator2;

                //Log.d("wujiang", "mAdapter's onItemSelected");

                if (mLastView != null && hasFocus == false) {
                    animator1 = ObjectAnimator.ofFloat(mLastView, "scaleX", 1.02f, 1f);
                    animator2 = ObjectAnimator.ofFloat(mLastView, "scaleY", 1.05f, 1f);

                    AnimatorSet animSet = new AnimatorSet();
                    animSet.setDuration(200);
                    animSet.playTogether(animator1, animator2);
                    animSet.start();
                }

                if (view != null && hasFocus == true) {
                    View scale_view = view.findViewById(R.id.ll_index_name);
                    animator1 = ObjectAnimator.ofFloat(scale_view, "scaleX", 1f, 1.02f);
                    animator2 = ObjectAnimator.ofFloat(scale_view, "scaleY", 1f, 1.05f);

                    AnimatorSet animSet = new AnimatorSet();
                    animSet.setDuration(200);
                    animSet.playTogether(animator1, animator2);
                    animSet.start();

                    mLastView = scale_view;
                } else {
                    mLastView = null;
                }
            }
        });

        mChannelAdapter.setOnItemClickLister(new OnRecycleViewItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                
            }
        });

        mChannelAdapter.setOnKeyListener(new OnRecyclerViewItemKeyListener() {
            @Override
            public boolean recyclerViewItemOnKey(View view, int keyCode, KeyEvent event, int position) {
                if (event.getAction() == KeyEvent.ACTION_UP) {
                    return false;
                }

                switch (keyCode) {
                    case KeyEvent.KEYCODE_DPAD_UP:
                        if (position == 0) {
                            mBtnSpace.requestFocus();
                            mUserChannelRecyclerView.scrollToPosition(mChannelAdapter.getItemCount() - 1);
                            mUserChannelRecyclerView.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    requestFocus(mUserChannelRecyclerView, mChannelAdapter.getItemCount() - 1);
                                }
                            }, 100);
                            return true;
                        }
                        break;

                    case KeyEvent.KEYCODE_DPAD_DOWN:
                        int item_count = mUserChannelRecyclerView.getAdapter().getItemCount();
                        if (position == (item_count - 1) ) {
                            mBtnSpace.requestFocus();
                            mUserChannelRecyclerView.scrollToPosition(0);
                            mUserChannelRecyclerView.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    requestFocus(mUserChannelRecyclerView, 0);
                                }
                            }, 100);
                            return true;
                        }

                    default:
                        return true;
                }
                return false;
            }
        });
    }

private void requestFocus(RecyclerView recyclerView, int position) {
        View view = recyclerView.getChildAt(position);
        LinearLayoutManager llM = (LinearLayoutManager) recyclerView.getLayoutManager();
        if (view != null) {
            view.requestFocus();
        } else if (llM.findViewByPosition(position) != null) {
            llM.findViewByPosition(position).requestFocus();
        } else {
            recyclerView.requestFocus();
        }
    }

        重點看recyclerViewItemOnKey。先調用scrollToPosition滑到指定的位置,然後延時100MS調用requestFocus讓指定的view獲取焦點。

        那mBtnSpace.requestFocus()是幹什麼用的呢?

        如果沒有mBtnSpace.requestFocus(),當你用遙控器一下一下按的時候,焦點能正確的從第一項跳到最後一項,從最後一項跳到第一項。但是當你一直按着遙控器,跳到第一項或者最後一項後焦點就飛掉了(因爲我們的UI往往比較複雜)。

        於是我就定義了一個很小的透明的Button,讓它先獲取焦點,這樣就能保證焦點不飛。只讓這個Button獲取焦點還不夠,要過濾掉所有的按鍵消息。

mBtnSpace.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                return true;
            }
        });

                                                                                    THE            END

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章