RecyclerView添加head和footer

一、实现基本原理

利用RecyclerView的getItemViewType方法,设置不同的item的类型,在onCreateViewHolder(parent, viewType)方法中根据不同的viewType,设置不同的item的UI。

二、footer的添加(分页加载)

2.1 需要添加的footer

footer样式

ps:要求文字部分能够动态的替换,如(点击重试、加载完成)

2.2 判断recyclerview是否滑动到最后一个

/**
 * 判断当前RecyclerView是否滑动到最后
 * 
 * @param recyclerView
 * @return
 */
private boolean isSlideToBottom(RecyclerView recyclerView) {
    if (recyclerView == null) {
        return false;
    }
    if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) {
        return true;
    }
    return false;
}

2.3 针对分页加载的封装

2.3.1 希望达成的效果
  • 需要分页加载的RecyclerView实现封装好的Adapter即可达成分页加载的功能
  • 分页加载需要有加载下一页,点击重试,加载完成的基本功能
  • 如果所有的item <=10(可指定),不出现footer
2.3.2 设置加载下一页的条件

加载下一页条件

2.3.3 实现代码
/**
 * Created by zhufeng on 2016/8/12.
 * 用于上拉加载的RecyclerView的适配器
 */
public abstract class PullToLoadAdapter extends RecyclerView.Adapter {
    private final int TYPE_FOOTER = -1;
    private Context mContext;
    private RecyclerStatus status;
    /**
     * 锁住当前状态(防止多次加载)
     * 在网络加载时locked = true
     * 需要在网络加载成功后置为false
     */
    private boolean locked = false;
    /**
     * 是否出现上拉加载的状态提示条
     */
    private boolean pullLoadEnable = false;
    private OnProgressListener onProgressListener;
    private OnCompleteListener onCompleteListener;

    public PullToLoadAdapter(Context mContext) {
        this.mContext = mContext;
        status = RecyclerStatus.NONE;
    }

    @Override
    public int getItemCount() {
        if (pullLoadEnable) {
            return getItemCountChild() + 1;
        } else {
            return getItemCountChild();
        }
    }

    protected abstract int getItemCountChild();

    @Override
    public int getItemViewType(int position) {
        if (pullLoadEnable && position == getItemCountChild()) {
            return TYPE_FOOTER;
        }
        if (getItemViewTypeChild(position) == TYPE_FOOTER) {
            throw new IllegalArgumentException("type类型不能与底部条一样,请修改继承类的getItemViewTypeChild方法返回值");
        }
        return getItemViewTypeChild(position);
    }

    protected abstract int getItemViewTypeChild(int position);

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_FOOTER) {
            View contentView = LayoutInflater.from(mContext).inflate(R.layout.view_recycler_footer, parent, false);
            return new FooterViewHolder(contentView);
        } else {
            return onCreateViewHolderChild(parent, viewType);
        }
    }

    protected abstract RecyclerView.ViewHolder onCreateViewHolderChild(ViewGroup parent, int viewType);

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof FooterViewHolder) {
            ((FooterViewHolder) holder).text.setText(status.getName());
            if (status == RecyclerStatus.LOADING) {
                ((FooterViewHolder) holder).progressBar.setVisibility(View.VISIBLE);
            } else {
                ((FooterViewHolder) holder).progressBar.setVisibility(View.GONE);
            }
            ((FooterViewHolder) holder).text.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onProgressListener != null) {
                        if (status == RecyclerStatus.ERROR) {
                            onProgressListener.tryAgain();
                        }
                    }
                    if (onCompleteListener != null) {
                        if (status == RecyclerStatus.COMPLETE) {
                            onCompleteListener.onComplete();
                        }
                    }
                }
            });
        } else {
            onBindViewHolderChild(holder, position);
        }
    }

    protected abstract void onBindViewHolderChild(RecyclerView.ViewHolder holder, int position);

    public void setLocked(boolean locked) {
        if (this.locked != locked) {
            this.locked = locked;
        }
    }

    public void setStatus(RecyclerStatus status) {
        if (this.status != status) {
            this.status = status;
            if (this.status == RecyclerStatus.NONE) {
                pullLoadEnable = false;
            } else {
                pullLoadEnable = true;
            }
        }
    }

    public void setOnProgressListener(OnProgressListener onProgressListener) {
        this.onProgressListener = onProgressListener;
    }

    public void setOnCompleteListener(OnCompleteListener onCompleteListener) {
        this.onCompleteListener = onCompleteListener;
    }

    public void addBindRecyclerView(RecyclerView recyclerView) {
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (isSlideToBottom(recyclerView)) {
                    if (status == RecyclerStatus.LOADING) {
                        if (!locked) {
                            locked = true;
                            onProgressListener.nextPage();
                        }
                    }
                }
            }
        });
    }

    /**
     * 判断当前RecyclerView是否滑动到最后
     *
     * @param recyclerView
     * @return
     */
    private boolean isSlideToBottom(RecyclerView recyclerView) {
        if (recyclerView == null) {
            return false;
        }
        if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) {
            return true;
        }
        return false;
    }

    private class FooterViewHolder extends RecyclerView.ViewHolder {
        public TextView text;
        public ProgressBar progressBar;

        public FooterViewHolder(View itemView) {
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.footer);
            progressBar = (ProgressBar) itemView.findViewById(R.id.progress_item);
        }
    }

    public interface OnProgressListener {
        void nextPage();

        void tryAgain();
    }

    public interface OnCompleteListener {
        void onComplete();
    }

    public enum RecyclerStatus {
        NONE(""),
        LOADING("加载中"),
        ERROR("点击重试"),
        COMPLETE("加载完成");

        String name;

        RecyclerStatus(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}
2.3.4 使用示例
  1. Adapter继承PullToLoadAdapter

  2. 实现onCreateViewHolderChild、onBindViewHolderChild、getItemCountChild、getItemViewTypeChild方法,分别对应RecyclerView.Adapter中的onCreateViewHolder、onBindViewHolder、getItemCount、getItemViewType,用法一样

  3. 实现adapter的setOnProgressListener方法,如:

mAdapter.setOnProgressListener(new PullToLoadAdapter.OnProgressListener() {
    @Override
    public void nextPage() {
        //进行下一页的数据加载
    }

    @Override
    public void tryAgain() {
        //数据加载重试
    }
});
  1. 数据加载完成时:
if(是否加载完全){
    if(是否需要显示加载完成){
        mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.COMPLETE);
    }else{
        mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.NONE);
    }
}else{
    mAdapter.setLocked(false);
    mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.LOADING);
}
  1. 数据加载失败时:
mAdapter.setStatus(PullToLoadAdapter.RecyclerStatus.ERROR);
mAdapter.notifyDataSetChanged();

三、header的添加

使用getItemViewType即可,也可以配合PullToLoadAdaptergetItemViewTypeChild使用。这里就不详细说明了。

四、示例代码下载

等待上传

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值