RecyclerView中带有嵌套的可展开列表在标题中。

huangapple go评论76阅读模式
英文:

Recycleview with nested expandable lists in header

问题

以下是您提供的代码部分的翻译:

// RecycleView 适配器
public class RecycleAdapterPlantSearch extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // ...(此处省略了一部分代码)
}

// 嵌套的头部 RecycleView
public class SimpleDemoExpandableItemAdapter extends AbstractExpandableItemAdapter<MyGroupViewHolder, MyChildViewHolder> implements View.OnClickListener {
    // ...(此处省略了一部分代码)
}

请注意,代码部分可能会很长,为了节省空间,我只翻译了类的声明部分,并省略了具体的实现细节。如果您需要更详细的翻译或解释,请随时告知。

英文:

I am designing a relatively complex UI, i have searched stackoverflow and haven't found similar design. There could be many approaches to this, but i would like to ask expert opionions on how to achieve this and i would like to share my approach and make sure i am doing it the right way. My approach is that i have created a recycleview with header and inside header recycleview i am using an expandable recycleview library developed by h6ah4i (taken from github). Please let me know if there's a better approach to this.

The following image preview is a live mockup of final result i would like to get. It's not the actual screen. My question is what is the best way to achieve this, should i use expandable recycleview or expandable listview in recycleview header. I appreciate any answer as approaches or libraries it doesn't have to be similar to my code. Any suggestions are welcomed. I hope this post will also help other people like me in search of similar solution.

RecycleView Adapter

