一、RecyclerView的焦点记忆封装的学习
https://www.jianshu.com/p/75465a7fdd0f
二、整体代码压缩包
三、实现步骤:
1.将聚焦封装,继承Recyclerview即可
2.将原有的适配器的recyclerview改成FocusKeepRecyclerView
(1)在activity_main.xml中将RecyclerView改成FocusKeepRecyclerView<br /><br /> (2)在RecyclerViewAdapterDemo中将RecyclerView改成FocusKeepRecyclerView<br /><br /><br /> (3)在MainActivity中将RecyclerView改成FocusKeepRecyclerView<br />
3.添加item点击,以获取焦点
(1)定义一个接口,创建item点击方法<br /><br /> (2)创建点击事件,当它不为空的时候,获取点击的位置<br /><br /> (3)获取到的点击位置,按确定时,弹窗显示当前获取的位置数<br />
4.创建item_seletor.xml布局文件,选中和未选中的背景颜色的变化
四、整体代码
1.activity_main.xml布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.example.customrecyclerview.FocusKeepRecyclerViewandroid:id="@+id/rv_demo"android:layout_width="match_parent"android:focusable="true"android:layout_height="match_parent"/></LinearLayout>
2.item_recycler_view.xml布局文件
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="8dp"android:background="@drawable/item_seletor"tools:context=".MainActivity"><TextViewandroid:id="@+id/tv_view"android:layout_width="100dp"android:layout_height="100dp"android:gravity="center"android:text="测试"android:textSize="20sp"android:textColor="#E2583F"android:focusable="true"/></LinearLayout>
3.item_seletor.xml布局文件
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"><item android:state_focused="true" android:drawable="@color/teal_200"/><item android:state_focused="false" android:drawable="@color/teal_700"/></selector>
4.FocusKeepRecyclerView文件代码
package com.example.customrecyclerview;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.view.ViewGroup;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.recyclerview.widget.RecyclerView;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;public FocusKeepRecyclerView(@NonNull Context context) {super(context, null);}public FocusKeepRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs, 0);}public FocusKeepRecyclerView(@NonNull Context context,@Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);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) {this.mCanFocusOutHorizontal = canFocusOutHorizontal;}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 nextFocusItemView = findContainingItemView(view);if (nextFocusItemView == null) {if (!mCanFocusOutVertical && (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP)) {//屏蔽焦点纵向移出recyclerviewreturn focused;}if (!mCanFocusOutHorizontal && (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT)) {//屏蔽焦点横向移出recyclerviewreturn 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 setFocusGainListener(FocusGainListener focusGainListener) {this.mFocusGainListener = focusGainListener;}public interface FocusGainListener {void onFocusGain(View child, View focused);}@Overridepublic void requestChildFocus(View child, View focused) {mCurrentFocusPosition = getChildViewHolder(child).getAdapterPosition();Log.i(TAG, "focusPos=" + focused);if (!hasFocus()) {//recyclerview 子view重新获取焦点,调用移入焦点的事件监听if (mFocusGainListener != null) {mFocusGainListener.onFocusGain(child, focused);}}//执行过super.requestChildFocus之后hasFocus会变成truesuper.requestChildFocus(child, focused);mCurrentFocusPosition = getChildViewHolder(child).getAdapterPosition();Log.i(TAG, "focusPos=" + mCurrentFocusPosition);}//实现焦点记忆的关键代码@Overridepublic 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@Overrideprotected 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;}}}
5.RecyclerViewAdapterDemo文件代码
package com.example.customrecyclerview;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import androidx.annotation.NonNull;//import androidx.recyclerview.widget.RecyclerView;import java.util.List;// 1.创建适配器类继承自RecyclerView.Adapter,泛型传入RecyclerView.ViewHolder类。public class RecyclerViewAdapterDemo extendsFocusKeepRecyclerView.Adapter<RecyclerViewAdapterDemo.MyViewHolder> {private Context context;private List<String> list;private View inflater;public RecyclerViewAdapterDemo(Context context, List<String> list){this.context=context;this.list=list;}private OnItemClickListener onItemClickListener;public interface OnItemClickListener{void onClick(int position);}public void setOnItemClickListener(OnItemClickListener listener){this.onItemClickListener = listener;}//3.重写RecyclerView.Adapter类的相关方法。@NonNull@Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {inflater= LayoutInflater.from(context).inflate(R.layout.item_recycler_view,parent,false);MyViewHolder viewHolder=new MyViewHolder(inflater);return viewHolder;}@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {holder.tv_view.setText(list.get(position));holder.itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(onItemClickListener!=null){onItemClickListener.onClick(position);}}});}@Overridepublic int getItemCount() {return list.size();}// 2.创建内部类即RecyclerView.ViewHolder类的子类MyViewHolder,并初始化item的控件。class MyViewHolder extends FocusKeepRecyclerView.ViewHolder{private TextView tv_view;public MyViewHolder(@NonNull View itemView) {super(itemView);tv_view=itemView.findViewById(R.id.tv_view);}}}
6.MainActivity文件代码
package com.example.customrecyclerview;import androidx.appcompat.app.AppCompatActivity;import androidx.recyclerview.widget.GridLayoutManager;import androidx.recyclerview.widget.LinearLayoutManager;import androidx.recyclerview.widget.RecyclerView;import android.content.Context;import android.os.Bundle;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {// 1.获取RecyclerView对象private FocusKeepRecyclerView recyclerView;private RecyclerViewAdapterDemo adapterDemo;private Context context;private List<String> list;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);context=this;// 2.初始化数据recyclerView=findViewById(R.id.rv_demo);//3.适配器实例化list=new ArrayList<>();for (int i=0;i<9;i++){list.add("第"+i+"个测试");}adapterDemo=new RecyclerViewAdapterDemo(context,list);// 4.设置LayoutManagerGridLayoutManager manager=new GridLayoutManager(context,3);manager.setOrientation(GridLayoutManager.VERTICAL);// LinearLayoutManager manager=new LinearLayoutManager(context);// manager.setOrientation(LinearLayoutManager.VERTICAL);recyclerView.setLayoutManager(manager);// 5. 设置AdapterrecyclerView.setAdapter(adapterDemo);adapterDemo.setOnItemClickListener(new RecyclerViewAdapterDemo.OnItemClickListener() {@Overridepublic void onClick(int position) {Toast.makeText(MainActivity.this,""+position,Toast.LENGTH_SHORT).show();}});}}
7.结果图:<br />
