以起始接触点画一条直线
draw a straight line with a starting touch point
我希望我的 swift 代码绘制一条水平直线。现在它选择一个点,用户延伸锚定在第一个点的线。我只希望用户能够向左或向右画线。我尝试交替 bezier.addLine(to: CGPoint(x:startTouch!.x, y:startTouch!.y)) 但这似乎没有任何效果。
import UIKit
class ViewController2: UIViewController {
@IBOutlet weak var drawingPlace: UIImageView!
var startTouch : CGPoint?
var secondTouch : CGPoint?
var currentContext : CGContext?
var prevImage : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemOrange
drawingPlace.backgroundColor = .gray
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
startTouch = touch?.location(in: drawingPlace)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
secondTouch = touch.location(in: drawingPlace)
if(self.currentContext == nil){
UIGraphicsBeginImageContext(drawingPlace.frame.size)
self.currentContext = UIGraphicsGetCurrentContext()
}else{
self.currentContext?.clear(CGRect(x: 0, y: 0, width: drawingPlace.frame.width, height: drawingPlace.frame.height))
}
self.prevImage?.draw(in: self.drawingPlace.bounds)
let bezier = UIBezierPath()
bezier.move(to: startTouch!)
bezier.addLine(to: secondTouch!)
bezier.addLine(to: CGPoint(x:startTouch!.x, y:startTouch!.y))
bezier.close()
UIColor.blue.set()
self.currentContext?.setLineWidth(4)
self.currentContext?.addPath(bezier.cgPath)
self.currentContext?.strokePath()
let img2 = self.currentContext?.makeImage()
drawingPlace.image = UIImage.init(cgImage: img2!)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.currentContext = nil
self.prevImage = self.drawingPlace.image
}
}
如果要画水平线,创建一个CGPoint
,x
是触摸的位置,y
是起点的位置。这将导致一条水平线。
话虽如此,这里还有一些其他观察结果:
如果调用UIGraphicsBeginImageContext
,则必须调用UIGraphicsEndImageContext
。您应该在 touchesMoved
内执行此操作,而不是试图挂在该调用之外的上下文中。
如果你这样做,我们现在一般会用UIGraphicsImageRenderer
。
就我个人而言,我不会尝试为每次触摸都渲染图像。这是一个相当昂贵的操作。我只想添加一个 CAShapeLayer
,然后更新该层的 path
。让 CAShapeLayer
负责路径的渲染。
我不太确定您为什么要遍历触摸数组。我会拿一个然后用那个。
我可能会建议使用预测触摸来最大程度地减少感知到的延迟。
startTouch
实际上是CGPoint
,而不是UITouch
,所以我可能会叫它startPoint
。
如果你想制作快照图像,我会在 touchesEnded
中进行,而不是在 touchesMoved
.
中进行
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
var startPoint: CGPoint?
let shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 4
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.blue.cgColor
return shapeLayer
}()
override func viewDidLoad() {
super.viewDidLoad()
imageView.backgroundColor = .systemOrange
imageView.layer.addSublayer(shapeLayer)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
startPoint = touch?.location(in: imageView)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard var touch = touches.first else { return }
if let predicted = event?.predictedTouches(for: touch)?.last {
touch = predicted
}
updatePath(in: imageView, to: touch)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
updatePath(in: imageView, to: touch)
let image = UIGraphicsImageRenderer(bounds: imageView.bounds).image { _ in
imageView.drawHierarchy(in: imageView.bounds, afterScreenUpdates: true)
}
shapeLayer.path = nil
imageView.image = image
}
}
private extension ViewController {
func updatePath(in view: UIView, to touch: UITouch) {
let point = touch.location(in: view)
guard view.bounds.contains(point) else { return }
let bezier = UIBezierPath()
bezier.move(to: startPoint!)
bezier.addLine(to: CGPoint(x: point.x, y: startPoint!.y))
shapeLayer.path = bezier.cgPath
}
}
这只是将当前行呈现为 CAShapeLayer
,但是当笔划完成时,它会创建图像视图的快照(永久捕获图像中的笔划),删除形状图层的路径,并更新图像视图的 image
.
但希望这能回答关于如何使线水平的问题。
我希望我的 swift 代码绘制一条水平直线。现在它选择一个点,用户延伸锚定在第一个点的线。我只希望用户能够向左或向右画线。我尝试交替 bezier.addLine(to: CGPoint(x:startTouch!.x, y:startTouch!.y)) 但这似乎没有任何效果。
import UIKit
class ViewController2: UIViewController {
@IBOutlet weak var drawingPlace: UIImageView!
var startTouch : CGPoint?
var secondTouch : CGPoint?
var currentContext : CGContext?
var prevImage : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemOrange
drawingPlace.backgroundColor = .gray
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
startTouch = touch?.location(in: drawingPlace)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
secondTouch = touch.location(in: drawingPlace)
if(self.currentContext == nil){
UIGraphicsBeginImageContext(drawingPlace.frame.size)
self.currentContext = UIGraphicsGetCurrentContext()
}else{
self.currentContext?.clear(CGRect(x: 0, y: 0, width: drawingPlace.frame.width, height: drawingPlace.frame.height))
}
self.prevImage?.draw(in: self.drawingPlace.bounds)
let bezier = UIBezierPath()
bezier.move(to: startTouch!)
bezier.addLine(to: secondTouch!)
bezier.addLine(to: CGPoint(x:startTouch!.x, y:startTouch!.y))
bezier.close()
UIColor.blue.set()
self.currentContext?.setLineWidth(4)
self.currentContext?.addPath(bezier.cgPath)
self.currentContext?.strokePath()
let img2 = self.currentContext?.makeImage()
drawingPlace.image = UIImage.init(cgImage: img2!)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.currentContext = nil
self.prevImage = self.drawingPlace.image
}
}
如果要画水平线,创建一个CGPoint
,x
是触摸的位置,y
是起点的位置。这将导致一条水平线。
话虽如此,这里还有一些其他观察结果:
如果调用
UIGraphicsBeginImageContext
,则必须调用UIGraphicsEndImageContext
。您应该在touchesMoved
内执行此操作,而不是试图挂在该调用之外的上下文中。如果你这样做,我们现在一般会用
UIGraphicsImageRenderer
。就我个人而言,我不会尝试为每次触摸都渲染图像。这是一个相当昂贵的操作。我只想添加一个
CAShapeLayer
,然后更新该层的path
。让CAShapeLayer
负责路径的渲染。我不太确定您为什么要遍历触摸数组。我会拿一个然后用那个。
我可能会建议使用预测触摸来最大程度地减少感知到的延迟。
startTouch
实际上是CGPoint
,而不是UITouch
,所以我可能会叫它startPoint
。如果你想制作快照图像,我会在
中进行touchesEnded
中进行,而不是在touchesMoved
.
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
var startPoint: CGPoint?
let shapeLayer: CAShapeLayer = {
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 4
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.blue.cgColor
return shapeLayer
}()
override func viewDidLoad() {
super.viewDidLoad()
imageView.backgroundColor = .systemOrange
imageView.layer.addSublayer(shapeLayer)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
startPoint = touch?.location(in: imageView)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard var touch = touches.first else { return }
if let predicted = event?.predictedTouches(for: touch)?.last {
touch = predicted
}
updatePath(in: imageView, to: touch)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
updatePath(in: imageView, to: touch)
let image = UIGraphicsImageRenderer(bounds: imageView.bounds).image { _ in
imageView.drawHierarchy(in: imageView.bounds, afterScreenUpdates: true)
}
shapeLayer.path = nil
imageView.image = image
}
}
private extension ViewController {
func updatePath(in view: UIView, to touch: UITouch) {
let point = touch.location(in: view)
guard view.bounds.contains(point) else { return }
let bezier = UIBezierPath()
bezier.move(to: startPoint!)
bezier.addLine(to: CGPoint(x: point.x, y: startPoint!.y))
shapeLayer.path = bezier.cgPath
}
}
这只是将当前行呈现为 CAShapeLayer
,但是当笔划完成时,它会创建图像视图的快照(永久捕获图像中的笔划),删除形状图层的路径,并更新图像视图的 image
.
但希望这能回答关于如何使线水平的问题。