Tencent / QMUI_iOS

QMUI iOS——致力于提高项目 UI 开发效率的解决方案
http://qmuiteam.com/ios
Other
7.05k stars 1.37k forks source link

QMUIFloatLayoutView 在 UITableView 和 UICollectionView 中复用时未更新内部控件 frame #1357

Closed 0x1306a94 closed 2 years ago

0x1306a94 commented 2 years ago

Bug 表现 例如在 Cell 中添加一个 QMUIFloatLayoutView,然后加一堆 UIButton 进去, 然后在列表滑动时会出现 内部的 button frame 未更新, 通过日志发现出问题的Cell, 没有触发 layoutSubviews 也就间接导致没有触发 layoutSubviewsWithSize:shouldLayout: 但是如果在 Cell 更新 Button 内容后,手动调用 [button sizeToFit] 就不会出现, 这种有没有更好的处理方式呢?

截图

QQ20211228-171638@2x

如何重现 QMUIFloatLayoutViewDemo.zip 注释Demo ViewController.m221 行后运行,然后滑动就能复现

预期的表现

其他信息

fanyuecheng commented 2 years ago

大概是FloatLayoutView的布局应该是的写在cell的layoutSubviews里

0x1306a94 commented 2 years ago

一样的> 大概是FloatLayoutView的布局应该是的写在cell的layoutSubviews里

MoLice commented 2 years ago

这跟 QMUIFloatLayoutView 无关吧?你把一个 floatLayoutView(或者任何其他 view) 放到 cell 里,因为 cell 是复用的,所以在滚动过程中,floatLayoutView 的内容发生变化了,但却没人告诉 floatLayoutView “你的内容变了,你需要刷新一下 subviews 的布局”,那么 floatLayoutView 的 layoutSubviews 只能依赖系统的默认逻辑去触发刷新——被 add/remove 到 view 层级树里、frame.size 发生变化。所以你的业务代码什么时候会有问题—— button 内容变了,但 button 占据的行数没变,因为行数没变,所以 cell 高度没变,cell 高度没变,所以 floatLayoutView 的 frame 没变,floatLayoutView 的 frame 没变,它的 layoutSubviews 就不会被调用,layoutSubviews 不会被调用,内部的 subview 的 sizeThatFits、setFrame 就不会被调用,于是你就看到 issue 的现象。

你提的调用 button 的 sizeToFit 的方法只是间接起作用,直接解法是在你的 cell layoutSubviews 里主动调用 floatLayoutView setNeedsLayout。

0x1306a94 commented 2 years ago

这跟 QMUIFloatLayoutView 无关吧?你把一个 floatLayoutView(或者任何其他 view) 放到 cell 里,因为 cell 是复用的,所以在滚动过程中,floatLayoutView 的内容发生变化了,但却没人告诉 floatLayoutView “你的内容变了,你需要刷新一下 subviews 的布局”,那么 floatLayoutView 的 layoutSubviews 只能依赖系统的默认逻辑去触发刷新——被 add/remove 到 view 层级树里、frame.size 发生变化。所以你的业务代码什么时候会有问题—— button 内容变了,但 button 占据的行数没变,因为行数没变,所以 cell 高度没变,cell 高度没变,所以 floatLayoutView 的 frame 没变,floatLayoutView 的 frame 没变,它的 layoutSubviews 就不会被调用,layoutSubviews 不会被调用,内部的 subview 的 sizeThatFits、setFrame 就不会被调用,于是你就看到 issue 的现象。

你提的调用 button 的 sizeToFit 的方法只是间接起作用,直接解法是在你的 cell layoutSubviews 里主动调用 floatLayoutView setNeedsLayout。

好的