Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android RecyclerView瀑布流布局添加Footer實現上拉加載

Android RecyclerView瀑布流布局添加Footer實現上拉加載

編輯:關於android開發

Android RecyclerView瀑布流布局添加Footer實現上拉加載


這篇文章應該是晚到了好幾個月,之前想寫,但是中途遇到了一些棘手的問題,無奈沒有去寫。寫這篇文章的最初來源是一個朋友問我在Android中如何實現瀑布流布局?,當時我的回答是使用RecyclerView,後來他又問我那怎麼實現上拉加載並添加Footer呢?我想都沒想就回答他根據type的不同去添加一個Footer,監聽滾動事件,當滑動到最後顯示footer並回調對應的接口,那麼,這個過程就會遇到一個Footer布局顯示的問題,就像下面這張圖一樣。

瀑布流布局

可以看到,我們 的 Footer布局並沒有占據全屏,而是作為瀑布流布局的一部分了。這顯然不是我們想要的。

當然,除了為瀑布流布局添加Footer實現上拉加載外,我們還想要對GridLayout添加Footer實現上拉加載,同樣的,在GridLayout中,布局也不是我們想要的結果。效果也是這樣。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="網格布局" src="http://www.bkjia.com/uploads/allimg/151204/04191V356-1.jpg" title="\" />

也把我們的Footer作為了GridLayout的一部分,並沒有全屏進行顯示。

那麼接下來,我們需要解決幾個問題,即可以實現正確的添加Footer並實現上拉加載功能了。

如何實現上拉加載更多?這個解決方法很簡單,就是為RecyclerView添加滾動監聽事件,根據布局的不同編寫對應的邏輯代碼,實現滑到到底部加載更多的功能。 如何正確的添加Footer,使其能夠占據寬度為全屏顯示?這個有點棘手,但是並不是不能解決,我們需要對適配器進行一些處理就能實現該功能。 此外我們還想要添加一個Header,用於展示ViewPager或者圖片等信息。這個原理和添加Footer是一樣的。

首先定義一個處理上拉加載的接口

 {
    /**
     * 加載更多前回調,比如顯示Footer的操作
     */
    void onStart();

    /**
     * 加載更多業務處理,如網絡請求數據
     */
    void onLoadMore();

    /**
     * 由於onLoadMore可能是異步調用的,所以onFinish需要手動調用,完成數據的刷新,隱藏Footer等
     * @param list onLoadMore中返回的數據
     */
    void onFinish(List list);
}
 data-snippet-id=ext.cc07bacad0a477ab79bf37c7a4816d6c data-snippet-saved=false data-csrftoken=ZTMcU6vd-NgDp77SKpjjlkSUOG4bk4z3Haps data-codota-status=done>public interface OnLoadMoreListener {
    /**
     * 加載更多前回調,比如顯示Footer的操作
     */
    void onStart();

    /**
     * 加載更多業務處理,如網絡請求數據
     */
    void onLoadMore();

    /**
     * 由於onLoadMore可能是異步調用的,所以onFinish需要手動調用,完成數據的刷新,隱藏Footer等
     * @param list onLoadMore中返回的數據
     */
    void onFinish(List list);
}

然後我們自己定義一個抽象類,用於繼承RecyclerView.OnScrollListener並實現我們定義的接口OnLoadMoreListener,如果需要上拉加載更多,直接為RecyclerView添加滾動監聽為我們的實現類即可,就像這樣子

(){
            @Override
            public void onStart() {

            }

            @Override
            public void onLoadMore() {

            }

            @Override
            public void onFinish(List contents) {

            }
        }); data-snippet-id=ext.0844dddee4a714a4268444c38a586fc9 data-snippet-saved=false data-csrftoken=4LFZmucK-NSOMJIOwLJFxok_hrTLKo8Fn7k4 data-codota-status=done>mRecyclerView.addOnScrollListener(new OnRecyclerViewScrollListener(){
            @Override
            public void onStart() {

            }

            @Override
            public void onLoadMore() {

            }

            @Override
            public void onFinish(List contents) {

            }
        });

