首页 > 系统 > Android > 正文

Android RecyclerView的焦点记忆封装

2019-10-22 18:13:12
字体:
来源:转载
供稿:网友

上一篇中介绍了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等方法。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表