面对一个新控件,首先要学会使用,然后再逐步学习其原理,RecyclerView作为ListView 的替代,灵活性更强,我把它理解为一个插线板,需要什么功能就插入什么,非常方便。
初学Android时,习惯于控件直接绑定内容,例如TextView,直接可以设置文字信息,对于ListView和RecyclerView这种展示大量数据的控件非常不理解,所以对控件的使用也非常不熟悉。使用控件时,我们主要会处理三个主体:Layout(View)、adapter、ItemModel。三个主体理解到位了,对于此类控件的使用变会的容易些。
Layout不用过多解释,要使用这类控件,一般最少要涉及2个layout,一个作为Activity的Layout,一个作为列表Item的layout
ItemModel,可以把他看做数据,即每个列表要展示的内容。
adapter就是将内容绑定到view 的工具。可以理解为MVC模式
首先再Android studio中导入RecyclerView,网上有一万种方法,读者可以自行查阅。
导入RecyclerView后,便要创建上面说的三种主体,首先是Layout,创建一个Activity的Layout,如下,Activity中只包含了一个RecyclerView。
另外一个Layout为RecyclerView每一个列表的视图,本文每个Item显示一个数字,所以界面只包含了一个TextView:
然后创建adapter继承RecyclerView.Adapter, 需要重写三个方法,分别是onCreateViewHolder、onBindViewHolder、getItemCount
ViewHolder可以理解为一个View的容器,列表在滚动的时候,为了避免不断的findViewByID影响效率,将view存放在ViewHolder中进行复用,例如每页展示7个Items,当向上滑动时,item1划出界面,就可以将item的viewholder复用,更新为下方可见的item内容,避免不断的findViewByID
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView)itemView.findViewById(R.id.view_text);
}
}
onCreateViewHolder的作用就是创建ViewHolder,在列表刚打开时,由于之前没有创建过ViewHolder,无法复用,所以需要重新创建,新建一个item的view,放到ViewHolder容器中。
public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_item_view,parent,false);
MyAdapter.ViewHolder viewHolder = new MyAdapter.ViewHolder(view);
return viewHolder;
}
上面讲了每个ViewHolder在复用时需要更新里面View的内容,相当于把新的View内容与VIewHolder连接起来,所以每次需要在ViewHolder中更新view时都会调用这个方法
@Override
public void onBindViewHolder(@NonNull MyAdapter.ViewHolder holder, int position) {
holder.textView.setText(Items.get(position).toString());
}
adapter创建好后,需要准备ItemModel,本文每个列表只显示数字,所以不需要新建数据结构,只是生成了20个数字。
和其他控件一样,在使用时需要在Activity中进行绑定,对于RecyclerView需要设置其排列方向、动画、以及与adapter进行绑定,完整的Activity如下:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initRV();
}
private void initRV(){
mAdapter = new MyAdapter(initData());
mLayoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
mRecyclerView = (RecyclerView) findViewById(R.id.RVContent);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.HORIZONTAL));
}
private ArrayList initData(){
ArrayList data = new ArrayList<>();
for(int i=0;i<20;i++){
data.add(i);
}
return data;
}
}
我调整了TextView的宽高和颜色,并设置排列方式为水平排列,效果如下:
RecyclerView和ListView不同,为了保证RecyclerView的灵活性,item之间的间隔的设计也独立了出来,通过调用adapter的addItemDecortion方法添加间隔。
1.系统自带的间隔线:
addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL))
2.自定义间隔
系统自带的分割线是通过DividerItemDecoration类进行实现的,查看源码可以看到,这个类是通过继承RecyclerView.ItemDecoration实现间隔的样式:
public class DividerItemDecoration extends ItemDecoration
我们也可以通过继承来实现自己的间隔,需要重写onDraw和getItemOffsets方法,onDraw主要实现我们要在间隔中绘制的内容,getItemOffsets用来设置每个Item周围的间隔大小,本文自定义一种空白间隔,不绘制内容,第一个和最后一个item的两边间距50,中间的item间距12,自定义ItemDecoration如下:
class mItemDecoration extends RecyclerView.ItemDecoration{
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) parent.getLayoutManager();
Context context = MainActivity.this;
if(parent.getChildAdapterPosition(view) == 0){
outRect.left = dip2px(context,50);
outRect.right = dip2px(context,12);
} else if(parent.getChildAdapterPosition(view) == linearLayoutManager.getItemCount()-1){
outRect.right = dip2px(context,50);
outRect.left = dip2px(context,12);
} else{
outRect.left = dip2px(context,12);
outRect.right = dip2px(context,12);
}
}
}
不绘制内容,所以没有重写onDraw方法,需要间隔,所以只重写了getItemOffsets方法,方法中outRect表示每个Item外围的宽度,默认为0,通过getChildAdapterPosition()方法可以得到当前绘制的间隔是哪个Item的。recyclerView设置为自定义的间隔效果如下:
这样一个简单的RecyclerVIew的使用就完成了。