将 UICollectionViewFlowLayout 与 UIDynamicAnimator 一起使用时,layoutAttributesForItem 中的框架错误

问题描述

所以我实现了一个带有自定义 UICollectionViewFlowLayout 的 UICollectionView,其中包含一个 UIDynamicAnimator,用于在滚动时为我的单元格设置动画。我使用 2013 WWDC reference 来复制消息退回。

一切正常,只是我注意到在我的单元格中添加的圆形视图的一侧有一个奇怪的切口。请参阅下面的屏幕截图:

weird cut

  1. 是使用 UIDynamicAnimator 初始化我的 FlowLayout 时单元格的屏幕截图。 (没什么特别的,我只是展示一件我 添加链接到我的动画师的 uicollisionbehavior,请参阅下面的代码
  2. 在没有动画师的情况下使用简单的 FlowLayout 时是同一个单元格

如果我们仔细观察,我们会发现 n°1 的红色边缺少一条 1 像素的垂直线,而绿色边还有一条。

这会导致我的单元格中包含的每个子视图都有剪切效果(无论是视图还是图像等)

所以我进行了调查以了解导致这种情况的原因,我发现从第二次进入方法 layoutAttributesForElements(in rect: CGRect) 时返回的 x 位置是错误的。

我的方法 sizeforItemAt() 返回一个经典的 CGSize(width: collectionView.bounds.width,height: 100),但 dynamicAnimator.items(in: rect) 为我的单元返回一个等于 CGRect(0.1666666666666572,0.0,375.0,100.0) 的帧。

这个 x 位置应该是 0,因为我自己没有应用任何变换。

0.1666666666666572 等于 1/6,这看起来像是浮点精度问题。

有没有人知道是什么导致了这种情况,以及如何解决

import Foundation
import UIKit

// Minimal implementation of https://developer.apple.com/videos/play/wwdc2013/217/ to reproduce 0.16667 error

class MinimalWWDCFlowLayout: UICollectionViewFlowLayout {
    lazy var behavior: uicollisionbehavior = .init()
    lazy var dynamicAnimator: UIDynamicAnimator = {
        let res = UIDynamicAnimator(collectionViewLayout: self)
        res.addBehavior(behavior)
        return res
    }()

    override func prepare() {
        super.prepare()

        guard let items = super.layoutAttributesForElements(in: .init(origin: .zero,size: collectionViewContentSize)),let firstItem = items.first else {
            return
        }
        guard behavior.items.isEmpty else {
            return
        }
        behavior.addItem(firstItem) // This create a debug log when called twice (no error,just a log)
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let items = dynamicAnimator.items(in: rect) as? [UICollectionViewLayoutAttributes]

        guard let firstItem = items?.first else { return nil }
        print("?️ item frame: \(firstItem.frame))") // This is returning frame.x = 0.1666..67. Calling super.layoutAttributesForElements(in:) instead is returning 0 as expected.

        return items
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return dynamicAnimator.layoutAttributesForCell(at: indexPath)
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return false
    }
}

注意:这似乎只发生在具有 3 倍分辨率的设备上。在 iPhone 11 上运行此代码可以正常工作,但会在 iPhone 11 Pro 上导致所描述的错误

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...