1. 程式人生 > >RecyclerView實現底部載入更多功能

RecyclerView實現底部載入更多功能

     這兩天在公司沒有什麼任務分配,就研究了下咱們Google在Android5.0 推出的一個用來代替ListView的列表控制元件----RecyclerView。發現功能上確實比ListView強大了不少,可擴充套件性也增強了不少。但是使用過RecyclerView的Programmers應該都知道,RecyclerView無法直接程式碼新增頭佈局和腳佈局。那麼他喵的怎麼樣實現最常用的底部載入更多資料呢?帶著這樣的疑惑我在StackOverFlow上搜索到了一個有參考價值的答案並寫了一個Demo實現了它。參考連結附上:http://stackoverflow.com/questions/30681905/adding-items-to-endless-scroll-recyclerview-with-progressbar-at-bottom?answertab=active#tab-top  

廢話不多說,開始進入正題,直接上程式碼!

第一步:建立兩個介面

public interface LoadMoreDataListener {
    public abstract void loadMoreData();
}
public interface RecyclerOnItemClickListener {
    public abstract void onClick(View view);
}

第二步:根據XML中的佈局來建立一個Activity

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private TextView tv_empty;
    private List<String> list = new ArrayList<>();
    private List<String> moreData = new ArrayList<>();
    private List<String> refreshData = new ArrayList<>();
    private MyAdapter myAdapter;
    private Handler handler = new Handler();
    private SwipeRefreshLayout sfl;

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

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //// TODO: 點選FAB後的操作
            }
        });

        init();
    }

    private void init() {
        initData();
        initRefreshData();
        initMoreData();
        initView();
        initListener();
    }

    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.mRecyclerView);
        tv_empty = (TextView) findViewById(R.id.tv_empty);
        sfl = (SwipeRefreshLayout) findViewById(R.id.sfl);
        sfl.setColorSchemeColors(Color.parseColor("#FF4081"));
        //建立一個LinearLayoutManager物件
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        //建立adapter物件
        myAdapter = new MyAdapter(this, mRecyclerView);
        mRecyclerView.setAdapter(myAdapter);
        myAdapter.setData(list);//設定資料


        if (list.isEmpty()) {
            mRecyclerView.setVisibility(View.GONE);
            tv_empty.setVisibility(View.VISIBLE);
        } else {
            mRecyclerView.setVisibility(View.VISIBLE);
            tv_empty.setVisibility(View.GONE);
        }

    }

    //初始化資料
    private void initData() {
        for (int i = 0; i < 20; i++) {
            list.add("handsome is wrong?" + i);
        }
    }

    //初始化載入更多資料
    private void initMoreData() {
        for (int i = 0; i < 10; i++) {
            moreData.add("life is good" + i);
        }
    }

    private void initRefreshData() {
        for (int i = 0; i < 2; i++) {
            refreshData.add("refreshData" + i);
        }
    }


    //初始化監聽
    private void initListener() {
        sfl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                //模擬下拉重新整理資料操作
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        list.addAll(0, refreshData);
                        myAdapter.notifyDataSetChanged();
                        sfl.setRefreshing(false);
                    }
                }, 1000);
            }
        });

        //載入更多回調監聽
        myAdapter.setOnMoreDataLoadListener(new LoadMoreDataListener() {
            @Override
            public void loadMoreData() {
                //加入null值此時adapter會判斷item的type
                list.add(null);
                myAdapter.notifyDataSetChanged();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //移除重新整理的progressBar
                        list.remove(list.size() - 1);
                        myAdapter.notifyDataSetChanged();
                        list.addAll(moreData);
                        myAdapter.notifyDataSetChanged();
                        myAdapter.setLoaded();
                    }
                }, 2000);

            }
        });

        myAdapter.setOnItemClickListener(new RecyclerOnItemClickListener() {
            @Override
            public void onClick(View view) {
                //Toast.makeText(MainActivity.this, "能不能不要這麼帥", Toast.LENGTH_SHORT).show();
                Snackbar.make(view, "Iam BadGuy_Leo", Snackbar.LENGTH_SHORT).show();
            }
        });
    }


}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.byzk.loadmorerecyclerview.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
content_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.byzk.loadmorerecyclerview.MainActivity"
    tools:showIn="@layout/activity_main">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/sfl"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/mRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:padding="5dp"
            android:scrollbars="vertical">

        </android.support.v7.widget.RecyclerView>
    </android.support.v4.widget.SwipeRefreshLayout>

    <TextView
        android:id="@+id/tv_empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="暫無資料"
        android:textColor="@color/colorAccent"
        android:visibility="gone" />


</RelativeLayout>

建立RecyclerView的條目佈局 item_view
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clickable="true"
    android:orientation="horizontal"
    card_view:cardUseCompatPadding="true">


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:background="?android:selectableItemBackground"
        android:gravity="center">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_margin="5dp"
            android:text="Name"
            android:textColor="@android:color/black"
            android:textSize="18sp" />

    </RelativeLayout>

</android.support.v7.widget.CardView>

建立腳佈局item_footer
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="10dp">

    <ProgressBar
        android:id="@+id/pb"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

