SwipeRecyclerView 的下拉重新整理和載入更多的實現,simple版,有引入包的過程

我能做的就是儘量向詩靠攏發表於2018-10-06

參考連結,框架地址
SwipeRecyclerView

效果圖:

  1. 下拉重新整理
  2. 載入更多

在這裡插入圖片描述

本部落格內容

  1. 導包步驟
  2. 關鍵點,易出錯地方說明
  3. 完整程式碼

0. 導包步驟

Gradle

implementation 'com.yanzhenjie:recyclerview-swipe:1.1.4'

關鍵點,易出錯地方

  1. 第一次載入資料。一定要掉用方法 不然重新整理和載入更多失效
mRecyclerView.loadMoreFinish(false, true); 
  1. 自定義載入更多 ,實現介面
SwipeMenuRecyclerView.LoadMoreView, 

注:載入更多動畫,預設只有一個,可以設定顏色,如果要其他載入動畫,需要自定義,本人能力有限,暫時不會,會後續更新

完整程式碼:(相關注釋在程式碼裡)

colors.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>
    <color name="text_color">#FF333333</color>

    <color name="red_normal">#FF0000</color>
    <color name="red_pressed">#FF6666</color>
    <color name="green_normal">#37C000</color>
    <color name="green_pressed">#30A070</color>
    <color name="purple_normal">#9932CC</color>
    <color name="purple_pressed">#9F79EE</color>

    <color name="white">#FFFFFFFF</color>
    <color name="white_pressed">#FFCFCFCF</color>

    <color name="divider_color">#FFB7B2B2</color>
</resources>

recyclerview_demo_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="wrap_content">
    <TextView
        android:id="@+id/name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="名字"
        android:textSize="45dp" />

</LinearLayout>

layout_fotter_loadmore.xml

<?xml version="1.0" encoding="utf-8"?>
<merge
    xmlns:android="http://schemas.android.com/apk/res/android">

    <com.yanzhenjie.loading.LoadingView
        android:id="@+id/loading_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>

    <TextView
        android:id="@+id/tv_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:visibility="gone"/>

</merge>

activity_main.xml

<?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"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.yanzhenjie.recyclerview.swipe.SwipeMenuRecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>

RecyclerViewAdaper.java


import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class RecyclerViewAdaper extends RecyclerView.Adapter<RecyclerViewAdaper.MyHoler> {

    private List<String> list;

    public RecyclerViewAdaper(List<String> list) {
        this.list = list;
    }


    @NonNull
    @Override
    public MyHoler onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
       View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_demo_item,viewGroup,false);
       MyHoler myHoler = new MyHoler(view);
        return myHoler;
    }

    @Override
    public void onBindViewHolder(@NonNull MyHoler myHoler, int i) {

        myHoler.name.setText(list.get(i));
    }

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

    public void notifyDataSetChanged(List<String> mDataList) {
        this.list = mDataList;
        this.notifyDataSetChanged();
    }

    public class MyHoler extends RecyclerView.ViewHolder {

        TextView name;
        public MyHoler(@NonNull View itemView) {
            super(itemView);
            name = itemView.findViewById(R.id.name);
        }
    }
}

MainActivity.java


import android.content.Context;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.yanzhenjie.loading.LoadingView;
import com.yanzhenjie.recyclerview.swipe.SwipeItemClickListener;
import com.yanzhenjie.recyclerview.swipe.SwipeMenuRecyclerView;
import com.yanzhenjie.recyclerview.swipe.widget.DefaultItemDecoration;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    private SwipeRefreshLayout mRefreshLayout;
    private SwipeMenuRecyclerView mRecyclerView;
    private RecyclerViewAdaper mAdapter;
    private List<String> mDataList;


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

    private void loadMore() {

        mRefreshLayout = findViewById(R.id.refreshLayout);
        mRefreshLayout.setOnRefreshListener(mRefreshListener); // 重新整理監聽。

        mRecyclerView = findViewById(R.id.recyclerView);
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));   // 佈局管理者
        mRecyclerView.addItemDecoration(new DefaultItemDecoration(ContextCompat.getColor(this, R.color.divider_color))); // 分割線樣式
        mRecyclerView.setSwipeItemClickListener(mItemClickListener);// item點選事件


        // 自定義的核心就是DefineLoadMoreView類。
        DefineLoadMoreView loadMoreView = new DefineLoadMoreView(this);
