盒子
盒子
文章目录
  1. 源码实现
  2. RecyclerView的滚动事件
  3. 点击事件
  4. 其它常用方法
  5. RecyclerView的封装
    1. 第一次拙劣(错误)的封装
    2. 通用框架
    1. notifyDataSetChange不起作用
    2. 只显示一条Item
    3. 无法操作Item中的控件

探索RecyclerView

首先需要添加进来

com.android.support:recyclerview-v7:28.0.0-beta01

源码实现

eg:

LuffyRecycler:

1
2
3
4
5
6
7
8
9
10
11
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.recycler_layout);

RecyclerView recyclerView=findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter adapter=new RecyclerAdapter(this);
recyclerView.setAdapter(adapter);
}

RecyclerAdapter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import io.github.grooters.luffy.R;

private class InerHolder extends RecyclerView.ViewHolder{
private TextView textView;
private InerHolder(@NonNull View itemView) {
super(itemView);
textView=itemView.findViewById(R.id.recycler_textView);
}
}
private class RecyclerAdapter extends RecyclerView.Adapter {
private Context context;
public RecyclerAdapter(Context context) {
super();
this.context=context;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new InerHolder(LayoutInflater.from(context).inflate(R.layout.recycler_item,viewGroup,false));
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
//此处若不想转型,可按第二种写法创建Adapter
((InerHolder)viewHolder).textView.setText("i:"+i);
}
@Override
public long getItemId(int position) {
return super.getItemId(position);
}
@Override
public int getItemCount() {
//输出一个Item
return 1;
}
}

第二种Adapter写法(详见泛型):
LuffyRecycler:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private class InerHolder extends RecyclerView.ViewHolder{
private TextView textView;
private InerHolder(@NonNull View itemView) {
super(itemView);
textView=findViewById(R.id.recycler_textView);
}
}
private class InerAdapter extends RecyclerView.Adapter<InerHolder>{
@NonNull
@Override
public InerHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new InerHolder(LayoutInflater.from(getApplicationContext()).inflate(R.layout.recycler_item,viewGroup,false));
}
@Override
public void onBindViewHolder(@NonNull InerHolder inerHolder, int i) {
inerHolder.textView.setText("i:"+i);
}
@Override
public int getItemCount() {
return 1;
}
@Override
public long getItemId(int position) {
return super.getItemId(position);
}
}

RecyclerView的滚动事件

RecyclerView有两种滚动状态:

  1. 静止 -> 被迫拖拽移动 -> 静止

  2. 静止 -> 被迫拖拽移动 -> 自己滚动 -> 静止

在滚动过程中,会回调两个方法:

  1. onScrollStateChanged

滚动状态变化时

  1. onScrolled

滚动时

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
Log.i(TAG, "onScrollStateChanged");
//目前的状态
Log.i(TAG, "newState: " + newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Log.i(TAG, "onScrolled");
//水平滚动距离
Log.i(TAG, "dx: " + dx);
//垂直滚动距离
Log.i(TAG, "dy: " + dy);
Log.i(TAG, "CHECK_SCROLL_UP: " + recyclerView.canScrollVertically(TAG_CHECK_SCROLL_UP));
Log.i(TAG, "CHECK_SCROLL_DOWN: " + recyclerView.canScrollVertically(TAG_CHECK_SCROLL_DOWN));
}
});

newState:

public static final int SCROLL_STATE_IDLE = 0; //停止滚动
public static final int SCROLL_STATE_DRAGGING = 1; //正在被外部拖拽,一般为用户正在用手指滚动
public static final int SCROLL_STATE_SETTLING = 2; //自动滚动开始

点击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private class StudentViewHolder extends RecyclerView.ViewHolder{
private TextView textViewId,textViewName,textViewDepartment;
private ImageView imageView;
private StudentViewHolder(@NonNull View itemView) {
super(itemView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//adapter.notifyItemChanged(1,1);
adapter.notifyItemChanged(1);
Log.i(TAG,"onClick");
}
});
imageView=itemView.findViewById(R.id.img);
textViewId=itemView.findViewById(R.id.textView_id);
textViewName=itemView.findViewById(R.id.textVew_name);
textViewDepartment=itemView.findViewById(R.id.textView_department);
}
}

void notifyItemChanged (int position)

更新指定行

void notifyItemChanged (int position, Object payload)

payload只需传入任意值

更新position行,可防止图片闪现,配合以下使用:

public void onBindViewHolder(@NonNull StudentViewHolder holder, int position, @NonNull List payloads)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Override
public void onBindViewHolder(@NonNull StudentViewHolder studentViewHolder, int i) {
Log.i(TAG,"onBindViewHolder");
studentViewHolder.textViewId.setText(students.get(i).getId());
studentViewHolder.textViewName.setText(students.get(i).getName());
studentViewHolder.textViewDepartment.setText(students.get(i).getDepartment());
}
@Override
public void onBindViewHolder(@NonNull StudentViewHolder holder, int position, @NonNull List<Object> payloads) {
super.onBindViewHolder(holder, position, payloads);
if(payloads.isEmpty()){
onBindViewHolder(holder,position);
}else{
holder.textViewId.setText("haha:"+position);
holder.textViewName.setText(students.get(position).getName());
holder.textViewDepartment.setText(students.get(position).getDepartment());
}
}

