如何将 UIBezierPath 添加到使用自动布局的 UIView?
How can I add a UIBezierPath to a UIView that uses auto layout?
在我的项目中,我想向 UIView
添加一行(此 UIView
使用自动布局)。
我正在使用 UIBezierPath
和 CAShapeLayer
来画线。
这是我的代码:
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...):
在我的项目中,我想向 UIView
添加一行(此 UIView
使用自动布局)。
我正在使用 UIBezierPath
和 CAShapeLayer
来画线。
这是我的代码:
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...):