3.Android RecyclerView快速添加头部和底部 删除错位

从月薪3000到年薪60万。从专科生到深圳一线大厂。关注我就能达到大师级水平,这话我终于敢说了, 年薪60万不是梦!

请问:怎么可以把代码格式调整?我贴出来换格式了。你们直接去Github下载工程!

今天开始讲RecycleView的系列教程。分割线,分组,局部刷新,动态添加,缓存原理,抖音效果,瀑布流。嵌套,动画等等



实现方案一:RecyclerView实现添加HeaderView和FooterView的核心就是在Adapter里面的onCreateViewHolder根据viewType来判断是列表项还是HeaderView来分别加载不同的布局文件。

bug:添加头部之后没法进行局部刷新。有bug

原因:添加头和尾部之后,position就变了!!!

实现方案二:  装饰设计模式:传入一个引用,让它的功能变的更强!!!!

比如:文件流读取:fileInputstream -----inpuststeeam

模仿listView添加头部和尾部

重点:

1.adapter套一层adapter

2.自定义recycleView

3.通过观察者模式监听

mAdapter =new MyRecycleViewAdapter(mList);

mRecyAttendanceAdapter =new WrapRecyclerAdapter(mAdapter);

private void initView() {

mRecyclerView = findViewById(R.id.rv_list);

    mLinearLayoutManager =new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    //设置布局管理器

    mRecyclerView.setLayoutManager(mLinearLayoutManager);

    mAdapter =new MyRecycleViewAdapter(mList);

    mRecyAttendanceAdapter =new WrapRecyclerAdapter(mAdapter);

    // 设置适配器

    mRecyclerView.setAdapter(mRecyAttendanceAdapter);

    // 实例化头部View

    View headerView = LayoutInflater.from(this).inflate(R.layout.header, mRecyclerView, false);

    // 添加头部

    mRecyclerView.addHeaderView(headerView);

    mAdapter.setOnItemClickListener(new RecyAttendanceAdapter.OnItemClickListener() {

@Override

        public void onItemClick(View view, int position) {

mAdapter.removeItem(position);

            Toast.makeText(MyHeadActivity.this, "position:" + position, Toast.LENGTH_LONG);

        }

@Override

        public void onItemLongClick(View view, int position) {

}

});

}

public class WrapRecyclerAdapterextends RecyclerView.Adapter {

private final static StringTAG ="WrapRecyclerAdapter";

    // 用来存放底部和头部View的集合  比Map要高效一些

    // 可以点击进入看一下官方的解释

    /**

* SparseArrays map integers to Objects.  Unlike a normal array of Objects,

* there can be gaps in the indices.  It is intended to be more memory efficient

* than using a HashMap to map Integers to Objects, both because it avoids

* auto-boxing keys and its data structure doesn't rely on an extra entry object

* for each mapping.

*/

    private SparseArraymHeaderViews;

    private SparseArraymFooterViews;

    // 基本的头部类型开始位置  用于viewType

    private static int BASE_ITEM_TYPE_HEADER =10000000;

    // 基本的底部类型开始位置  用于viewType

    private static int BASE_ITEM_TYPE_FOOTER =20000000;

    // 列表的Adapter

    private RecyclerView.AdaptermAdapter;

    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {

this.mAdapter = adapter;

        mHeaderViews =new SparseArray<>();

        mFooterViews =new SparseArray<>();

    }

@Override

    public RecyclerView.ViewHolderonCreateViewHolder(ViewGroup parent, int viewType) {

// viewType 可能就是 SparseArray 的key

        if (isHeaderViewType(viewType)) {

View headerView =mHeaderViews.get(viewType);

            return createHeaderFooterViewHolder(headerView);

        }

if (isFooterViewType(viewType)) {

View footerView =mFooterViews.get(viewType);

            return createHeaderFooterViewHolder(footerView);

        }

return mAdapter.onCreateViewHolder(parent, viewType);

    }

/**

    * 是不是底部类型

    */

    private boolean isFooterViewType(int viewType) {

int position =mFooterViews.indexOfKey(viewType);

        return position >=0;

    }

/**

    * 创建头部或者底部的ViewHolder

*/

    private RecyclerView.ViewHoldercreateHeaderFooterViewHolder(View view) {

return new RecyclerView.ViewHolder(view) {

};

    }

/**

    * 是不是头部类型

    */

    private boolean isHeaderViewType(int viewType) {

int position =mHeaderViews.indexOfKey(viewType);

        return position >=0;

    }

@Override

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

if (isHeaderPosition(position) || isFooterPosition(position)) {

return;

        }

// 计算一下位置

        position = position -mHeaderViews.size();

        mAdapter.onBindViewHolder(holder, position);

    }

@Override

    public int getItemViewType(int position) {

if (isHeaderPosition(position)) {

// 直接返回position位置的key

            return mHeaderViews.keyAt(position);

        }

if (isFooterPosition(position)) {

// 直接返回position位置的key

            position = position -mHeaderViews.size() -mAdapter.getItemCount();

            return mFooterViews.keyAt(position);

        }

// 返回列表Adapter的getItemViewType

        position = position -mHeaderViews.size();

        return mAdapter.getItemViewType(position);

    }

/**

    * 是不是底部位置

    */

    private boolean isFooterPosition(int position) {

return position >= (mHeaderViews.size() +mAdapter.getItemCount());

    }

/**

    * 是不是头部位置

    */

    private boolean isHeaderPosition(int position) {

return position

    }

@Override

    public int getItemCount() {

// 条数三者相加 = 底部条数 + 头部条数 + Adapter的条数

        return mAdapter.getItemCount() +mHeaderViews.size() +mFooterViews.size();

    }

/**

    * 获取列表的Adapter

*/

    private RecyclerView.AdaptergetAdapter() {

return mAdapter;

    }

// 添加头部

    public void addHeaderView(View view) {

int position =mHeaderViews.indexOfValue(view);

        if (position <0) {

mHeaderViews.put(BASE_ITEM_TYPE_HEADER++, view);

        }

notifyDataSetChanged();

    }

// 添加底部

    public void addFooterView(View view) {

int position =mFooterViews.indexOfValue(view);

        if (position <0) {

mFooterViews.put(BASE_ITEM_TYPE_FOOTER++, view);

        }

notifyDataSetChanged();

    }

// 移除头部

    public void removeHeaderView(View view) {

int index =mHeaderViews.indexOfValue(view);

        if (index <0)return;

        mHeaderViews.removeAt(index);

        notifyDataSetChanged();

    }

// 移除底部

    public void removeFooterView(View view) {

int index =mFooterViews.indexOfValue(view);

        if (index <0)return;

        mFooterViews.removeAt(index);

        notifyDataSetChanged();

    }

/**

    * 解决GridLayoutManager添加头部和底部不占用一行的问题

    *

    * @param recycler

    * @version 1.0

*/

    public void adjustSpanSize(RecyclerView recycler) {

if (recycler.getLayoutManager()instanceof GridLayoutManager) {

final GridLayoutManager layoutManager = (GridLayoutManager) recycler.getLayoutManager();

            layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {

@Override

                public int getSpanSize(int position) {

boolean isHeaderOrFooter =

isHeaderPosition(position) || isFooterPosition(position);

                    return isHeaderOrFooter ?layoutManager.getSpanCount() :1;

                }

});

        }

}

}

public class WrapRecyclerViewextends RecyclerView {

// 包裹了一层的头部底部Adapter

    private WrapRecyclerAdaptermWrapRecyclerAdapter;

    // 这个是列表数据的Adapter

    private RecyclerView.AdaptermAdapter;

    public WrapRecyclerView(Context context) {

super(context);

    }

public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

    }

public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

    }

@Override

    public void setAdapter(Adapter adapter) {

// 为了防止多次设置Adapter

        if (mAdapter !=null) {

mAdapter.unregisterAdapterDataObserver(mDataObserver);

            mAdapter =null;

        }

this.mAdapter = adapter;

        if (adapterinstanceof WrapRecyclerAdapter) {

mWrapRecyclerAdapter = (WrapRecyclerAdapter) adapter;

        }else {

mWrapRecyclerAdapter =new WrapRecyclerAdapter(adapter);

        }

super.setAdapter(mWrapRecyclerAdapter);

        // 注册一个观察者

        mAdapter.registerAdapterDataObserver(mDataObserver);

        // 解决GridLayout添加头部和底部也要占据一行

        mWrapRecyclerAdapter.adjustSpanSize(this);

    }

// 添加头部

    public void addHeaderView(View view) {

// 如果没有Adapter那么就不添加,也可以选择抛异常提示

        // 让他必须先设置Adapter然后才能添加,这里是仿照ListView的处理方式

        if (mWrapRecyclerAdapter !=null) {

mWrapRecyclerAdapter.addHeaderView(view);

        }

}

// 添加底部

    public void addFooterView(View view) {

if (mWrapRecyclerAdapter !=null) {

mWrapRecyclerAdapter.addFooterView(view);

        }

}

// 移除头部

    public void removeHeaderView(View view) {

if (mWrapRecyclerAdapter !=null) {

mWrapRecyclerAdapter.removeHeaderView(view);

        }

}

// 移除底部

    public void removeFooterView(View view) {

if (mWrapRecyclerAdapter !=null) {

mWrapRecyclerAdapter.removeFooterView(view);

        }

}

private AdapterDataObservermDataObserver =new AdapterDataObserver() {

@Override

        public void onChanged() {

if (mAdapter ==null)return;

            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果

            if (mWrapRecyclerAdapter !=mAdapter)

mWrapRecyclerAdapter.notifyDataSetChanged();

        }

@Override

        public void onItemRangeRemoved(int positionStart, int itemCount) {

if (mAdapter ==null)return;

            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果

            if (mWrapRecyclerAdapter !=mAdapter)

mWrapRecyclerAdapter.notifyItemRemoved(positionStart);

        }

@Override

        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {

if (mAdapter ==null)return;

            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved没效果

            if (mWrapRecyclerAdapter !=mAdapter)

mWrapRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);

        }

@Override

        public void onItemRangeChanged(int positionStart, int itemCount) {

if (mAdapter ==null)return;

            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果

            if (mWrapRecyclerAdapter !=mAdapter)

mWrapRecyclerAdapter.notifyItemChanged(positionStart);

        }

@Override

        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {

if (mAdapter ==null)return;

            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果

            if (mWrapRecyclerAdapter !=mAdapter)

mWrapRecyclerAdapter.notifyItemChanged(positionStart,payload);

        }

@Override

        public void onItemRangeInserted(int positionStart, int itemCount) {

if (mAdapter ==null)return;

            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted没效果

            if (mWrapRecyclerAdapter !=mAdapter)

mWrapRecyclerAdapter.notifyItemInserted(positionStart);

        }

};

}

}


demo地址:https://github.com/pengcaihua123456/shennandadao

你可能感兴趣的:(3.Android RecyclerView快速添加头部和底部 删除错位)