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等方法。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。