Android RecyclerView的焦点记忆封装
时间:2021-09-29 08:49:09|栏目:Android代码|点击: 次
上一篇中介绍了TV开发中的列表焦点实现
android tv列表焦点记忆实现 ,是用外部代码控制的方式实现的,比较繁琐,现在介绍用自定义RecyclerView的方式来实现,并增加了其他的功能:限制纵向和横向移出焦点,移入移出焦点的事件监听等。
代码实现如下:
import android.content.Context; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; public class FocusKeepRecyclerView extends RecyclerView { private static final String TAG = FocusKeepRecyclerView.class.getSimpleName(); //是否可以纵向移出 private boolean mCanFocusOutVertical = true; //是否可以横向移出 private boolean mCanFocusOutHorizontal = true; //焦点移出recyclerview的事件监听 private FocusLostListener mFocusLostListener; //焦点移入recyclerview的事件监听 private FocusGainListener mFocusGainListener; //默认第一次选中第一个位置 private int mCurrentFocusPosition = 0; public FocusKeepRecyclerView(Context context) { this(context, null); } public FocusKeepRecyclerView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public FocusKeepRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); setChildrenDrawingOrderEnabled(true); setItemAnimator(null); this.setFocusable(true); } public boolean isCanFocusOutVertical() { return mCanFocusOutVertical; } public void setCanFocusOutVertical(boolean canFocusOutVertical) { mCanFocusOutVertical = canFocusOutVertical; } public boolean isCanFocusOutHorizontal() { return mCanFocusOutHorizontal; } public void setCanFocusOutHorizontal(boolean canFocusOutHorizontal) { mCanFocusOutHorizontal = canFocusOutHorizontal; } @Override public View focusSearch(int direction) { return super.focusSearch(direction); } //覆写focusSearch寻焦策略 @Override public View focusSearch(View focused, int direction) { Log.i(TAG, "focusSearch " + focused + ",direction= " + direction); View view = super.focusSearch(focused, direction); if (focused == null) { return view; } if (view != null) { //该方法返回焦点view所在的父view,如果是在recyclerview之外,就会是null.所以根据是否是null,来判断是否是移出了recyclerview View nextFocusItemView = findContainingItemView(view); if (nextFocusItemView == null) { if (!mCanFocusOutVertical && (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP)) { //屏蔽焦点纵向移出recyclerview return focused; } if (!mCanFocusOutHorizontal && (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT)) { //屏蔽焦点横向移出recyclerview return focused; } //调用移出的监听 if (mFocusLostListener != null) { mFocusLostListener.onFocusLost(focused, direction); } return view; } } return view; } public void setFocusLostListener(FocusLostListener focusLostListener) { this.mFocusLostListener = focusLostListener; } public interface FocusLostListener { void onFocusLost(View lastFocusChild, int direction); } public void setGainFocusListener(FocusGainListener focusListener) { this.mFocusGainListener = focusListener; } public interface FocusGainListener { void onFocusGain(View child, View focued); } @Override public void requestChildFocus(View child, View focused) { Log.i(TAG, "nextchild= " + child + ",focused = " + focused); if (!hasFocus()) { //recyclerview 子view 重新获取焦点,调用移入焦点的事件监听 if (mFocusGainListener != null) { mFocusGainListener.onFocusGain(child, focused); } } super.requestChildFocus(child, focused);//执行过super.requestChildFocus之后hasFocus会变成true mCurrentFocusPosition = getChildViewHolder(child).getAdapterPosition(); Log.i(TAG,"focusPos = "+mCurrentFocusPosition); } //实现焦点记忆的关键代码 @Override public void addFocusables(ArrayList<View> views, int direction, int focusableMode) { View view = null; if (this.hasFocus() || mCurrentFocusPosition < 0 || (view = getLayoutManager().findViewByPosition(mCurrentFocusPosition)) == null) { super.addFocusables(views,direction,focusableMode); }else if(view.isFocusable()){ //将当前的view放到Focusable views列表中,再次移入焦点时会取到该view,实现焦点记忆功能 views.add(view); }else{ super.addFocusables(views,direction,focusableMode); } } /** * 控制当前焦点最后绘制,防止焦点放大后被遮挡 * 原顺序123456789,当4是focus时,绘制顺序变为123567894 * @param childCount * @param i * @return */ @Override protected int getChildDrawingOrder(int childCount, int i) { View focusedChild = getFocusedChild(); Log.i(TAG,"focusedChild ="+focusedChild); if(focusedChild== null){ return super.getChildDrawingOrder(childCount, i); }else{ int index = indexOfChild(focusedChild); Log.i(TAG, " index = " + index + ",i=" + i + ",count=" + childCount); if(i == childCount-1){ return index; } if(i<index){ return i; } return i+1; } } }
代码实现和注释说明如上。
可以直接作为一个recyclerview使用,已经具有了焦点记忆的功能了,不需要在外层增加额外的代码;要增加限制纵向和横向移出焦点,移入移出焦点的事件监听的功能,可以再调用上面的setXXXListener等方法。
栏 目:Android代码
下一篇:Android APK文件在电脑(PC虚拟机)上面运行方法
本文标题:Android RecyclerView的焦点记忆封装
本文地址:http://www.codeinn.net/misctech/178074.html