您的位置:首页 > 其它

RecyclerView使用、上拉加载、局部刷新、多种布局、点击事件和坑

2017-01-06 12:25 543 查看

一、Recycler的基础使用

先来了解一下它是干啥的:

可以实现ListView的效果

可以实现GridView的效果

可以实现瀑布流的效果

主要是通过设置它的setLayoutManager来决定它长的啥样

//这里用线性显示 类似于listview
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));

//这里用线性宫格显示 类似于grid view
mRecyclerView.setLayoutManager(new GridLayoutManager(this, 2));

//这里用线性宫格显示 类似于瀑布流
mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL));


接下来就以线性布局的为例:

1、要使用RecyclerView要先在build.gradle中添加依赖(不要忘了同步哈)

compile 'com.android.support:design:25.0.0'


2、在XML中使用RecyclerView

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_list_view_demo"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.ws.myapplication.activitys.ListViewDemoActivity">

<android.support.v7.widget.RecyclerView
android:id="@+id/pullLoadMoreRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</RelativeLayout>


3、在Activity或者Fragment中找到控件,并设置数据(下面以Activity为例哈)

//找到控件
recyclerView = (RecyclerView) findViewById(R.id.pullLoadMoreRecyclerView);
//设置想要的样式
linearLayoutManager = new LinearLayoutManager(ListViewDemoActivity.this);
recyclerView.setLayoutManager(linearLayoutManager);
//初始化Adapter
mRecyclerViewAdapter = new RecyclerViewAdapter();
//像ListView一样给RecyclerView绑定Adapter
recyclerView.setAdapter(mRecyclerViewAdapter);


4、关键就是RecyclerView的Adapter

首先RecyclerView的Adapter不是继承BaseAdapter而是继承RecyclerView.Adapter

RecyclerView的ViewHolder也是继承的RecyclerView.ViewHolder(public权限的)

//注意这里面的泛形,它是onCreateViewHolder返回的类型,也是onBindViewHolder的参数类型
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

public RecyclerViewAdapter() {

}

//创建每个Item
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//没个Item要显示的样子
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_item, parent, false);
return new ViewHolder(view);
}

//给每个Item设置数据
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.textView.setText(list.get(position));
}

@Override
public int getItemCount() {
return list.size();
}

public class ViewHolder extends RecyclerView.ViewHolder {

TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.recycler_text);
}
}
}


二、RecyclerView多种布局和上拉刷新

RecyclerView的多种布局与ListView有些相似也有不同,它不需要重写两个方法,只需要一个getItemViewType就可以了;而且它的默认值是0,它返回的是整数就可以,不需要连续。

如果要实现RecyclerView的上拉刷新,可以给它加一个FooterView,来实现上拉加载的效果。

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private int load_more_status;
//上拉加载更多
public static final int  PULLUP_LOAD_MORE=0;
//正在加载中
public static final int  LOADING_MORE=1;

public RecyclerViewAdapter() {

}
//viewType是getItemViewType返回的数据
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//根据viewType来判断要创建哪个类型的view
if(viewType == 0){
View view = LayoutInflater.from(ListViewDemoActivity.this).inflate(R.layout.footer_layout,parent,false);
return new FooterHolder(view);
}else {
View view = LayoutInflater.from(ListViewDemoActivity.this).inflate(R.layout.recycler_view_item,parent,false);
return new ViewHolder(view);
}
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//通过holder来确定显示的是哪个类型的View
if(holder instanceof FooterHolder){
switch (load_more_status) {
case PULLUP_LOAD_MORE:
((FooterHolder) holder).textView.setText("上拉加载更多");
break;
case LOADING_MORE:
((FooterHolder) holder).textView.setText("正在加载更多");
break;
}
}else if(holder instanceof ViewHolder){
((ViewHolder) holder).textView.setText(list.get(position));
holder.itemView.setTag(position);
}
}

//因为要添加一个FooterView所以总体返回的数据应给+1
@Override
public int getItemCount() {
return list.size()+1;
}
//是最后一个的时候显示FooterView,否则正常显示
@Override
public int getItemViewType(int position) {
if(position+1==getItemCount()){
return 0;
}
return 1;
}
//正常布局的ViewHolder
public class ViewHolder extends RecyclerView.ViewHolder {

TextView textView;
public ViewHolder(final View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.recycler_text);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("-------------->","tag:"+itemView.getTag());
//在ViewHolder中通过getAdapterPosition方法获取在adapter中的位置,和设置tag效果相同
Log.e("---------->", "getAdapterPosition()" + getAdapterPosition());
}
});
}
}
//FooterView布局的ViewHolder
public class FooterHolder extends RecyclerView.ViewHolder{
TextView textView;
public FooterHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text);
}
}

