swift 中的约束有问题

Constraint having issues in swift

我遇到了约束问题。我正在使用 UIBezierPath 和自动布局。我已经完成了此处给出的几乎所有内容,但问题仍未解决,这就是我发布此问题的原因。我正在使用以下函数来圆化我视图的某个角落(我使用故事板制作的)

func addShadowAndCorner(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
    
    let shadowLayer = CAShapeLayer()
    let size = CGSize(width: cornerRadius, height: cornerRadius)
    let cgPath = UIBezierPath(roundedRect: self.curvedView.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
    shadowLayer.path = cgPath //2
    shadowLayer.fillColor = fillColor.cgColor //3
    shadowLayer.shadowColor = shadowColor.cgColor //4
    shadowLayer.shadowPath = cgPath
    shadowLayer.shadowOffset = offSet //5
    shadowLayer.shadowOpacity = opacity
    shadowLayer.shadowRadius = shadowRadius
    self.curvedView.layer.addSublayer(shadowLayer)
}

然后我调用这个函数如下

func configureView() {
    self.view.backgroundColor = UIColor(named: "appBackgroundColor")
    curvedView.backgroundColor = .clear
    self.addShadowAndCorner(shadowColor: .darkGray, offSet: CGSize.init(width: 3.0, height: 3.0), opacity: 0.6, shadowRadius: 8, cornerRadius: 80, corners: [.topRight, .bottomLeft], fillColor: .white)
}

我在“override func viewDidLayoutSubviews()”中调用了上面的函数。但是对于不同 phone 大小

的约束,我没有得到预期的行为

在 iPhone 11 模拟器上 运行 时代码运行良好,屏幕截图分享如下。

但是当 运行 在 iPhone SE 模拟器上使用相同的代码时,它无法按预期工作。下面分享了 iPhone SE

的屏幕截图

storyboard 中 curvedView 的约束是。

请帮帮我。提前致谢

你应该在 didLayoutSubviews 中应用影子代码。那时你的观点知道他们的框架大小。确保你也调用 super。

注意不要每次都通过从 didLayoutSubviews 调用 addShadowAndCorner 函数来重新添加阴影子层。

通过创建自定义 UIView 子类,您将获得最可靠(和灵活)的结果。

这是一个简单的例子:

class MyCustomView: UIView {

    // properties with default values
    var shadowColor: UIColor = .darkGray
    var offset: CGSize = .zero
    var opacity: Float = 1.0
    var shadowRadius: CGFloat = 0.0
    var cornerRadius: CGFloat = 0.0
    var corners: UIRectCorner = []
    var fillColor: UIColor = .white
    
    let shadowLayer = CAShapeLayer()

    convenience init(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
        self.init(frame: .zero)
        self.shadowColor = shadowColor
        self.offset = offSet
        self.opacity = opacity
        self.shadowRadius = shadowRadius
        self.cornerRadius = cornerRadius
        self.corners = corners
        self.fillColor = fillColor
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        layer.addSublayer(shadowLayer)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let size = CGSize(width: cornerRadius, height: cornerRadius)
        let cgPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
        shadowLayer.path = cgPath //2
        shadowLayer.fillColor = fillColor.cgColor //3
        shadowLayer.shadowColor = shadowColor.cgColor //4
        shadowLayer.shadowPath = cgPath
        shadowLayer.shadowOffset = offset //5
        shadowLayer.shadowOpacity = opacity
        shadowLayer.shadowRadius = shadowRadius
    }

    func configureView(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
        self.shadowColor = shadowColor
        self.offset = offSet
        self.opacity = opacity
        self.shadowRadius = shadowRadius
        self.cornerRadius = cornerRadius
        self.corners = corners
        self.fillColor = fillColor
        setNeedsLayout()
    }

}

然后您可以在情节提要中添加一个 UIView,将其自定义 Class 分配给 MyCustomView,将其连接到一个 @IBOutlet,然后在 viewDidLoad():

class MyTestVC: UIViewController {
    
    @IBOutlet var curvedView: MyCustomView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        curvedView.backgroundColor = .clear
        curvedView.configureView(shadowColor: .darkGray, offSet: CGSize.init(width: 3.0, height: 3.0), opacity: 0.6, shadowRadius: 8, cornerRadius: 80, corners: [.topRight, .bottomLeft], fillColor: .white)

    }
}

