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

一、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


<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

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

  2. 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 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点击事件

你可能感兴趣的:(android)