iOS Swift 绘制到屏幕
iOS Swift draw to screen
我是 iOS 开发的新手,需要比我更有经验的人的帮助。我在互联网上搜索,但找不到任何有效的解决方案。
我需要像 Android 中的 canvas 那样在屏幕上绘图。目前我有一个 CADisplayLink
来每帧调用一个函数。这运作良好。问题是:我实际上如何在每一帧向屏幕绘制任何东西,例如矩形、圆形或直线?
这就是我所拥有的(我将此 class 链接到情节提要中的视图):
class Canvas: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineWidth(2.0)
context?.setStrokeColor(UIColor.green.cgColor)
context?.move(to: CGPoint(x: 30, y: 30))
context?.addLine(to: CGPoint(x: Double(xBall), y: Double(yBall)))
context?.strokePath()
}
}
使用下面的代码我实际上可以在屏幕上画一条线:
let canvas = Canvas()
canvas.draw(CGRect())
问题是,这只能工作一次。当我的循环中有 canvas.draw(CGRect())
重复每一帧时,它适用于第一帧(xBall
和 yBall
的初始值)并且再也不会。当我在 draw
方法中打印值时,它会在每一帧被调用并且变量具有正确的值。但它不会将其绘制到屏幕上。我尝试在 draw
方法中添加行 setNeedsDisplay()
,结果相似。
任何帮助将不胜感激!谢谢!
如果你参考draw(_:)
documentation,它说:
This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay()
or setNeedsDisplay(_:)
method instead.
常见的方法是让你的视图控制器 viewDidLoad
方法添加 Canvas
view:
override func viewDidLoad() {
super.viewDidLoad()
let canvas = Canvas()
canvas.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(canvas)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
您不会自己调用 draw(_:)
,而是 OS 会自动调用。您需要做的就是使用 addSubview(_:)
将其添加到您的视图层次结构中。然后你可以让你的 CADisplayLink
更新属性并调用 setNeedsDisplay
(或者,更好的是,将 didSet
观察者添加到那些为你调用 setNeedsDisplay
的属性)。
顺便说一句,如果您不想以编程方式添加它,如上所示,您可以直接在 Interface Builder 中添加 Canvas
。只需将 UIView
拖到您的故事板场景上,添加所有适当的约束,转到“身份”检查器,并将基本 class 名称设置为 Canvas
:
如果您将 class 标记为 @IBDesignable
,您实际上可以在 Interface Builder 中看到正确呈现的路径,如上所示。
多项改进:
如果您打算自己实现 draw(_:)
,而不是使用 UIGraphicsGetCurrentContext
获取图形上下文,您可能只是 stroke
一个 UIBezierPath
:
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: CGPoint(x: 30, y: 30))
path.addLine(to: CGPoint(x: xBall, y: yBall))
path.lineWidth = 2
UIColor.green.setStroke()
path.stroke()
}
与您的解决方案一样,这需要在您更新 xBall
和 yBall
之后,如果您调用 setNeedsDisplay
以使用更新后的路径重新呈现视图。
有时我们甚至不会实施 draw(_:)
。我们只需添加一个 CAShapeLayer
作为子层:
@IBDesignable
class Canvas: UIView {
var xBall = ...
var yBall = ...
let shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = 2
return shapeLayer
}()
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
func configure() {
layer.addSublayer(shapeLayer)
updatePath()
}
func updatePath() {
let path = UIBezierPath()
path.move(to: CGPoint(x: 30, y: 30))
path.addLine(to: CGPoint(x: xBall, y: yBall))
shapeLayer.path = path.cgPath
}
}
在这种方法中,您只需更新 shapeLayer
的 path
,OS 将为您渲染形状图层(及其 path
) .
我是 iOS 开发的新手,需要比我更有经验的人的帮助。我在互联网上搜索,但找不到任何有效的解决方案。
我需要像 Android 中的 canvas 那样在屏幕上绘图。目前我有一个 CADisplayLink
来每帧调用一个函数。这运作良好。问题是:我实际上如何在每一帧向屏幕绘制任何东西,例如矩形、圆形或直线?
这就是我所拥有的(我将此 class 链接到情节提要中的视图):
class Canvas: UIView {
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
context?.setLineWidth(2.0)
context?.setStrokeColor(UIColor.green.cgColor)
context?.move(to: CGPoint(x: 30, y: 30))
context?.addLine(to: CGPoint(x: Double(xBall), y: Double(yBall)))
context?.strokePath()
}
}
使用下面的代码我实际上可以在屏幕上画一条线:
let canvas = Canvas()
canvas.draw(CGRect())
问题是,这只能工作一次。当我的循环中有 canvas.draw(CGRect())
重复每一帧时,它适用于第一帧(xBall
和 yBall
的初始值)并且再也不会。当我在 draw
方法中打印值时,它会在每一帧被调用并且变量具有正确的值。但它不会将其绘制到屏幕上。我尝试在 draw
方法中添加行 setNeedsDisplay()
,结果相似。
任何帮助将不胜感激!谢谢!
如果你参考draw(_:)
documentation,它说:
This method is called when a view is first displayed or when an event occurs that invalidates a visible part of the view. You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the
setNeedsDisplay()
orsetNeedsDisplay(_:)
method instead.
常见的方法是让你的视图控制器 viewDidLoad
方法添加 Canvas
view:
override func viewDidLoad() {
super.viewDidLoad()
let canvas = Canvas()
canvas.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(canvas)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
您不会自己调用 draw(_:)
,而是 OS 会自动调用。您需要做的就是使用 addSubview(_:)
将其添加到您的视图层次结构中。然后你可以让你的 CADisplayLink
更新属性并调用 setNeedsDisplay
(或者,更好的是,将 didSet
观察者添加到那些为你调用 setNeedsDisplay
的属性)。
顺便说一句,如果您不想以编程方式添加它,如上所示,您可以直接在 Interface Builder 中添加 Canvas
。只需将 UIView
拖到您的故事板场景上,添加所有适当的约束,转到“身份”检查器,并将基本 class 名称设置为 Canvas
:
如果您将 class 标记为 @IBDesignable
,您实际上可以在 Interface Builder 中看到正确呈现的路径,如上所示。
多项改进:
如果您打算自己实现
draw(_:)
,而不是使用UIGraphicsGetCurrentContext
获取图形上下文,您可能只是stroke
一个UIBezierPath
:override func draw(_ rect: CGRect) { let path = UIBezierPath() path.move(to: CGPoint(x: 30, y: 30)) path.addLine(to: CGPoint(x: xBall, y: yBall)) path.lineWidth = 2 UIColor.green.setStroke() path.stroke() }
与您的解决方案一样,这需要在您更新
xBall
和yBall
之后,如果您调用setNeedsDisplay
以使用更新后的路径重新呈现视图。有时我们甚至不会实施
draw(_:)
。我们只需添加一个CAShapeLayer
作为子层:@IBDesignable class Canvas: UIView { var xBall = ... var yBall = ... let shapeLayer: CAShapeLayer = { let shapeLayer = CAShapeLayer() shapeLayer.strokeColor = UIColor.green.cgColor shapeLayer.fillColor = UIColor.clear.cgColor shapeLayer.lineWidth = 2 return shapeLayer }() override init(frame: CGRect = .zero) { super.init(frame: frame) configure() } required init?(coder: NSCoder) { super.init(coder: coder) configure() } func configure() { layer.addSublayer(shapeLayer) updatePath() } func updatePath() { let path = UIBezierPath() path.move(to: CGPoint(x: 30, y: 30)) path.addLine(to: CGPoint(x: xBall, y: yBall)) shapeLayer.path = path.cgPath } }
在这种方法中,您只需更新
shapeLayer
的path
,OS 将为您渲染形状图层(及其path
) .