提问者:小点点

在Swift5中同时缩小UIView和它的子视图?


我创建了UIView,它有一个子视图,它包含使用UIBEZIERPath创建的shape对象,并且UIView具有固定的高度和宽度(图1)。 当我点击蓝色按钮时,它应该缩小到另一个固定的宽度和高度。 我已经将CGaffineTransform应用到子视图中,我猜它是正确地缩小的,但是由于TopAnchorLeftAchor具有常量值,缩小后它不能正确显示(图2)。我将在这里附上我的源代码和屏幕截图,请分析一下,有人能建议更好的方法吗? 并非常感谢您的反馈和意见。

代码:

import UIKit

class ViewController: UIViewController {
    
    var screenView: UIView!
    var button: UIButton!
    
    let widthOfScaleDownView: CGFloat = 200
    let heightOfScaleDownView: CGFloat = 300
    
    override func viewDidLoad() {
        
        screenView = UIView(frame: .zero)
        screenView.translatesAutoresizingMaskIntoConstraints = false
        screenView.backgroundColor = UIColor.red
        self.view.addSubview(screenView)
        NSLayoutConstraint.activate([
            screenView.heightAnchor.constraint(equalToConstant: 800),
            screenView.widthAnchor.constraint(equalToConstant: 600),
            screenView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
            screenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0)
        ])
        button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.blue
        self.view.addSubview(button)
        NSLayoutConstraint.activate([
            button.heightAnchor.constraint(equalToConstant: 50),
            button.widthAnchor.constraint(equalToConstant: 100),
            button.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 950),
            button.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 350)
        ])
        button.setTitle("click", for: .normal)
        button.setTitleColor(UIColor.white, for: .normal)
        button.addTarget(self, action: #selector(scaleDownView(_:)), for: .touchUpInside)
        
        let shapeView = UIView(frame: .zero)
        shapeView.translatesAutoresizingMaskIntoConstraints = false
        let rect = CGRect(x: 0, y: 0, width: 300, height: 300)
        let shape = UIBezierPath(roundedRect: rect, cornerRadius: 50)
        let layer = CAShapeLayer()
        layer.path = shape.cgPath
        layer.lineWidth = 2
        shapeView.layer.addSublayer(layer)
        
        screenView.addSubview(shapeView)
        NSLayoutConstraint.activate([
            shapeView.topAnchor.constraint(equalTo: screenView.topAnchor, constant: 250),
            shapeView.leftAnchor.constraint(equalTo: screenView.leftAnchor, constant: 150)
        ])
    }
    
    @IBAction func scaleDownView(_ sender: UIButton) {
        let widthScale = widthOfScaleDownView/screenView.frame.width
        let heightScale = heightOfScaleDownView/screenView.frame.height
        screenView.subviews.forEach{ view in
            view.transform = CGAffineTransform(scaleX: widthScale, y: heightScale)
        }
        
        NSLayoutConstraint.activate([
            screenView.heightAnchor.constraint(equalToConstant: heightOfScaleDownView),
            screenView.widthAnchor.constraint(equalToConstant: widthOfScaleDownView),
            screenView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
            screenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0)
        ])
        
    }
    
    
}


共1个答案

匿名用户

几件事。。。

1-当您使用CGaffineTransform更改视图时,它将自动影响视图的子视图。 所以不需要循环。

2-转换是累积的,因此当“返回”到原始刻度时,使用.identity而不是另一个刻度转换。

3-不能多次设置约束。 所以如果你做了:

screenView.heightAnchor.constraint(equalToConstant: 800)

然后你也会:

screenView.heightAnchor.constraint(equalToConstant: heightOfScaleDownView)

您将获得自动布局冲突。。。 视图不能同时具有800分高和300分高。

请看一下我对您的代码所做的更改。 我还在缩放变换中添加了一个1秒的动画,这样你就可以看到它在做什么:

class ViewController: UIViewController {
    
    var screenView: UIView!
    var button: UIButton!
    
    let widthOfScaleDownView: CGFloat = 200
    let heightOfScaleDownView: CGFloat = 300
    
    override func viewDidLoad() {
        
        screenView = UIView(frame: .zero)
        screenView.translatesAutoresizingMaskIntoConstraints = false
        screenView.backgroundColor = UIColor.red
        self.view.addSubview(screenView)
        
        // constrain screenView
        //  width: 800 height: 600
        //  centered X and Y
        NSLayoutConstraint.activate([
            screenView.heightAnchor.constraint(equalToConstant: 800),
            screenView.widthAnchor.constraint(equalToConstant: 600),
            screenView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
            screenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0)
        ])

        button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.blue
        self.view.addSubview(button)
        NSLayoutConstraint.activate([
            button.heightAnchor.constraint(equalToConstant: 50),
            button.widthAnchor.constraint(equalToConstant: 100),
            button.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 950),
            button.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 350)
        ])
        button.setTitle("click", for: .normal)
        button.setTitleColor(UIColor.white, for: .normal)
        button.addTarget(self, action: #selector(scaleDownView(_:)), for: .touchUpInside)
        
        let shapeView = UIView(frame: .zero)
        shapeView.translatesAutoresizingMaskIntoConstraints = false
        let rect = CGRect(x: 0, y: 0, width: 300, height: 300)
        let shape = UIBezierPath(roundedRect: rect, cornerRadius: 50)
        let layer = CAShapeLayer()
        layer.path = shape.cgPath
        layer.lineWidth = 2
        shapeView.layer.addSublayer(layer)
        
        screenView.addSubview(shapeView)
        
        // constrain shapeView
        //  width: 300 height: 300
        //  centered X and Y in screenView
        NSLayoutConstraint.activate([
            shapeView.widthAnchor.constraint(equalToConstant: 300.0),
            shapeView.heightAnchor.constraint(equalToConstant: 300.0),
            shapeView.centerXAnchor.constraint(equalTo: screenView.centerXAnchor),
            shapeView.centerYAnchor.constraint(equalTo: screenView.centerYAnchor),
        ])
    }
    
    @IBAction func scaleDownView(_ sender: UIButton) {
        let widthScale = widthOfScaleDownView/screenView.frame.width
        let heightScale = heightOfScaleDownView/screenView.frame.height

        UIView.animate(withDuration: 1.0) {
            // if we have already been scaled down
            if widthScale == 1 {
                // animate the scale transform back to original (don't add another transform)
                self.screenView.transform = .identity
            } else {
                // animate the scale-down transform
                self.screenView.transform = CGAffineTransform(scaleX: widthScale, y: heightScale)
            }
        }

        // do NOT change screenView constraints!
    }
    
}