RecyclerView的刷新分頁

RecyclerView 的簡單使用及點擊事件,參考前面幾篇文章:php

在開發中經常使用到刷新分頁,這裏實現一個 RecyclerView 的簡單的刷新分頁操做,測試效果見文末,實現過程參考以下:java

實現思路

  1. 加載更多數據使用到 RecyclerView 加載多種佈局,根據 ViewType 判斷加載數據 Item 仍是加載 FooterItem ;
  2. 經過線程模擬加載數據;
  3. 爲 RecyclerView 添加 addOnScrollListener 事件來監聽用戶的滑動操做;
  4. 根據用戶滑動狀態以及具體狀況開始加載數據
  5. 通知數據更新;

如何得到 firstVisibleItemPosition

爲了可以在數據加載中動態判斷何時加載數據,須要知道屏幕上顯示的第一個可見的 Item 的位置,固然了這裏使用的是佈局管理器是 LinearLayoutManager ,這樣查找屏幕上第一個可見的 Item 就顯得容易多了,下面介紹一些 LinearLayoutManager 的四個方法:android

findFirstVisibleItemPosition()

得到屏幕上第一個可見 Item 的 position,只要該 Item 有一部分可見,那麼返回的 position 就是該Item 的 position。微信

findFirstCompletelyVisibleItemPosition()

得到屏幕上第一個完整可見的 Item 的 position,只要該 Item 有一部分不可見,那麼返回的 position 就是該 Item 對應的下一個能顯示完整的 Item 的position。ide

findLastVisibleItemPosition()

得到屏幕上最後一個可見 Item 的 position,只要該 Item 有一部分可見,那麼返回的 position 就是該Item 的 position。佈局

findLastCompletelyVisibleItemPosition()

得到屏幕上最後一個完整可見的 Item 的 position,只要該 Item 有一部分不可見,那麼返回的 position 就是該 Item 對應的上一個能顯示完整的 Item 的position。post

準備數據

/** * 初始化數據 * @return */
    public void initData(){
        for (int i=0;i<30;i++){
            arrayList.add("第"+i+"條數據");
        }
    }
    
    /** * 線程模擬加載數據 */
    class LoadDataThread extends Thread{
        @Override
        public void run() {
            initData();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通知主線程更新數據
            Message message = handler.obtainMessage();
            message.what = UPDATE_DATA;
            message.obj = arrayList;
            handler.sendMessage(message);
        }
    }
複製代碼

代碼參考

主佈局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.manu.mrecyclerview.MainActivity">
    <android.support.v7.widget.RecyclerView android:id="@+id/rv" android:layout_width="match_parent" android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
</LinearLayout>

複製代碼

Item佈局

/**item.xml**/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="5dp">
    <TextView android:id="@+id/tv_recycle" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="data" android:background="#cac3c3" android:padding="10dp" android:textSize="20sp"/>
</LinearLayout>

複製代碼

/**item_footer.xml**/
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal">
    <ProgressBar style="?android:attr/progressBarStyleSmall" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/progressBar" />
    <TextView android:text="正在努力加載中,請稍後..." android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textView" />
</LinearLayout>

複製代碼

Adapter

這裏使用了 RecyclerView 根據不一樣的 ViewType 加載多種佈局的用法,使用時根據不一樣的佈局建立不一樣的 ViewHolder , 而後根據不一樣的 Viewholder 爲對應的 Item 添加數據,注意 getItemViewType() 方法的用法,Adapter 代碼參考以下:學習

/** * Created by jzman on 2017/6/04 * RecycleView的Adapter */
public class RvAdapter1 extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements View.OnClickListener{
    private static final int ITEM_FOOTER = 0x1;
    private static final int ITEM_DATA = 0x2;
    private Context mContext;
    private RecyclerView recyclerView;
    private ArrayList<String> mList;

    public RvAdapter1() {}

    public RvAdapter1(Context mContext, ArrayList<String> mList) {
        this.mContext = mContext;
        this.mList = mList;
    }

    public void setmList(ArrayList<String> mList) {
        this.mList = mList;
    }