由於RecyclerView默認有三種布局,所以我們要對這三種布局分別進行判斷上拉加載,處理的邏輯有點不同,首先添加如下定義

 extends RecyclerView.OnScrollListener implements OnLoadMoreListener {

    public static enum layoutManagerType {
        LINEAR_LAYOUT,
        GRID_LAYOUT,
        STAGGERED_GRID_LAYOUT
    }
    protected layoutManagerType mLayoutManagerType;

    private boolean mIsLoadingMore = false;

    public boolean isLoadingMore() {
        return mIsLoadingMore;
    }

    public void setLoadingMore(boolean loadingMore) {
        mIsLoadingMore = loadingMore;
    }

}
 data-snippet-id=ext.967dc8ab948ebc337a4f7395fe22dd9c data-snippet-saved=false data-csrftoken=wKKbaPlN-NACfZ3XMzeRxhcjoTme0vLqzs0A data-codota-status=done>public abstract class OnRecyclerViewScrollListener extends RecyclerView.OnScrollListener implements OnLoadMoreListener {

    public static enum layoutManagerType {
        LINEAR_LAYOUT,
        GRID_LAYOUT,
        STAGGERED_GRID_LAYOUT
    }
    protected layoutManagerType mLayoutManagerType;

    private boolean mIsLoadingMore = false;

    public boolean isLoadingMore() {
        return mIsLoadingMore;
    }

    public void setLoadingMore(boolean loadingMore) {
        mIsLoadingMore = loadingMore;
    }

}

這個類是泛型的,接收一個實現了Item接口的類。主要是定義了一個枚舉類,裡面是布局的類型,然後是一個布爾變量,用於判斷當前是否正在加載更多。

RecyclerViewAdapter.Item主要是一個接口,其定義如下

    public interface Item {
        int TYPE_HEADER = 0;
        int TYPE_FOOTER = 1;
        /**
         * 返回item類型,其值不能為0或者1;
         *
         * @return
         */
        int getType();
    }

我們的RecyclerView的Item實體類需要實現Item接口,並返還item的類型,默認情況下header的類型為0,footer的類型為1。

接下來最重要的事就是實現onScrolledonScrollStateChanged方法,根據布局的不同判斷是否需要加載更多操作。

 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE
                && lastVisibleItemPosition >= totalItemCount - 1) {
            if (!isLoadingMore()){
                mIsLoadingMore =true;
                onStart();
                onLoadMore();
            }
        }
    }

    private int findMax(int[] lastPositions) {
        int max = lastPositions[0];
        for (int value : lastPositions) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    } data-snippet-id=ext.b411da8ce079e7d03088c032c7dbb07b data-snippet-saved=false data-csrftoken=ZfLZwkcC-e0C6W5TY9NiIB3-uEal0irNnhIY data-codota-status=done>    private int[] lastPositions;
    private int lastVisibleItemPosition;
    private int currentScrollState = 0;

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

        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (mLayoutManagerType == null) {
            if (layoutManager instanceof LinearLayoutManager) {
                mLayoutManagerType = layoutManagerType.LINEAR_LAYOUT;
            } else if (layoutManager instanceof GridLayoutManager) {
                mLayoutManagerType = layoutManagerType.GRID_LAYOUT;
            } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                mLayoutManagerType = layoutManagerType.STAGGERED_GRID_LAYOUT;
            } else {
                throw new RuntimeException(Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager);
            }
        }

        switch (mLayoutManagerType) {
            case LINEAR_LAYOUT:
                lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
                break;
            case GRID_LAYOUT:
                lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
                break;
            case STAGGERED_GRID_LAYOUT:
                StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                if (lastPositions == null) {
                    lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
                }
                staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
                lastVisibleItemPosition = findMax(lastPositions);
                break;
            default:
                break;
        }
    }

    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
        currentScrollState = newState;
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        int visibleItemCount = layoutManager.getChildCount();
        int totalItemCount = layoutManager.getItemCount();
        if (visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE
                && lastVisibleItemPosition >= totalItemCount - 1) {
            if (!isLoadingMore()){
                mIsLoadingMore =true;
                onStart();
                onLoadMore();
            }
        }
    }

    private int findMax(int[] lastPositions) {
        int max = lastPositions[0];
        for (int value : lastPositions) {
            if (value > max) {
                max = value;
            }
        }
        return max;
    }

