RecyclerView简单案例&添加下拉刷新(SwipeRefreshLayout)、上拉加载(lastVisibleItem)

版权声明:本文为博主原创文章,如需转载请声明作者信息,谢谢。 https://blog.csdn.net/itCatface/article/details/77861906

效果图如下


这里写图片描述

一、先看各个布局

  1. activity_main
    使用SwipeRefreshLayout包裹RecyclerView

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <android.support.v4.widget.SwipeRefreshLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/srl"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
    
        </android.support.v4.widget.SwipeRefreshLayout>
    
    </LinearLayout>
  2. list_item
    只显示一个一个字符串

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >
    
        <TextView
            android:id="@+id/tv_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="15dp"
            android:textSize="18sp" />
    
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#fcc" />
    
    </LinearLayout>
  3. list_foot
    最后一个条目可见时加载更多数据(一个loading和文字提示)

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:gravity="center_vertical"
                  android:orientation="horizontal"
                  android:padding="10dp">
    
        <ProgressBar
            android:id="@+id/pb_loading"
            style="@android:style/Widget.ProgressBar.Inverse"
            android:layout_width="26dp"
            android:layout_height="26dp"
            android:layout_marginLeft="130dp"/>
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:text="松开加载"
            android:textColor="#c0f0"
            android:textSize="20sp"/>
    
    </LinearLayout>

二、适配器的实现(★)

  1. RecyclerView的适配器(要熟练掌握哦)
    分析数据应该如何展示,完整代码紧跟在分析之后

    1. 怎么区分当前位置要展示的具体布局类型
      ListView中我们很熟悉了,通过getViewTypeCount(): Int获取需要展示的布局数目(如2),然后通过getItemViewType(): Int获取当前位置需要展示的具体布局类型
      ↑ VS ↓
      RecyclerView中仅使用getItemViewType(): Int即可获得当前位置对应的布局类型,用法和ListView的getItemViewType(): Int别无它异,具体参考下面的完整代码

    2. ViewHolder如何创建
      ListView中需要手动创建静态Holder,并在getView(): View中先后手动setTag()getTag()来获取holder,然后进行控件内容的填充
      ↑ VS ↓
      RecyclerView已帮我们集成进了ViewHolder(这也是Recycler的核心),只要继承RecyclerView.Adapter时添加泛型RecyclerView.ViewHolder,然后分别添加各布局对应的Holder类(类中初始化控件),最后在onCreateViewHolder: RecyclerView.ViewHolder中通过各布局类型创建对应的Holder实例即可

    3. 如何通过ViewHolder填充数据
      ListView中在getView(): View的缓存复用、holder的setTag()完成后直接进行控件内容的填充
      ↑ VS ↓
      RecyclerView中,我们单独在onBindViewHolder(holder): void方法中通过转换holder类型后进行控件内容的填充

    public class SampleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        // 要展示的数据集合
        private List<String> mDatas;
    
        // 判断布局类型
        private static final int TYPE_ITEM = 0;
        private static final int TYPE_FOOT = 1;
    
    
        /**
         * 初始化工作(在这里是获得了数据集合)
         */
        public SampleAdapter(List<String> datas) {
            mDatas = datas;
        }
    
    
        /**
         * 当前位置应该展示的条目布局的类型
         */
        @Override public int getItemViewType(int position) {
            // 数据集合最后一行数据之后的那一行就应该加载脚布局
            if (position + 1 == getItemCount()) {
                return TYPE_FOOT;
            } else {
                return TYPE_ITEM;
            }
        }
    
    
        /**
         * 设置各布局,并返回与其对应的ViewHolder实例
         */
        @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = null;
            RecyclerView.ViewHolder holder = null;
    
            if (viewType == TYPE_ITEM) {
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, null);
                holder = new ItemHolder(view);
    
            } else if (viewType == TYPE_FOOT) {
                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_foot, null);
                holder = new FootHolder(view);
            } else {
                // 默认的布局及其对应的ViewHolder实例,防止发生意外
                // default view = ...
                // default holder = ...
            }
    
            return holder;
        }
    
    
        /**
         * 填充各布局的控件内容
         */
        @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
            if (holder instanceof ItemHolder) {
                ((ItemHolder) holder).tvText.setText(String.valueOf(mDatas.get(position)));
            }
        }
    
    
        /**
         * 要展示的条目总数(包括所有数据集合和额外添加的头、身、脚条目数量)
         */
        @Override public int getItemCount() {
            return mDatas.size() + 1;
        }
    
    
        /****************************************
         * 各布局类型的ViewHolder
         */
        class FootHolder extends RecyclerView.ViewHolder {
            public FootHolder(View view) {
                super(view);
            }
        }
    
        class ItemHolder extends RecyclerView.ViewHolder {
            // 展示一行字符串
            @BindView(R.id.tv_text) TextView tvText;
    
            public ItemHolder(View view) {
                super(view);
                ButterKnife.bind(this, view);
            }
        }
    }