第三步:建立一個RecyclerView的Adapter 這一步是非常關鍵的一步,使用過RecyclerView的programmer應該都知道它無法設定條目點選事件——!所以必須自己寫一個介面回撥,來自己定製點選事件。程式碼如下
/**
 * Author: lihongxiang
 * Time: 上午 11:14
 * Email:[email protected]
 */

public class MyAdapter extends RecyclerView.Adapter {

    private static final int VIEW_ITEM = 0;
    private static final int VIEW_PROG = 1;
    private final Context mContext;
    private final RecyclerView mRecyclerView;
    private List<String> mData;
    private final LayoutInflater inflater;
    private boolean isLoading;
    private int totalItemCount;
    private int lastVisibleItemPosition;
    //當前滾動的position下面最小的items的臨界值
    private int visibleThreshold = 5;


    public MyAdapter(Context context, RecyclerView recyclerView) {
        mContext = context;
        inflater = LayoutInflater.from(context);
        mRecyclerView = recyclerView;
        if (mRecyclerView.getLayoutManager() instanceof LinearLayoutManager) {
            final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
            //mRecyclerView新增滑動事件監聽
            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    totalItemCount = linearLayoutManager.getItemCount();
                    lastVisibleItemPosition = linearLayoutManager.findLastVisibleItemPosition();
                    Log.d("test", "totalItemCount =" + totalItemCount + "-----" + "lastVisibleItemPosition =" + lastVisibleItemPosition);
                    if (!isLoading && totalItemCount <= (lastVisibleItemPosition + visibleThreshold)) {
                        //此時是重新整理狀態
                        if (mMoreDataListener != null)
                            mMoreDataListener.loadMoreData();
                        isLoading = true;
                    }
                }
            });
        }

    }

    public void setLoaded() {
        isLoading = false;
    }

   @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder holder;
        if (viewType == VIEW_ITEM) {
            holder = new MyViewHolder(inflater.inflate(R.layout.item_view, parent, false));
        } else {
            holder = new MyProgressViewHolder(inflater.inflate(R.layout.item_footer, parent, false));
        }
        return holder;
    }
 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof MyViewHolder) {
            if (((MyViewHolder) holder).tv_name != null)
                ((MyViewHolder) holder).tv_name.setText(mData.get(position));
        } else if (holder instanceof MyProgressViewHolder) {
            if (((MyProgressViewHolder) holder).pb != null)
                ((MyProgressViewHolder) holder).pb.setIndeterminate(true);
        }
    }


    @Override
    public int getItemCount() {
        return mData == null ? 0 : mData.size();
    }


    //根據不同的資料返回不同的viewType
    @Override
    public int getItemViewType(int position) {
        return mData.get(position) != null ? VIEW_ITEM : VIEW_PROG;

    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        private final TextView tv_name;

        public MyViewHolder(View itemView) {
            super(itemView);
            tv_name = (TextView) itemView.findViewById(R.id.tv_name);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mOnitemClickListener != null)
                        mOnitemClickListener.onClick(v);
                }
            });
        }

    }

    public class MyProgressViewHolder extends RecyclerView.ViewHolder {

        private final ProgressBar pb;

        public MyProgressViewHolder(View itemView) {
            super(itemView);
            pb = (ProgressBar) itemView.findViewById(R.id.pb);
        }

    }

    //設定資料的方法
    public void setData(List<String> data) {
        mData = data;
    }

    private LoadMoreDataListener mMoreDataListener;

    //載入更多監聽方法
    public void setOnMoreDataLoadListener(LoadMoreDataListener onMoreDataLoadListener) {
        mMoreDataListener = onMoreDataLoadListener;
    }

    private RecyclerOnItemClickListener mOnitemClickListener;

    //點選事件監聽方法
    public void setOnItemClickListener(RecyclerOnItemClickListener onItemClickListener) {
        mOnitemClickListener = onItemClickListener;
    }
}



通過以上幾部操作,就可以實現RecyclerView的底部載入更多的功能了,同時我用SwipeRefreshLayout實現了下拉重新整理。

今天第一次寫技術部落格,應該有很多地方寫的不夠妥當,望各位大神們指點!大笑實現效果如下!


相關推薦

RecyclerView實現底部載入功能

     這兩天在公司沒有什麼任務分配,就研究了下咱們Google在Android5.0 推出的一個用來代替ListView的列表控制元件----RecyclerView。發現功能上確實比ListView強大了不少,可擴充套件性也增強了不少。但是使用過RecyclerVie

Vue滾動底部 載入功能說明

今天,閒來無事就寫了一個關於Vue滾動底部載入更多的功能,話不多說,直接上程式碼!##先宣告我自己使用cli3寫的 做這個功能最主要的就是獲取3個值 scrollTop,clientHeight,scrollHeight 之後判斷3值之間的關係效果自然就出來了

使用Angularjs jQuery在手機上實現滑動條到底自動載入功能

                關鍵詞:directive infiniteScroll infiniteScrollDistance infiniteScrollDisabled $window.on $window.off在網上查了很多相關技術,在電腦瀏覽器上能正常的實現自動載入更多功能,但是放到手機AP

