Swift 用一个起始接触点画一条直线

Swift 用一个起始接触点画一条直线,swift,uibezierpath,cgrect,touchesbegan,uigraphicscontext,Swift,Uibezierpath,Cgrect,Touchesbegan,Uigraphicscontext,我要我的swift代码画一条直线。现在,它选择一个点,用户将延伸定位在第一个点上的线。我只希望用户能够画线左或右。我尝试交替使用bezier.addLine(to:CGPoint(x:startTouch!.x,y:startTouch!.y)),但似乎没有任何效果 import UIKit class ViewController2: UIViewController { @IBOutlet weak var drawingPlace: UIImageView! var

我要我的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
    }

}
导入UIKit
类ViewController2:UIViewController{
@IBVAR绘图地点:UIImageView!
var startTouch:CGPoint?
var secondTouch:CGPoint?
var currentContext:CGContext?
var-prevImage:UIImage?
重写func viewDidLoad(){
super.viewDidLoad()
view.backgroundColor=.systemOrange
drawingPlace.backgroundColor=.gray
}
覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
让我们先接触
startTouch=触摸?位置(在:绘图位置)
}
覆盖功能触摸移动(touchs:Set,带有事件:UIEvent?){
接触{
secondTouch=触摸位置(在:drawingPlace)
if(self.currentContext==nil){
UIGraphicsBeginImageContext(drawingPlace.frame.size)
self.currentContext=UIGraphicsGetCurrentContext()
}否则{
self.currentContext?.clear(CGRect(x:0,y:0,width:drawingPlace.frame.width,height:drawingPlace.frame.height))
}
self.prevImage?.draw(在:self.drawingPlace.bounds中)
设bezier=UIBezierPath()
bezier.移动(到:startTouch!)
bezier.addLine(收件人:secondTouch!)
添加线(到:CGPoint(x:startTouch!.x,y:startTouch!.y))
bezier.close()
UIColor.blue.set()
self.currentContext?.setLineWidth(4)
self.currentContext?.addPath(bezier.cgPath)
self.currentContext?.strokePath()
设img2=self.currentContext?.makeImage()
drawingPlace.image=UIImage.init(cgImage:img2!)
}
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
self.currentContext=nil
self.prevImage=self.drawingPlace.image
}
}

如果要绘制水平线,请创建一个
CGPoint
,其
x
是触摸的位置,其
y
是起始点。这将产生一条水平线


话虽如此,以下是一些其他观察结果:

  • 如果调用
    UIGraphicsBeginImageContext
    ,则必须调用
    UIGraphicsEndImageContext
    。您应该在
    touchsmoved
    中执行此操作,而不是试图在调用之后保留上下文

  • 如果您要这样做,我们现在通常会使用
    UIGraphicsImageRenderer

  • 就我个人而言,我不会尝试为每次触摸渲染图像。那是一个相当昂贵的手术。我只需添加一个
    CAShapeLayer
    ,然后更新该层的
    路径。让
    CAShapeLayer
    处理路径的渲染

  • 我不太清楚为什么要遍历触摸数组。我只要拿一个就可以了

  • 我可能会建议使用预测性触碰来最小化感知的滞后

  • startTouch
    实际上是一个
    CGPoint
    ,而不是
    UITouch
    ,因此我可以将其称为
    startPoint

  • 如果您想制作快照图像,我会在
    touchesend
    中进行,而不是在
    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
        }
    }
    
    类ViewController:UIViewController{
    @IBVAR imageView:UIImageView!
    var起始点:CGPoint?
    let shapeLayer:CAShapeLayer={
    设shapeLayer=CAShapeLayer()
    shapeLayer.lineWidth=4
    shapeLayer.fillColor=UIColor.clear.cgColor
    shapeLayer.strokeColor=UIColor.blue.cgColor
    回程成形器
    }()
    重写func viewDidLoad(){
    super.viewDidLoad()
    imageView.backgroundColor=.systemOrange
    imageView.layer.addSublayer(shapeLayer)
    }
    覆盖func TouchesBegind(Touchs:Set,带有事件:UIEvent?){
    让我们先接触
    开始点=触摸?位置(在:图像视图中)
    }
    覆盖功能触摸移动(touchs:Set,带有事件:UIEvent?){
    guard var touch=touchs.first-else{return}
    如果let predicted=event?.predictedtouchs(for:touch)?.last{
    触摸=预测
    }
    更新路径(在:图像视图中,至:触摸)
    }
    覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
    guard let touch=touch.first else{return}
    更新路径(在:图像视图中,至:触摸)
    让image=UIGraphicsImageRenderer(边界:imageView.bounds)
    imageView.drawHierarchy(in:imageView.bounds,AfterScreenUpdate:true)
    }
    shapeLayer.path=nil
    imageView.image=image
    }
    }
    专用扩展视图控制器{
    func updatePath(在视图中:UIView,要触摸:UITouch){
    让点=触摸位置(在:视图中)
    guard view.bounds.contains(point)else{return}
    设bezier=UIBezierPath()
    bezier.移动(到:startPoint!)
    添加线(到:CGPoint(x:point.x,y:startPoint!.y))
    shapeLayer.path=bezier.cgPath
    }
    }
    
    这只是将当前行渲染为
    CAShapeLayer
    ,但当笔划完成时,它会创建图像视图的快照(永久捕获图像中的笔划),删除形状层的路径,并更新图像视图的
    图像


    但希望这能回答如何使线条水平的问题。

    你能更新你的代码吗,这样我就可以在@IBOutlet-weak-var-drawingPlace:UIImageView中绘图了!我可以在你的代码里画任何东西