文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

android的RecylerView基本使用

2022-06-06 13:44

关注

文章目录一、RecylerView基本使用1. 添加依赖2. 添加布局3. 添加adapter4. 添加item_recycler.xml5. MainActivity代码6. 效果7. 代码地址二、RecyclerView-setLayoutManager1. 效果12. 效果23. 效果34. 效果4三、分割线1. 布局中添加分割线2. 默认分割线3. 自定义Drawable分割线4.自定义分割线四、点击事件1. 利用回调机制实现1.1 添加两个内部接口:1.2 添加变量:1.3 在`onBindViewHolder`添加实现回调的方法:1.4 实现接口:2. 利用内部接口OnItemTouchListener实现2.1 新建一个 RecyclerViewClickListener 类2.2 MainActivity的调用2.3 提示3. 利用GestureDetector(手势检测类)3.1 修改RecyclerViewClickListener 类3.2 修改调用方法3.3 github代码五、修改数据和背景1. 在`RecyclerAdapter`添加修改方法2. 添加数据按钮和修改按钮3. MainActivity.java添加代码4. github代码5. 效果六、添加header和footer1.1 添加header和footer的布局文件1.2 添加属性1.3 在构造方法中添加mHeaderView和mFooterView对象1.4 根据view类型判断加载布局1.5 返回对象1.6 包括header和footer在内的每个item的设置1.7 item数目的变化1.8 ViewHolder中关联布局1.9 完整的adapter1.10 MainActivity中使用1.11 github代码1.12 效果 一、RecylerView基本使用 1. 添加依赖 直接添加依赖:
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha01'
File ->Project Structure ->Dependencies image.png image.png 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. 效果

RecyclerView效果图.png

7. 代码地址

地址:https://github.com/lanjiabin/RecyclerListView
版本选择

RecyclerView(一)
这个版本

image.png

二、RecyclerView-setLayoutManager 1. 效果1

setLayoutManager的用法是掌握RecyclerView是一个重要过程。可以设置列表的更多的灵活性。
首先要把

item_recycler.xml
里的TextView中的
android:layout_width="match_parent"
改成
android:layout_width="wrap_content"
,不然很难看出效果。

先来看看默认效果:
代码:

 		//设置布局方向
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

效果:垂直往下
默认效果.png

2. 效果2

代码:随后我们修改LinearLayoutManager(this)里面的参数,第二个参数表示水平布局,第三个参数表示是否反转,就会呈现出另一个效果。

 		//设置布局方向-水平布局-不反转
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,false));

效果:可以左右滑动,第一个数据在左边开始
image.png

看看反转的情况:

  		//设置布局方向-水平布局-反转
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL,true));

效果:第一个数据是从右边开始的,可以左右滑动。
image.png

3. 效果3

表格布局,第一个参数表示上下文,第二个参数表示表格有多少列。
代码:

		//设置布局方向-表格布局
        mRecyclerView.setLayoutManager(new GridLayoutManager(this,5));

效果:分为5列,可以上下滑动
image.png

4. 效果4

上面实现了列,那在这里也可以实现多少行。
代码:

  		//设置布局方向-表格布局-行
        mRecyclerView.setLayoutManager(new GridLayoutManager(this,5,GridLayoutManager.HORIZONTAL,false));

效果:可以发现,有5列,而且数据还是从竖直来排过去的。
image.png

三、分割线 1. 布局中添加分割线

item_recycler.xml
添加一个布局作为分割线。


效果:
image.png

2. 默认分割线
 		//添加Android自带的分割线
        mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));

效果:
image.png

3. 自定义Drawable分割线

查看

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);

效果:
image.png

4.自定义分割线

这个类放上了前面的几个方法,做成一个自定义类,方便统一管理和使用。

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();
            }
        });

效果:
1.gif

2. 利用内部接口OnItemTouchListener实现

这其实就是利用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需要处理的点击事件逻辑很简单,那么可以使用方法一;如果需要处理比较复杂的点击事件,比如说,双击、长按等点击事件,则需要使用方法二去实现各种复杂的逻辑。

3. 利用GestureDetector(手势检测类)

在实现方法二的RecyclerViewClickListener的时候,在内部对事件的实现了单击、长按的判断,但是这个长按事件不是标准的,只有松开手指的时候才会触发长按事件,这也算是一点瑕疵,同时如果要增加别的事件,比如说双击事件,则需要增加相应的逻辑,如果需要判断的事件种类变多则会给我们的代码编写带来困难,那么有没有更加简便的方法呢?
其实安卓SDK为我们提供了一个手势检测类:GestureDetector来处理各种不同的手势,那么我们完全可以利用GestureDetector来对方法二进行改进。

3.1 修改RecyclerViewClickListener 类
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();
            }
        }));

效果和方法一是一样的。

3.3 github代码

image.png

五、修改数据和背景

先认识官方提供的方法

//该方法用于当增加一个数据的时候,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代码

image.png

5. 效果

2.gif

六、添加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代码

image.png

1.12 效果

3.gif


作者:蓝家彬


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