具體邏輯見代碼,LinearLayoutManager 和 GridLayoutManager的處理邏輯類似,只不過StaggeredGridLayoutManager 的處理稍微復雜一點,因為布局是錯亂的,所以需要自己找到最底下的布局是哪一個,關鍵代碼就是這兩句

staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
lastVisibleItemPosition = findMax(lastPositions);

就這樣子,其實已經出現了上拉加載更多的功能了,這時候你使用一下這個滾動監聽,是完全沒有什麼問題的,只不過沒有顯示Footer布局而已。接下來我們最重要的事就是改造適配器。

 extends RecyclerView.Adapter {
    public interface Item {
        int TYPE_HEADER = 0;
        int TYPE_FOOTER = 1;
        /**
         * 返回item類型,其值不能為0或者1;
         *
         * @return
         */
        int getType();
    }
} data-snippet-id=ext.01de7a81de0436de231e7ad760887dc6 data-snippet-saved=false data-csrftoken=nYu9aDrN-39XDjVOtmj-NZc7IqaJOGHYqM2M data-codota-status=done>public abstract class RecyclerViewAdapter extends RecyclerView.Adapter {
    public interface Item {
        int TYPE_HEADER = 0;
        int TYPE_FOOTER = 1;
        /**
         * 返回item類型,其值不能為0或者1;
         *
         * @return
         */
        int getType();
    }
}

這是最基本的結構,內部定義了上面提到的Item接口,我們的Item實體類需要實現該接口,用於判斷Item的類型。

定義Getter和Setter方法

 list = null;
    protected int headerViewRes;
    protected int footerViewRes;
    protected boolean hasHeader = false;
    protected boolean hasFooter = false;


    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public boolean isHeader(int position) {
        return hasHeader() && position == 0;
    }

    public boolean isFooter(int position) {
        if(hasHeader()){
            return hasFooter() && position == list.size() + 1;
        }else {
            return hasFooter() && position == list.size();
        }
    }

    public int getHeaderView() {
        return headerViewRes;
    }

    public int getFooterView() {
        return footerViewRes;
    }

    public void setHeaderView(int headerViewRes) {

        if (headerViewRes != 0) {
            if (!hasHeader()){
                this.headerViewRes = headerViewRes;
                this.hasHeader = true;
                notifyItemInserted(0);
            }else{
                this.headerViewRes = headerViewRes;
                notifyDataSetChanged();
            }

        } else {
            if (hasHeader()){
                this.hasHeader = false;
                notifyItemRemoved(0);
            }

        }

    }

    public void setFooterView(int footerViewRes) {
        if (footerViewRes != 0) {
            if (!hasFooter()){
                this.footerViewRes = footerViewRes;
                this.hasFooter = true;
                if (hasHeader()){
                    notifyItemInserted(list.size()+1);
                }else{
                    notifyItemInserted(list.size());
                }
            }else{
                this.footerViewRes = footerViewRes;
                notifyDataSetChanged();
            }

        } else {
            if(hasFooter()){
                this.hasFooter = false;
                if (hasHeader()){
                    notifyItemRemoved(list.size()+1);
                }else{
                    notifyItemRemoved(list.size());
                }

            }

        }

    }

    public boolean hasHeader() {
        return hasHeader;
    }

    public boolean hasFooter() {
        return hasFooter;
    }
 data-snippet-id=ext.72dd5fef3970bc085d96a545ec056844 data-snippet-saved=false data-csrftoken=G8UjOima-1-KCwXw_kyU44e5miZtTO5o-yE8 data-codota-status=done>    protected List list = null;
    protected int headerViewRes;
    protected int footerViewRes;
    protected boolean hasHeader = false;
    protected boolean hasFooter = false;


    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public boolean isHeader(int position) {
        return hasHeader() && position == 0;
    }

    public boolean isFooter(int position) {
        if(hasHeader()){
            return hasFooter() && position == list.size() + 1;
        }else {
            return hasFooter() && position == list.size();
        }
    }

    public int getHeaderView() {
        return headerViewRes;
    }

    public int getFooterView() {
        return footerViewRes;
    }

    public void setHeaderView(int headerViewRes) {

        if (headerViewRes != 0) {
            if (!hasHeader()){
                this.headerViewRes = headerViewRes;
                this.hasHeader = true;
                notifyItemInserted(0);
            }else{
                this.headerViewRes = headerViewRes;
                notifyDataSetChanged();
            }

        } else {
            if (hasHeader()){
                this.hasHeader = false;
                notifyItemRemoved(0);
            }

        }

    }

    public void setFooterView(int footerViewRes) {
        if (footerViewRes != 0) {
            if (!hasFooter()){
                this.footerViewRes = footerViewRes;
                this.hasFooter = true;
                if (hasHeader()){
                    notifyItemInserted(list.size()+1);
                }else{
                    notifyItemInserted(list.size());
                }
            }else{
                this.footerViewRes = footerViewRes;
                notifyDataSetChanged();
            }

        } else {
            if(hasFooter()){
                this.hasFooter = false;
                if (hasHeader()){
                    notifyItemRemoved(list.size()+1);
                }else{
                    notifyItemRemoved(list.size());
                }

            }

        }

    }

    public boolean hasHeader() {
        return hasHeader;
    }

    public boolean hasFooter() {
        return hasFooter;
    }

