首先上实例:
项目工程文件:
界面布局:
activity_tab.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" android:background="@color/fastlane_background" android:orientation="vertical" tools:context=".activity.TabActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/rv_tan" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:descendantFocusability="afterDescendants" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="4" android:orientation="horizontal"> <ImageView android:id="@+id/main_img" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:background="@drawable/bg_recyclerview_item" android:focusable="true" android:focusableInTouchMode="true" android:padding="15dp" android:src="@drawable/pro2" /> <!-- <androidx.recyclerview.widget.RecyclerView android:id="@+id/main_tab_rv" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2"/>--> <com.example.focusdome.view.FocusRecyclerView android:id="@+id/main_tab_rv" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/button_tab_rv" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout>
layout_found_h_recycler_item.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:focusable="true" android:background="@drawable/bg_recyclerview_item" android:padding="20dp" > <com.example.focusdome.view.CircleImageView android:id="@+id/f_h_c_img" android:layout_width="109dp" android:layout_height="0dp" android:layout_gravity="center" android:layout_weight="3" android:src="@drawable/pro5" /> <TextView android:id="@+id/f_h_c_txt" android:layout_width="120dp" android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:text="1111" android:textSize="10dp" /> </LinearLayout>
layout_main_recycler_txtrecycler.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" android:background="@drawable/bg_recyclerview_item" > <TextView android:id="@+id/main_rv_rv_txt" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="center" /> </LinearLayout>
layout_recycler_text_item.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:orientation="horizontal" android:gravity="center" android:background="@drawable/bg_recyclerview_item" android:focusable="true"> <TextView android:id="@+id/tv" android:layout_width="120dp" android:layout_height="60dp" android:textColor="#ffffff" android:textSize="16sp" android:text="" android:padding="10dp" android:gravity="center" /> </LinearLayout>
资源文件:
bg_recyclerview_item.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/bg_recyclerview_focus" android:state_selected="true" /> <item android:drawable="@drawable/bg_recyclerview_focus" android:state_focused="true" /> <item android:drawable="@drawable/bg_recyclerview_focus" android:state_pressed="true" /> <item android:drawable="@color/transparent"/> </selector>
bg_recyclerview_focus.xml:
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> <item> <shape android:shape="rectangle"> <solid android:color="#80B469FF" /> <corners android:radius="10dp" /> </shape> </item> <item android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp"> <shape android:shape="rectangle"> <solid android:color="#60B469FF" /> <corners android:radius="8dp" /> </shape> </item> <item android:bottom="5dp" android:left="5dp" android:right="5dp" android:top="5dp"> <shape android:layout_width="wrap_content" android:shape="rectangle"> <stroke android:width="1dp" android:color="#6672f8" /> </shape> </item> <item android:bottom="6dp" android:left="6dp" android:right="6dp" android:top="6dp"> <shape android:shape="rectangle"> <stroke android:width="1dp" android:color="#6672f8" /> </shape> </item> <item android:bottom="7dp" android:left="7dp" android:right="7dp" android:top="7dp"> <color android:color="@color/color_141843"/> </item> </layer-list>
activity代码:
package com.example.focusdome.activity; import androidx.appcompat.app.AppCompatActivity; import androidx.core.view.ViewCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.example.focusdome.R; import com.example.focusdome.adapter.BtnRecyclerViewAdapter; import com.example.focusdome.adapter.MainRecyclerViewAdapter; import com.example.focusdome.adapter.MyRecyclerViewAdapter; import com.example.focusdome.model.RecyclerMainModel; import com.example.focusdome.view.FocusLinearLayoutManager; import com.example.focusdome.view.SpaceDecoration; import java.util.ArrayList; public class TabActivity extends Activity implements MyRecyclerViewAdapter.OnItemClickListener,MyRecyclerViewAdapter.OnItemFocusChangeListener{ private MyRecyclerViewAdapter adapter; private RecyclerView recyclerView; private String[] titles = {"首页", "游戏","教育","生活","娱乐","新闻","直播","我的"}; private ImageView imageView; //主体部分 private MainRecyclerViewAdapter mAdapter; private RecyclerView mainRecyclerView; private ArrayList<RecyclerMainModel> list = new ArrayList<>(); //底部部分 private BtnRecyclerViewAdapter btnRecyclerViewAdapter; private RecyclerView btnRecyclerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_tab); initView(); initAdapter(); //初始化主体部分recycle mainRecyclerView = findViewById(R.id.main_tab_rv); list.add(new RecyclerMainModel("第一张",R.drawable.pre)); list.add(new RecyclerMainModel("第二张",R.drawable.pro)); list.add(new RecyclerMainModel("第三张",R.drawable.pro2)); list.add(new RecyclerMainModel("第四张",R.drawable.pro3)); list.add(new RecyclerMainModel("第五张",R.drawable.pro4)); list.add(new RecyclerMainModel("第六张",R.drawable.hp_one)); list.add(new RecyclerMainModel("第七张",R.drawable.hp_four)); list.add(new RecyclerMainModel("第八张",R.drawable.hp_five)); mAdapter = new MainRecyclerViewAdapter(this, list, new MainRecyclerViewAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Log.v("点击:", "" + position + view.getId()); imageView.setImageResource(list.get(position).getM_imgId()); //imageView.setScaleType(ImageView.ScaleType.CENTER); } }/*, new MainRecyclerViewAdapter.OnItemFocusChangeListener() { @Override public void onItemFocusChange(View view, int position, boolean hasFocus) { // Toast.makeText(TabActivity.this,"focus"+position,Toast.LENGTH_LONG).show(); imageView.setImageResource(list.get(position).getM_imgId()); } }*/) { //获得焦点时处理 @Override protected void onItemFocus(View itemView,int positon) { imageView.setImageResource(list.get(positon).getM_imgId()); System.out.println("获取焦点成功!"+positon); Log.i("view:",itemView.getId()+"23333"); itemView.setSelected(true); View view = itemView.findViewById(R.id.main_rv_rv_txt); view.setSelected(true); } //失去焦点时 @Override protected void onItemGetNormal(View itemView) { System.out.println("失去焦点成功!"); Log.i("view:",itemView.getId()+"32222"); itemView.setSelected(false); View view = itemView.findViewById(R.id.main_rv_rv_txt); view.setSelected(true); } }; FocusLinearLayoutManager linearLayoutManager = new FocusLinearLayoutManager(this,LinearLayoutManager.VERTICAL,false); mainRecyclerView.setLayoutManager(linearLayoutManager); mainRecyclerView.addItemDecoration(new SpaceDecoration(30)); mainRecyclerView.setAdapter(mAdapter); //初始化底部部分 btnRecyclerView = (RecyclerView)findViewById(R.id.button_tab_rv); btnRecyclerViewAdapter = new BtnRecyclerViewAdapter(this, list) { @Override protected void onItemFocus(View itemView, int position) { itemView.setSelected(true); //View view = itemView. } @Override protected void onItemGetNormal(View itemView) { itemView.setSelected(false); } }; FocusLinearLayoutManager linearLayoutManager1 = new FocusLinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false); btnRecyclerView.setLayoutManager(linearLayoutManager1); btnRecyclerView.setAdapter(btnRecyclerViewAdapter); } private void initView() { recyclerView = findViewById(R.id.rv_tan); imageView= findViewById(R.id.main_img); imageView.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean b) { Log.v("img_focus",""+view.getId()); } }); } private void initAdapter() { adapter = new MyRecyclerViewAdapter(this, titles); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false); recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setAdapter(adapter); recyclerView.requestFocus(); adapter.setmOnItemClickListener(this); adapter.setmOnItemClickListener(this); } @Override public void onItemClick(View view, int position) { Log.i("Activity:onItemClick","mOnItemFocusChangeListener.onItemFocusChange(v, position, hasFocus);"); } @Override public void onItemFocusChange(View view, int position, boolean hasFocus) { } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } @Override public boolean dispatchKeyEvent(KeyEvent event) { //View v = getCurrentFocus(); return super.dispatchKeyEvent(event); } }
adapter代码:
其余的adapter基本和这个差不多
package com.example.focusdome.adapter; import android.content.Context; import android.os.Build; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.view.ViewCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.example.focusdome.R; import com.example.focusdome.activity.TabActivity; import com.example.focusdome.model.RecyclerMainModel; import java.util.ArrayList; public abstract class BtnRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private Context context; private ArrayList<RecyclerMainModel> data; private MyRecyclerViewAdapter.OnItemFocusChangeListener mOnItemFocusChangeListener; private MyRecyclerViewAdapter.OnItemClickListener mOnItemClickListener; private final LayoutInflater layoutInflater; private int defaultFocus = 0; private boolean needFocus = true; public BtnRecyclerViewAdapter(Context context, ArrayList<RecyclerMainModel> list) { this.context = context; this.data = list; layoutInflater = LayoutInflater.from(context); } public interface OnItemClickListener{ void onItemClick(View view, int position); } public interface OnItemFocusChangeListener{ void onItemFocusChange(View view, int position, boolean hasFocus); } public final void setmOnItemClickListener(@Nullable MyRecyclerViewAdapter.OnItemClickListener listener){ mOnItemClickListener = listener; } private void setmOnItemFocusChangeListener(@Nullable MyRecyclerViewAdapter.OnItemFocusChangeListener focusChangeListener){ this.mOnItemFocusChangeListener = focusChangeListener; } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = layoutInflater.inflate(R.layout.layout_found_h_recycler_item,parent,false); return new RecyclerViewHolder(v); } @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,final int position) { RecyclerViewHolder viewHolder = (RecyclerViewHolder)holder; viewHolder.imageView.setImageResource(data.get(position).getM_imgId()); viewHolder.textView.setText(data.get(position).getM_txt()); if (mOnItemClickListener != null) { holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnItemClickListener.onItemClick(v, position); Log.e("click事件:","你点击了"+v.getId()); } }); } holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus){ focusStatus(v,position); }else { normalStatus(v); } Log.i("adapter:","onFocusChange"); } }); if (needFocus) { Log.i("进行移动:",":"); if (defaultFocus < 0) { defaultFocus = 0; } if (defaultFocus >= getItemCount()) { defaultFocus = getItemCount() - 1; } if (defaultFocus == position) { if (!holder.itemView.isFocusable()) { defaultFocus++; } else { holder.itemView.requestFocus(); } } } else { //setNeedFocus(position == (getItemCount() - 1)); } } @Override public int getItemCount() { return data.size(); } private class RecyclerViewHolder extends RecyclerView.ViewHolder { public TextView textView; public ImageView imageView; public RecyclerViewHolder(@NonNull View itemView) { super(itemView); textView = (TextView) itemView.findViewById(R.id.f_h_c_txt); imageView = (ImageView)itemView.findViewById(R.id.f_h_c_img); } } /** * item获得焦点时调用 * * @param itemView view */ private void focusStatus(View itemView,int position) { if (itemView == null) { return; } float scalX,scalY; scalX = 1.1f; scalY = 1.1f; if (Build.VERSION.SDK_INT >= 21) { //抬高Z轴 ViewCompat.animate(itemView).scaleX(scalX).scaleY(scalY).translationZ(1.3f).start(); } else { ViewCompat.animate(itemView).scaleX(scalX).scaleY(scalY).start(); ViewGroup parent = (ViewGroup) itemView.getParent(); parent.requestLayout(); parent.invalidate(); } onItemFocus(itemView,position); } /** * 当item获得焦点时处理 * * @param itemView itemView */ protected abstract void onItemFocus(View itemView,int position); /** * item失去焦点时 * * @param itemView item对应的View */ private void normalStatus(View itemView) { if (itemView == null) { return; } if (Build.VERSION.SDK_INT >= 21) { ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).translationZ(0).start(); } else { ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).start(); ViewGroup parent = (ViewGroup) itemView.getParent(); parent.requestLayout(); parent.invalidate(); } onItemGetNormal(itemView); } /** * 当条目失去焦点时调用 * * @param itemView 条目对应的View */ protected abstract void onItemGetNormal(View itemView); }
model代码:
package com.example.focusdome.model; public class RecyclerMainModel { private String m_txt; private int m_imgId; public RecyclerMainModel(String m_txt, int m_imgId) { this.m_txt = m_txt; this.m_imgId = m_imgId; } public String getM_txt() { return m_txt; } public void setM_txt(String m_txt) { this.m_txt = m_txt; } public int getM_imgId() { return m_imgId; } public void setM_imgId(int m_imgId) { this.m_imgId = m_imgId; } }
view代码:
CircleImageView.java:
自定义圆形ImageView
package com.example.focusdome.view; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; @SuppressLint("AppCompatCustomView") public class CircleImageView extends ImageView { //画笔 private Paint mPaint; //圆形图片的半径 private int mRadius; //图片的宿放比例 private float mScale; public CircleImageView(Context context) { super(context); } public CircleImageView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public CircleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //由于是圆形,宽高应保持一致 int size = Math.min(getMeasuredWidth(), getMeasuredHeight()); mRadius = size / 2; setMeasuredDimension(size, size); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { mPaint = new Paint(); mPaint.setColor(Color.WHITE); Drawable drawable = getDrawable(); if (null != drawable) { Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); //初始化BitmapShader,传入bitmap对象 BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); //计算缩放比例 mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth()); Matrix matrix = new Matrix(); matrix.setScale(mScale, mScale); bitmapShader.setLocalMatrix(matrix); mPaint.setShader(bitmapShader); //画圆形,指定好坐标,半径,画笔 canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); } else { super.onDraw(canvas); } } }
自定义RecyclerView,重写dispatchKeyEvent()方法,进行焦点控制:
FocusRecyclerView:
package com.example.focusdome.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.FocusFinder; import android.view.KeyEvent; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; public class FocusRecyclerView extends RecyclerView { public FocusRecyclerView(@NonNull Context context) { super(context); } public FocusRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public FocusRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_DOWN) { int keyCode = event.getKeyCode(); //水平垂直的时候:按下左键或者右键 if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT /*|| keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP*/) { //获取当前焦点的视图 View focusedView = getFocusedChild(); View nextFocusView; try { /* switch (keyCode){ case KeyEvent.KEYCODE_DPAD_LEFT: Log.v("left","往左"); //通过findNextFocus获取下一个需要的焦点的vie nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_LEFT); break; case KeyEvent.KEYCODE_DPAD_RIGHT: Log.v("right","往右"); nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_RIGHT); break; case KeyEvent.KEYCODE_DPAD_UP: Log.v("up","往上"); nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_UP); break; case KeyEvent.KEYCODE_DPAD_DOWN: nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_DOWN); Log.v("down","往下"); break; default: nextFocusView = null; break; }*/ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) { Log.v("left", "焦点往左跑"); //通过findNextFocus获取下一个需要得到的焦点的view nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_LEFT); if(nextFocusView == null){ Log.v("同级","View查找"); // nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView.getRootView().,View.FOCUS_LEFT); nextFocusView = focusedView.getParent().focusSearch(focusedView,View.FOCUS_LEFT); } } else { Log.v("right", "右边跑"); //通过findNextFocus获取下一个需要得到的焦点的View nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_RIGHT); } } catch (Exception e) { nextFocusView = null; } //如果获取失败,消耗掉事件,不让系统处理,并让原先的view获取焦点 if (nextFocusView == null) { focusedView.requestFocus(); return true; } } } return super.dispatchKeyEvent(event); } @Override public View focusSearch(int direction) { return super.focusSearch(direction); } }
SpaceDecoration.java
package com.example.focusdome.view; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.view.View; import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.OrientationHelper; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.StaggeredGridLayoutManager; import com.chad.library.adapter.base.BaseQuickAdapter; import static android.widget.LinearLayout.VERTICAL; public class SpaceDecoration extends RecyclerView.ItemDecoration { private int space; private int headerCount = -1; private int footerCount = Integer.MAX_VALUE; private boolean mPaddingEdgeSide = true; private boolean mPaddingStart = true; private boolean mPaddingHeaderFooter = false; private ColorDrawable mColorDrawable; private boolean mDrawLastItem = true; private boolean mDrawHeaderFooter = false; public SpaceDecoration(int space) { this.mColorDrawable = new ColorDrawable(Color.parseColor("#e7e7e7")); this.space = space; } public SpaceDecoration(int space, int color) { this.mColorDrawable = new ColorDrawable(color); this.space = space; } public void setPaddingEdgeSide(boolean mPaddingEdgeSide) { this.mPaddingEdgeSide = mPaddingEdgeSide; } public void setPaddingStart(boolean mPaddingStart) { this.mPaddingStart = mPaddingStart; } public void setPaddingHeaderFooter(boolean mPaddingHeaderFooter) { this.mPaddingHeaderFooter = mPaddingHeaderFooter; } @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { int position = parent.getChildAdapterPosition(view); int spanCount = 0; int orientation = 0; int spanIndex = 0; int headerCount = 0, footerCount = 0; if (parent.getAdapter() instanceof BaseQuickAdapter) { headerCount = ((BaseQuickAdapter) parent.getAdapter()).getHeaderLayoutCount(); footerCount = ((BaseQuickAdapter) parent.getAdapter()).getFooterLayoutCount(); } RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof StaggeredGridLayoutManager) { orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation(); spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount(); spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex(); } else if (layoutManager instanceof GridLayoutManager) { orientation = ((GridLayoutManager) layoutManager).getOrientation(); spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); spanIndex = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex(); } else if (layoutManager instanceof LinearLayoutManager) { orientation = ((LinearLayoutManager) layoutManager).getOrientation(); spanCount = 1; spanIndex = 0; } /** * 普通Item的尺寸 */ if ((position >= headerCount && position < parent.getAdapter().getItemCount() - footerCount)) { if (orientation == VERTICAL) { float expectedWidth = (float) (parent.getWidth() - space * (spanCount + (mPaddingEdgeSide ? 1 : -1))) / spanCount; float originWidth = (float) parent.getWidth() / spanCount; float expectedX = (mPaddingEdgeSide ? space : 0) + (expectedWidth + space) * spanIndex; float originX = originWidth * spanIndex; outRect.left = (int) (expectedX - originX); outRect.right = (int) (originWidth - outRect.left - expectedWidth); if (position - headerCount < spanCount && mPaddingStart) { outRect.top = space; } outRect.bottom = space; return; } else { float expectedHeight = (float) (parent.getHeight() - space * (spanCount + (mPaddingEdgeSide ? 1 : -1))) / spanCount; float originHeight = (float) parent.getHeight() / spanCount; float expectedY = (mPaddingEdgeSide ? space : 0) + (expectedHeight + space) * spanIndex; float originY = originHeight * spanIndex; outRect.bottom = (int) (expectedY - originY); outRect.top = (int) (originHeight - outRect.bottom - expectedHeight); if (position - headerCount < spanCount && mPaddingStart) { outRect.left = space; } outRect.right = space; return; } } else if (mPaddingHeaderFooter) { if (orientation == VERTICAL) { outRect.right = outRect.left = mPaddingEdgeSide ? space : 0; outRect.top = mPaddingStart ? space : 0; } else { outRect.top = outRect.bottom = mPaddingEdgeSide ? space : 0; outRect.left = mPaddingStart ? space : 0; } } } @Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { if (parent.getAdapter() == null) { return; } int orientation = 0; int headerCount = 0, footerCount = 0, dataCount; if (parent.getAdapter() instanceof BaseQuickAdapter) { headerCount = ((BaseQuickAdapter) parent.getAdapter()).getHeaderLayoutCount(); footerCount = ((BaseQuickAdapter) parent.getAdapter()).getFooterLayoutCount(); dataCount = parent.getAdapter().getItemCount(); } else { dataCount = parent.getAdapter().getItemCount(); } int dataStartPosition = headerCount; int dataEndPosition = headerCount + dataCount; RecyclerView.LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof StaggeredGridLayoutManager) { orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation(); } else if (layoutManager instanceof GridLayoutManager) { orientation = ((GridLayoutManager) layoutManager).getOrientation(); } else if (layoutManager instanceof LinearLayoutManager) { orientation = ((LinearLayoutManager) layoutManager).getOrientation(); } int start, end; if (orientation == OrientationHelper.VERTICAL) { start = parent.getPaddingLeft(); end = parent.getWidth() - parent.getPaddingRight(); } else { start = parent.getPaddingTop(); end = parent.getHeight() - parent.getPaddingBottom(); } int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View child = parent.getChildAt(i); int position = parent.getChildAdapterPosition(child); if (position >= dataStartPosition && position < dataEndPosition - 1//数据项除了最后一项 || (position == dataEndPosition - 1 && mDrawLastItem)//数据项最后一项 || (!(position >= dataStartPosition && position < dataEndPosition) && mDrawHeaderFooter)//header&footer且可绘制 ) { if (orientation == OrientationHelper.VERTICAL) { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int top = child.getBottom() + params.bottomMargin; int bottom = top; mColorDrawable.setBounds(start, top, end, bottom); mColorDrawable.draw(c); } else { RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int left = child.getRight() + params.rightMargin; int right = left; mColorDrawable.setBounds(left, start, right, end); mColorDrawable.draw(c); } } } } }
防止按键速度过快RecyclerView焦点乱飞问题:
FocusLinearLayoutManager.java
package com.example.focusdome.view; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.LinearLayoutManager; public class FocusLinearLayoutManager extends LinearLayoutManager { public FocusLinearLayoutManager(Context context) { super(context); } public FocusLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); } public FocusLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Nullable @Override public View onInterceptFocusSearch(@NonNull View focused, int direction) { Log.v("manger","ssssss"); int currentPosition = getPosition(getFocusedChild()); int count = getItemCount(); int lastVisiblePosition = findLastVisibleItemPosition(); switch (direction){ case View.FOCUS_RIGHT: currentPosition++; break; case View.FOCUS_LEFT: currentPosition++; break; case View.FOCUS_DOWN: currentPosition++; break; case View.FOCUS_UP: currentPosition++; break; } if (currentPosition<0||currentPosition>count){ return focused; }else { if (currentPosition>lastVisiblePosition){ scrollToPosition(currentPosition); } } return super.onInterceptFocusSearch(focused, direction); } }
项目地址:https://download.csdn.net/download/qq_41861266/12691503