高效的屏幕外UIView渲染和镜像

Qby*_*yte 7 rendering off-screen uiview ios swift

我有一个"屏幕外"的UIView层次结构,我希望在屏幕的不同位置进行渲染.此外,应该可以仅显示此视图层次结构的一部分,并且应该反映对此层次结构所做的所有更改.

困难:

  • 如果要将所有更改合并到视图层次结构中,则该UIView方法drawHierarchy(in:afterScreenUpdates:)始终调用draw(_ rect:),因此对于大型层次结构而言效率非常低.您必须在每次屏幕更新时重绘它或观察所有视图的所有更改属性.绘制视图层次结构文档
  • UIView方法snapshotView(afterScreenUpdates:)也没有多大帮助,因为如果此层次结构是"屏幕外",我还没有找到获得正确视图层次结构图的方法.快照视图文档

"屏幕外":此视图层次结构的根视图不是应用程序UI的一部分.它没有超级视图.

您可以在下面看到我的想法的直观表示:

例

Cen*_*Guy 0

这是我将如何去做的。首先,我将复制您要复制的视图。我为此写了一个小扩展:

extension UIView {
    func duplicate<T: UIView>() -> T {
        return NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: self)) as! T
    }

    func copyProperties(fromView: UIView, recursive: Bool = true) {
        contentMode = fromView.contentMode
        tag = fromView.tag

        backgroundColor = fromView.backgroundColor
        tintColor = fromView.tintColor

        layer.cornerRadius = fromView.layer.cornerRadius
        layer.maskedCorners = fromView.layer.maskedCorners

        layer.borderColor = fromView.layer.borderColor
        layer.borderWidth = fromView.layer.borderWidth

        layer.shadowOpacity = fromView.layer.shadowOpacity
        layer.shadowRadius = fromView.layer.shadowRadius
        layer.shadowPath = fromView.layer.shadowPath
        layer.shadowColor = fromView.layer.shadowColor
        layer.shadowOffset = fromView.layer.shadowOffset

        clipsToBounds = fromView.clipsToBounds
        layer.masksToBounds = fromView.layer.masksToBounds
        mask = fromView.mask
        layer.mask = fromView.layer.mask

        alpha = fromView.alpha
        isHidden = fromView.isHidden
        if let gradientLayer = layer as? CAGradientLayer, let fromGradientLayer = fromView.layer as? CAGradientLayer {
            gradientLayer.colors = fromGradientLayer.colors
            gradientLayer.startPoint = fromGradientLayer.startPoint
            gradientLayer.endPoint = fromGradientLayer.endPoint
            gradientLayer.locations = fromGradientLayer.locations
            gradientLayer.type = fromGradientLayer.type
        }

        if let imgView = self as? UIImageView, let fromImgView = fromView as? UIImageView {
            imgView.tintColor = .clear
            imgView.image = fromImgView.image?.withRenderingMode(fromImgView.image?.renderingMode ?? .automatic)
            imgView.tintColor = fromImgView.tintColor
        }

        if let btn = self as? UIButton, let fromBtn = fromView as? UIButton {
            btn.setImage(fromBtn.image(for: fromBtn.state), for: fromBtn.state)
        }

        if let textField = self as? UITextField, let fromTextField = fromView as? UITextField {
            if let leftView = fromTextField.leftView {
                textField.leftView = leftView.duplicate()
                textField.leftView?.copyProperties(fromView: leftView)
            }

            if let rightView = fromTextField.rightView {
                textField.rightView = rightView.duplicate()
                textField.rightView?.copyProperties(fromView: rightView)
            }

            textField.attributedText = fromTextField.attributedText
            textField.attributedPlaceholder = fromTextField.attributedPlaceholder
        }

        if let lbl = self as? UILabel, let fromLbl = fromView as? UILabel {
            lbl.attributedText = fromLbl.attributedText
            lbl.textAlignment = fromLbl.textAlignment
            lbl.font = fromLbl.font
            lbl.bounds = fromLbl.bounds
        }

       if recursive {
            for (i, view) in subviews.enumerated() {
                if i >= fromView.subviews.count {
                    break
                }

                view.copyProperties(fromView: fromView.subviews[i])
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用此扩展,只需执行以下操作

let duplicateView = originalView.duplicate()
duplicateView.copyProperties(fromView: originalView)
parentView.addSubview(duplicateView)
Run Code Online (Sandbox Code Playgroud)

然后我会屏蔽重复视图以仅获取您想要的特定部分

let mask = UIView(frame: CGRect(x: 0, y: 0, width: yourNewWidth, height: yourNewHeight))
mask.backgroundColor = .black
duplicateView.mask = mask
Run Code Online (Sandbox Code Playgroud)

最后,我将使用 CGAffineTransform 将其缩放到您想要的任何大小

duplicateView.transform = CGAffineTransform(scaleX: xScale, y: yScale)
Run Code Online (Sandbox Code Playgroud)

copyProperties 函数应该可以正常工作,但如果需要,您可以更改它,以将更多内容从一个视图复制到另一个视图。

祝你好运,让我知道进展如何:)