You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于C#高效实现多ViewHolder与多View及Fragment场景适配问询

嘿,这个场景我之前做类似分类列表需求的时候碰到过,核心就是把「数据源过滤」和「多类型ViewHolder复用」拆解开处理,既高效又好维护。下面给你一套具体的实现思路:

核心实现方案

1. 统一数据模型,标记Item类型

先给所有对象定义一个基接口,让A、B、C、D都实现它,这样既能用统一的集合存储,又能快速区分每个Item的类型:

// 定义基接口,标记Item类型
public interface BaseItem
{
    ItemType GetItemType();
}

// 枚举所有Item类型,方便后续判断
public enum ItemType
{
    TypeA,
    TypeB,
    TypeC,
    TypeD
}

// A类型实体类示例
public class A : BaseItem
{
    // A的业务属性
    public string UniqueAProperty { get; set; }

    public ItemType GetItemType() => ItemType.TypeA;
}

// B、C、D类同理,各自实现GetItemType返回对应的枚举值

2. 针对不同Fragment做数据源过滤

不需要给每个Fragment单独存数据副本,基于主集合做按需过滤即可。如果数据量大或切换频繁,可以缓存过滤结果提升性能:

基础过滤方式(适合小数据量场景)

假设主集合在ViewModel或全局单例中维护,每个Fragment直接通过Linq过滤:

// 主集合(示例:ViewModel中维护)
private List<BaseItem> _allItems = new List<BaseItem>();

// Fragment 2 只显示A类型
public List<BaseItem> GetFragment2Items()
{
    return _allItems.Where(item => item.GetItemType() == ItemType.TypeA).ToList();
}

// Fragment 4 显示C和D类型
public List<BaseItem> GetFragment4Items()
{
    return _allItems.Where(item => 
        item.GetItemType() == ItemType.TypeC || 
        item.GetItemType() == ItemType.TypeD).ToList();
}

缓存优化(适合大数据量/频繁切换场景)

在ViewModel中维护每个Fragment对应的过滤后列表,主数据更新时同步更新缓存:

// 缓存每个Fragment的过滤结果
private Dictionary<FragmentType, List<BaseItem>> _filteredCache = new Dictionary<FragmentType, List<BaseItem>>();

// 主数据更新时,同步更新所有缓存
public void UpdateAllItems(List<BaseItem> newItems)
{
    _allItems = newItems;
    // 更新Fragment2的缓存
    _filteredCache[FragmentType.Fragment2] = _allItems.Where(item => item.GetItemType() == ItemType.TypeA).ToList();
    // 更新Fragment4的缓存,以此类推...
}

// Fragment直接取缓存数据
public List<BaseItem> GetCachedItems(FragmentType type)
{
    return _filteredCache.TryGetValue(type, out var items) ? items : new List<BaseItem>();
}

3. 实现多类型ViewHolder的RecyclerView Adapter

这是核心部分,通过重写GetItemViewType让RecyclerView识别不同Item类型,然后创建对应的ViewHolder:

第一步:创建各类型的ViewHolder

把每个Item的布局绑定逻辑封装在对应的ViewHolder里,让Adapter更简洁:

// A类型的ViewHolder
public class AViewHolder : RecyclerView.ViewHolder
{
    private TextView _aPropertyTv;

    public AViewHolder(View itemView) : base(itemView)
    {
        // 初始化控件
        _aPropertyTv = itemView.FindViewById<TextView>(Resource.Id.tv_a_property);
    }

    // 绑定数据的方法
    public void Bind(A item)
    {
        _aPropertyTv.Text = item.UniqueAProperty;
        // 其他绑定逻辑,比如设置点击事件等
    }
}

// B、C、D类型的ViewHolder同理,各自绑定对应的布局和数据

第二步:实现多类型Adapter

重写GetItemViewType、OnCreateViewHolder和OnBindViewHolder方法:

public class MultiTypeItemAdapter : RecyclerView.Adapter
{
    private List<BaseItem> _items;

    public MultiTypeItemAdapter(List<BaseItem> items)
    {
        _items = items;
    }

    // 重写获取Item类型的方法,返回对应的枚举值转int
    public override int GetItemViewType(int position)
    {
        return (int)_items[position].GetItemType();
    }

    // 根据ViewType创建对应的ViewHolder
    public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        var inflater = LayoutInflater.From(parent.Context);
        switch ((ItemType)viewType)
        {
            case ItemType.TypeA:
                var aView = inflater.Inflate(Resource.Layout.item_type_a, parent, false);
                return new AViewHolder(aView);
            case ItemType.TypeB:
                var bView = inflater.Inflate(Resource.Layout.item_type_b, parent, false);
                return new BViewHolder(bView);
            case ItemType.TypeC:
                var cView = inflater.Inflate(Resource.Layout.item_type_c, parent, false);
                return new CViewHolder(cView);
            case ItemType.TypeD:
                var dView = inflater.Inflate(Resource.Layout.item_type_d, parent, false);
                return new DViewHolder(dView);
            default:
                throw new ArgumentOutOfRangeException(nameof(viewType), "未知的Item类型");
        }
    }

    // 根据ViewHolder类型绑定对应的数据
    public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        var item = _items[position];
        switch (holder)
        {
            case AViewHolder aHolder:
                aHolder.Bind((A)item);
                break;
            case BViewHolder bHolder:
                bHolder.Bind((B)item);
                break;
            case CViewHolder cHolder:
                cHolder.Bind((C)item);
                break;
            case DViewHolder dHolder:
                dHolder.Bind((D)item);
                break;
        }
    }

    public override int ItemCount => _items?.Count ?? 0;

    // 提供更新数据源的方法,方便Fragment数据变化时刷新
    public void UpdateItems(List<BaseItem> newItems)
    {
        _items = newItems;
        NotifyDataSetChanged();
        // 如果需要更精细的刷新,可以用NotifyItemRangeInserted等方法,性能更好
    }
}

4. Fragment中使用Adapter

每个Fragment初始化自己的Adapter,传入过滤后的数据源即可:

public class Fragment1 : Fragment
{
    private MultiTypeItemAdapter _adapter;
    private RecyclerView _recyclerView;

    public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        var view = inflater.Inflate(Resource.Layout.fragment_recycler, container, false);
        _recyclerView = view.FindViewById<RecyclerView>(Resource.Id.recycler_view);
        // 初始化LayoutManager
        _recyclerView.SetLayoutManager(new LinearLayoutManager(Context));
        
        // 获取过滤后的数据源(比如从ViewModel获取)
        var items = ViewModel.GetFragment1Items(); // Fragment1显示所有类型
        _adapter = new MultiTypeItemAdapter(items);
        _recyclerView.SetAdapter(_adapter);

        return view;
    }

    // 当主数据更新时,刷新Adapter
    public void OnDataUpdated()
    {
        var newItems = ViewModel.GetFragment1Items();
        _adapter.UpdateItems(newItems);
    }
}

5. 额外优化建议

  • 复用Adapter实例:每个Fragment保留自己的Adapter对象,不要每次切换都重新创建,只更新数据源即可,减少对象创建开销。
  • 精细化刷新:如果主数据只是局部更新,不要直接调用NotifyDataSetChanged(),而是用NotifyItemInserted、NotifyItemChanged等方法,提升RecyclerView的刷新性能。
  • 布局复用:如果C和D类型的布局很相似,可以考虑复用同一个布局和ViewHolder,通过数据类型来区分显示逻辑,减少ViewHolder的数量。

内容的提问来源于stack exchange,提问作者iLikeKFC

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:37:19