public class RecycleAdapterPlantSearch extends RecyclerView.Adapter&lt;RecyclerView.ViewHolder&gt; {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private List&lt;Plants&gt; plantsList;
private Context context;
private OnItemClickListener onItemClickListener;
public RecycleAdapterPlantSearch(Context context, List&lt;Plants&gt; plantsList, OnItemClickListener onClickListener) {
this.context = context;
this.plantsList = plantsList;
onItemClickListener = onClickListener;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
// Here Inflating your recyclerview item layout
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_plant_search_plant_item, parent, false);
return new ItemViewHolder(itemView, onItemClickListener);
} else if (viewType == TYPE_HEADER) {
// Here Inflating your header view
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_view_plant_search_header, parent, false);
return new HeaderViewHolder(itemView, onItemClickListener);
} else return null;
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
/*
position 0 is for header
*/
if (holder instanceof HeaderViewHolder) {
// setheadersdata_flag = true;
HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
// You have to set your header items values with the help of model class and you can modify as per your needs
// Setup expandable feature and RecyclerView
RecyclerViewExpandableItemManager expMgr = new RecyclerViewExpandableItemManager(null);
SimpleDemoExpandableItemAdapter.OnListItemClickMessageListener clickListener = message -&gt; {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
};
List&lt;BadgesVM&gt; badgesVMList = null;
badgesVMList = new ArrayList() {{
add(new BadgesVM(&quot;447&quot;, &quot;Bienenfreundlich&quot;, &quot;bienenfreundlich&quot;, false));
add(new BadgesVM(&quot;320,322&quot;, &quot;Vogelfreundlich&quot;, &quot;vogelfreundlich&quot;, false));
add(new BadgesVM(&quot;321&quot;, &quot;Insektenfreundlich&quot;, &quot;insektenfreundlich&quot;, false));
add(new BadgesVM(&quot;445&quot;, &quot;&#214;kologisch wertvoll&quot;, &quot;oekologisch&quot;, false));
add(new BadgesVM(&quot;531&quot;, &quot;Schmetterlings freundlich&quot;, &quot;schmetterlings&quot;, false));
add(new BadgesVM(&quot;530&quot;, &quot;Heimische Pflanze&#39;&quot;, &quot;heimische Pflanze&#39;&quot;, false));
}};
// Create wrapped adapter:  MyItemAdapter -&gt; expMgr.createWrappedAdapter -&gt; MyHeaderFooterAdapter
RecyclerView.Adapter adapter;
adapter = new SimpleDemoExpandableItemAdapter(context, expMgr,badgesVMList, clickListener);
adapter = expMgr.createWrappedAdapter(adapter);
//adapter = new DemoHeaderFooterAdapter(adapter, null);
headerViewHolder.recyclerViewExpandable.setAdapter(adapter);
headerViewHolder.recyclerViewExpandable.setLayoutManager(new LinearLayoutManager(context));
// NOTE: need to disable change animations to ripple effect work properly
((SimpleItemAnimator) headerViewHolder.recyclerViewExpandable.getItemAnimator()).setSupportsChangeAnimations(false);
expMgr.attachRecyclerView(headerViewHolder.recyclerViewExpandable);
} else if (holder instanceof ItemViewHolder) {
final ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
itemViewHolder.plantDescText.setText(plantsList.get(position - 1).getDescription());
RequestOptions options = new RequestOptions()
.centerCrop()
.placeholder(R.drawable.background_small);
String imageUrl = APP_URL.BASE_ROUTE_INTERN + plantsList.get(position - 1).getImages().get(0).getSrcAttr();
Glide.with(context).load(imageUrl).apply(options).into(itemViewHolder.plantImg);
}
}
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
@Override
public long getItemId(int position) {
return position;
}
// getItemCount increasing the position to 1. This will be the row of header
@Override
public int getItemCount() {
return plantsList.size() + 1;
}
public interface OnItemClickListener {
void OnItemClickListener(View view, int position);
void RecycleViewExtraDetails(ChipGroup chipGroup);
void nestedRecycleViewsSpecialOdd(RecyclerView nestedRecycleView);
}
private class HeaderViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView searchNameTxt, searchFamilyTxt, plantGroupTxt, plantFamilySearchTxt, ecologyFilterTxt,
frostSearchTxt;
private ChipGroup chipGroup;
private Button filterSearchBtn;
private CardView ecologyCv;
private CardView detailSearchCv;
private RecyclerView recyclerViewExpandable;
public HeaderViewHolder(View headerView, OnItemClickListener onItemClickListener) {
super(headerView);
searchNameTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_search);
searchFamilyTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_search);
ecologyCv = headerView.findViewById(R.id.cardView_plant_search_header_ecology);
detailSearchCv = headerView.findViewById(R.id.cardView_plant_search_header_detail_search);
plantGroupTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_group);
plantFamilySearchTxt = headerView.findViewById(R.id.textView_plant_search_header_plant_family);
ecologyFilterTxt = headerView.findViewById(R.id.textView_plant_search_header_ecology_filter);
frostSearchTxt = headerView.findViewById(R.id.textView_plant_search_header_frost_filter);
chipGroup = headerView.findViewById(R.id.chip_group_plant_search_header);
filterSearchBtn = headerView.findViewById(R.id.button_plant_search_header_filter_search);
recyclerViewExpandable = headerView.findViewById(R.id.expandable_list_view_plant_search);
searchNameTxt.setOnClickListener(this);
searchFamilyTxt.setOnClickListener(this);
ecologyCv.setOnClickListener(this);
detailSearchCv.setOnClickListener(this);
plantGroupTxt.setOnClickListener(this);
plantFamilySearchTxt.setOnClickListener(this);
ecologyFilterTxt.setOnClickListener(this);
filterSearchBtn.setOnClickListener(this);
frostSearchTxt.setOnClickListener(this);
}
@Override
public void onClick(View view) {
onItemClickListener.OnItemClickListener(view, getAdapterPosition());
onItemClickListener.RecycleViewExtraDetails(chipGroup);
}
}
public class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private Button readMoreBtn;
private TextView plantDescText;
private ImageView plantImg;
public ItemViewHolder(View itemView, OnItemClickListener onItemClickListener) {
super(itemView);
plantDescText = itemView.findViewById(R.id.textView_plant_search_plants_item_description_text);
readMoreBtn = itemView.findViewById(R.id.button_plant_search_plant_item_read_more);
plantImg = itemView.findViewById(R.id.imageView_plant_search_plants_item_plant_image);
readMoreBtn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
onItemClickListener.OnItemClickListener(view, getAdapterPosition() - 1);
}
}
}

nested header recycleview

