如何在RecyclerView中使用多个LayoutManager和MergeAdapter?

5

我正在使用MergeAdapter(又称ConcatAdapter)进行编程。

https://medium.com/androiddevelopers/merge-adapters-sequentially-with-mergeadapter-294d2942127a

但我需要做的是第一个适配器显示网格布局,第二个适配器显示线性布局,因此,如果我这样做

 val headerAdapter = HeaderAdapter(requireContext(), Header("TestHeader"))
        val dividerViewAdapter = DividerViewAdapter(requireContext())
        val animalAdapter = DividerViewAdapter(requireContext(),DataSource.animalList) // -> this should be shown as a GridLayout
        val mergeAdapter = MergeAdapter(headerAdapter,dividerViewAdapter,animalAdapter)
        test_rv.layoutManager = LinearLayoutManager(requireContext())
        test_rv.adapter = mergeAdapter

现在这段代码可以正常工作,但由于它有一个LinearLayoutManager,所有内容都将显示为LinearLayout,其中我的animalAdapter将无法按照我想要的方式显示。
是否有任何方法为不同的适配器设置不同的layoutmanager,以便以我想要的方式显示数据?
3个回答

2

GridLayoutManager.setSpanSizeLookup在类似的情况下非常有用。您可以使用GridLayoutManager,而不是使用多个布局管理器。

例如,当我依次添加1个垂直、3个水平和4个垂直对象时,代码如下:

ConcatAdapter concatAdapter = new ConcatAdapter(
        verticalItemAdapter, // contains  1 vertical item
        horizontalItemAdapter, // contains 3 horizontal items
        verticalItemAdapter, // contains 4 vertical items
);
int verticalSpanCount = 1;
int horizontalSpanCount = 3;

GridLayoutManager layoutManager = new GridLayoutManager(context, horizontalSpanCount);
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
    @Override
    public int getSpanSize(int position) {
        return concatAdapter.getWrappedAdapterAndPosition(position).first instanceof HorizontalItemAdapter
                ? verticalSpanCount 
                : horizontalSpanCount;
    }
});
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(concatAdapter);

编辑:

不要忘记实现androidx.recyclerview库,以使用ConcatAdapter的所有功能:

implement "androidx.recyclerview:recyclerview:1.3.0-rc01"

找不到函数'concatAdapter.getWrappedAdapterAndPosition',请指导我如何解决这个问题。 - Khalid ElSayed
@KhalidElSayed 我更新了我的答案,你需要实现androidx.recyclerview库来使用AndroidX RecyclerView组件。 - Atakan Yildirim

2
实际上,这是我解决问题的方法:
    class HorizontalContainerAdapter(private val lifecycleOwner: LifecycleOwner, val adapter : ListAdapter<*, *>) :
ListAdapter<String, HorizontalContainerAdapter.Holder>(diffCallback) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
    val inflater = LayoutInflater.from(parent.context)
    return Holder(DataBindingUtil.inflate(inflater, R.layout.item_horizontal_container, parent, false), adapter)
}

override fun onBindViewHolder(holder: Holder, position: Int) {
    holder.binding.lifecycleOwner = lifecycleOwner
}

override fun getItemViewType(position: Int): Int {
    return R.layout.item_horizontal_container
}

override fun getItemCount(): Int {
     return 1
}

class Holder(val binding: ItemHorizontalContainerBinding, adapter: ListAdapter<*, *>) : RecyclerView.ViewHolder(binding.root) {

    init {
        binding.recyclerView.layoutManager = LinearLayoutManager(binding.recyclerView.context, LinearLayoutManager.HORIZONTAL, false)
        binding.recyclerView.adapter = adapter
    }
}

companion object {
    val diffCallback by lazy {
        object :
            DiffUtil.ItemCallback<String>() {

            override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
                return oldItem == newItem
            }

            override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
                return oldItem == newItem
            }
        }
    }
}

MergeAdapter / ConcatAdapter与水平和垂直布局

祝你好运


1
不,不能使多个LayoutManager与一个RecyclerView相关联。LayoutManager是针对整个RecyclerView的,并且与Adapter无关。换句话说:适配器没有布局管理器; 相反,RecyclerView具有布局管理器和适配器。
如果不是这种情况,则在一行中从GridLayoutManager切换到LinearLayoutManager等等时,行为会变得非常奇怪。
对于您特定的情况,线性布局中的一行(用于垂直列表)或列(用于水平列表)与具有跨度计数等于跨度数的网格中的项目相同,因此,如果正确设置跨度计数,则可以仅使用GridLayoutManager来整个RecyclerView。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接