如何将 UIBezierPath 添加到使用自动布局的 UIView?

How can I add a UIBezierPath to a UIView that uses auto layout?

在我的项目中,我想向 UIView 添加一行(此 UIView 使用自动布局)。 我正在使用 UIBezierPathCAShapeLayer 来画线。

这是我的代码:

let myView = UIView()
self.view.addSubView(myView)
myView.translatesAutoresizingMaskIntoConstraints = false
myView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
myView.heightAnchor.constraint(equalToConstant: 40).isActive = true
myView.widthAnchor.constraint(equalToConstant: 100).isActive = true
myView.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true

let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: myView.frame.height/2))
path.addLine(to: CGPoint(x: myView.frame.width, y: myView.frame.height/2))

let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = 11.0

myView.layer.addSublayer(shapeLayer)

但我的问题是 viewController 中没有显示任何行。 当我使用此代码时,一切正常并且该行显示完美:

let myView = UIView(frame: CGRect(x: 0, y: 160, width: 100, height: 40))
self.view.addSubView(myView)

我该如何解决这个问题?我必须使用自动布局。

我想我发现了你的问题。您已经定义了一个框架为 (0, 0, 0, 0) 的 UIView。如果您随后在该视图中绘制一条线,该线的坐标与该视图相关,则不会得到任何线。

我假设您希望视图在 0, 160 上,高度为 40,宽度为 100。那么该线应该 运行 从 (0, 20) 到 (100, 20)。

在这方面您的约束设置不正确,因为您的视图最终位于屏幕右上角。

我编写了以下可能有用的代码。您可以随心所欲地设置约束条件。

像这样制作自定义视图 (MyLineView):

import UIKit

class MyLineView: UIView {

    private let lineColor = UIColor.black

    override func draw(_ rect: CGRect) {

        let path = UIBezierPath()
        lineColor.setStroke()
        path.lineWidth = 11

        path.move(to: CGPoint(x: self.frame.origin.x, y: self.frame.size.height / 2))
        path.addLine(to: CGPoint(x: self.frame.size.width, y: self.frame.size.height / 2))
        path.stroke()

        print(self.frame)
    }
}

然后你可以像这样编写你的视图控制器:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

//        let myView = UIView(frame: CGRect(x: 0, y: 160, width: 100, height: 40))
        let myView = MyLineView()

        let viewPositionX: CGFloat = 0
        let viewPositionY: CGFloat = 160
        let viewWidth: CGFloat = 100
        let viewHeight: CGFloat = 40

        let topConstraint = viewPositionY + viewHeight - self.view.frame.size.height
        let widthConstraint = viewWidth - self.view.frame.size.width

        myView.backgroundColor = UIColor.green

        self.view.addSubview(myView)
        myView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint(item: myView, attribute: .leading, relatedBy: .equal, toItem: self.view, attribute: .leading, multiplier: 1, constant: viewPositionX).isActive = true
        NSLayoutConstraint(item: myView, attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top, multiplier: 1, constant: viewPositionY).isActive = true
        NSLayoutConstraint(item: myView, attribute: .bottom, relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1, constant: topConstraint).isActive = true
        NSLayoutConstraint(item: myView, attribute: .trailing, relatedBy: .equal, toItem: self.view, attribute: .trailing, multiplier: 1, constant: widthConstraint).isActive = true
    }
}

我刚刚添加了绿色背景颜色以查看视图的位置。这适用于我的 phone。希望这有帮助。

最好的办法是使用自定义 UIView 子类并在 layoutSubviews() 中设置图层路径。这样您就可以在需要时获得合适的框架。

这是一个简单的例子:

class LineView: UIView {

    let shapeLayer: CAShapeLayer = CAShapeLayer()

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }

    func commonInit() -> Void {

        layer.addSublayer(shapeLayer)
        shapeLayer.strokeColor = UIColor.black.cgColor
        shapeLayer.lineWidth = 11.0

    }

    override func layoutSubviews() {
        super.layoutSubviews()

        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: bounds.midY))
        path.addLine(to: CGPoint(x: bounds.maxX, y: bounds.midY))

        shapeLayer.path = path.cgPath

    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let myView = LineView()
        myView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(myView)
        NSLayoutConstraint.activate([
            myView.topAnchor.constraint(equalTo: self.view.topAnchor),
            myView.heightAnchor.constraint(equalToConstant: 40),
            myView.widthAnchor.constraint(equalToConstant: 100),
            myView.rightAnchor.constraint(equalTo: self.view.rightAnchor),
        ])

        // if you want to see the frame of myView
        //myView.backgroundColor = .yellow

    }

}

结果 - 背景为黄色,因此我们可以看到框架,并且有您的约束(您可能想使用 safeArea...):