自定義RecyclerView添加HeaderView,添加FooterView,實現(xiàn)滑動到底部,加載更多

顯示效果圖

同步更新CSDN

http://blog.csdn.net/wuyinlei/article/details/52662960

PS

接觸過RecyclerView的應(yīng)該會有個感覺,那就是我不想在使用ListView和GridView了,因為這個控件是可以實現(xiàn)那兩個控件(ListView和GridView)所實現(xiàn)的幾乎所有吧,哈哈我也沒用他們倆干過多少的變種哈。所以在新項目中
自然也要使用這個RecyclerView來實現(xiàn)效果啊。

產(chǎn)品要求

頭部可以任意定義的,比如說Banner圖輪播,各種列表顯示,幾種分類,然后滑動到底部(RecyclerView)顯示加載更多提示,然后子線程請求數(shù)據(jù),進行數(shù)據(jù)加載,更新UI,如果沒有數(shù)據(jù),就給一個友好的用戶提示。

剛開始想法

因為這個看起來很好辦的,整個放到一個ScrollView里面,這樣可以實現(xiàn)整體可以滑動,然后監(jiān)聽ScrollView滑動到底部的事件,然后去請求數(shù)據(jù),但是我自己實現(xiàn)過一次,效果是可以了,但是滑動起來是有阻尼的(感覺啊),滑動不過2-3個item就會停止,感覺雖然效果實現(xiàn)了,但是用戶體驗卻不怎么好,(PS:還沒找到為啥有阻尼,可能自己使用了一個RelativeLayout的(實現(xiàn)上拉加載更多監(jiān)聽和下拉刷新監(jiān)聽的自定義類吧)),有空去自己看下原因吧。

去實現(xiàn)

說實話,對于RecyclerView自己還是了解一些的,也寫過一些簡單的介紹,之前也自己實現(xiàn)了一個下拉加載更多的提交到的了git,大家可以去參考下。(小弟功底有限,還請多多包涵https://github.com/wuyinlei/RecycleViewRefreshDemo),那么今天這個實現(xiàn)的上拉加載更多也是按照這個思路去實現(xiàn)的,就是通過監(jiān)聽RecyclerView滑動到底部的方法來判斷是否要顯示底布局,然后去加載數(shù)據(jù)。

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override 
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
            } 
 
            @Override 
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                //是否是最后一個顯示的item位置
                int lastVisiableItemPosition = manager.findLastVisibleItemPosition();
                if (lastVisiableItemPosition + 1 == mCategoryAdapter.getItemCount()){
                    if (!isLoading){
                        isLoading = true;  //標(biāo)志位  防止重復(fù)加載數(shù)據(jù)
                        handler.postDelayed(new Runnable() {
                            @Override 
                            public void run() { 
                                //requestData(); 
                                requestLoadMoreData();   //請求數(shù)據(jù)
                                //    Toast.makeText(MainActivity.this, "已經(jīng)沒有新的了", Toast.LENGTH_SHORT).show(); 
                                isLoading = false;  //加載完成數(shù)據(jù)   更新標(biāo)志位
                                // adapter.notifyItemRemoved(adapter.getItemCount()); 
                            } 
                        },2000); 
                    } 
                } 
            } 
        }); 
 private void requestLoadMoreData(){ 
 
        index++;  //這個是模擬加載幾次之后通知沒有數(shù)據(jù)的
 
        if (index <= 3) {
            initData(); 
        } else { 
            Toast.makeText(MainActivity.this, "已經(jīng)沒有新的了", Toast.LENGTH_SHORT).show();
        } 
        // swipeRefreshLayout.setRefreshing(false); 
        mCategoryAdapter.notifyItemRemoved(mCategoryAdapter.getItemCount());  //加載完成之后移除footerView,也就是隱藏(去除加載中的view)
 
    } 
 

這樣就可以很簡單的實現(xiàn)上拉加載更多的邏輯實現(xiàn)了,(這個需要添加一個footerView,接下來就來分析一下如果添加FooterView,還有就是添加HeaderView)

