java - 在扩展 RecyclerView.Adapter 时使用装饰器模式是否合适?

标签 java android android-recyclerview

我已经编写了一个似乎可以完美运行的 FooterAdapter

我意识到 ViewHolder 有一个字段 mPosition 在每个元素中保存状态,这让我怀疑使用装饰器模式无法实现标题,因为它会在每个 Adapter 中占据不同的位置。

也就是说,除非包装器/装饰器 Adapter 没有改变其他元素。也就是说:页脚是可以的,只要不需要绑定(bind)数据即可。

如果 Wrapper 适配器是可能的,那么我们将需要更多访问 ViewHolder 的权限?我不确定字段如何

预期用途:

headerView = new View( context );
footerView = new View( context );

MyAdapter myAdapter = new MyAdapter();
HeaderAdapter headerAdapter = new HeaderAdapter( myAdapter , headerView );
FooterAdapter footerAdapter = new FooterAdapter( headerAdapter , footerView );

RecyclerView recyclerView = new RecyclerView();
recyclerView.setAdapter( footerAdapter );

这真的很酷,因为这样我们就可以向任意 Adapter 添加页眉和页脚,而不必担心索引和偏移项目计数。

页脚适配器.java

public class FooterAdapter extends RecyclerView.Adapter
{
    private static final String TAG = "FooterAdapter";
    private final RecyclerView.Adapter<RecyclerView.ViewHolder> wrappedAdapter;

    private View footer;

    public static final int FOOTER_TYPE = 0x72846fe;

    public FooterAdapter( RecyclerView.Adapter<RecyclerView.ViewHolder> wrappedAdapter , View footer )
    {
        this.footer = footer;
        this.wrappedAdapter = wrappedAdapter;
        wrappedAdapter.registerAdapterDataObserver(new ThisObserver());
    }

    @Override
    public int getItemViewType(int position)
    {
        if( position == wrappedAdapter.getItemCount() ) return FOOTER_TYPE;
        return wrappedAdapter.getItemViewType(position);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if( viewType == FOOTER_TYPE )
        {
            return new RecyclerView.ViewHolder( footer ){};
        }else
        {
            return wrappedAdapter.onCreateViewHolder(parent,viewType);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if( holder.getItemViewType() == FOOTER_TYPE ) return;
        return wrappedAdapter.bindViewHolder( holder , position );
    }

    @Override
    public int getItemCount() {
        return wrappedAdapter.getItemCount() + 1;
    }


    private class ThisObserver extends AdapterDataObserver
    {
        public void onChanged() {
            notifyDataSetChanged();
        }

        public void onItemRangeChanged(int positionStart, int itemCount) {
            notifyItemRangeChanged(positionStart,itemCount);
        }

        public void onItemRangeInserted(int positionStart, int itemCount) {
            notifyItemRangeInserted(positionStart,itemCount);
        }

        public void onItemRangeRemoved(int positionStart, int itemCount) {
            notifyItemRangeRemoved(positionStart,itemCount);
        }

        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            int lower = Math.min( fromPosition , toPosition );
            int upper = Math.max( fromPosition , toPosition );
            for( int i = itemCount-1 ; i < itemCount ; i++ )
            {
                notifyItemMoved(upper+i,lower+i+(toPosition-fromPosition));
            }
        }
    }
}

HeaderAdapter.java

public class HeaderAdapter extends RecyclerView.Adapter
{
    private static final String TAG = "HeaderAdapter";
    private final RecyclerView.Adapter<RecyclerView.ViewHolder> wrappedAdapter;

    private View header;

    public static final int HEADER_TYPE = 0x747efe;

    public HeaderAdapter( RecyclerView.Adapter<RecyclerView.ViewHolder> wrappedAdapter , View header )
    {
        this.header = header;
        this.wrappedAdapter = wrappedAdapter;
        wrappedAdapter.registerAdapterDataObserver(new ThisObserver());
    }

    @Override
    public int getItemViewType(int position)
    {
        return position == 0 ? HEADER_TYPE : wrappedAdapter.getItemViewType(position - 1);
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if( viewType == HEADER_TYPE )
        {
            return new RecyclerView.ViewHolder( header ){};
        }else
        {
            return new RecyclerView.ViewHolder( wrappedAdapter.onCreateViewHolder(parent,viewType).itemView ){};
            // I thought some kind of wrapping (hack?) like this might get 
            // around the different indexing in different Adapters, but 
            // it doesn't work, it would probably needs more 
            // information, or to be able to observe changes in 
            // the "child" ViewHolder.
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if( holder.getItemViewType() != HEADER_TYPE ) wrappedAdapter.bindViewHolder( holder , position - 1 );
    }

    @Override
    public int getItemCount() {
        return wrappedAdapter.getItemCount() + 1;
    }


    private class ThisObserver extends RecyclerView.AdapterDataObserver
    {

        public void onChanged() {
            notifyDataSetChanged();
        }

        public void onItemRangeChanged(int positionStart, int itemCount) {
            notifyItemRangeChanged(1+positionStart,itemCount);
        }

        public void onItemRangeInserted(final int positionStart, final int itemCount) {
            notifyItemRangeInserted(1 + positionStart, itemCount);
        }

        public void onItemRangeRemoved(int positionStart, int itemCount) {
            notifyItemRangeRemoved(1 + positionStart, itemCount);
        }

        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            fromPosition++;
            toPosition++;
            int lower = Math.min( fromPosition , toPosition );
            int upper = Math.max( fromPosition , toPosition );
            for( int i = itemCount-1 ; i < itemCount ; i++ ) notifyItemMoved(upper+i,lower+i+(toPosition-fromPosition));
        }
    }
}

最佳答案

事实证明,页脚并不完美。

因此您不能将此模式用于页眉或页脚。

当您删除项目时,页脚希望停留在它达到的最高索引处。

有许多我们无法访问的包级变量。我认为预期的用途是一次编写整个类。

无论如何,页眉和页脚可能更适合 LayoutManager,我的意思是,我们已经知道它们是什么,它们不需要“适应”

关于java - 在扩展 RecyclerView.Adapter 时使用装饰器模式是否合适?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32037400/

相关文章:

java - 这些嵌套循环的大 O

子类中的 Java 静态构造函数访问

android - 如何获取选定的弹出菜单项位置值并传递它

android - 带有自定义 LayoutManager 的 RecyclerView 不显示滚动条

android - 在数据加载到 Recycler View 之前加载 View

Java项目依赖

java - doOnNext() 不会被调用 Spring Webflux

android - 在 Android 模拟器上,尝试加载 webview 我得到 net::err_cache_miss

android - Gradle Build因Android Studio异常而失败

android - ViewPager Items 的延迟加载数据