內部邏輯看上去一大堆,其實並不復雜,關鍵是需要判斷Header存不存在,Header存在與不存在的情況下Footer的位置是不同的,注意這一點,編寫對應的邏輯即可,當然你的邏輯可以與我不同。

接下來是構造函數,傳入我們的數據集,Header和Footer的布局資源

 list) {
        this.list = list;
    }

    public RecyclerViewAdapter(List list, int headerViewRes) {
        this.list = list;
        setHeaderView(headerViewRes);
    }

    public RecyclerViewAdapter(List list, int headerViewRes, int footerViewRes) {
        this.list = list;
        setHeaderView(headerViewRes);
        setFooterView(footerViewRes);
    } data-snippet-id=ext.6372b2bda1ab6b1e7140ac92cd96e966 data-snippet-saved=false data-csrftoken=k6EABupp-4lQ3IJEjk1h7etGMpwNpCMNrukE data-codota-status=done>    public RecyclerViewAdapter(List list) {
        this.list = list;
    }

    public RecyclerViewAdapter(List list, int headerViewRes) {
        this.list = list;
        setHeaderView(headerViewRes);
    }

    public RecyclerViewAdapter(List list, int headerViewRes, int footerViewRes) {
        this.list = list;
        setHeaderView(headerViewRes);
        setFooterView(footerViewRes);
    }

實現我們的Header布局和Footer布局的ViewHolder,其實就是定義兩個類

    static class HeaderViewHolder extends RecyclerView.ViewHolder {
        public HeaderViewHolder(View itemView) {
            super(itemView);
        }
    }

    static class FooterViewHolder extends RecyclerView.ViewHolder {
        public FooterViewHolder(View itemView) {
            super(itemView);
        }
    }

重寫getItemCountgetItemViewType方法

getItemCount中我們需要根據是否有Header和Footer來返回對應的Item數

  @Override
    public int getItemCount() {
        int count = 0;
        count += (hasHeader() ? 1 : 0);
        count += (hasFooter() ? 1 : 0);
        count += list.size();
        return count;
    }

getItemViewType就需要根據判斷位置判斷是否具有Header來判斷對應的Item的類型

 @Override
    public int getItemViewType(int position) {
        int size = list.size();
        if (hasHeader()) {
            if (position == 0) {
                return Item.TYPE_HEADER;
            } else {
                if (position == size + 1) {
                    return Item.TYPE_FOOTER;
                } else {
                    return list.get(position - 1).getType();
                }
            }

        } else {
            if (position == size) {
                return Item.TYPE_FOOTER;
            } else {
                return list.get(position).getType();
            }
        }
    }

