前言
本文介绍RecyclerView的基础使用!
1、将RecyclerView展示成ListView样式
2、将RecyclerView展示成GridView样式
3、给RecyclerView添加点击事件
4、给RecyclerView添加滑动监听
5、设置RecyclerView为横向滑动
1、将RecyclerView展示成ListView样式
导入依赖
compile 'com.android.support:recyclerview-v7:25.2.0'
如何使用
第一步:
//在这里,高度宽度也可以是固定宽高
第二步:代码中配置
myRecyclerView = (RecyclerView) findViewById(R.id.myRecyclerView); //找到RecyclerView
//找到控件
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);
//表示展示成为listview的形式
myRecyclerView.setLayoutManager(layoutManager);
//关键代码,告诉RecyclerView它自己要展示成为什么样子
第三步:准备适配器
public class LikeListViewAdapter extends RecyclerView.Adapter {
private List list ; //表示数据源
private Context context; //表示上下文,用来创建视图
public LikeListViewAdapter(Context context) {
this.context = context;
list = new ArrayList<>();
}
/**此方法是必要的方法,在这里面完成构建视图,相当于ListView中getView()方法中第一步
参数是ViewGroup 与 viewType(用于RecyclerView的多套布局),返回值是MyViewHolder对象*/
@Override
public MyViewHodler onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item1,parent,false);
MyViewHodler m = new MyViewHodler(view);
return m;//这三步之间是通过MyViewHolder对象进行传递的
}
/**在这里面完成配置数据源给相应的视图,相当于ListView中getView()方法中第三步
*/
@Override
public void onBindViewHolder(MyViewHodler holder, int position) {
holder.name.setText(list.get(position).getName());
holder.time.setText(list.get(position).getTime());
}
//告诉RecyclerView有多少条目
@Override
public int getItemCount() {
return list.size();
}
//前面提到的MyViewHolder对象,相当于ListView中getView()第二步
public class MyViewHodler extends RecyclerView.ViewHolder
{
TextView name,time;
//必须要重写其构造方法,发现参数是View,可以认为是每一个条目的View(视图)
public MyViewHodler(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.textview_name);
time = (TextView) itemView.findViewById(R.id.textview_time);
//完成findViewById的过程
}
};
//还需要给外界暴露,使其可以改变里面list的内容
public void setList(List list){
this.list = list;
// notifyDataSetChanged(); //没有什么效果
notifyItemRangeChanged(0,20); //也没有什么动画效果
}
}
我认为这里面的数据使用过MyViewHolder对象来进行传递,将这三个步骤串联起来。
第四步:将适配器交给RecyclerView
liAdater = new LikeListViewAdapter(MainActivity.this); //得到适配器对象
myRecyclerView.setAdapter(liAdater); //交给RecyclerView,此时是没有数据的
第五步 :配置展示的数据
for (int i = 0; i < 20; i++) {
beans1 b = new beans1();
b.setName("项"+i);
b.setTime(""+i);
list.add(b);
}
liAdater.setList(list); //通知更新界面
如图所示:
解释说明
(1)如图所示,里面是没有红线的,那个是在布局的时候画上的,不和ListView一样自带分割线,这样给了很大的自主性。
(2)你在每一个条目的布局中展示成什么样子,那么他就会是什么样子,你给他多高,那么在屏幕上展示就有多高,比如我设置
RecyclerView的高度是200dp,每一条目都是match_parent,那么刚好在RecyclerView可见区域展示,但只能是一条item.
如果我设置每一item的高度是300dp,RecyclerView依旧是200dp那么高,但是里面内容会展示不全,因为其不会压缩item,
所以呢,在RecyclerView可见视图上,只能展示一部分。那么可以模仿成为淘宝一样翻转的广告页面。
(3)对于宽度,如果每一个item 宽度小于RecyclerView的宽度,那么都会展示出来见下图一:
如果每一个item的宽度大于RecyclerView的宽度,那么就会展示不全,如图二:
(4)其实,如果你的Item 设计成宽度和高度都是match_parent,表示,宽高和RecyclerView一样,那么只能展示一条item.
2、将RecyclerView展示成GridView样式
代码
别的做法和前面一样,唯一不同的是,告诉ReyclerView展示成为什么样子时候用下面这句(上面第二步)
GridLayoutManager gridLayoutamnager = new GridLayoutManager(MainActivity.this,3);//将一行平分成为3份空间
gridLayoutamnager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){
@Override
public int getSpanSize(int position) {
if (position%4==0){
return 2;
//表示%4==0的position,其可以独占该行按照比例划分空间的2个位置,但是如果要是,一行就划分了3份空间,但是要让其占有比这个
//会怎么样,如图,图三:
//会显示Item at position 0 requires 5 spans but GridLayoutManager has only 3 spans.
//就是如果你将行空间划分为三份,但是你这里return 4那么就会程序就会崩溃
}
return 1;//其他的表示就占一份空间就好
}
});
myRecyclerView.setLayoutManager(gridLayoutamnager);
//如果要是没有上述setSpanSizeLookup()方法,效果如图四:
说明
(1)如果你每个条目设计的宽度设计成match_parent,高度也是,那么高度不会压缩,但是,宽度会有变,如前面图四
(2)如果你的宽度是自己定义的,如果宽度大于屏幕的宽度,那么每一部分只会显示item的一部分,如果要是小于屏幕的宽度,
那么就会出现相互重叠的效果如下图
3、给RecyclerView添加点击事件
第一步
采用接口回调的方式来实现,先准备一个接口,放在自定义的Adapter文件里面,不用当做内部类的形式
interface sendListener{
void send(int positon);
}
这里只用position当做参数,是为了 演示,具体可以根据自己的需求来提供不同的参数
第二步
让适配器持有这个自定义接口的对象,并且对外暴露
private sendListener sendListener; //持有这个接口的对象
public void setSendListener(com.yuyi.myrecyclerstudy.sendListener sendListener) {
this.sendListener = sendListener;
}//对外暴露规则
第三步
在自定义的ViewHolder里面完成调用
public class MyViewHodler extends RecyclerView.ViewHolder{
TextView name,time;//定义的两个变量
//必须要重写其构造方法,发现参数是View,可以认为是每一个条目的View(视图)
//可以认为是第二步
public MyViewHodler(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.textview_name);
time = (TextView) itemView.findViewById(R.id.textview_time);
//在这里得到了视图,因此在这里对于视图进行加点击事件
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (sendListener != null){
sendListener.send(getLayoutPosition());
//通过getLayoutPosition得到其位置,这个是关键。这里对于这个条目进行添加点击事件
}
}
}); //另外这里是对于itemView加的点击事件,如果情况特殊完全可以只对于某个View加上点击事件。
}
}
第四步
在外界就可以使用其点击事件了
liAdater.setSendListener(new sendListener() {
@Override
public void send(final int positon) {
Toast.makeText(MainActivity.this,""+positon,Toast.LENGTH_SHORT).show();
}
}
效果如图:
总结
原本这样,RecyclerView已经具有点击事件了,可以满足正常的需求了,但是RecyclerView本身提供了
很大的自由性和一些动画,这里就顺便演示某些动画效果
补充一
在自定义的Adapter类中加上,增添一个条目和删除一个条目的对外的方法
//针对于带有动画的删除一个item
public void removeItem(int position){
list.remove(position);
notifyItemRemoved(position);
}
//针对与带有动画的增加一个item
public void addItem(int position,beans1 b){
list.add(position,b);//先改变数据源
notifyItemInserted(position);
}
补充二
在点击事件处理时候加上AlertDialog 进行处理,完成效果:
liAdater.setSendListener(new sendListener() {
@Override
public void send(final int positon) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle("请选择你的操作");
builder.setNegativeButton("删除", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
liAdater.removeItem(positon);
}
});
builder.setPositiveButton("增加", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
beans1 b = new beans1();
b.setTime("99");
b.setName("新");
liAdater.addItem(positon,b);
}
});
builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
Toast.makeText(MainActivity.this,"用户取消了操作",Toast.LENGTH_SHORT).show();
}
});
builder.show();
}
});
效果如图:
4、给RecyclerView添加滑动监听
SwipeRefreshLayout
这是谷歌官方推荐的搭配的方法。
需要使用android.support.V4.widget.SwipeRefreshlayout
监听方法
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
//在这里不会直接更新,还需要你手动去调用刷新的方法
}
});
可以设置刷新圆圈的颜色
swipeRefreshLayout.setColorSchemeColors(Color.RED,Color.BULE);
//这里面设置颜色最多是四个,可以实现转一个圈显示一个颜色
可以设置刷新圆圈出来的位置
swipeRefreshlayout.setProgressViewOffset(true,200,300);
//实现的功能是,true:会收缩,参数二是开始的位置,参数三是结束的位置
//形成一种收缩移动的动画既视感
可以设置圆圈消失
swipeRefreshlayout.setRefreshing(false);
分页加载
介绍
很多人直接会用系统提供的addOnScrollListener()方法,如下所示:
myRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE){
/**new State 一共有三种状态
* SCROLL_STATE_IDLE:目前RecyclerView不是滚动,也就是静止
* SCROLL_STATE_DRAGGING:RecyclerView目前被外部输入如用户触摸输入。
* SCROLL_STATE_SETTLING:RecyclerView目前动画虽然不是在最后一个位置外部控制。
//这里进行加载更多数据的操作
}
}
});
弊端
上述方法类似与ViewPager的滑动监听,只要你一滑动RecyclerView,那么就会调用,
如上述的约束条件,只要动了,就会就会静止,就会调用,哪怕你没有到ReyclerView
数据的底部,所以不可取
解决
需要对这个监听进行约束,首先定义新的类,在Adaper类中,不是当做内部类
class OnlastItem extends RecyclerView.OnScrollListener{
boolean isButton =false;
}
//关键,一定要继承RecyclerView.OnScrollListener接口
在Adapter类中一定要重写onViewAttachedToWindow()方法
@Override
public void onViewAttachedToWindow(MyViewHodler holder) {
super.onViewAttachedToWindow(holder);
int positon = holder.getLayoutPosition();
if (positon == list.size()-1){
onlastItem.isButton =true;
}
}
上述方法介绍
Called when a view created by this adapter has been attached to a window.
这个方法会频繁的调用,只要一个屏幕外的item进入当前视野,就会调用,但是有一点需要注意的是,
window指的是当前可见的视图,一个item 哪怕,你只看到一点点,那么也算是进入了屏幕上了,
就是所谓的window 上了。
那么你初始化展示了RecyclerView的内容后,这个方法也会根据在window上可见的数目,调用相应的次数。
继续上述步骤
在Adapter类中:
//持有滑动的变量
private OnlastItem onlastItem;
//对外暴露其方法
public void setOnlastItem(OnlastItem onlastItem) {
this.onlastItem = onlastItem;
}
给RecyclerView设置监听方法
//滑动监听
OnlastItem on = new OnlastItem(){
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
/*当RecyclerView滚动。这将是
称为滚动后完成。这个回调也被称为后如果可见项目范围改变布局
计算。在这种情况下,dx和dy将0。
dx表示水平滚动,dy表示垂直滚动*/
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
要调用的回调方法当RecyclerView滚动状态改变。
/**new State 一共有三种状态
* SCROLL_STATE_IDLE:目前RecyclerView不是滚动。
* SCROLL_STATE_DRAGGING:RecyclerView目前被外部输入如用户触摸输入。
* SCROLL_STATE_SETTLING:RecyclerView目前动画虽然不是在最后一个位置
外部控制。
* */
if (newState == RecyclerView.SCROLL_STATE_IDLE&&isButton==true){
//这里用不是滚动状态的实现,并且还有一个判断,是退出屏幕了
if (newState == RecyclerView.SCROLL_STATE_IDLE){
//进行联网数据操作
isButton =false;//这个置反很关键
}
}
}
};
myRecyclerView.addOnScrollListener(on); //关键方法
liAdater.setOnlastItem(on); //关键方法
5、设置RecyclerView为横向滑动
先看效果图
关键代码
LinearLayoutManager laoutManager = new LinearLayoutManager(this);
//上述代码告诉RecyclerView 的layoutmanger,展示成为listview样式
laoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
//告诉它是水平展示,要不然默认是竖直方向
myRecyclerView.setLayoutManager(laoutManager);
//最后交给layoutManger