首页
社区
课程
招聘
[原创]企业微信Duilib奇怪的RecyclerView
发表于: 2025-10-22 16:12 1259

[原创]企业微信Duilib奇怪的RecyclerView

2025-10-22 16:12
1259

之前分析了个人微信Duilib的RecyclerView:[原创]微信Duilib的List优化和代价
当时的企业微信还没有RecyclerView,最近看了下,发现已经有类似的RecyclerView。
只是看起来有点奇怪,所以简单梳理一下背后的设计思路。

类似spy++,写了一个Duilib的界面元素查看工具,列表List相关的布局如下:

一般来说,Tree 类似 List的复杂结构。设计上一般两种方案:1、像原生的Duilib是Tree继承List;2、像QT是Tree和List并列,但继承同一个抽象类。但从界面布局上可以看出mmListView里面包含了mmTreeView,奇怪的点就在这里。

界面布局的关系不一定映射底层代码实现的关系,于是进一步看看这两个类:

从继承关系可以看出,mmListView和mmTreeView算是并列的,但又不像QT一样继承同一个抽象类。反而是mmListView继承mmTreeViewDataSource,提供数据给mmTreeView使用,也就是说,mmListView提供了列表的所有元素,而mmTreeView从中拿到部分元素做显示。这样子就可以进行Data和View的分离,从而实现RecyclerView。

类的关系理清,进一步就是数据的结构,看看最底层的数据是怎么组织起来的。
mmTreeView继承CContainerUI,没有重写AddAt,也就是说mmTreeView的元素数据结构和CContainerUI一样都是数组。

滚动列表,包含元素的数组会整体移动,可以看出确实有回收复用:
图片描述

换句话说,mmTreeView就是RecyclerView,但是底层并不是概念上的树形结构。

有了数据结构,再看看列表滚动对应的逻辑代码:

滚动修改控件位置:

向下滚动:

向上滚动:

特殊的是,元素只是被移除,没有真正的删除,方便后续复用:

List是一维结构,Tree是二维结构,理论上也可以先实现Tree,然后List基于Tree特殊处理,让二维结构降成一维结构。

好奇Tree本身又是怎么实现的,树形Tree相关的布局如下:

再看看继承关系:

这就意味着mmTreeView3和mmTreeView一样底层都是数组。

Data和View确实是分离了,也实现了回收和复用。但不管是一维的List还是二维的Tree,在界面上显示都是一个一维的列表(二维的Tree通过缩进元素表达层次结构)。至于mmTreeView和mmTreeView3实际上都是RecyclerView。

class mmListView
  class mmTreeView
    class xxxItemView
class mmListView
  class mmTreeView
    class xxxItemView
mmListView继承:CContainerUI、mmTreeViewDataSource
mmTreeView继承:CVerticalLayoutUI(继承CContainerUI)
mmListView继承:CContainerUI、mmTreeViewDataSource
mmTreeView继承:CVerticalLayoutUI(继承CContainerUI)
DuiLib::CContainerUI::AddAt
    DuiLib::CStdPtrArray::InsertAt
DuiLib::CContainerUI::AddAt
    DuiLib::CStdPtrArray::InsertAt
int __thiscall mmTreeView::SetScrollPos(int this, struct tagSIZE a2)
  offset = curScrollPos - *(this + 0x588);
  *(this + 0x588) = curScrollPos;
  if ( offset >= 0 )
    sub_1B67AD(this, v6);                   // ⬇向下滚动
  else
    sub_1B66EE(this, v6);                   // ⬆向上滚动
int __thiscall mmTreeView::SetScrollPos(int this, struct tagSIZE a2)
  offset = curScrollPos - *(this + 0x588);
  *(this + 0x588) = curScrollPos;
  if ( offset >= 0 )

传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 15
支持
分享
最新回复 (4)
雪    币: 16
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
666666
2025-10-30 14:26
0
雪    币: 2
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3

设计很巧妙!用mmTreeView直接复用mmListView的数据源,通过数组结构既实现视图数据分离,又同时支持列表和树形展示。这种"数组模拟树形"的思路既保证性能又简化实现,相关架构可参考思维导图

最后于 2025-11-6 17:50 被mb_cizqyhuh编辑 ,原因:
2025-11-6 17:42
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
666
2025-11-28 18:30
0
雪    币: 229
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
牛逼
2025-12-7 16:55
0
游客
登录 | 注册 方可回帖
返回