Android RecyclerView的焦点记忆封装
上一篇中介绍了TV开发中的列表焦点实现
androidtv列表焦点记忆实现,是用外部代码控制的方式实现的,比较繁琐,现在介绍用自定义RecyclerView的方式来实现,并增加了其他的功能:限制纵向和横向移出焦点,移入移出焦点的事件监听等。
代码实现如下:
importandroid.content.Context;
importandroid.support.annotation.Nullable;
importandroid.support.v7.widget.RecyclerView;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.KeyEvent;
importandroid.view.View;
importandroid.view.ViewGroup;
importjava.util.ArrayList;
publicclassFocusKeepRecyclerViewextendsRecyclerView{
privatestaticfinalStringTAG=FocusKeepRecyclerView.class.getSimpleName();
//是否可以纵向移出
privatebooleanmCanFocusOutVertical=true;
//是否可以横向移出
privatebooleanmCanFocusOutHorizontal=true;
//焦点移出recyclerview的事件监听
privateFocusLostListenermFocusLostListener;
//焦点移入recyclerview的事件监听
privateFocusGainListenermFocusGainListener;
//默认第一次选中第一个位置
privateintmCurrentFocusPosition=0;
publicFocusKeepRecyclerView(Contextcontext){
this(context,null);
}
publicFocusKeepRecyclerView(Contextcontext,@NullableAttributeSetattrs){
this(context,attrs,0);
}
publicFocusKeepRecyclerView(Contextcontext,@NullableAttributeSetattrs,intdefStyle){
super(context,attrs,defStyle);
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
setChildrenDrawingOrderEnabled(true);
setItemAnimator(null);
this.setFocusable(true);
}
publicbooleanisCanFocusOutVertical(){
returnmCanFocusOutVertical;
}
publicvoidsetCanFocusOutVertical(booleancanFocusOutVertical){
mCanFocusOutVertical=canFocusOutVertical;
}
publicbooleanisCanFocusOutHorizontal(){
returnmCanFocusOutHorizontal;
}
publicvoidsetCanFocusOutHorizontal(booleancanFocusOutHorizontal){
mCanFocusOutHorizontal=canFocusOutHorizontal;
}
@Override
publicViewfocusSearch(intdirection){
returnsuper.focusSearch(direction);
}
//覆写focusSearch寻焦策略
@Override
publicViewfocusSearch(Viewfocused,intdirection){
Log.i(TAG,"focusSearch"+focused+",direction="+direction);
Viewview=super.focusSearch(focused,direction);
if(focused==null){
returnview;
}
if(view!=null){
//该方法返回焦点view所在的父view,如果是在recyclerview之外,就会是null.所以根据是否是null,来判断是否是移出了recyclerview
ViewnextFocusItemView=findContainingItemView(view);
if(nextFocusItemView==null){
if(!mCanFocusOutVertical&&(direction==View.FOCUS_DOWN||direction==View.FOCUS_UP)){
//屏蔽焦点纵向移出recyclerview
returnfocused;
}
if(!mCanFocusOutHorizontal&&(direction==View.FOCUS_LEFT||direction==View.FOCUS_RIGHT)){
//屏蔽焦点横向移出recyclerview
returnfocused;
}
//调用移出的监听
if(mFocusLostListener!=null){
mFocusLostListener.onFocusLost(focused,direction);
}
returnview;
}
}
returnview;
}
publicvoidsetFocusLostListener(FocusLostListenerfocusLostListener){
this.mFocusLostListener=focusLostListener;
}
publicinterfaceFocusLostListener{
voidonFocusLost(ViewlastFocusChild,intdirection);
}
publicvoidsetGainFocusListener(FocusGainListenerfocusListener){
this.mFocusGainListener=focusListener;
}
publicinterfaceFocusGainListener{
voidonFocusGain(Viewchild,Viewfocued);
}
@Override
publicvoidrequestChildFocus(Viewchild,Viewfocused){
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
publicvoidaddFocusables(ArrayListviews,intdirection,intfocusableMode){
Viewview=null;
if(this.hasFocus()||mCurrentFocusPosition<0||(view=getLayoutManager().findViewByPosition(mCurrentFocusPosition))==null){
super.addFocusables(views,direction,focusableMode);
}elseif(view.isFocusable()){
//将当前的view放到Focusableviews列表中,再次移入焦点时会取到该view,实现焦点记忆功能
views.add(view);
}else{
super.addFocusables(views,direction,focusableMode);
}
}
/**
*控制当前焦点最后绘制,防止焦点放大后被遮挡
*原顺序123456789,当4是focus时,绘制顺序变为123567894
*@paramchildCount
*@parami
*@return
*/
@Override
protectedintgetChildDrawingOrder(intchildCount,inti){
ViewfocusedChild=getFocusedChild();
Log.i(TAG,"focusedChild="+focusedChild);
if(focusedChild==null){
returnsuper.getChildDrawingOrder(childCount,i);
}else{
intindex=indexOfChild(focusedChild);
Log.i(TAG,"index="+index+",i="+i+",count="+childCount);
if(i==childCount-1){
returnindex;
}
if(i
代码实现和注释说明如上。
可以直接作为一个recyclerview使用,已经具有了焦点记忆的功能了,不需要在外层增加额外的代码;要增加限制纵向和横向移出焦点,移入移出焦点的事件监听的功能,可以再调用上面的setXXXListener等方法。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。