/**
* //上拉加载更多
* PULLUP_LOAD_MORE=0;
* //正在加载中
* LOADING_MORE=1;
* //加载完成已经没有更多数据了
* NO_MORE_DATA=2;
* @param status
*/
public void changeMoreStatus(int status){
load_more_status=status;
}
}


//上拉加载
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);

//设置加载的状态
mRecyclerViewAdapter.changeMoreStatus(RecyclerViewAdapter.LOADING_MORE);
//判断到底部的条件
if (newState == RecyclerView.SCROLL_STATE_IDLE && linearLayoutManager.findLastVisibleItemPosition() + 1 == mRecyclerViewAdapter.getItemCount()) {
Log.e("--------->", "到底");
//可以直接addAll
for (int i = 0; i < 30; i++) {
list.add("测试数据hhhhhhh:" + i);
}

//刷新数据
mRecyclerViewAdapter.notifyDataSetChanged();
mRecyclerViewAdapter.changeMoreStatus(RecyclerViewAdapter.PULLUP_LOAD_MORE);
}
}

@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});


1、使用notifyDataSetChanged();会重新执行onBindViewHolder()。

2、在ViewHolder中使用getAdapterPosition()获取在adapter中的位置。

3、如过在ongBindViewHolder的点击事件中调用了notifyDataSetChanged()可能会报错Cannot call this method while RecyclerView is computing a layout orscrolling,这时可以把点击事件移到ViewHolder中

详细错误参考

(如果逻辑中真的恰巧要在onBindViewHolder 中去刷新,然后还报错,那么可以使用handler机制,通过发消息去解决。)

三、RecyclerView局部刷新

局部刷新分结构上的刷新和非结构上的,关于添加和移除是结构上的移除,所以分清情况使用哪种。

// 更新列表position位置上的数据可以调用
notifyItemChanged(int position)

//列表position位置添加一条数据时可以调用,伴有动画效果
notifyItemInserted(int position)

//列表position位置移除一条数据时调用,伴有动画效果
notifyItemRemoved(int position)

//列表fromPosition位置的数据移到toPosition位置时调用,伴有动画效果
notifyItemMoved(int fromPosition, int toPosition)

//列表从positionStart位置到itemCount数量的列表项进行数据刷新
notifyItemRangeChanged(int positionStart, int itemCount)

//列表从positionStart位置到itemCount数量的列表项批量添加数据时调用,伴有动画效果
notifyItemRangeInserted(int positionStart, int itemCount)

//列表从positionStart位置到itemCount数量的列表项批量删除数据时调用,伴有动画效果
notifyItemRangeRemoved(int positionStart, int itemCount)


能用局部刷新就不要使用notifyDataSetChanged();

public class RecyclerViewDemoActivity extends AppCompatActivity {

private List<String> list;
private RecyclerView recyclerView;
private MyApapter apapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler_view_demo);

recyclerView = (RecyclerView) findViewById(R.id.recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(RecyclerViewDemoActivity.this));
apapter = new MyApapter();
recyclerView.setAdapter(apapter);

list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
list.add("数据" + i);
}

}
//添加一条
public void addOne(View view) {
list.add(3,"我是添加的一个");
apapter.notifyItemInserted(3);
}
//添加多条
public void addMore(View view) {
for(int i = 5;i<9;i++){
list.add(i,"添加了一片哈哈");
}
apapter.notifyItemRangeInserted(5,4);

}
//移除一条
public void removeOne(View view) {
list.remove(1);
apapter.notifyItemRemoved(1);
}
//移除多条
public void removeMore(View view) {
for(int i = 20;i>15;i--){
list.remove(i);
}
apapter.notifyItemRangeRemoved(15,4);
}
//刷新一条
public void changeItem(View view) {
list.set(2,"我就改了怎么的^_^");
apapter.notifyItemChanged(2);
}

private class MyApapter extends RecyclerView.Adapter<MyApapter.MyViewHolder> {

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(RecyclerViewDemoActivity.this).inflate(R.layout.recycler_view_item, parent, false);
return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.textView.setText(list.get(position));
}

@Override
public int getItemCount() {
return list.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;

public MyViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.recycler_text);
}
}
}
}


四、RecyclerView点击事件

看另一片博客RecyclerView点击事件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