其它常用方法

1
2
//从位置0移动到5
recyclerView.getAdapter().notifyItemMoved(0,5)

RecyclerView的封装

第一次拙劣(错误)的封装

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class RecyclerWidget extends RecyclerView {
private static final String TAG=RecyclerWidget.class.getSimpleName();
private Context context;
private int viewId;
private RecyclerMethodInterface recyclerMethodInterface;
public RecyclerWidget(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
Log.i(TAG,"RecyclerWidget");
}
public void initRecycler(Context context, int vireId){
Log.i(TAG,"initRecycler:"+vireId);
this.context=context;
this.viewId=vireId;
}

public RecyclerAdapter setRecyclerAdapter(RecyclerMethodInterface recyclerMethodInterface){
this.recyclerMethodInterface=recyclerMethodInterface;
RecyclerAdapter adapter=new RecyclerAdapter();
//注意不能漏掉这句
setLayoutManager(new LinearLayoutManager(context));
Log.i(TAG,"setRecyclerAdapter");
setAdapter(adapter);
return adapter;
}
private class InnerHolder extends ViewHolder{
private InnerHolder(@NonNull View itemView) {
super(itemView);
Log.i(TAG,"InnerHolder");
}
}
public class RecyclerAdapter extends Adapter{
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
Log.i(TAG,"onCreateViewHolder");
return new InnerHolder(LayoutInflater.from(context).inflate(viewId,viewGroup,false));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
Log.i(TAG,"onBindViewHolder");
if(recyclerMethodInterface!=null){
recyclerMethodInterface.onBindViewHolder(viewHolder,i);
}
}
@Override
public long getItemId(int position) {
if(recyclerMethodInterface!=null){
return recyclerMethodInterface.getItemId(position);
}else{
return super.getItemId(position);
}
}
@Override
public int getItemCount() {
if(recyclerMethodInterface!=null){
return recyclerMethodInterface.getItemCount();
}else{
return 0;
}
}
}
public interface RecyclerMethodInterface{
void onBindViewHolder(@NonNull ViewHolder viewHolder, int i);
long getItemId(int position);
int getItemCount();
}
}

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
RecyclerWidget recyclerWidget=findViewById(R.id.widget_recycler);
recyclerWidget.initRecycler(context,R.layout.dialog_page_item);
adapter=recyclerWidget.setRecyclerAdapter(new RecyclerWidget.RecyclerMethodInterface() {
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return 0;
}
});

通用框架

从以下文章获取思路:
为RecyclerView打造通用Adapter 让RecyclerView更加好用

创建通用Holder

由于在Holder中需要获取未知数量与类型的控件,所以可通过View型集合来存储

  1. 在Holder构造方法中获取Context,Item布局赋值和创建View集合对象

  2. 定义一个静态方法创建Holder对象,并传入Context,Item布局

  3. 定义一个方法根据id获取控件,并将其以id为索引添加到view集合中,以供下次直接获取

创建通用Adapter,包括单布局,多布局和分类布局三种

  • 单布局
    1. 构造方法获取Context,布局id和数据内容

    2. 定义一个抽象方法(该方法提供给客户端重写)

    3. 在onCreateViewHolder中调用静态方法创建Holder

    4. 在onBindViewHolder中调用抽象方法

  • 多布局
  • 需要多创建一个接口,里面定义根据type获取布局和根据数据和位置返回type两个接口方法

    1. 在重写方法getItemViewType中调用获取type的接口方法

    2. 在重写方法onCreateViewHolder中调用根据type获取布局的接口方法

    3. 调用静态方法传入相应布局创建Holder

    notifyDataSetChange不起作用

    数据对象更新前和更新后必须是同一个对象,否则notifyDataSetChange将无效

    因为其绑定的是第一个数据对象,更新数据时重新创建了一个数据对象,但原来那个数据对象并未改变,所以notifyDataSetChange后不会产生改变

    控件,即RecyclerView也必须是同一个对象

    只显示一条Item

    若使用new LinearLayoutManager(this)Item布局高度不能使用match_parent

    因为如果高度使用match_parent,一条Item便会占据整个屏幕,导致只显示一条Item

    无法操作Item中的控件

    1
    2
    3
    4
    public static GeneralHolder getHolder(Context context, ViewGroup parent, int layoutId){
    View itemView=LayoutInflater.from(context).inflate(layoutId,null);
    return new GeneralHolder(itemView,context);
    }

    想要操作Item中的控件,就必须为itemView提供parent布局

    无法通过以上代码中的itemView操作Item中的控件,因为没有提供parent布局,需要更改为:

    1
    View itemView=LayoutInflater.from(context).inflate(layoutId,parent,false);
    支持一下
    扫一扫,支持Grooter
    • 微信扫一扫
    • 支付宝扫一扫