Is there an addHeaderView equivalent for RecyclerView?

后端 未结 19 1646
独厮守ぢ
独厮守ぢ 2020-11-21 23:35

I\'m looking for an equivalent to addHeaderView for a recycler view. Basically I want to have an image with 2 buttons be added as a header to the listview. Is there a differ

19条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-22 00:23

    I have implemented the same approach proposed by EC84B4 answer, but I abstracted RecycleViewAdapter and make it easily resuable by means of interfaces.

    So in order to use my approach you should add following base classes and interfaces to your project:

    1) Interface that provides data for Adapter (collection of generic type T, and additional parameters (if needed) of generic type P)

    public interface IRecycleViewListHolder{
                P getAdapterParameters();
                T getItem(int position);
                int getSize();
        }
    

    2) Factory for binding your items (header/item):

    public interface IViewHolderBinderFactory {
            void bindView(RecyclerView.ViewHolder holder, int position,IRecycleViewListHolder dataHolder);
    }
    

    3) Factory for viewHolders (header/items):

    public interface IViewHolderFactory {
        RecyclerView.ViewHolder provideInflatedViewHolder(int viewType, LayoutInflater layoutInflater,@NonNull ViewGroup parent);
    }
    

    4) Base class for Adapter with Header:

    public class RecycleViewHeaderBased extends RecyclerView.Adapter{
    
        public final static int HEADER_TYPE = 1;
        public final static int ITEM_TYPE = 0;
        private final IRecycleViewListHolder dataHolder;
        private final IViewHolderBinderFactory binderFactory;
        private final IViewHolderFactory viewHolderFactory;
    
        public RecycleViewHeaderBased(IRecycleViewListHolder dataHolder, IViewHolderBinderFactory binderFactory, IViewHolderFactory viewHolderFactory) {
            this.dataHolder = dataHolder;
            this.binderFactory = binderFactory;
            this.viewHolderFactory = viewHolderFactory;
        }
    
        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
            return viewHolderFactory.provideInflatedViewHolder(viewType,layoutInflater,parent);
        }
    
        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
                binderFactory.bindView(holder, position,dataHolder);
        }
    
        @Override
        public int getItemViewType(int position) {
            if(position == 0)
                return HEADER_TYPE;
            return ITEM_TYPE;
        }
    
        @Override
        public int getItemCount() {
            return dataHolder.getSize()+1;
        }
    }
    

    Usage example:

    1) IRecycleViewListHolder implementation:

    public class AssetTaskListData implements IRecycleViewListHolder, GroupedRecord> {
        private List> assetCountList;
        private GroupedRecord record;
    
        public AssetTaskListData(Map assetCountListSrc, GroupedRecord record) {
            this.assetCountList =  new ArrayList<>();
            for(Object  entry: assetCountListSrc.entrySet().toArray()){
                Map.Entry entryTyped = (Map.Entry)entry;
                assetCountList.add(entryTyped);
            }
            this.record = record;
        }
    
        @Override
        public GroupedRecord getAdapterParameters() {
            return record;
        }
    
        @Override
        public Map.Entry getItem(int position) {
            return assetCountList.get(position-1);
        }
    
        @Override
        public int getSize() {
            return assetCountList.size();
        }
    }
    

    2) IViewHolderBinderFactory implementation:

    public class AssetTaskListBinderFactory implements IViewHolderBinderFactory, GroupedRecord> {
        @Override
        public void bindView(RecyclerView.ViewHolder holder, int position, IRecycleViewListHolder, GroupedRecord> dataHolder) {
            if (holder instanceof AssetItemViewHolder) {
                Integer assetId = dataHolder.getItem(position).getKey();
                Integer assetCount = dataHolder.getItem(position).getValue();
                ((AssetItemViewHolder) holder).bindItem(dataHolder.getAdapterParameters().getRecordId(), assetId, assetCount);
            } else {
                ((AssetHeaderViewHolder) holder).bindItem(dataHolder.getAdapterParameters());
            }
        }
    }
    

    3) IViewHolderFactory implementation:

    public class AssetTaskListViewHolderFactory implements IViewHolderFactory {
        private IPropertyTypeIconMapper iconMapper;
        private ITypeCaster caster;
    
        public AssetTaskListViewHolderFactory(IPropertyTypeIconMapper iconMapper, ITypeCaster caster) {
            this.iconMapper = iconMapper;
            this.caster = caster;
        }
    
        @Override
        public RecyclerView.ViewHolder provideInflatedViewHolder(int viewType, LayoutInflater layoutInflater, @NonNull ViewGroup parent) {
            if (viewType == RecycleViewHeaderBased.HEADER_TYPE) {
                AssetBasedHeaderItemBinding item = DataBindingUtil.inflate(layoutInflater, R.layout.asset_based_header_item, parent, false);
                return new AssetHeaderViewHolder(item.getRoot(), item, caster);
            }
            AssetBasedListItemBinding item = DataBindingUtil.inflate(layoutInflater, R.layout.asset_based_list_item, parent, false);
            return new AssetItemViewHolder(item.getRoot(), item, iconMapper, parent.getContext());
        }
    }
    

    4) Deriving adapter

    public class AssetHeaderTaskListAdapter extends RecycleViewHeaderBased, GroupedRecord> {
       public AssetHeaderTaskListAdapter(IRecycleViewListHolder, GroupedRecord> dataHolder,
                                          IViewHolderBinderFactory binderFactory,
                                          IViewHolderFactory viewHolderFactory) {
            super(dataHolder, binderFactory, viewHolderFactory);
        }
    }
    

    5) Instantiate adapter class:

    private void setUpAdapter() {
            Map objectTypesCountForGroupedTask = groupedTaskRepository.getObjectTypesCountForGroupedTask(this.groupedRecordId);
            AssetTaskListData assetTaskListData = new AssetTaskListData(objectTypesCountForGroupedTask, getGroupedRecord());
            adapter = new AssetHeaderTaskListAdapter(assetTaskListData,new AssetTaskListBinderFactory(),new AssetTaskListViewHolderFactory(iconMapper,caster));
            assetTaskListRecycler.setAdapter(adapter);
        }
    

    P.S.: AssetItemViewHolder, AssetBasedListItemBinding, etc. my application own structures that should be swapped by your own, for your own purposes.

提交回复
热议问题