三、Activity中如何展示并添加刷新和加载逻辑

注意数据集合发生变化,需要使用mAdapter.notifyItemRemoved(position)来告知适配器以进行界面刷新

public class MainActivity extends BaseActivity {

    @BindView(R.id.srl) SwipeRefreshLayout srl;
    @BindView(R.id.rv) RecyclerView rv;

    /**
     * 布局管理器
     * 1. LinearLayoutManager:支持横向、纵向
     * 2. GridLayoutManager:网格
     * 3. StaggeredGridLayoutManager:瀑布流
     */
    private LinearLayoutManager mLayoutManager;

    private List<String> mDatas;
    private SampleAdapter mAdapter;

    // 记录最后可见条目
    private int lastVisible;

    // 分别记录刷新和加载次数
    int refreshTimes = 0;
    int addmoreTimes = 0;


    @Override int layoutId() {
        return R.layout.activity_main;
    }


    /**
     * 初始化数据
     */
    @Override void initData() {
        mDatas = new ArrayList<String>();
        for (int i = 0; i < 15; i++) {
            mDatas.add("数据== " + (i + 1) + " ==");
        }
    }


    @Override void initView() {
        srl.setColorSchemeResources(R.color.color1, R.color.color2, R.color.color3, R.color.color4);
        srl.setOnRefreshListener(this);

        rv.setOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                // 不在滑动和最后可见条目是脚布局时加载更多
                if (newState == RecyclerView.SCROLL_STATE_IDLE && lastVisible + 1 == mAdapter.getItemCount()) {
                    addmore();
                }
            }

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

        });

        rv.setHasFixedSize(true);
        mLayoutManager = new LinearLayoutManager(this);
        rv.setLayoutManager(mLayoutManager);
        rv.setItemAnimator(new DefaultItemAnimator());

        mAdapter = new SampleAdapter(mDatas);
        rv.setAdapter(mAdapter);
    }


    /**
     * 模仿下拉刷新
     */
    @Override void srlRefresh() {
        mDatas.add(0, "刷新 " + ++refreshTimes + "次");

        new Timer().schedule(new TimerTask() {
            @Override public void run() {
                runOnUiThread(new Runnable() {
                    @Override public void run() {
                        Toast.makeText(MainActivity.this, "刷新" + refreshTimes, Toast.LENGTH_SHORT).show();
                        srl.setRefreshing(false);
                        mAdapter.notifyDataSetChanged();
                    }
                });
            }
        }, 1000);
    }


    /**
     * 模仿上拉加载
     */
    void addmore() {
        new Timer().schedule(new TimerTask() {
            @Override public void run() {
                runOnUiThread(new Runnable() {
                    @Override public void run() {
                        mDatas.add("数据增加" + ++addmoreTimes);
                        Toast.makeText(MainActivity.this, "加载" + addmoreTimes, Toast.LENGTH_SHORT).show();
                        mAdapter.notifyItemInserted(mDatas.size());
                    }
                });
            }
        }, 1000);
    }
}

猜你喜欢

转载自blog.csdn.net/itCatface/article/details/77861906