    /** * 用於建立ViewHolder * @param parent * @param viewTypez * @return */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view ;
        RecyclerView.ViewHolder vh = null;
        switch (viewType){
            case ITEM_DATA:
                view = LayoutInflater.from(mContext).inflate(R.layout.item,null);
                view.setOnClickListener(this);
                vh = new DataViewHolder(view);
                //使用代碼設置寬高(xml佈局設置無效時)
                view.setLayoutParams(new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
                break;
            case ITEM_FOOTER:
                view = LayoutInflater.from(mContext).inflate(R.layout.item_footer,null);
                //使用代碼設置寬高(xml佈局設置無效時)
                vh = new FooterViewHolder(view);
                view.setLayoutParams(new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
                break;
        }
        return vh;
    }

    /** * 獲取Item的View類型 * @param position * @return */
    @Override
    public int getItemViewType(int position) {
        //根據 Item 的 position 返回不一樣的 Viewtype
        if (position == (getItemCount())-1){
            return ITEM_FOOTER;
        }else{
            return ITEM_DATA;
        }
    }

    /** * 綁定數據 * @param holder * @param position */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof DataViewHolder){
            DataViewHolder dataViewHolder = (DataViewHolder) holder;
            dataViewHolder.tv_data.setText(mList.get(position));
        }else if (holder instanceof FooterViewHolder){

        }
    }

    /** * 選項總數 * @return */
    @Override
    public int getItemCount() {
        return mList.size()+1;
    }

    @Override
    public void onClick(View view) {
        //根據RecyclerView得到當前View的位置
        int position = recyclerView.getChildAdapterPosition(view);
        //程序執行到此,會去執行具體實現的onItemClick()方法
        if (onItemClickListener!=null){
            onItemClickListener.onItemClick(recyclerView,view,position,mList.get(position));
        }
    }

    /** * 建立ViewHolder */
    public static class DataViewHolder extends RecyclerView.ViewHolder{
        TextView tv_data;
        public DataViewHolder(View itemView) {
            super(itemView);
            tv_data = (TextView) itemView.findViewById(R.id.tv_recycle);
        }
    }

    /** * 建立footer的ViewHolder */
    public static class FooterViewHolder extends RecyclerView.ViewHolder{
        public FooterViewHolder(View itemView) {
            super(itemView);
        }
    }

    private OnItemClickListener onItemClickListener;
    public void setOnItemClickListener(OnItemClickListener onItemClickListener){
        this.onItemClickListener = onItemClickListener;
    }

    /** * 定義RecyclerView選項單擊事件的回調接口 */
    public interface OnItemClickListener{
        //參數(父組件,當前單擊的View,單擊的View的位置,數據)
        void onItemClick(RecyclerView parent,View view, int position, String data);
    }
    /** * 將RecycleView附加到Adapter上 */
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.recyclerView= recyclerView;
    }
    /** * 將RecycleView從Adapter解除 */
    @Override
    public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        this.recyclerView = null;
    }
}

複製代碼

MainActivity

這裏主要注意 rv.addOnScrollListener(new OnScrollListener() ...裏面的具體實現,MainActivity 代碼參考以下:測試

/** * Created by jzman on 2017/6/04 0013. */
public class MainActivity extends AppCompatActivity {
    private static final int UPDATE_DATA = 0x3;
    
    private RecyclerView rv;
    RvAdapter1 adapter;

    private ArrayList<String> arrayList = new ArrayList<>();
    //加載更多數據時最後一項的索引
    private int lastLoadDataItemPosition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        rv = (RecyclerView) findViewById(R.id.rv);

        //設置佈局管理器
        rv.setLayoutManager(new LinearLayoutManager(this));//線性
// rv.setLayoutManager(new GridLayoutManager(this,4));//線性
// rv.setLayoutManager(new StaggeredGridLayoutManager(4,StaggeredGridLayoutManager.VERTICAL));//線性
        initData();
        adapter = new RvAdapter1(this,arrayList);
        adapter.setOnItemClickListener(new RvAdapter1.OnItemClickListener() {
            @Override
            public void onItemClick(RecyclerView parent, View view, int position, String data) {
                Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
            }
        });

        rv.addOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (newState == SCROLL_STATE_IDLE &&
                        lastLoadDataItemPosition == adapter.getItemCount()){
                    new LoadDataThread().start();
                }
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {

                LayoutManager layoutManager = recyclerView.getLayoutManager();
                if (layoutManager instanceof LinearLayoutManager){
                    LinearLayoutManager manager = (LinearLayoutManager) layoutManager;
                    int firstVisibleItem = manager.findFirstVisibleItemPosition();
                    int l = manager.findLastCompletelyVisibleItemPosition();
                    lastLoadDataItemPosition = firstVisibleItem+(l-firstVisibleItem)+1;
                }
            }
        });

        rv.setAdapter(adapter);
    }

    /** * 初始化數據 * @return */
    public void initData(){
        for (int i=0;i<25;i++){
            arrayList.add("第"+i+"條數據");
        }
    }

    /** * 線程模擬加載數據 */
    class LoadDataThread extends Thread{
        @Override
        public void run() {
            initData();
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Message message = handler.obtainMessage();
            message.what = UPDATE_DATA;
            message.obj = arrayList;
            handler.sendMessage(message);
        }
    }

    private Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case UPDATE_DATA:
                    arrayList = (ArrayList<String>) msg.obj;
                    adapter.setmList(arrayList);
                    adapter.notifyDataSetChanged();
                    break;
            }
        }
    };
}

複製代碼

測試效果

jzman-blog

可關注微信公衆號:jzman-blog 獲取最新文章更新,一塊兒交流學習!this

jzman-blog
相關文章
相關標籤/搜索