好文推荐
作者:JonesYang
转载:https://juejin.cn/post/6899614958632812557#heading-3
ListView 相关
ListView 是什么?(上古神器)不,是不是该问 RecyclerView 是什么?(也是上古神器?在它的替代品出来之前最好别这样称呼)趁着这段时间,我想我也应该把这些乱七八糟的东西整理一下。
OK,不演了,ListView 和 RecyclerView 都是用来展示列表数据了。相比与 ListView ,RecyclerView 更加强大,下面先说 ListView。
ListView 适配器
关于 ListView 先简单看一下它的适配器代码:
public class ListViewAdapter extends BaseAdapter {
//用于加载 item
private LayoutInflater mInflater;
//通过构造函数 把 Context 传递进来
public ListViewAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
/**
* 获取的数据存储在这个集合中,一般来说这个集合中存储了子项的 item
*/
private List mList = new ArrayList();
/**
* @return 返回集合的大小
*/
@Override
public int getCount() {
return mList.size();
}
/**
* @param position
* @return 返回具体的 item
*/
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
/**
* 作用:加载 子项 item 的布局
*
* @param position item 的位置
* @param convertView item 进行复用,避免一个 item 发生多次加载的情况
* @param parent 父容器,根据具体的情况而定
* @return item
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null){
convertView = mInflater.inflate(R.layout.activity_detail,parent,false);
}
//对 item 进行复用,返回 convertView
return convertView;
}
}
ListView 的优化
可以看到,基本上每一个 item 都需要在 getView() 中加载,如果 item 的数量过多,就会产生性能问题,影响用户体验。这个时候我们就需要使用 ViewHolder(开发者自定义类),这是 ListViewAdapter 的内部类,它的代码如下:
/**
* 作用:加载 子项 item 的布局
*
* @param position item 的位置
* @param convertView item 进行复用,避免一个 item 发生多次加载的情况
* @param parent 父容器,根据具体的情况而定
* @return item
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null){
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.activity_detail,parent,false);
convertView.setTag(holder);
} else {
如果 convertView 不为空,直接进行复用
holder = (ViewHolder) convertView.getTag();
}
//对 item 进行复用,返回 convertView
return convertView;
}
//这是一个内部类
private class ViewHolder{
//获取 item 的控件都定义在这里
}
好了,关于 ListView 就到这里了,下面总结两个关键点:
- 自定义 ListViewAdapter ,继承 BaseAdapter。
- 自定义 ViewHolder 和 convertView 一起完成复用优化工作。
RecyclerView 相关
下面开始写 RecyclerView ,先把 RecyclerView 的关键点总结在这里。其实和 ListView 是差不多的,主要有两条:
- RecyclerViewAdapter 继承 Recyclerview.Adapter ,其内部类 ViewHolder 继承 RecyclerView.ViewHolder。
- 设置布局管理器,控制布局效果
RecyclerView 适配器
先看下面 RecyclerView 适配器的代码:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
/**
* 这个方法主要生成为每个Item inflater出一个View,但是该方法返回的是一个ViewHolder。
* 该方法把View直接封装在ViewHolder中,然后我们面向的是ViewHolder这个实例,
* 当然这个ViewHolder需要我们自己去编写。
*
* @param parent
* @param viewType
* @return viewHolder
*/
@NonNull
@Override
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return null;
}
/**
* 这个方法主要用于适配渲染数据到View中,
* 方法提供给你了一viewHolder而不是原来的convertView
*
* @param holder
* @param position
*/
@Override
public void onBindViewHolder(@NonNull RecyclerViewAdapter.ViewHolder holder, int position) {
//在这里更新 UI
}
/**
* @return 返回 item 的数量
*/
@Override
public int getItemCount() {
return 0;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(@NonNull View itemView) {
super(itemView);
}
}
}
从基础使用上看,我们明显可以看出,RecyclerView 相比 ListView 在基础使用上的区别主要有如下几点:
- ViewHolder 的编写规范化了。
- RecyclerView 复用 item 的工作 Google 全帮你搞定了,不需要再像 ListView 那样自己调用 setTag()。
- RecyclerView 需要设置 KayoutManager
如何在 Activity 中使用 RecyclerView
接下来看一下如何在 Activity 中使用 RecyclerView :(ListView 大致相同)
//1、设置布局管理器
LinearLayoutManager manager = new LinearLayoutManager(this);
RecyclerView recyclerView = findViewById(R.id.detail_rv);
recyclerView.setLayoutManager(manager);
//2、设置适配器
RecyclerViewAdapter adapter = new RecyclerViewAdapter();
recyclerView.setAdapter(adapter);
RecyclerView 的布局管理器
关于 RecyclerView ,还得再说一下它的布局管理器,RecyclerView 提供了三种布局管理器可供选择:
- LinerLayoutManager 以垂直或者水平列表方式展示
- GridLayoutManager 以网格方式展示item
- StaggeredGridLayoutManager 以瀑布流方式展示Item
之所以说 RecyclerView 更加强大,也正是因为 RecyclerView 提供了多种布局管理器,只需在 Activity 中进行设置即可。另外,关于布局管理器的一些API如下:
canScrollHorizontally();//能否横向滚动
canScrollVertically();//能否纵向滚动
scrollToPosition(int position);//滚动到指定位置
setOrientation(int orientation);//设置滚动的方向
getOrientation();//获取滚动方向
findViewByPosition(int position);//获取指定位置的Item View
findFirstCompletelyVisibleItemPosition();//获取第一个完全可见的Item位置
findFirstVisibleItemPosition();//获取第一个可见Item的位置
findLastCompletelyVisibleItemPosition();//获取最后一个完全可见的Item位置
findLastVisibleItemPosition();//获取最后一个可见Item的位置
RecyclerView 的分割线
我们可以为 REcyclerview 的 item 绘制分割线,用系统已经定义好的分割线:
//添加分割线
myRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));
同样,我们也可以定义自己的分割线,实现不同的效果:
自定义间隔样式需要继承RecyclerView.ItemDecoration类,该类是个抽象类,官方目前并没有提供默认的实现类,主要有三个方法。
- onDraw(Canvas c, RecyclerView parent, State state),在Item绘制之前被调用,该方法主要用于绘制间隔样式。
- onDrawOver(Canvas c, RecyclerView parent, State state),在Item绘制之前被调用,该方法主要用于绘制间隔样式。
- getItemOffsets(Rect outRect, View view, RecyclerView parent, State state),设置item的偏移量,偏移的部分用于填充间隔样式,即设置分割线的宽、高;在RecyclerView的onMesure()中会调用该方法
喜欢本文的话,不妨顺手给我点个小赞、评论区留言或者转发支持一下呗~
网友评论