implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha01'
File ->Project Structure ->Dependencies
2. 添加布局
3. 添加adapter
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;
public class RecyclerAdapter extends RecyclerView.Adapter {
private List mList;
private Context mContext;
public RecyclerAdapter(Context context, List list) {
this.mContext = context;
this.mList = list;
}
public void removeData(int position) {
mList.remove(position);
notifyItemRemoved(position);
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
MyViewHolder holder = new MyViewHolder(
LayoutInflater.from(mContext)
.inflate(
R.layout.item_recycler,
parent,
false));
return holder;
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
holder.textView.setText(mList.get(position));
}
@Override
public int getItemCount() {
return mList.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
textView = itemView.findViewById(R.id.tv);
}
}
}
4. 添加item_recycler.xml
5. MainActivity代码
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerAdapter mRecyclerAdapter;
private List mList = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
public void initView() {
//添加测试数据
for (int i = 0; i < 100; i++) {
mList.add(i + " ");
}
//布局关联
mRecyclerView = findViewById(R.id.recyclerListView);
//设置布局方向
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//设置item增加和删除时的动画,这里设置默认动画
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
//设置adapter关联的list
mRecyclerAdapter = new RecyclerAdapter(this, mList);
//数据更新
mRecyclerAdapter.notifyDataSetChanged();
//关联adapter
mRecyclerView.setAdapter(mRecyclerAdapter);
}
}
6. 效果
7. 代码地址
地址:https://github.com/lanjiabin/RecyclerListView
版本选择
RecyclerView(一)
这个版本
setLayoutManager的用法是掌握RecyclerView是一个重要过程。可以设置列表的更多的灵活性。
首先要把
item_recycler.xml
里的TextView中的android:layout_width="match_parent"
改成android:layout_width="wrap_content"
,不然很难看出效果。
先来看看默认效果:
代码:
//设置布局方向
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
效果:垂直往下
代码:随后我们修改LinearLayoutManager(this)里面的参数,第二个参数表示水平布局,第三个参数表示是否反转,就会呈现出另一个效果。
//设置布局方向-水平布局-不反转
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false));
效果:可以左右滑动,第一个数据在左边开始
看看反转的情况:
//设置布局方向-水平布局-反转
mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,true));
效果:第一个数据是从右边开始的,可以左右滑动。
表格布局,第一个参数表示上下文,第二个参数表示表格有多少列。
代码:
//设置布局方向-表格布局
mRecyclerView.setLayoutManager(new GridLayoutManager(this,5));
效果:分为5列,可以上下滑动
上面实现了列,那在这里也可以实现多少行。
代码:
//设置布局方向-表格布局-行
mRecyclerView.setLayoutManager(new GridLayoutManager(this,5,GridLayoutManager.HORIZONTAL,false));
效果:可以发现,有5列,而且数据还是从竖直来排过去的。
在
item_recycler.xml
添加一个布局作为分割线。
效果:
//添加Android自带的分割线
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
效果:
查看
DividerItemDecoration ``extends RecyclerView.ItemDecoration
源码有setDrawable
这个方法,我们只需要传入一个Drawable
对象就可以了。
public void setDrawable(@NonNull Drawable drawable) {
if (drawable == null) {
throw new IllegalArgumentException("Drawable cannot be null.");
}
mDivider = drawable;
}
在drawable文件夹中添加一个xml文件:recyclerview_divideritem.xml
代码:
然后使用这个文件:
DividerItemDecoration divider=new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
divider.setDrawable(ContextCompat.getDrawable(this,R.drawable.recyclerview_divideritem));
//添加Android自定分割线
mRecyclerView.addItemDecoration(divider);
效果:
这个类放上了前面的几个方法,做成一个自定义类,方便统一管理和使用。
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class RecycleViewDivider extends RecyclerView.ItemDecoration {
private Paint mPaint;
private Drawable mDivider;
private int mDividerHeight = 2;//分割线高度,默认为1px
private int mOrientation;//列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
private static final int[] ATTRS = new int[]{android.R.attr.listDivider};//使用系统自带的listDivider
public RecycleViewDivider(Context context, int orientation) {
if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
throw new IllegalArgumentException("请输入正确的参数!");
}
mOrientation = orientation;
final TypedArray a = context.obtainStyledAttributes(ATTRS);//使用TypeArray加载该系统资源
mDivider = a.getDrawable(0);
a.recycle();//缓存
}
public RecycleViewDivider(Context context, int orientation, int drawableId) {
this(context, orientation);
mDivider = ContextCompat.getDrawable(context, drawableId);
mDividerHeight = mDivider.getIntrinsicHeight();
}
public RecycleViewDivider(Context context, int orientation, int dividerHeight, int dividerColor) {
this(context, orientation);
mDividerHeight = dividerHeight;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(dividerColor);
mPaint.setStyle(Paint.Style.FILL);
}
//获取分割线尺寸
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
//设置偏移的高度是mDivider.getIntrinsicHeight,该高度正是分割线的高度
outRect.set(0, 0, 0, mDividerHeight);
}
//绘制分割线
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (mOrientation == LinearLayoutManager.VERTICAL) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
//绘制横向 item 分割线
private void drawHorizontal(Canvas canvas, RecyclerView parent) {
final int left = parent.getPaddingLeft();//获取分割线的左边距,即RecyclerView的padding值
final int right = parent.getMeasuredWidth() - parent.getPaddingRight();//分割线右边距
final int childSize = parent.getChildCount();
//遍历所有item view,为它们的下方绘制分割线
for (int i = 0; i < childSize; i++) {
final View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int top = child.getBottom() + layoutParams.bottomMargin;
final int bottom = top + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}
//绘制纵向 item 分割线
private void drawVertical(Canvas canvas, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
final int childSize = parent.getChildCount();
for (int i = 0; i < childSize; i++) {
final View child = parent.getChildAt(i);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
final int left = child.getRight() + layoutParams.rightMargin;
final int right = left + mDividerHeight;
if (mDivider != null) {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(canvas);
}
if (mPaint != null) {
canvas.drawRect(left, top, right, bottom, mPaint);
}
}
}
}
使用方式:
//1.添加默认分割线:高度为2px,颜色为灰色
mRecyclerView.addItemDecoration(new RecycleViewDivider(this, LinearLayoutManager.HORIZONTAL));
//2.添加自定义分割线:可自定义分割线drawable
mRecyclerView.addItemDecoration(new RecycleViewDivider(
this, LinearLayoutManager.HORIZONTAL, R.drawable.recyclerview_divideritem));
//3.添加自定义分割线:可自定义分割线高度和颜色
mRecyclerView.addItemDecoration(new RecycleViewDivider(
this, LinearLayoutManager.HORIZONTAL, 3, getResources().getColor(R.color.colorPrimaryDark)));
四、点击事件
1. 利用回调机制实现
1.1 添加两个内部接口:
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public interface OnItemLongClickListener {
void onItemLongClick(View view, int position);
}
1.2 添加变量:
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
public void setmOnItemClickListener(OnItemClickListener mOnItemClickListener) {
this.mOnItemClickListener = mOnItemClickListener;
}
public void setmOnItemLongClickListener(OnItemLongClickListener mOnItemLongClickListener) {
this.mOnItemLongClickListener = mOnItemLongClickListener;
}
1.3 在onBindViewHolder
添加实现回调的方法:
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
holder.textView.setText(mList.get(position));
//判断是否设置了监听器
if(mOnItemClickListener != null){
//为ItemView设置监听器
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getLayoutPosition(); // 1
mOnItemClickListener.onItemClick(holder.itemView,position); // 2
}
});
}
if(mOnItemLongClickListener != null){
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int position = holder.getLayoutPosition();
mOnItemLongClickListener.onItemLongClick(holder.itemView,position);
//返回true 表示消耗了事件 事件不会继续传递
return true;
}
});
}
}
1.4 实现接口:
//item单击
mRecyclerAdapter.setmOnItemClickListener(new RecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this,"点击了:"+position,Toast.LENGTH_SHORT).show();
}
});
//item长按监听
mRecyclerAdapter.setmOnItemLongClickListener(new RecyclerAdapter.OnItemLongClickListener() {
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this,"长点击了:"+position,Toast.LENGTH_SHORT).show();
}
});
效果:
这其实就是利用View 的事件分发与拦截机制。
2.1 新建一个 RecyclerViewClickListener 类import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import androidx.recyclerview.widget.RecyclerView;
public class RecyclerViewClickListener implements RecyclerView.OnItemTouchListener {
private int mLastDownX,mLastDownY;
//该值记录了最小滑动距离
private int touchSlop ;
private OnItemClickListener mListener;
//是否是单击事件
private boolean isSingleTapUp = false;
//是否是长按事件
private boolean isLongPressUp = false;
private boolean isMove = false;
private long mDownTime;
//内部接口,定义点击方法以及长按方法
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
public RecyclerViewClickListener(Context context, OnItemClickListener listener){
touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mListener = listener;
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
int x = (int) e.getX();
int y = (int) e.getY();
switch (e.getAction()){
case MotionEvent.ACTION_DOWN:
mLastDownX = x;
mLastDownY = y;
mDownTime = System.currentTimeMillis();
isMove = false;
break;
case MotionEvent.ACTION_MOVE:
if(Math.abs(x - mLastDownX)>touchSlop || Math.abs(y - mLastDownY)>touchSlop){
isMove = true;
}
break;
case MotionEvent.ACTION_UP:
if(isMove){
break;
}
if(System.currentTimeMillis()-mDownTime > 1000){
isLongPressUp = true;
}else {
isSingleTapUp = true;
}
break;
}
if(isSingleTapUp ){
//根据触摸坐标来获取childView
View childView = rv.findChildViewUnder(e.getX(),e.getY());
isSingleTapUp = false;
if(childView != null){
//回调mListener#onItemClick方法
mListener.onItemClick(childView,rv.getChildLayoutPosition(childView));
return true;
}
return false;
}
if (isLongPressUp ){
View childView = rv.findChildViewUnder(e.getX(),e.getY());
isLongPressUp = false;
if(childView != null){
mListener.onItemLongClick(childView, rv.getChildLayoutPosition(childView));
return true;
}
return false;
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
2.2 MainActivity的调用
//点击事件,单击和长击。缺陷:长按的时候,只有把手放起来,才会触发长按事件。
mRecyclerView.addOnItemTouchListener(new RecyclerViewClickListener(this, new RecyclerViewClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this,"点击了:"+position,Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this,"长点击了:"+position,Toast.LENGTH_SHORT).show();
}
}));
2.3 提示
方法一和方法二的区别:
首先,方法一我们是直接在MyAdapter数据适配器中,为itemview设置了内置监听器,再通过这个监听器实现我们的回调方法,相当于回调了两次,同时这个方法与MyAdapter的耦合度比较高,也违反了单一职责原则,当然其简易性也是突出的优点。
而方法二,我们利用了onTouchListener接口对事件进行了拦截,在拦截中处理我们的点击事件,实现了与适配器的解耦,但是复杂程度会比方法一大。总地来说,如果RecyclerView需要处理的点击事件逻辑很简单,那么可以使用方法一;如果需要处理比较复杂的点击事件,比如说,双击、长按等点击事件,则需要使用方法二去实现各种复杂的逻辑。
在实现方法二的RecyclerViewClickListener的时候,在内部对事件的实现了单击、长按的判断,但是这个长按事件不是标准的,只有松开手指的时候才会触发长按事件,这也算是一点瑕疵,同时如果要增加别的事件,比如说双击事件,则需要增加相应的逻辑,如果需要判断的事件种类变多则会给我们的代码编写带来困难,那么有没有更加简便的方法呢?
其实安卓SDK为我们提供了一个手势检测类:GestureDetector来处理各种不同的手势,那么我们完全可以利用GestureDetector来对方法二进行改进。
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
public class RecyclerViewClickListener implements RecyclerView.OnItemTouchListener {
private GestureDetector mGestureDetector;
private OnItemClickListener mListener;
//内部接口,定义点击方法以及长按方法
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
public RecyclerViewClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context,
new GestureDetector.SimpleOnGestureListener() {
//单击事件
@Override
public boolean onSingleTapUp(MotionEvent e) {
View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null) {
mListener.onItemClick(childView, recyclerView.getChildLayoutPosition(childView));
return true;
}
return false;
}
//长按事件
@Override
public void onLongPress(MotionEvent e) {
View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null) {
mListener.onItemLongClick(childView, recyclerView.getChildLayoutPosition(childView));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
//把事件交给GestureDetector处理
if (mGestureDetector.onTouchEvent(e)) {
return true;
} else
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
3.2 修改调用方法
//利用GestureDetector手势检测类来实现回调
mRecyclerView.addOnItemTouchListener(new RecyclerViewClickListener(this, mRecyclerView, new RecyclerViewClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this,"单击了:"+position,Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this,"长击了:"+position,Toast.LENGTH_SHORT).show();
}
}));
效果和方法一是一样的。
先认识官方提供的方法
//该方法用于当增加一个数据的时候,position表示新增数据显示的位置
final void notifyItemInserted(int position)
//该方法用于删除一个数据的时候,position表示数据删除的位置
final void notifyItemRemoved(int position)
//该方法表示所在position对应的item位置不会改变,但是该item内容发生变化
final void notifyItemChanged(int position)
//该方法一般用于:适配器之前装载的数据大部分已经过时了,需要重新更新数据
//调用该方法的时候,recyclerView会重新计算子item及所有子item重新布局
//出于效率考虑,官方建议用更加精确的方法(比如上面三个方法)来取代这个方法
final void notifyDataSetChanged()
1. 在RecyclerAdapter
添加修改方法
//记录用户选择了RecyclerListView哪个item
//赋值-1是为了防止默认选中position=0的item
private int mPosition = -1;
//获取当前点击item的position
public void getCurrentPosition(int position) {
this.mPosition = position;
}
//移除数据
public void removeData(int position) {
mList.remove(position);
notifyItemRemoved(position);
}
//新增数据
public void addData(int position) {
mList.add(position, "Add One" + position);
notifyItemInserted(position);
}
//更改某个位置的数据
public void changeData(int position) {
mList.set(position, "Item " + position + " has changed");
notifyItemChanged(position);
}
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
holder.textView.setText(mList.get(position));
//修改选中item的颜色
if (mPosition == position) {
holder.textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorPrimaryDark));
} else {
holder.textView.setBackgroundColor(mContext.getResources().getColor(R.color.white));
}
}
2. 添加数据按钮和修改按钮
在activity_main.xml中加入
3. MainActivity.java添加代码
private Button addDataButton, changeData;
//记录用户选择了RecyclerListView哪个item
private int mPosition;
public void initView() {
addDataButton = findViewById(R.id.addData);
changeData = findViewById(R.id.changeData);
addDataButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//添加数据到选择item的上方
mRecyclerAdapter.addData(mPosition);
}
});
changeData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//修改选中item的数据
mRecyclerAdapter.changeData(mPosition);
}
});
}
//利用GestureDetector手势检测类来实现回调
mRecyclerView.addOnItemTouchListener(new RecyclerViewClickListener(this, mRecyclerView, new RecyclerViewClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
//颜色改变了,更新Adapter
mRecyclerAdapter.notifyDataSetChanged();
//记录用户选择了哪个item
mPosition = position;
//传递点击了哪个item,以此用来更新选中item的颜色
mRecyclerAdapter.getCurrentPosition(position);
Toast.makeText(MainActivity.this, "单击了:" + position, Toast.LENGTH_SHORT).show();
}
@Override
public void onItemLongClick(View view, int position) {
Toast.makeText(MainActivity.this, "长击了:" + position, Toast.LENGTH_SHORT).show();
//删除长按的item
mRecyclerAdapter.removeData(position);
}
}));
4. github代码
5. 效果
六、添加header和footer
1.1 添加header和footer的布局文件
footer_recylerview.xml和header_recylerview.xml是一样的,不过id不同而已。
1.2 添加属性
private int mPosition = -1;
public static final int TYPE_HEADER = 0; //说明是带有Header的
public static final int TYPE_FOOTER = 1; //说明是带有Footer的
public static final int TYPE_NORMAL = 2; //说明是不带有header和footer的
private View mHeaderView;
private View mFooterView;
1.3 在构造方法中添加mHeaderView和mFooterView对象
public RecyclerAdapter(Context context, List list, RecyclerView recyclerView) {
this.mContext = context;
this.mList = list;
this.mHeaderView = LayoutInflater.from(mContext).inflate(R.layout.header_recylerview, recyclerView, false);
this.mFooterView = LayoutInflater.from(mContext).inflate(R.layout.footer_recylerview, recyclerView, false);
}
1.4 根据view类型判断加载布局
//获取item的view的类型
@Override
public int getItemViewType(int position) {
if (mHeaderView == null && mFooterView == null) {
return TYPE_NORMAL;
}
if (position == 0 && mHeaderView != null) {
return TYPE_HEADER;
}
if (position == getItemCount() - 1 && mFooterView != null) {
return TYPE_FOOTER;
}
return TYPE_NORMAL;
}
1.5 返回对象
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (mHeaderView != null && viewType == TYPE_HEADER) {
return new MyViewHolder(mHeaderView);
}
if (mFooterView != null && viewType == TYPE_FOOTER) {
return new MyViewHolder(mFooterView);
}
MyViewHolder holder = new MyViewHolder(
LayoutInflater.from(mContext)
.inflate(
R.layout.item_recyclerview,
parent,
false));
return holder;
}
1.6 包括header和footer在内的每个item的设置
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
if (getItemViewType(position) == TYPE_NORMAL) {
if (holder instanceof MyViewHolder) {
holder.textView.setText(mList.get(position - 1));
//修改选中item的颜色
if (mPosition == position) {
holder.textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorPrimaryDark));
} else {
holder.textView.setBackgroundColor(mContext.getResources().getColor(R.color.white));
}
return;
}
return;
} else if (getItemViewType(position) == TYPE_HEADER) {
holder.headerTextView.setText("----我是头部header----");
return;
} else if (getItemViewType(position) == TYPE_FOOTER) {
holder.footerTextView.setText("++++我是尾部footer+++++");
return;
}
}
1.7 item数目的变化
由于添加了header和footer,所以item会发生变化。
@Override
public int getItemCount() {
if (mHeaderView == null && mFooterView == null) {
return mList.size();
} else if (mHeaderView == null && mFooterView != null) {
return mList.size() + 1;
} else if (mHeaderView != null && mFooterView == null) {
return mList.size() + 1;
} else {
return mList.size() + 2;
}
1.8 ViewHolder中关联布局
class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView, headerTextView, footerTextView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
if (itemView == mHeaderView) {
headerTextView = mHeaderView.findViewById(R.id.headerTextView);
return;
}
if (itemView == mFooterView) {
footerTextView = mFooterView.findViewById(R.id.footerTextView);
return;
}
textView = itemView.findViewById(R.id.tv);
}
}
1.9 完整的adapter
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;
public class RecyclerAdapter extends RecyclerView.Adapter {
private List mList;
private Context mContext;
private int mPosition = -1;
public static final int TYPE_HEADER = 0; //说明是带有Header的
public static final int TYPE_FOOTER = 1; //说明是带有Footer的
public static final int TYPE_NORMAL = 2; //说明是不带有header和footer的
private View mHeaderView;
private View mFooterView;
public RecyclerAdapter(Context context, List list, RecyclerView recyclerView) {
this.mContext = context;
this.mList = list;
this.mHeaderView = LayoutInflater.from(mContext).inflate(R.layout.header_recylerview, recyclerView, false);
this.mFooterView = LayoutInflater.from(mContext).inflate(R.layout.footer_recylerview, recyclerView, false);
}
//获取当前点击item的position
public void getCurrentPosition(int position) {
this.mPosition = position;
}
//移除数据
public void removeData(int position) {
mList.remove(position - 1);
notifyItemRemoved(position);
}
//新增数据
public void addData(int position) {
mList.add(position, "Add One" + position);
notifyItemInserted(position);
}
//更改某个位置的数据
public void changeData(int position) {
mList.set(position, "Item " + position + " has changed");
notifyItemChanged(position);
}
//获取item的view的类型
@Override
public int getItemViewType(int position) {
if (mHeaderView == null && mFooterView == null) {
return TYPE_NORMAL;
}
if (position == 0 && mHeaderView != null) {
return TYPE_HEADER;
}
if (position == getItemCount() - 1 && mFooterView != null) {
return TYPE_FOOTER;
}
return TYPE_NORMAL;
}
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (mHeaderView != null && viewType == TYPE_HEADER) {
return new MyViewHolder(mHeaderView);
}
if (mFooterView != null && viewType == TYPE_FOOTER) {
return new MyViewHolder(mFooterView);
}
MyViewHolder holder = new MyViewHolder(
LayoutInflater.from(mContext)
.inflate(
R.layout.item_recyclerview,
parent,
false));
return holder;
}
@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
if (getItemViewType(position) == TYPE_NORMAL) {
if (holder instanceof MyViewHolder) {
holder.textView.setText(mList.get(position - 1));
//修改选中item的颜色
if (mPosition == position) {
holder.textView.setBackgroundColor(mContext.getResources().getColor(R.color.colorPrimaryDark));
} else {
holder.textView.setBackgroundColor(mContext.getResources().getColor(R.color.white));
}
return;
}
return;
} else if (getItemViewType(position) == TYPE_HEADER) {
holder.headerTextView.setText("----我是头部header----");
return;
} else if (getItemViewType(position) == TYPE_FOOTER) {
holder.footerTextView.setText("++++我是尾部footer+++++");
return;
}
}
@Override
public int getItemCount() {
if (mHeaderView == null && mFooterView == null) {
return mList.size();
} else if (mHeaderView == null && mFooterView != null) {
return mList.size() + 1;
} else if (mHeaderView != null && mFooterView == null) {
return mList.size() + 1;
} else {
return mList.size() + 2;
}
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView, headerTextView, footerTextView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
if (itemView == mHeaderView) {
headerTextView = mHeaderView.findViewById(R.id.headerTextView);
return;
}
if (itemView == mFooterView) {
footerTextView = mFooterView.findViewById(R.id.footerTextView);
return;
}
textView = itemView.findViewById(R.id.tv);
}
}
}
1.10 MainActivity中使用
这里有一些细节更新,就是数组越界问题,具体看GitHub代码。
//设置adapter关联的list
mRecyclerAdapter = new RecyclerAdapter(this, mList,mRecyclerView);
完整的MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerAdapter mRecyclerAdapter;
private List mList = new ArrayList();
private Button addDataButton, changeData;
private int mPosition=-1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initRecyclerView();
}
public void initView() {
addDataButton = findViewById(R.id.addData);
changeData = findViewById(R.id.changeData);
mRecyclerView = findViewById(R.id.recyclerListView);
//添加数据到选择item的上方
addDataButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mPosition>=0 && mPosition=0 && mPosition<mList.size()){
mRecyclerAdapter.changeData(mPosition);
mRecyclerAdapter.notifyDataSetChanged();
}
}
});
}
public void initRecyclerView() {
//添加测试数据
for (int i = 0; i 0 && position<=mList.size()){
//长按删除的item
mRecyclerAdapter.removeData(position);
}
Toast.makeText(MainActivity.this, "长击了:" + (position), Toast.LENGTH_SHORT).show();
}
}));
//关联adapter
mRecyclerView.setAdapter(mRecyclerAdapter);
}
}
1.11 github代码
作者:蓝家彬