載入 功能實現

傳送ajax請求,獲取資料。判斷code狀態。通過模板引擎渲染的頁面。根據服務端資料的總條數判斷是否 顯示載入更多 按鈕。 程式碼 1 <script src="./static/assets/vendors/jquery/jquery.js"></script>

vue簡單實現滑動到底部載入

思路: 如果可視區的高度域dom元素的getBoundingClientRect().bottom高度相同說明已經到了底部,可以實現載入了 template: <template> <div class="content"> <d

繼承SwipeRefreshLayout實現上拉載入功能

Android 的SwipeRefreshLayout是一個比較好的下拉重新整理控制元件,現在已經有越來越多的企業開始使用這個控制元件了。但是遺憾的是這個控制元件並沒有上拉載入更多的功能,所以自己抽空,根據網上已有的例子,自己寫了一個。 首先必須要做的是建立一個類繼承SwipeRefresh

js實現載入功能例項 & 點選列表跳轉到詳情頁(tap)

寫在前面: 實際操作過程中,因為要用ajax去請求很多次資料,所以效能方面肯定會打折扣,拼接資料也是很麻煩,對於列表資料比較多的情況,寫起來不方便,也不好修改維護,不過功能實現很完整,我正在考慮去看看Vue裡面不用修改v-for嘗試著讓它在陣列上面做文章。 h5專案裡需要實現簡單的分頁功

jQuery+Asp.net 實現簡單的下拉載入功能

原來做過的商城專案現在需要增加下拉載入的功能,簡單的實現了一下。大概可以整理一下思路跟程式碼。 把需要下拉載入的內容進行轉為JSON處理存在當前頁面: <script type="text/javascript">var objson = eval([{"Id":"5991","produ

RecyclerView 上拉載入及滾動到底部的判斷(上)

關於下拉重新整理上拉載入更多,網上有很多例子;下拉重新整理比較簡單直接使用系統提供 SwipeRefreshLayout 即可,比較麻煩的是上拉載入更多,實現上拉的方法多種多樣,這裡對各個方法總結一下。 需求分析 RecyclerView 滾動到底部後,

js實現載入功能例項

這篇文章主要介紹了js實現載入更多功能的方法,以例項演示了載入更多的程式碼實現,非常具有實用價值,需要的朋友可以參考下 專案的一個前端頁面展示已購買商品時,要求能下拉載入更多。關於如何實現『載入更多』功能,網上有外掛可用,例如比較著名的使用iscro

載入功能實現

實現點選載入更多按鈕,以及上拉載入更多資料 import React from 'react' import PureRenderMixin from 'react-addons-pure-render-mixin' import { getLis

頁面滾動scroll到最底部 - 載入資料

頁面滾動scroll到最底部 - 載入更多資料 上拉內容區域,拉到底部實現分頁功能,向後端請求更多資料載入到頁面上 vue專案,使用純js實現,網上顯示了很多外掛可以實現,我使用了幾個,都不是我需要的效果,可能沒研究明白,沒辦法只能原生實現,具體實現思路如下~ 思路:通過滾動條判斷是否到

Xamarin.Forms 中ListView實現到底載入

Xamarin.Forms 中ListView實現到底載入更多 在移動應用開發中,為了更好的使用者體驗,ListView控制元件的分頁效果通常是利用ListView到底載入來實現。 在Xamarin.Forms中ListView如何實現到底載入呢? 通過利用ListView的ItemAppearing來

微信小程式實現滾動載入

微信小程式實現滾動載入更多 1.需要用到的元件和api scroll-view(可滾動檢視區域) wx.showToast(OBJECT)顯示訊息提示窗 2.需要用到的屬性  

自定義ListView下拉重新整理上拉載入功能

本篇的自定義listview包含下拉重新整理和上拉載入更多都是自定義。如果你想把重新整理的圖片做的更炫只需要更換下圖片加上適當的動畫就OK咯!由於沒有合適的圖片就用了個粗糙的。不好看請見諒。 //部分程式碼(都做了註釋): /** * @author: ZQF_

RecyclerView上拉載入下拉重新整理優雅姿勢

BaseRecyclerViewAdapterHelper+EasyRefreshLayout優雅實現recyclerView上拉載入更多下拉重新整理直接上程式碼:佈局:<com.ajguan.l

解決AppBarLayout 與SwipeRefreshLayout RecyclerView 上拉載入導致的延遲

import android.content.Context; import android.support.design.widget.AppBarLayout; import android.support.design.widget.CoordinatorLayout;

android 下拉重新整理+底部載入 QJPageReloadView使用

前:本文為QiaoJim原創,轉載請附原文連結,謝謝合作! ----------------------------------------------------------------------------------------------- 本篇主要簡單介紹QJ

js程式碼實現“文章載入

這裡提前準備好資料。 演示資料格式:blog.json { "list": [ { "title": "這是title", "u

vue中實現滾動載入

在以前的前端刀耕火種時代要實現滾動載入更多想要大家都是很快實現了,在vue會有一點麻煩,最近自己研究了一下,做了一個簡單的demo,供大家參考: <template> <div> <ul>