首页 > 解决方案 > 加速视图的碎片化

问题描述

我有以下代码(在 的扩展内UIView)将 aUIView分成一定数量的片段:

public func fragment(into numberOfFragments: Int) -> [UIView] {

        var fragments = [UIView]()    

        guard let containerView = superview, let snapshot = snapshotView(afterScreenUpdates: true) else { return fragments }

        let fragmentWidth = snapshot.frame.width / CGFloat(numberOfFragments)
        let fragmentHeight = snapshot.frame.height / CGFloat(numberOfFragments)

        for x in stride(from: 0.0, to: snapshot.frame.width, by: fragmentWidth) {
            for y in stride(from: 0.0, to: snapshot.frame.height, by: fragmentHeight) {

                let rect = CGRect(x: x, y: y, width: fragmentWidth, height: fragmentHeight)

                if let fragment = snapshot.resizableSnapshotView(from: rect, afterScreenUpdates: true, withCapInsets: .zero) {        

                    fragment.frame = convert(rect, to: containerView)
                    containerView.addSubview(fragment)
                    fragments.append(fragment)

                }

            }

        }

        return fragments

    }

但是,numberOfFragments=20此代码大约需要 2 秒才能完成。有没有办法以更快的方式实现同​​样的结果?我应该改用动画/过渡吗?

非常感谢。

标签: iosswiftuiviewsplitsnapshot-view

解决方案


此解决方案使用 UIImageViews 而不是 UIViews。它裁剪单个捕获的屏幕截图,而不是调用更昂贵的resizableSnapshotView400 次。afterScreenUpdates如果设置为 false(适用于我的测试用例),时间从 ~2.0 秒下降到 0.088 秒。如果afterScreenUpdates您的目的需要,则时间约为 0.15 秒。仍然 - 比 2.0 秒快得多!

public func fragment(into numberOfFragments: Int) -> [UIImageView] {

    var fragments = [UIImageView]()

    guard let containerView = superview else { return fragments }

    let renderer = UIGraphicsImageRenderer(size: containerView.bounds.size)
    let image = renderer.image { ctx in
        containerView.drawHierarchy(in: containerView.bounds, afterScreenUpdates: false)
    }

    let fragmentWidth = containerView.frame.width / CGFloat(numberOfFragments)
    let fragmentHeight = containerView.frame.height / CGFloat(numberOfFragments)

    for x in stride(from: 0.0, to: containerView.frame.width, by: fragmentWidth) {
        for y in stride(from: 0.0, to: containerView.frame.height, by: fragmentHeight) {

            let rect = CGRect(x: x, y: y, width: fragmentWidth, height: fragmentHeight)

            if let imageFrag = cropImage(image, toRect: rect) {
                let fragment = UIImageView(image: imageFrag)
                fragment.frame = convert(rect, to: containerView)
                containerView.addSubview(fragment)
                fragments.append(fragment)
            }
        }
    }

    return fragments

}


func cropImage(_ inputImage: UIImage, toRect cropRect: CGRect) -> UIImage?
{

    let imageViewScale = UIScreen.main.scale

    // Scale cropRect to handle images larger than shown-on-screen size
    let cropZone = CGRect(x:cropRect.origin.x * imageViewScale,
                          y:cropRect.origin.y * imageViewScale,
                          width:cropRect.size.width * imageViewScale,
                          height:cropRect.size.height * imageViewScale)

    // Perform cropping in Core Graphics
    guard let cutImageRef: CGImage = inputImage.cgImage?.cropping(to:cropZone)
        else {
            return nil
    }

    // Return image to UIImage
    let croppedImage: UIImage = UIImage(cgImage: cutImageRef)
    return croppedImage
}

推荐阅读