1. 程式人生 > >RecyclerView簡單案例&新增下拉重新整理(SwipeRefreshLayout)、上拉載入(lastVisibleItem)

RecyclerView簡單案例&新增下拉重新整理(SwipeRefreshLayout)、上拉載入(lastVisibleItem)

效果圖如下


這裡寫圖片描述

一、先看各個佈局

  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);
    }
}