創建ViewHolder,根據類型的不同創建對應的ViewHolder,如果不是Header和Footer之外的類型,交由抽象方法onCreateHolder處理


    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (hasHeader() && viewType == Item.TYPE_HEADER) {
            View v = LayoutInflater.from(parent.getContext()).inflate(getHeaderView(), parent, false);
            return new HeaderViewHolder(v);
        } else if (hasFooter() && viewType == Item.TYPE_FOOTER) {
            View v = LayoutInflater.from(parent.getContext()).inflate(getFooterView(), parent, false);
            return new FooterViewHolder(v);
        } else {
            return onCreateHolder(parent, viewType);
        }
    }
    public abstract RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType);

綁定數據,同創建ViewHolder,根據位置的不同來獲得item的類型,如果是Header就回調抽象方法onBindHeaderView,如果是Footer就回調抽象方法onBindFooterView,否則就回調抽象方法onBindItemView,將對應的holder和實體類傳入。

 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == Item.TYPE_HEADER) {
            HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
            View headerView = headerHolder.itemView;

            onBindHeaderView(headerView);
        } else if (getItemViewType(position) == Item.TYPE_FOOTER) {
            FooterViewHolder footerHolder = (FooterViewHolder) holder;
            View footerView = footerHolder.itemView;

            onBindFooterView(footerView);
        } else {
            T i = getItemByPosition(position);
            onBindItemView(holder, i);

        }

    }
    protected abstract void onBindHeaderView(View headerView);

    protected abstract void onBindFooterView(View footerView);

    protected abstract void onBindItemView(RecyclerView.ViewHolder holder, T item);

這樣子,已經能夠處理Header和Footer了,但是顯示位置還是不正確的,接下來我們需要對GridLayout和StaggeredGridLayout做特殊處理。

定義抽象類GridLayoutAdapter繼承RecyclerViewAdapter

 extends RecyclerViewAdapter {
    public GridLayoutAdapter(List list) {
        super(list);
    }
    public GridLayoutAdapter(List list, int headerViewRes) {
        super(list, headerViewRes);
    }

    public GridLayoutAdapter(List list, int headerViewRes, int footerViewRes) {
        super(list, headerViewRes, footerViewRes);
    }
}
 data-snippet-id=ext.5cd27c2bff04b4da41feaaf441a38265 data-snippet-saved=false data-csrftoken=w9Cl4TWF-O0ViW_ZUngJb8YbZI0s7dPij290 data-codota-status=done>public abstract class GridLayoutAdapter extends RecyclerViewAdapter {
    public GridLayoutAdapter(List list) {
        super(list);
    }
    public GridLayoutAdapter(List list, int headerViewRes) {
        super(list, headerViewRes);
    }

    public GridLayoutAdapter(List list, int headerViewRes, int footerViewRes) {
        super(list, headerViewRes, footerViewRes);
    }
}

定義一個內部類GridSpanSizeLookup 繼承GridLayoutManager.SpanSizeLookup,調用父類isHeader和isFooter方法判斷是否是頭或者尾,如果是則返回gridManager.getSpanCount();即一個item占據一行的span數,否則就返回1


    class GridSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
        @Override
        public int getSpanSize(int position) {
            if (isHeader(position) || isFooter(position)) {
                return gridManager.getSpanCount();
            }
            return 1;
        }
    }

最重要的一步就是重寫onAttachedToRecyclerView,判斷是否是GridLayout布局,然後通過setSpanSizeLookup設置為我們的內部類

    private GridSpanSizeLookup mGridSpanSizeLookup;
    private GridLayoutManager gridManager;
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            gridManager = ((GridLayoutManager) manager);
            if (mGridSpanSizeLookup == null) {
                mGridSpanSizeLookup = new GridSpanSizeLookup();
            }
            gridManager.setSpanSizeLookup(mGridSpanSizeLookup);
        }
    }

