声明:

该结构是自BRVAH框架修改而来,有兴趣的朋友可以优先了解下BRVAH适配器框架。


支持:

几乎支持原生RecyclerView.Adapter所能实现的所有效果。

使用:

/**     * 单类型适配器     * 注意点:     * layoutItem对应布局需要设置名为 item的variable     *     * @param recyclerView     * @param layoutItem     * @param           数据实体类型     */    private  void singleAdapter(RecyclerView recyclerView, @LayoutRes int layoutItem) {        BaseHxAdapter adapter = new BaseHxAdapter<>(layoutItem);        //将适配器与RecyclerView绑定        adapter.bindToRecyclerView(recyclerView);        //设置加载更多监听,该步骤同时也做了bindToRecyclerView的操作,如果设置加载更多监听,那么可以不用调用adapter.bindToRecyclerView(recyclerView);        adapter.setOnLoadMoreListener(() -> {        }, recyclerView);        //该方法需要在bindToRecyclerView()之后调用,或者在adapter.setOnLoadMoreListener之后调用,确保RecyclerView对象已与Adapter绑定        //判断数据是否满屏,如果没有满屏,那么将会隐藏加载更多,否则显示        adapter.disableLoadMoreIfNotFullPage();        //表示是否启用加载更多;可用adapter.disableLoadMoreIfNotFullPage()代替,但是disableLoadMoreIfNotFullPage方法在数据未满屏时,默认不启用加载更多        adapter.setEnableLoadMore(true);        //表示一页数据加载完成        adapter.loadMoreComplete();        //表示全部数据加载结束,参数 true or false;true时,表示不显示“没有更多数据了”,false表示显示        adapter.loadMoreEnd(true);        //表示加载更多时数据加载失败        adapter.loadMoreFail();        //设置新数据集,一般在请求完数据或者刷新数据后调用        adapter.setNewData(null);        //表示在当前数据集末尾,新增一个数据集,一般在加载更多请求完成后调用        adapter.addData((ArrayList) null);        //获取数据实体对象        adapter.getItem(0);        //获取适配器的数据集        List list = adapter.getData();        //移除某行数据        adapter.remove(0);        //替换数据集内容;当前适配器的数据集对象引用不变,只变数据;如果想改变适配器的数据集的引用,可以调用setNewData();        adapter.replaceData((ArrayList) null);    }    /**     * 多类型数据适配器;     * 注意点:     * 1.数据实体需实现IMultiItemType接口,并与layoutItems对应     * 2.layoutItems对应布局需要设置名为 item的variable     *     * @param recyclerView     * @param layoutItems     */    private void multipleAdapter(RecyclerView recyclerView, @LayoutRes int... layoutItems) {        BaseMultiItemHxAdapter adapter = new BaseMultiItemHxAdapter() {            @Override            protected void bindTypeAndLayout() {                for (int i = 0; i < layoutItems.length; i++) {                    addItemType(i, layoutItems[0]);                }            }        };        //其余步骤,与singleAdapter相同    }

关键代码:

/** * function:RecyclerView适配器 * author: frj * modify date: 2018/6/7 */public class BaseHxAdapter extends RecyclerView.Adapter {    /**     * 加载更多类型     */    private static final int TYPE_LOAD_MORE = 0x111;    /**     * 普通项类型     */    private static final int TYPE_ITEM = 0;    /**     * 加载图层     */    private LoadMoreView mLoadMoreView;    //表示加载状态是否可用    private boolean mNextLoadEnable = false;    /**     * 表示是否启用加载更多     */    private boolean mLoadMoreEnable = false;    /**     * 表示加载更多是否是正在加载中     */    private boolean mLoading = false;    private int mLastPosition = -1;    private RecyclerView mRecyclerView;    /**     * 加载更多监听     */    private OnLoadMoreListener onLoadMoreListener;    /**     * 数据条目布局id     */    private @LayoutRes    int mItemLayoutId;    /**     * 数据集合     */    protected List mData;    protected Context mContext;    protected LayoutInflater mLayoutInflater;    public BaseHxAdapter(@LayoutRes int layoutResId) {        mData = new ArrayList<>();        this.mItemLayoutId = layoutResId;        this.mLoadMoreView = new SimpleLoadMoreView();    }    public BaseHxAdapter(@LayoutRes int layoutResId, List data) {        this(layoutResId);        setNewData(data);    }    @NonNull    @Override    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {        RecyclerView.ViewHolder viewHolder = null;        this.mContext = parent.getContext();        this.mLayoutInflater = LayoutInflater.from(mContext);        //加载更多        if (viewType == TYPE_LOAD_MORE) {            viewHolder = new LoadMoreViewHolder(getItemView(getLoadMoreView().getLayoutId(), parent));        } else {            viewHolder = V.create(parent, getItemLayoutId(viewType));        }        return viewHolder;    }    @Override    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {        int itemType = getItemViewType(position);        //由于LoadMore是一个单独的ViewHolder类型,所以此处单独加判断        if (itemType == TYPE_LOAD_MORE) {            if (mLoadMoreView != null) {                autoLoadMore(position);                mLoadMoreView.convert((LoadMoreViewHolder) holder);            }        } else {            bindDataItem(holder, position);        }    }    @Override    public int getItemCount() {        return mData.size() + getLoadMoreViewCount();    }    @Override    public int getItemViewType(int position) {        if (mLoadMoreEnable) {            if (position == mData.size()) {                return TYPE_LOAD_MORE;            }        }        return getDefItemViewType(position);    }    /**     * View附加到Window回调     *     * @param holder     */    @Override    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {        super.onViewAttachedToWindow(holder);        int type = holder.getItemViewType();        if (TYPE_LOAD_MORE == type) {            setFullSpan(holder);        }    }    /**     * 获取Item布局     *     * @return     */    protected int getItemLayoutId(int viewType) {        return mItemLayoutId;    }    /**     * 加载不同的项类型     *     * @param position     * @return     */    protected int getDefItemViewType(int position) {        return TYPE_ITEM;    }    /**     * 绑定数据对象     *     * @param holder     * @param position     */    protected void bindDataItem(RecyclerView.ViewHolder holder, int position) {        if (holder != null) {            ItemViewHolder itemViewHolder = (ItemViewHolder) holder;            itemViewHolder.bindItem(getItem(position));        }    }    /**     * 设置新数据     *     * @param data     */    public void setNewData(@Nullable List data) {        this.mData = data == null ? new ArrayList() : data;        if (onLoadMoreListener != null) {            mNextLoadEnable = true;            mLoadMoreEnable = true;            mLoading = false;            mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);        }        mLastPosition = -1;        notifyDataSetChanged();    }    /**     * 在指定位置插入数据     *     * @param position     * @param item     * @deprecated 用 {@link #addData(int, Object)} 插入     */    @Deprecated    public void add(@IntRange(from = 0) int position, @NonNull K item) {        addData(position, item);    }    /**     * 插入新数据至指定位置     *     * @param position     */    public void addData(@IntRange(from = 0) int position, @NonNull K data) {        mData.add(position, data);        notifyItemInserted(position);        compatibilityDataSizeChanged(1);    }    /**     * add one new data     */    public void addData(@NonNull K data) {        mData.add(data);        notifyItemInserted(mData.size());        compatibilityDataSizeChanged(1);    }    /**     * 移除指定位置项     *     * @param position     */    public void remove(@IntRange(from = 0) int position) {        if (mData == null                || position < 0                || position >= mData.size()) {            return;        }        mData.remove(position);        int internalPosition = position;        notifyItemRemoved(internalPosition);        compatibilityDataSizeChanged(0);        notifyItemRangeChanged(internalPosition, mData.size() - internalPosition);    }    /**     * 改变数据     */    public void setData(@IntRange(from = 0) int index, @NonNull K data) {        mData.set(index, data);        notifyItemChanged(index);    }    /**     * 添加新数据至指定位置     *     * @param position 插入位置     * @param newData  新数据集     */    public void addData(@IntRange(from = 0) int position, @NonNull Collection<? extends K> newData) {        mData.addAll(position, newData);        notifyItemRangeInserted(position + 0, newData.size());        compatibilityDataSizeChanged(newData.size());    }    /**     * 将新数据添加到末尾     *     * @param newData 新数据集合     */    public void addData(@NonNull Collection<? extends K> newData) {        mData.addAll(newData);        notifyItemRangeInserted(mData.size() - newData.size(), newData.size());        compatibilityDataSizeChanged(newData.size());    }    /**     * use data to replace all item in mData. this method is different {@link #setNewData(List)},     * it doesn't change the mData reference     *     * @param data data collection     */    public void replaceData(@NonNull Collection<? extends K> data) {        // 不是同一个引用才清空列表        if (data != mData) {            mData.clear();            mData.addAll(data);        }        notifyDataSetChanged();    }    /**     * 兼容的数据改变     *     * @param size 需要兼容的数据大小     */    private void compatibilityDataSizeChanged(int size) {        final int dataSize = mData == null ? 0 : mData.size();        if (dataSize == size) {            notifyDataSetChanged();        }    }    /**     * 获取数据项集合     *     * @return 列表数据     */    @NonNull    public List getData() {        return mData;    }    /**     * 获取指定位置的数据项     *     * @param position     * @return     */    @Nullable    public K getItem(@IntRange(from = 0) int position) {        if (position >= 0 && position < mData.size()) {            return mData.get(position);        } else {            return null;        }    }    /**     * 刷新项数据     *     * @param position     */    public final void refreshNotifyItemChanged(int position) {        notifyItemChanged(position);    }    /**     * 检查RecyclerView对象是否为空     */    private void checkNotNull() {        if (mRecyclerView == null) {            throw new RuntimeException("please bind recyclerView first!");        }    }    protected RecyclerView getRecyclerView() {        return mRecyclerView;    }    private void setRecyclerView(RecyclerView recyclerView) {        mRecyclerView = recyclerView;    }    /**     * 绑定RecyclerView对象,如果已绑定,抛出异常     */    public void bindToRecyclerView(RecyclerView recyclerView) {        if (getRecyclerView() != null) {            throw new RuntimeException("Don't bind twice");        }        setRecyclerView(recyclerView);        if (getRecyclerView().getAdapter() == null) {            getRecyclerView().setAdapter(this);        }    }    /**     * 获取加载更多管理类     *     * @return     */    protected LoadMoreView getLoadMoreView() {        if (mLoadMoreView == null) {            mLoadMoreView = new SimpleLoadMoreView();        }        return mLoadMoreView;    }    /**     * 绑定自定义的加载更多     *     * @param loadMoreView     */    public void setLoadMoreView(LoadMoreView loadMoreView) {        if (loadMoreView == null) {            return;        }        this.mLoadMoreView = loadMoreView;    }    /**     * 打开加载更多     *     * @param onLoadMoreListener     */    private void openLoadMore(OnLoadMoreListener onLoadMoreListener) {        this.onLoadMoreListener = onLoadMoreListener;        mNextLoadEnable = true;        mLoadMoreEnable = true;        mLoading = false;    }    /**     * 设置加载更多监听     *     * @param onLoadMoreListener     * @param recyclerView     */    public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener, RecyclerView recyclerView) {        openLoadMore(onLoadMoreListener);        bindToRecyclerView(recyclerView);    }    /**     * 返回加载更多的启用状态     *     * @return true表示启用,false表示未启用     */    public boolean isLoadMoreEnable() {        return mLoadMoreEnable;    }    /**     * 加载更多的数量     *     * @return 0 or 1     */    public int getLoadMoreViewCount() {        if (onLoadMoreListener == null || !mLoadMoreEnable) {            return 0;        }        if (!mNextLoadEnable && mLoadMoreView.isLoadEndMoreGone()) {            return 0;        }        if (mData.size() == 0) {            return 0;        }        return 1;    }    /**     * Gets to load more locations     *     * @return     */    public int getLoadMoreViewPosition() {        return mData.size();    }    /**     * 设置加载更多的启用状态     *     * @param enable true表示启用加载更多;false表示不启用     */    public void setEnableLoadMore(boolean enable) {        int oldLoadMoreCount = getLoadMoreViewCount();        mLoadMoreEnable = enable;        int newLoadMoreCount = getLoadMoreViewCount();        if (oldLoadMoreCount == 1) {            if (newLoadMoreCount == 0) {                notifyItemRemoved(getLoadMoreViewPosition());            }        } else {            if (newLoadMoreCount == 1) {                mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);                notifyItemInserted(getLoadMoreViewPosition());            }        }    }    /**     * @return 适配器是否正在显示加载更多进度     */    public boolean isLoading() {        return mLoading;    }    /**     * 加载结束,没有更多数据     */    public void loadMoreEnd() {        loadMoreEnd(false);    }    /**     * 加载结束没有更多数据     *     * @param gone true表示隐藏加载更多图层     */    public void loadMoreEnd(boolean gone) {        if (getLoadMoreViewCount() == 0) {            return;        }        mLoading = false;        mNextLoadEnable = false;        mLoadMoreView.setLoadMoreEndGone(gone);        if (gone) {            notifyItemRemoved(getLoadMoreViewPosition());        } else {            mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END);            notifyItemChanged(getLoadMoreViewPosition());        }    }    /**     * 加载完成     */    public void loadMoreComplete() {        if (getLoadMoreViewCount() == 0) {            return;        }        mLoading = false;        mNextLoadEnable = true;        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);        notifyItemChanged(getLoadMoreViewPosition());    }    /**     * 加载失败     */    public void loadMoreFail() {        if (getLoadMoreViewCount() == 0) {            return;        }        mLoading = false;        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL);        notifyItemChanged(getLoadMoreViewPosition());    }    /**     * 通知开始回调并加载更多     */    public void notifyLoadMoreToLoading() {        if (mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_LOADING) {            return;        }        mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);        notifyItemChanged(getItemCount() - 1);    }    /**     * 如果数据没有全屏,那么禁用加载更多;     * 使用前线绑定RecyclerView     *     * @see #disableLoadMoreIfNotFullPage(RecyclerView)     */    public void disableLoadMoreIfNotFullPage() {        checkNotNull();        disableLoadMoreIfNotFullPage(getRecyclerView());    }    /**     * 

* 不是配置项!! *

* 这个方法是用来检查是否满一屏的,所以只推荐在 {@link #setNewData(List)} 之后使用 * 原理很简单,先关闭 load more,检查完了再决定是否开启 *

* 不是配置项!! * * @param recyclerView your recyclerView * @see #setNewData(List) */ private void disableLoadMoreIfNotFullPage(RecyclerView recyclerView) { setEnableLoadMore(false); if (recyclerView == null) { return; } RecyclerView.LayoutManager manager = recyclerView.getLayoutManager(); if (manager == null) { return; } if (manager instanceof LinearLayoutManager) { final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) manager; recyclerView.postDelayed(new Runnable() { @Override public void run() { if (isFullScreen(linearLayoutManager)) { setEnableLoadMore(true); } } }, 50); } else if (manager instanceof StaggeredGridLayoutManager) { final StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) manager; recyclerView.postDelayed(new Runnable() { @Override public void run() { final int[] positions = new int[staggeredGridLayoutManager.getSpanCount()]; staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(positions); //得到当前显示的最大位置数 int pos = getTheBiggestNumber(positions) + 1; if (pos != getItemCount()) { setEnableLoadMore(true); } } }, 50); } } /** * 解析布局文件,获取View * * @param layoutResId 布局文件id * @param parent * @return */ protected View getItemView(@LayoutRes int layoutResId, ViewGroup parent) { return mLayoutInflater.inflate(layoutResId, parent, false); } /** * 得到最大数字 * * @param numbers * @return */ private int getTheBiggestNumber(int[] numbers) { int tmp = -1; if (numbers == null || numbers.length == 0) { return tmp; } for (int num : numbers) { if (num > tmp) { tmp = num; } } return tmp; } /** * 设置holder对应类型布局铺满 * * @param holder 要铺满的Holde */ protected void setFullSpan(RecyclerView.ViewHolder holder) { if (holder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) { StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder .itemView.getLayoutParams(); params.setFullSpan(true); } } /** * 判断是否满屏 * * @param llm * @return */ private boolean isFullScreen(LinearLayoutManager llm) { return (llm.findLastCompletelyVisibleItemPosition() + 1) != getItemCount() || llm.findFirstCompletelyVisibleItemPosition() != 0; } /** * 自动加载更多 * * @param position */ private void autoLoadMore(int position) { if (TYPE_LOAD_MORE != getItemViewType(position)) { return; } if (mLoadMoreView.getLoadMoreStatus() != LoadMoreView.STATUS_DEFAULT) { return; } mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING); if (!mLoading) { mLoading = true; if (mRecyclerView != null) { mRecyclerView.post(new Runnable() { @Override public void run() { if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); } } }); } else { if (onLoadMoreListener != null) { onLoadMoreListener.onLoadMore(); } } } } /** * 加载更多监听 */ public interface OnLoadMoreListener { /** * 加载更多回掉 */ void onLoadMore(); }}

/** * function:RecyclerView多类型适配器 * author: frj * modify date: 2018/6/7 */public abstract class BaseMultiItemHxAdapter extends BaseHxAdapter {    /**     * 布局引用集合     */    private SparseIntArray layouts;    /**     * 默认的布局类型     */    private static final int DEFAULT_VIEW_TYPE = -0xff;    /**     * 类型未找到     */    public static final int TYPE_NOT_FOUND = -404;    public BaseMultiItemHxAdapter() {        this(null);    }    public BaseMultiItemHxAdapter(List data) {        super(0, data);        bindTypeAndLayout();    }    @Override    protected int getDefItemViewType(int position) {        T item = mData.get(position);        if (item != null) {            return item.getItemType();        }        return DEFAULT_VIEW_TYPE;    }    @Override    protected void bindDataItem(RecyclerView.ViewHolder holder, int position) {        if (holder != null) {            ItemViewHolder itemViewHolder = (ItemViewHolder) holder;            itemViewHolder.bindItem(getItem(position));        }    }    /**     * 绑定类型和布局     */    protected abstract void bindTypeAndLayout();    /**     * 根据类型获取布局id     *     * @param viewType     * @return     */    private int getLayoutId(int viewType) {        return layouts.get(viewType, TYPE_NOT_FOUND);    }    /**     * 添加项类型及对应的布局文件id     *     * @param type        项类型     * @param layoutResId 布局文件id     */    protected void addItemType(int type, @LayoutRes int layoutResId) {        if (layouts == null) {            layouts = new SparseIntArray();        }        layouts.put(type, layoutResId);    }    /**     * 根据类型返回布局id     *     * @param viewType     * @return     */    @Override    protected int getItemLayoutId(int viewType) {        return getLayoutId(viewType);    }}
public class ItemViewHolder extends RecyclerView.ViewHolder {    public final T binding;    /**     * 创建ItemViewHolder     *     * @param parent     * @param layoutRes     * @return     */    public static ItemViewHolder create(@NonNull ViewGroup parent, @LayoutRes int layoutRes) {        return new ItemViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), layoutRes, parent, false));    }    public ItemViewHolder(T binding) {        super(binding.getRoot());        this.binding = binding;    }    /**     * 绑定数据对象     *     * @param item     * @param      */    public  void bindItem(K item) {        binding.setVariable(BR.item, item);        binding.executePendingBindings();    }}

/** * function: * author: frj * modify date: 2018/6/11 */public interface IMultiItemType {    /**     * 获取项类型     *     * @return     */    int getItemType();}

说明:

由于在ItemViewHolder中的bindItem()方法中,绑定的是固定名称 BR.item,如果项目中没有名为item的variable,项目编译会不通过,解决办法是在布局文件中定义名为item的variable。每个Item的布局文件建议都包含名为item的variable.

Demo下载


更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. Android(安卓)解决ListView里面多套布局多个EditText数据混乱问
  4. 1.Android的四大组件
  5. Android之Adapter用法总结(转载)
  6. Android数据库SQLite增改查删操作演示
  7. 27款Python 测试工具开源软件
  8. Android数据绑定组件RoboBinding使用详解
  9. android SharedPreferences 记录数据

随机推荐

  1. android监听当前应用
  2. Android(安卓)studio 常见错误以及问题
  3. android 自定义相册 多选
  4. Android版本及API等级关系
  5. java.lang.NullPointerException: Attemp
  6. android 操作文件
  7. Android更新UI的五种方式
  8. Duplicate files copied (Android(安卓)S
  9. android 之simpleAdapter详解
  10. android google directions