//        mRecyclerView.setAutoLoadMore(false); // 拉倒最下面時,是手動點選載入更多,還是自動載入更多,手動載入無載入更多動畫

//        mRecyclerView.addHeaderView(loadMoreView);  // 無效
        mRecyclerView.addFooterView(loadMoreView); // 新增為Footer。
        mRecyclerView.setLoadMoreView(loadMoreView); // 設定LoadMoreView更新監聽。
        mRecyclerView.setLoadMoreListener(mLoadMoreListener);

        mAdapter = new RecyclerViewAdaper(mDataList);
        mRecyclerView.setAdapter(mAdapter);

        // 請求伺服器載入資料。
        loadData();
    }

    /**
     * Item點選監聽。
     */
    private SwipeItemClickListener mItemClickListener = new SwipeItemClickListener() {
        @Override
        public void onItemClick(View itemView, int position) {
            Toast.makeText(MainActivity.this, "第" + position + "個", Toast.LENGTH_SHORT).show();
        }
    };

    /**
     * 下拉重新整理控制。
     * 重新整理頁面到初始載入的 item ,目的是使載入更多繼續有效
     */
    private SwipeRefreshLayout.OnRefreshListener mRefreshListener = new SwipeRefreshLayout.OnRefreshListener() {
        @Override
        public void onRefresh() {
            mRecyclerView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mRefreshLayout.setRefreshing(false);
                    loadData();
                }
            }, 1000); // 延時模擬請求伺服器。
        }
    };


    /**
     * 載入更多。
     * 第一次載入更多現實無資料載入
     * 使用下拉重新整理
     * 第二次載入更多資料,有更多資料被載入
     */
    int i = 1;   // i 只是為了更明顯顯示效果,可以刪除
    private SwipeMenuRecyclerView.LoadMoreListener mLoadMoreListener = new SwipeMenuRecyclerView.LoadMoreListener() {
        @Override
        public void onLoadMore() {
            mRecyclerView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(MainActivity.this, "" + i, Toast.LENGTH_SHORT).show();
                    if (i == 1) {
                        mRecyclerView.loadMoreFinish(false, false);
                        i++;
                    } else {
                        mRecyclerView.loadMoreFinish(false, true);
                        List<String> strings = createDataList(mAdapter.getItemCount());
                        mDataList.addAll(strings);
                        mAdapter.notifyItemRangeInserted(mDataList.size() - strings.size(), strings.size());
                    }
                }
            }, 1000);//  延時1000ms,執行
        }
    };

    // 載入更多是呼叫此方法 新增更多資料
    protected List<String> createDataList(int start) {
        List<String> strings = new ArrayList<>();
        for (int i = start; i < start + 20; i++) {
            strings.add("第" + i + "個Item");
        }
        return strings;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            finish();
        }
        return true;
    }

    /**
     * 第一次載入資料。一定要掉用方法 mRecyclerView.loadMoreFinish(false, true); 不然重新整理和載入更多失效
     */
    private void loadData() {
        mDataList = createDataList(0);
        mAdapter.notifyDataSetChanged(mDataList);
        mRefreshLayout.setRefreshing(false);

        // 第一次載入資料:一定要掉用這個方法。
        // 第一個引數:表示此次資料是否為空,假如你請求到的list為空(== null || list.size == 0),那麼這裡就要true。
        // 第二個引數:表示是否還有更多資料,根據伺服器返回給你的page等資訊判斷是否還有更多,這樣可以提供效能,如果不能判斷則傳true。
        mRecyclerView.loadMoreFinish(false, true);
    }

    /**
     * 這是這個類的主角,如何自定義LoadMoreView。
     */
    static final class DefineLoadMoreView extends LinearLayout implements SwipeMenuRecyclerView.LoadMoreView, View.OnClickListener {

        private LoadingView mLoadingView;  // 載入更多的動畫
        private TextView mTvMessage;

        private SwipeMenuRecyclerView.LoadMoreListener mLoadMoreListener;

        public DefineLoadMoreView(Context context) {
            super(context);
            setLayoutParams(new ViewGroup.LayoutParams(-1, -2));
            setGravity(Gravity.CENTER);
            setVisibility(GONE);

            DisplayMetrics displayMetrics = getResources().getDisplayMetrics();

            int minHeight = (int) (displayMetrics.density * 60 + 0.5);
            setMinimumHeight(minHeight);

            inflate(context, R.layout.layout_fotter_loadmore, this);
            mLoadingView = findViewById(R.id.loading_view);
            mTvMessage = findViewById(R.id.tv_message);

            int color1 = ContextCompat.getColor(getContext(), R.color.green_normal);
            int color2 = ContextCompat.getColor(getContext(), R.color.purple_normal);
            int color3 = ContextCompat.getColor(getContext(), R.color.colorAccent);

            mLoadingView.setCircleColors(color1, color2, color3);
            // 載入更多動畫,只有圓圈轉動的動畫
            setOnClickListener(this);
        }

        /**
         * 馬上開始回撥載入更多了,這裡應該顯示進度條。
         */

        @Override
        public void onLoading() {
            setVisibility(VISIBLE);
            mLoadingView.setVisibility(VISIBLE);
            mTvMessage.setVisibility(VISIBLE);
            mTvMessage.setText("正在努力載入,請稍後");
        }

        /**
         * 載入更多完成了。
         *
         * @param dataEmpty 是否請求到空資料。
         * @param hasMore   是否還有更多資料等待請求。
         */
        @Override
        public void onLoadFinish(boolean dataEmpty, boolean hasMore) {
            if (!hasMore) {
                setVisibility(VISIBLE);
                if (dataEmpty) {
                    mLoadingView.setVisibility(GONE);
                    mTvMessage.setVisibility(VISIBLE);
                    mTvMessage.setText("暫時沒有資料");
                } else {
                    mLoadingView.setVisibility(GONE);
                    mTvMessage.setVisibility(VISIBLE);
                    mTvMessage.setText("沒有更多資料啦");
                }
            } else {
                setVisibility(INVISIBLE);
            }
        }

        /**
         * 呼叫了setAutoLoadMore(false)後,在需要載入更多的時候,這個方法會被呼叫,並傳入載入更多的listener。
         */
        @Override
        public void onWaitToLoadMore(SwipeMenuRecyclerView.LoadMoreListener loadMoreListener) {
            this.mLoadMoreListener = loadMoreListener;

            setVisibility(VISIBLE);
            mLoadingView.setVisibility(GONE);
            mTvMessage.setVisibility(VISIBLE);
            mTvMessage.setText("點我載入更多");
        }

        /**
         * 載入出錯啦,下面的錯誤碼和錯誤資訊二選一。
         *
         * @param errorCode    錯誤碼。
         * @param errorMessage 錯誤資訊。
         */
        @Override
        public void onLoadError(int errorCode, String errorMessage) {
            setVisibility(VISIBLE);
            mLoadingView.setVisibility(GONE);
            mTvMessage.setVisibility(VISIBLE);

            // 這裡要不直接設定錯誤資訊,要不根據errorCode動態設定錯誤資料。
            mTvMessage.setText(errorMessage);
        }

        /**
         * 非自動載入更多時mLoadMoreListener才不為空。
         */
        @Override
        public void onClick(View v) {
            if (mLoadMoreListener != null) mLoadMoreListener.onLoadMore();
        }
    }
}

相關文章