同理,瀑布流布局也需要進行同樣的操作。

 extends RecyclerViewAdapter {
    public StaggeredGridLayoutAdapter(List list) {
        super(list);
    }

    public StaggeredGridLayoutAdapter(List list, int headerViewRes) {
        super(list, headerViewRes);
    }

    public StaggeredGridLayoutAdapter(List list, int headerViewRes, int footerViewRes) {
        super(list, headerViewRes, footerViewRes);
    }
} data-snippet-id=ext.e812372627c676958c74437dfafa2b7e data-snippet-saved=false data-csrftoken=rwV4GwoP-01GxkZUjrV3hy5T16J6sdHVtNfw data-codota-status=done>public abstract class StaggeredGridLayoutAdapter extends RecyclerViewAdapter {
    public StaggeredGridLayoutAdapter(List list) {
        super(list);
    }

    public StaggeredGridLayoutAdapter(List list, int headerViewRes) {
        super(list, headerViewRes);
    }

    public StaggeredGridLayoutAdapter(List list, int headerViewRes, int footerViewRes) {
        super(list, headerViewRes, footerViewRes);
    }
}

但是 StaggeredGridLayoutManager中沒有setSpanSizeLookup方法,慶幸的是StaggeredGridLayoutManager.LayoutParams中有setFullSpan方法可以達到同樣的效果。

這時候重寫的不再是onAttachedToRecyclerView方法而是onViewAttachedToWindow方法

  @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        if (isStaggeredGridLayout(holder)) {
            handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
        }
    }

    private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
        ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
        if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
            return true;
        }
        return false;
    }

    protected void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
        if (isHeader(position) || isFooter(position)) {
            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
            p.setFullSpan(true);
        }
    }

基本上,到這裡為止,就完成了所有的工作,在使用的時候要實現上拉加載顯示Footer,如果是瀑布流布局,就需要繼承StaggeredGridLayoutAdapter,如果是網格布局,就需要繼承GridLayoutAdapter,其他情況下,繼承RecyclerViewAdapter即可。

為了演示,這裡簡單進行使用,首先定義一個Item的實現類

public class Content implements RecyclerViewAdapter.Item {
    private int TYPE = 2;
    private String title;
    private String desc;
    private String url;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getIconUrl() {
        return url;
    }

    public void setIconUrl(String iconUrl) {
        this.url = iconUrl;
    }

    @Override
    public String toString() {
        return Content{ +
                title=' + title + ''' +
                , desc=' + desc + ''' +
                , icon= + url +
                '}';
    }

    @Override
    public int getType() {
        return TYPE;
    }
}

我們這裡以瀑布流布局為例,因此繼承StaggeredGridLayoutAdapter實現我們的適配器。

 {


    public MyAdapter(List list, int headerViewRes) {
        super(list, headerViewRes);
    }

    public MyAdapter(List list) {
        super(list);
    }

    public MyAdapter(List list, int headerViewRes, int footerViewRes) {
        super(list, headerViewRes, footerViewRes);
    }

    @Override
    public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) {
        View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.item_content,parent,false);
        return new ItemViewHolder(view);
    }

    @Override
    protected void onBindHeaderView(View headerView) {
        Log.e(TAG,這是HeadView數據綁定的過程);
        ImageView imageView= (ImageView) headerView.findViewById(R.id.icon);
        Picasso.with(headerView.getContext()).load(http://img.my.csdn.net/uploads/201508/05/1438760758_3497.jpg).into(imageView);
    }

    @Override
    protected void onBindFooterView(View footerView) {
        Log.e(TAG,這是FootView數據綁定的過程);
    }


    @Override
    protected void onBindItemView(RecyclerView.ViewHolder holder, Content item) {
        ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
        Picasso.with(holder.itemView.getContext()).load(item.getIconUrl()).into( itemViewHolder.icon);
        itemViewHolder.title.setText(item.getTitle());
        itemViewHolder.desc.setText(item.getDesc());
    }


    static class ItemViewHolder extends RecyclerView.ViewHolder {
        ImageView icon;
        TextView title;
        TextView desc;
        public ItemViewHolder(View itemView) {
            super(itemView);
            icon = (ImageView) itemView.findViewById(R.id.icon);
            title = (TextView) itemView.findViewById(R.id.title);
            desc = (TextView) itemView.findViewById(R.id.desc);
        }
    }
}
 data-snippet-id=ext.4d4a7785a31c04496906dd3c9d1b521f data-snippet-saved=false data-csrftoken=o878nlHA-zddyMlPClI7Ynxp04ZUqleF9Ko8 data-codota-status=done>public class MyAdapter extends StaggeredGridLayoutAdapter {


    public MyAdapter(List list, int headerViewRes) {
        super(list, headerViewRes);
    }

    public MyAdapter(List list) {
        super(list);
    }

    public MyAdapter(List list, int headerViewRes, int footerViewRes) {
        super(list, headerViewRes, footerViewRes);
    }

    @Override
    public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) {
        View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.item_content,parent,false);
        return new ItemViewHolder(view);
    }

    @Override
    protected void onBindHeaderView(View headerView) {
        Log.e(TAG,這是HeadView數據綁定的過程);
        ImageView imageView= (ImageView) headerView.findViewById(R.id.icon);
        Picasso.with(headerView.getContext()).load(http://img.my.csdn.net/uploads/201508/05/1438760758_3497.jpg).into(imageView);
    }

    @Override
    protected void onBindFooterView(View footerView) {
        Log.e(TAG,這是FootView數據綁定的過程);
    }


    @Override
    protected void onBindItemView(RecyclerView.ViewHolder holder, Content item) {
        ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
        Picasso.with(holder.itemView.getContext()).load(item.getIconUrl()).into( itemViewHolder.icon);
        itemViewHolder.title.setText(item.getTitle());
        itemViewHolder.desc.setText(item.getDesc());
    }


    static class ItemViewHolder extends RecyclerView.ViewHolder {
        ImageView icon;
        TextView title;
        TextView desc;
        public ItemViewHolder(View itemView) {
            super(itemView);
            icon = (ImageView) itemView.findViewById(R.id.icon);
            title = (TextView) itemView.findViewById(R.id.title);
            desc = (TextView) itemView.findViewById(R.id.desc);
        }
    }
}