Adapter如果寫

首先定義三個變量用來說明是哪一個View,(HeaderView、View、FooterView)

    public static final int TYPE_HEADER = 0;
    public static final int TYPE_NORMAL = 1;
    private static final int TYPE_FOOTER = 2;
RecyclerView提供個getItemViewType(int position)方法來判斷需要展示的哪種類型的View
        if (mHeaderView == null) return TYPE_NORMAL;
        if (position == 0) return TYPE_HEADER;
        if (mHeaderView != null && position +1 == getItemCount()) return TYPE_FOOTER;
        if (mHeaderView == null && position  == getItemCount()) return TYPE_FOOTER;
        return TYPE_NORMAL;

對于FooterView和HeaderView我們可以共用同一個ViewHolder(其實也就是使用一下,對于HeaderView的點擊事件我們是在Activity或者Fragment里面去寫的,后面有介紹)。這個時候我們在綁定ViewHolder的時候去判斷我們需要展示的哪種View

  @Override 
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mHeaderView != null && viewType == TYPE_HEADER) return new ViewHolder(mHeaderView);
        if (viewType == TYPE_FOOTER) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_foot, parent, false);
            return new FooterViewHolder(view);
        } 
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.category_item_layout, parent, false);
        return new ViewHolder(view);
    } 
對于正常View的ViewHolder也是正常的寫,按照之前的正常使用RecyclerView的方式。例如:
class ViewHolder extends RecyclerView.ViewHolder { 
 
        private LinearLayout mCategoryLl;
        private ImageView mCategoryImg;
        private TextView mCategoryTitle, mCategoryDes;
 
        public ViewHolder(View itemView) {
            super(itemView);
            mCategoryImg = (ImageView) itemView.findViewById(R.id.category_book_img);
            mCategoryTitle = (TextView) itemView.findViewById(R.id.category_title);
            mCategoryDes = (TextView) itemView.findViewById(R.id.category_book_des);
            mCategoryLl = (LinearLayout) itemView.findViewById(R.id.category_ll);
        } 
    } 
對于HeaderView,我們的處理方式(在Adapter里面進行)
public void setHeaderView(View headerView) {
        mHeaderView = headerView;
        notifyItemInserted(0);   //位于頂部,通知一下view的第一項
    } 
這個時候通過在activity或者fragment里面進行
 private void setHeader(RecyclerView view) {
        //找到控件布局
        View header = LayoutInflater.from(this).inflate(R.layout.category_item_header, view, false);
 
        mRlBoy = (RelativeLayout) header.findViewById(R.id.rl_boy);
        mRlGirl = (RelativeLayout) header.findViewById(R.id.rl_girl);
        mRlEnd = (RelativeLayout) header.findViewById(R.id.rl_end);
        mRlUpdate = (RelativeLayout) header.findViewById(R.id.rl_update);
 
        mCategoryAdapter.setHeaderView(header); //設(shè)置headerview
    } 
HeaderView控件監(jiān)聽方式可以如下:
  private void initListener() { 
        mRlBoy.setOnClickListener(this);
        mRlGirl.setOnClickListener(this);
        mRlEnd.setOnClickListener(this);
        mRlUpdate.setOnClickListener(this);
    } 

基本到此為止,就能實現(xiàn)一般的需求了,如果有復(fù)雜的,應(yīng)該還是存在其他方式的實現(xiàn),以后有空或者有此需求之后自己在去研究。

解決在GridView形式下,HeaderView和FooterView只顯示在最前面一個或者最后面一個(而不是占據(jù)一行bug)
 final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
        gridLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(gridLayoutManager);

        // gridLayoutManager  布局管理器
        gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
            @Override
            public int getSpanSize(int position) {
                //如果是第一個(添加HeaderView)   還有就是最后一個(FooterView)
                return position == mCategoryBean.size() + 1 || position == 0 ? gridLayoutManager.getSpanCount() : 1;
            }
        });

效果如開始哈,在次就貼下代碼吧。

代碼傳動門:demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容