public class SimpleDemoExpandableItemAdapter extends AbstractExpandableItemAdapter&lt;SimpleDemoExpandableItemAdapter.MyGroupViewHolder,
SimpleDemoExpandableItemAdapter.MyChildViewHolder&gt; implements View.OnClickListener {
RecyclerViewExpandableItemManager mExpandableItemManager;
List&lt;MyBaseItem&gt; mItems;
OnListItemClickMessageListener mOnItemClickListener;
List&lt;BadgesVM&gt; badgesVMList;
Context context;
static class MyBaseItem {
public final int id;
public final String text;
public MyBaseItem(int id, String text) {
this.id = id;
this.text = text;
}
}
static abstract class MyBaseViewHolder extends AbstractExpandableItemViewHolder {
TextView textView;
Slider frostSlider;
RecyclerView detailRecycleView;
public MyBaseViewHolder(View itemView) {
super(itemView);
textView = itemView.findViewById(android.R.id.text1);
frostSlider = itemView.findViewById(R.id.slider_plant_search_expandable);
detailRecycleView = itemView.findViewById(R.id.recycle_view_plant_search_detail_search);
}
}
static class MyGroupViewHolder extends MyBaseViewHolder {
public MyGroupViewHolder(View itemView) {
super(itemView);
}
}
static class MyChildViewHolder extends MyBaseViewHolder {
public MyChildViewHolder(View itemView) {
super(itemView);
}
}
public SimpleDemoExpandableItemAdapter(Context context, RecyclerViewExpandableItemManager expMgr, List&lt;BadgesVM&gt; badgesVMList, OnListItemClickMessageListener clickListener) {
mExpandableItemManager = expMgr;
mOnItemClickListener = clickListener;
this.badgesVMList = badgesVMList;
this.context = context;
setHasStableIds(true); // this is required for expandable feature.
mItems = new ArrayList&lt;&gt;();
mItems.add(new MyBaseItem(0, &quot;Filter nach &#246;kologischen Kriterien&quot;));
mItems.add(new MyBaseItem(1, &quot;Frosth&#228;rte&quot;));
mItems.add(new MyBaseItem(2, &quot;Detailsuche&quot;));
}
@Override
public int getGroupCount() {
return mItems.size();
}
@Override
public int getChildCount(int groupPosition) {
int childCount = 0;
int groupId = mItems.get(groupPosition).id;
if (groupId == 0) {
childCount = badgesVMList.size();
} else if (groupId == 1) {
childCount = 1; //contains only one item
} else if (groupId == 2) {
childCount = 1; //contains only one item
}
return childCount;
}
@Override
public long getGroupId(int groupPosition) {
// This method need to return unique value within all group items.
return mItems.get(groupPosition).id;
}
@Override
public long getChildId(int groupPosition, int childPosition) {
// This method need to return unique value within the group.
int groupId = mItems.get(groupPosition).id;
int childId = 0;
if (groupId == 0) {
badgesVMList.get(childPosition).getId();
} else if (groupId == 1) {
childId = 0;
} else if (groupId == 2) {
childId = 0;
}
return childId;
}
@Override
@NonNull
public MyGroupViewHolder onCreateGroupViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_group_item_for_expandable_minimal, parent, false);
MyGroupViewHolder vh = new MyGroupViewHolder(v);
vh.itemView.setOnClickListener(this);
return vh;
}
@Override
@NonNull
public MyChildViewHolder onCreateChildViewHolder(@NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_child_item_for_expandable_minimal, parent, false);
MyChildViewHolder vh = new MyChildViewHolder(v);
vh.itemView.setOnClickListener(this);
return vh;
}
@Override
public void onBindGroupViewHolder(@NonNull MyGroupViewHolder holder, int groupPosition, int viewType) {
MyBaseItem group = mItems.get(groupPosition);
holder.textView.setText(group.text);
}
@Override
public void onBindChildViewHolder(@NonNull MyChildViewHolder holder, int groupPosition, int childPosition, int viewType) {
int groupId = mItems.get(groupPosition).id;
if (groupId == 0) {
BadgesVM badgesVM = badgesVMList.get(childPosition);
holder.textView.setVisibility(View.VISIBLE);
holder.frostSlider.setVisibility(View.GONE);
holder.detailRecycleView.setVisibility(View.GONE);
holder.textView.setText(badgesVM.getName());
} else if (groupId == 1) {
holder.textView.setVisibility(View.GONE);
holder.frostSlider.setVisibility(View.VISIBLE);
holder.detailRecycleView.setVisibility(View.GONE);
} else if (groupId == 2) {
holder.textView.setVisibility(View.GONE);
holder.frostSlider.setVisibility(View.GONE);
holder.detailRecycleView.setVisibility(View.VISIBLE);
// Setup expandable feature and RecyclerView
RecyclerViewExpandableItemManager expMgr = new RecyclerViewExpandableItemManager(null);
DetailSearchExpandableItemAdapter.OnListItemClickMessageListener clickListener = message -&gt; {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
};
List&lt;BadgesVM&gt; badgesVMList = null;
badgesVMList = new ArrayList() {{
add(new BadgesVM(&quot;447&quot;, &quot;Bienenfreundlich&quot;, &quot;bienenfreundlich&quot;, false));
add(new BadgesVM(&quot;320,322&quot;, &quot;Vogelfreundlich&quot;, &quot;vogelfreundlich&quot;, false));
add(new BadgesVM(&quot;321&quot;, &quot;Insektenfreundlich&quot;, &quot;insektenfreundlich&quot;, false));
add(new BadgesVM(&quot;445&quot;, &quot;&#214;kologisch wertvoll&quot;, &quot;oekologisch&quot;, false));
add(new BadgesVM(&quot;531&quot;, &quot;Schmetterlings freundlich&quot;, &quot;schmetterlings&quot;, false));
add(new BadgesVM(&quot;530&quot;, &quot;Heimische Pflanze&#39;&quot;, &quot;heimische Pflanze&#39;&quot;, false));
}};
// Create wrapped adapter:  MyItemAdapter -&gt; expMgr.createWrappedAdapter -&gt; MyHeaderFooterAdapter
RecyclerView.Adapter adapter2;
adapter2 = new DetailSearchExpandableItemAdapter(context, expMgr, badgesVMList, clickListener);
adapter2 = expMgr.createWrappedAdapter(adapter2);
//adapter = new DemoHeaderFooterAdapter(adapter, null);
holder.detailRecycleView.setAdapter(adapter2);
holder.detailRecycleView.setLayoutManager(new LinearLayoutManager(context));
// NOTE: need to disable change animations to ripple effect work properly
((SimpleItemAnimator) holder.detailRecycleView.getItemAnimator()).setSupportsChangeAnimations(false);
expMgr.attachRecyclerView(holder.detailRecycleView);
}
}
@Override
public boolean onCheckCanExpandOrCollapseGroup(@NonNull MyGroupViewHolder holder, int groupPosition, int x, int y, boolean expand) {
// handles click event manually (to show Snackbar message)
return false;
}
@Override
public void onClick(View v) {
RecyclerView rv = RecyclerViewAdapterUtils.getParentRecyclerView(v);
RecyclerView.ViewHolder vh = rv.findContainingViewHolder(v);
int rootPosition = vh.getAdapterPosition();
if (rootPosition == RecyclerView.NO_POSITION) {
return;
}
// need to determine adapter local flat position like this:
RecyclerView.Adapter rootAdapter = rv.getAdapter();
int localFlatPosition = WrapperAdapterUtils.unwrapPosition(rootAdapter, this, rootPosition);
long expandablePosition = mExpandableItemManager.getExpandablePosition(localFlatPosition);
int groupPosition = RecyclerViewExpandableItemManager.getPackedPositionGroup(expandablePosition);
int childPosition = RecyclerViewExpandableItemManager.getPackedPositionChild(expandablePosition);
String message;
if (childPosition == RecyclerView.NO_POSITION) {
// Clicked item is a group!
// toggle expand/collapse
if (mExpandableItemManager.isGroupExpanded(groupPosition)) {
mExpandableItemManager.collapseGroup(groupPosition);
message = &quot;COLLAPSE: Group &quot; + groupPosition;
} else {
mExpandableItemManager.expandGroup(groupPosition);
message = &quot;EXPAND: Group &quot; + groupPosition;
}
} else {
// Clicked item is a child!
message = &quot;CLICKED: Child &quot; + groupPosition + &quot;-&quot; + childPosition;
}
mOnItemClickListener.onItemClicked(message);
}
public interface OnListItemClickMessageListener {
void onItemClicked(String message);
}
}

RecyclerView中带有嵌套的可展开列表在标题中。

答案1

得分: 2

你是对的,搜索一个能为你完成大部分工作的库是正确的,但我不喜欢你选择的库。它似乎不够灵活和简洁。我建议你看看Groupie,它的API非常清晰。另外,查看一下Reddit上关于库的一些讨论。

如果你想自己编写,我认为你可以在不使用嵌套的Adapter的情况下解决这个问题。只需创建一个“可展开组”项目类型。然后在getItemCount()中计算所有项目及其嵌套项目(在展开时)。可以查看Groupie源代码。

对于你的代码,还有一些建议:

  1. 我建议明确地将头部添加到提供给适配器的项目列表中。所以,不是使用List&lt;Plants&gt;,而是提供一个List&lt;Item&gt;,其中包括HeaderItemPlantsItem。这样,你的域模型(Plants)和适配器中的视图模型(项目)之间就有了明确的分离。
  2. 你的onBindViewHolder()方法做了太多的事情。让你的ViewHolder子类来处理这些。创建一个抽象的ViewHolder,其中包含一个抽象的bindTo(Item item)方法。然后在HeaderViewHolder子类中继承它并执行实际的工作(经过instanceof检查后)。
  3. 看一下view binding,它可以让你的代码更加简洁。(Kotlin4也是如此。)
英文:

You were right to search a library that does most of the work for you, but I don't like the library you picked. It does not seem very flexible and concise. I suggest to take a look at Groupie, its API is pretty clean. Also check Reddit for some discussion on libraries.

If you want to write it yourself I think you can solve it without nested Adapter's. Just create an 'expandable group' item type. Then in getItemCount() you count all items and their nested items (when expanded). Take a look at the Groupie source code.

Some additional feedback on your code:

  1. I would explicitly add the header to the list of items you give to your adapter. So instead of a List&lt;Plants&gt;, you rather provide a List&lt;Item&gt; and have a HeaderItem and PlantsItem. This way you have a clear separation between your domain models (Plants) and view models (the items) in your adapter.
  2. Your onBindViewHolder() method does way too much. Let your ViewHolder subclasses take care of that. Create an abstract ViewHolder with an abstract bindTo(Item item) method. Then in your HeaderViewHolder subclass it and do the actual work (after an instanceof check).
  3. Have a look at view binding, it can make your code more concise. (So does Kotlin.)

答案2

得分: 1

你可以使用ConcatAdapter,即使其中包含RecyclerView的适配器也可以拥有多个具有不同布局类型的ViewHolders。我在上一个项目中使用过,效果不错,你可以在这里查看。仪表板模块使用多个适配器来拥有不同类型的布局。

你还可以使用Google的iosched app中使用的方法,以更好的方式拥有一个适配器,其中你将逻辑从适配器移动到ViewHolders和它们的包装类ViewBinders中。ViewBinder负责调用onViewHolder、onCreateViewHolder和将数据类型绑定到ViewBinder以及将ViewBinder绑定到布局。有一篇关于如何在Medium上使用它的文章,如果我能找到链接,我会发出来。你还可以查看我为动画创建的这个示例,但是在简单形式下使用了ViewBinders来创建不同类型的布局。

以下是我希望在GridLayout中按顺序显示的数据类型和布局:

val data = mutableListOf<Any>().apply {

    // 添加矢量可绘制图形
    add(HeaderModel("动画矢量可绘制图形"))
    add(AVDModel(R.drawable.avd_likes))
    add(AVDModel(R.drawable.avd_settings))

    add(HeaderModel("可寻址矢量可绘制图形"))
    add(SeekableVDModel(R.drawable.avd_compass_rotation))
    add(SeekableVDModel(R.drawable.avd_views))
    add(SeekableVDModel(R.drawable.avd_hourglass))

    add(HeaderModel("时钟"))
    add(AVDModel(R.drawable.avd_clock_alarm))
    add(AVDModel(R.drawable.avd_clock_clock))
    add(AVDModel(R.drawable.avd_clock_stopwatch))
}

这些是我想在RecyclerView中使用的数据类型,它们与ViewHolder和布局的绑定方式对应。

private fun createViewBinders(): HashMap<ItemClazz, MappableItemBinder> {

    val avdViewBinder = AVDViewBinder()
    val seekableVDViewBinder = SeekableVDViewBinder()
    val headViewBinder = HeaderViewBinder()

    return HashMap<ItemClazz, MappableItemBinder>()
        .apply {

            put(
                avdViewBinder.modelClazz,
                avdViewBinder as MappableItemBinder
            )

            put(
                seekableVDViewBinder.modelClazz,
                seekableVDViewBinder as MappableItemBinder
            )

            put(
                headViewBinder.modelClazz,
                headViewBinder as MappableItemBinder
            )
        }
}

然后将数据列表List<Any>设置到适配器,并让适配器调用与数据绑定的相应布局。

val dataList: List<Any> = getVectorDrawableItemList()

val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)

val adapter = MultipleViewBinderListAdapter(
    createViewBinders(),
    RecyclerView.Adapter.StateRestorationPolicy.ALLOW
).apply {
    submitList(dataList)
}

对于可展开的列表,iosched应用程序采用的方法是不错的,有一个关于如何在RecyclerView中为可展开项添加动画的视频在这里。你可以在ViewHolder中设置状态,甚至可以使用MotionLayout从折叠状态动画到展开状态。所有这些都可以在没有任何第三方库的情况下完成,非常清晰。

英文:

You can use ConcatAdapter to have multiple adapters with ViewHolders that hold different type of layouts even with the ones that contain RecyclerViews, i used in my last project and it works fine, you can check it out here, dashboard module uses multiple adapters to have different type of layouts.

You can also use the approach they used in Google iosched app to have one adapter with multiple layouts in better way where you move logic from adapter to ViewHolders and their wrapper class ViewBinders. ViewBinder is responsible of
calling onViewHolder, onCreateViewHolder and bind data type to a ViewBinder and ViewBinder to a layout. There is an article about how to use it in medium, i will post the link if i can find it. You can also check out this sample i created for animations but used ViewBinders in a simple form to create different type of layouts.

Below is the type of data and layout i wish to show in GridLayout and in which order

val data = mutableListOf&lt;Any&gt;().apply {
// Add Vector Drawables
add(HeaderModel(&quot;Animated Vector Drawable&quot;))
add(AVDModel(R.drawable.avd_likes))
add(AVDModel(R.drawable.avd_settings))
add(HeaderModel(&quot;Seekable Vector Drawable&quot;))
add(SeekableVDModel(R.drawable.avd_compass_rotation))
add(SeekableVDModel(R.drawable.avd_views))
add(SeekableVDModel(R.drawable.avd_hourglass))
add(HeaderModel(&quot;Clocks&quot;))
add(AVDModel(R.drawable.avd_clock_alarm))
add(AVDModel(R.drawable.avd_clock_clock))
add(AVDModel(R.drawable.avd_clock_stopwatch))
}

These are correspond type of data i want to use in my RecyclerView, it's the types and binding to ViewHolder and layout in these classes.

private fun createViewBinders(): HashMap&lt;ItemClazz, MappableItemBinder&gt; {
val avdViewBinder = AVDViewBinder()
val seekableVDViewBinder = SeekableVDViewBinder()
val headViewBinder = HeaderViewBinder()
return HashMap&lt;ItemClazz, MappableItemBinder&gt;()
.apply {
put(
avdViewBinder.modelClazz,
avdViewBinder as MappableItemBinder
)
put(
seekableVDViewBinder.modelClazz,
seekableVDViewBinder as MappableItemBinder
)
put(
headViewBinder.modelClazz,
headViewBinder as MappableItemBinder
)
}
}

And set the data List<Any> to adapter and let adapter call corresponding layout that is bound to data

   val dataList:List&lt;Any&gt; = getVectorDrawableItemList()
val recyclerView = findViewById&lt;RecyclerView&gt;(R.id.recyclerView)
val adapter = MultipleViewBinderListAdapter(
createViewBinders(),
RecyclerView.Adapter.StateRestorationPolicy.ALLOW
).apply {
submitList(dataList)
}

For the expandable list, iosched app good way of doing it, there is video about how to animate expandable items in RecyclerVİew here. You can set state in ViewHolder and even use MotionLayout for animating from collapsed to expandable state. All can be done without any third party library and very clean way.

huangapple
  • 本文由 发表于 2020年10月6日 01:02:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/64213109.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定