现在,它会在框架发生变化时自动更新...例如在不同的设备或设备旋转时:

您可以通过如下代码创建它:

let curvedView = MyCustomView(shadowColor: .darkGray, offSet: CGSize.init(width: 3.0, height: 3.0), opacity: 0.6, shadowRadius: 8, cornerRadius: 80, corners: [.topRight, .bottomLeft], fillColor: .white)

并且,只需很少的努力,您就可以做到 @IBDesignable 并将您的属性配置为 @IBInspectable ... 然后,当您在 Storyboard 中布置它时,您可以直观地看到结果。

唯一棘手的 属性 是角,因为 UIRectCorner 没有直接的 @IBInspectable 选项...所以我们可以为每个角使用 Bool 属性:

@IBDesignable
class MyCustomView: UIView {
    
    // properties with default values
    @IBInspectable var shadowColor: UIColor = .darkGray
    @IBInspectable var offset: CGSize = .zero
    @IBInspectable var opacity: Float = 1.0
    @IBInspectable var shadowRadius: CGFloat = 0.0
    @IBInspectable var cornerRadius: CGFloat = 0.0
    @IBInspectable var topLeft: Bool = false
    @IBInspectable var topRight: Bool = false
    @IBInspectable var bottomLeft: Bool = false
    @IBInspectable var bottomRight: Bool = false
    @IBInspectable var fillColor: UIColor = .white
    
    private let shadowLayer = CAShapeLayer()
    
    convenience init(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
        self.init(frame: .zero)
        self.shadowColor = shadowColor
        self.offset = offSet
        self.opacity = opacity
        self.shadowRadius = shadowRadius
        self.cornerRadius = cornerRadius
        self.fillColor = fillColor
        
        self.topLeft = corners.contains(.topLeft)
        self.topRight = corners.contains(.topRight)
        self.bottomLeft = corners.contains(.bottomLeft)
        self.bottomRight = corners.contains(.bottomRight)
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        layer.addSublayer(shadowLayer)
    }
    override func layoutSubviews() {
        super.layoutSubviews()

        backgroundColor = .clear
        
        var corners: UIRectCorner = UIRectCorner()
        
        if self.topLeft { corners.insert(.topLeft) }
        if self.topRight { corners.insert(.topRight) }
        if self.bottomLeft { corners.insert(.bottomLeft) }
        if self.bottomRight { corners.insert(.bottomRight) }

        let size = CGSize(width: cornerRadius, height: cornerRadius)
        let cgPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
        shadowLayer.path = cgPath
        shadowLayer.fillColor = self.fillColor.cgColor
        shadowLayer.shadowColor = self.shadowColor.cgColor
        shadowLayer.shadowPath = cgPath
        shadowLayer.shadowOffset = self.offset
        shadowLayer.shadowOpacity = self.opacity
        shadowLayer.shadowRadius = self.shadowRadius
    }
    
    public func configureView(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
        self.shadowColor = shadowColor
        self.offset = offSet
        self.opacity = opacity
        self.shadowRadius = shadowRadius
        self.cornerRadius = cornerRadius
        self.fillColor = fillColor
        
        self.topLeft = corners.contains(.topLeft)
        self.topRight = corners.contains(.topRight)
        self.bottomLeft = corners.contains(.bottomLeft)
        self.bottomRight = corners.contains(.bottomRight)

        setNeedsLayout()
    }
    
}

现在,我们在 Storyboard 中得到了这个: