Android RecyclerView的焦點(diǎn)記憶封裝
上一篇中介紹了TV開(kāi)發(fā)中的列表焦點(diǎn)實(shí)現(xiàn)
android tv列表焦點(diǎn)記憶實(shí)現(xiàn) ,是用外部代碼控制的方式實(shí)現(xiàn)的,比較繁瑣,現(xiàn)在介紹用自定義RecyclerView的方式來(lái)實(shí)現(xiàn),并增加了其他的功能:限制縱向和橫向移出焦點(diǎn),移入移出焦點(diǎn)的事件監(jiān)聽(tīng)等。
代碼實(shí)現(xiàn)如下:
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; //焦點(diǎn)移出recyclerview的事件監(jiān)聽(tīng) private FocusLostListener mFocusLostListener; //焦點(diǎn)移入recyclerview的事件監(jiān)聽(tīng) private FocusGainListener mFocusGainListener; //默認(rèn)第一次選中第一個(gè)位置 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); } //覆寫(xiě)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) { //該方法返回焦點(diǎn)view所在的父view,如果是在recyclerview之外,就會(huì)是null.所以根據(jù)是否是null,來(lái)判斷是否是移出了recyclerview View nextFocusItemView = findContainingItemView(view); if (nextFocusItemView == null) { if (!mCanFocusOutVertical && (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP)) { //屏蔽焦點(diǎn)縱向移出recyclerview return focused; } if (!mCanFocusOutHorizontal && (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT)) { //屏蔽焦點(diǎn)橫向移出recyclerview return focused; } //調(diào)用移出的監(jiān)聽(tīng) 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 重新獲取焦點(diǎn),調(diào)用移入焦點(diǎn)的事件監(jiān)聽(tīng) if (mFocusGainListener != null) { mFocusGainListener.onFocusGain(child, focused); } } super.requestChildFocus(child, focused);//執(zhí)行過(guò)super.requestChildFocus之后hasFocus會(huì)變成true mCurrentFocusPosition = getChildViewHolder(child).getAdapterPosition(); Log.i(TAG,"focusPos = "+mCurrentFocusPosition); } //實(shí)現(xiàn)焦點(diǎn)記憶的關(guān)鍵代碼 @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()){ //將當(dāng)前的view放到Focusable views列表中,再次移入焦點(diǎn)時(shí)會(huì)取到該view,實(shí)現(xiàn)焦點(diǎn)記憶功能 views.add(view); }else{ super.addFocusables(views,direction,focusableMode); } } /** * 控制當(dāng)前焦點(diǎn)最后繪制,防止焦點(diǎn)放大后被遮擋 * 原順序123456789,當(dāng)4是focus時(shí),繪制順序變?yōu)?23567894 * @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; } } }
代碼實(shí)現(xiàn)和注釋說(shuō)明如上。
可以直接作為一個(gè)recyclerview使用,已經(jīng)具有了焦點(diǎn)記憶的功能了,不需要在外層增加額外的代碼;要增加限制縱向和橫向移出焦點(diǎn),移入移出焦點(diǎn)的事件監(jiān)聽(tīng)的功能,可以再調(diào)用上面的setXXXListener等方法。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Kotlin啟動(dòng)協(xié)程的三種方式示例詳解
這篇文章主要為大家介紹了Kotlin啟動(dòng)協(xié)程的三種方式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12Android從Fragment跳轉(zhuǎn)到其他Activity的簡(jiǎn)單實(shí)例
這篇文章主要介紹了Android從Fragment跳轉(zhuǎn)到其他Activity的簡(jiǎn)單實(shí)例,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02詳解Recyclerview item中有EditText使用刷新遇到的坑
這篇文章主要介紹了詳解Recyclerview item中有EditText使用刷新遇到的坑,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05Android利用WindowManager實(shí)現(xiàn)懸浮窗
這篇文章主要為大家詳細(xì)介紹了Android利用WindowManager實(shí)現(xiàn)懸浮窗效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android開(kāi)發(fā)自定義短信驗(yàn)證碼實(shí)現(xiàn)過(guò)程詳解
這篇文章主要為大家介紹了Android開(kāi)發(fā)自定義短信驗(yàn)證碼實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Android實(shí)現(xiàn)RecyclerView嵌套流式布局的詳細(xì)過(guò)程
最近在做需求的時(shí)候,碰到有各種篩選項(xiàng)的界面,下面這篇文章主要給大家介紹了關(guān)于Android實(shí)現(xiàn)RecyclerView嵌套流式布局的詳細(xì)過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12ViewPager 與 Fragment相結(jié)合實(shí)現(xiàn)微信界面實(shí)例代碼
這篇文章主要介紹了ViewPager 與 Fragment相結(jié)合實(shí)現(xiàn)微信界面實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-07-07