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
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.