使用也很簡單,在onStart中顯示footer,在onLoadMore中加載數據,這裡是模擬操作,異步返回數據後將數據傳入onFinish進行回調,回調完成後記得調用 setLoadingMore(false);來通知當前處於沒在加載的狀態,通過Handler發送數據到主線程進行UI更新,並因此Footer

  public class MainActivity extends AppCompatActivity {
    private RecyclerView mRecyclerView;
    private List list = new ArrayList();
    private RecyclerViewAdapter myAdapter;
    private  ArrayList arrayList;
    Handler mHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            List list= (List) msg.obj;
            myAdapter.getList().addAll(list);
            myAdapter.notifyDataSetChanged();
            myAdapter.setFooterView(0);
        }
    };

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

        initData();


        //mRecyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false));
        mRecyclerView.setLayoutManager(new GridLayoutManager(this,2));
       // mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
        myAdapter = new MyAdapter(list);
        //myAdapter.setHeaderView(R.layout.item_header);
        //myAdapter.setFooterView(R.layout.item_footer);
        mRecyclerView.setAdapter(myAdapter);

        arrayList=new ArrayList(myAdapter.getList());
        mRecyclerView.addOnScrollListener(new OnRecyclerViewScrollListener(){
            @Override
            public void onStart() {
                myAdapter.setFooterView(R.layout.item_footer);
                if (myAdapter.hasHeader()){
                    mRecyclerView.smoothScrollToPosition(myAdapter.getItemCount()+1);
                }else{
                    mRecyclerView.smoothScrollToPosition(myAdapter.getItemCount());
                }
            }

            @Override
            public void onLoadMore() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Log.e(TAG,模擬網絡請求數據);
                            Thread.sleep(5000);
                            //手動調用onFinish()
                            onFinish(arrayList);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }

            @Override
            public void onFinish(List contents) {
                Message message=Message.obtain();
                message.obj=contents;
                mHandler.sendMessage(message);
                setLoadingMore(false);
            }
        });
    }

    private void initData() {
        Content c = new Content();
        c.setIconUrl(http://p1.meituan.net/63.90/movie/7a29814fe6549b929df6e0ef9575ce699434172.jpg);
        c.setTitle(搖滾水果);
        c.setDesc(比基尼女郎,掀搖滾熱浪。濱江區濱文路577號華潤超市4樓。);
        list.add(c);
         //類似這樣的添加數據的過程,還有很多數據。。這裡不貼出來了
    }
}

最終的效果看動圖,如下

效果圖

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved