美文网首页
装饰者设计模式-RecyclerView添加头部和底部

装饰者设计模式-RecyclerView添加头部和底部

作者: _风听雨声 | 来源:发表于2020-04-09 11:48 被阅读0次

    引言

    装饰者设计模式,装饰者设计模式在Android系统源码中也能经常见到,如IO流、ContextWrapper,ListView的addHeaderView和addFooterView...等等,这些都是装饰者设计模式运用的直观体现。


    装饰者模式的概念

    装饰者模式又名包装(Wrapper)模式。装饰者模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

    装饰者模式动态地将责任附加到对象身上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。


    装饰者模式的实例-RecyclerView添加头部和底部实例

    RecyclerView是谷歌推出的ListView的替代方案,但是谷歌并没有帮我们去实现RecyclerView的添加头部和底部。ListView是谷歌实现了添加头部和底部,ListView是使用装饰者设计模式实现的。那么,如果我们要使用装饰者设计模式去实现RecyclerView的添加头部和底部要怎么实现呢?

    实现思路

    1.在WrapRecyclerViewAdapter构造方法将原来的adapter传入进来
    2.创建添加头部和底部的方法
    3.getItemCount()方法返回原来的item数量加上添加进来的HeadView和FooterView数量。
    4.在onCreateViewHolder() onBindViewHolder()根据position来判断当前是headView还是原adapter的itemView或者footerView,根据对应的数量,做相应的处理
    5.新建WrapRecyclerView继承自RecyclerView,实现添加头部和底部的方法
    6.注册AdapterDataObserver观察者将两个Adapter关联

    public class WrapRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
        private List<View> headerViews;
        private List<View> footerViews;
        private RecyclerView.Adapter mAdapter;
    
        public WrapRecyclerViewAdapter(@NonNull RecyclerView.Adapter adapter) {
            this.mAdapter = adapter;
            headerViews = new ArrayList<>();
            footerViews = new ArrayList<>();
        }
    
        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {
            int headViewCount = headerViews.size();
            if (position < headViewCount) {
                return createHeaderFooterHolderView(headerViews.get(position));
            }
            int justPosition = mAdapter.getItemCount() + headViewCount;
            if (position < justPosition) {
                return mAdapter.onCreateViewHolder(parent, mAdapter.getItemViewType(position));
            }
    
            return createHeaderFooterHolderView(footerViews.get(position - justPosition));
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            int headViewCount = headerViews.size();
            if (position < headViewCount) {
                return;
            }
            int justPosition = mAdapter.getItemCount() + headViewCount;
            if (position < justPosition) {
                mAdapter.onBindViewHolder(holder, position - headViewCount);
                return;
            }
        }
    
        @Override
        public int getItemCount() {
            return mAdapter.getItemCount() + headerViews.size() + footerViews.size();
        }
    
        @Override
        public int getItemViewType(int position) {
            return position;
        }
    
        private RecyclerView.ViewHolder createHeaderFooterHolderView(View view) {
            return new RecyclerView.ViewHolder(view) {
            };
        }
    
        public void addHeaderView(View view) {
            if (!headerViews.contains(view)) {
                headerViews.add(view);
                notifyDataSetChanged();
            }
        }
    
        public void addFooterView(View view) {
            if (!footerViews.contains(view)) {
                footerViews.add(view);
                notifyDataSetChanged();
            }
        }
    
        public void removeHeaderView(View view) {
            if (headerViews.contains(view)) {
                headerViews.remove(view);
                notifyDataSetChanged();
            }
        }
    
        public void removeFooterView(View view) {
            if (footerViews.contains(view)) {
                footerViews.remove(view);
                notifyDataSetChanged();
            }
        }
    }
    
    public class WrapRecyclerView extends RecyclerView {
        private Adapter mAdapter;
        private WrapRecyclerViewAdapter mWrapAdapter;
    
        public WrapRecyclerView(@NonNull Context context) {
            this(context, null);
        }
    
        public WrapRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WrapRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        @Override
        public void setAdapter(@Nullable Adapter adapter) {
            if (adapter != null) {
                this.mAdapter = adapter;
                mWrapAdapter = new WrapRecyclerViewAdapter(adapter);
                registerObserver();
            }
            super.setAdapter(mWrapAdapter);
        }
    
        private void registerObserver() {
            mAdapter.registerAdapterDataObserver(new AdapterDataObserver() {
                @Override
                public void onChanged() {
                    super.onChanged();
                    mWrapAdapter.notifyDataSetChanged();
                }
            });
        }
    
        public void addHeaderView(View view) {
            if (mWrapAdapter != null) {
                mWrapAdapter.addHeaderView(view);
            }
        }
    
        public void addFooterView(View view) {
            if (mWrapAdapter != null) {
                mWrapAdapter.addFooterView(view);
            }
        }
    
        public void removeHeaderView(View view) {
            if (mWrapAdapter != null) {
                mWrapAdapter.removeHeaderView(view);
            }
        }
    
        public void removeFooterView(View view) {
            if (mWrapAdapter != null) {
                mWrapAdapter.removeFooterView(view);
            }
        }
    }
    

    装饰者模式的优缺点

    装饰模式的优点

    (1)装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。

    (2)通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

    装饰模式的缺点

    由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

    相关文章

      网友评论

          本文标题:装饰者设计模式-RecyclerView添加头部和底部

          本文链接:https://www.haomeiwen.com/subject/qhnqmhtx.html