用起点画一条直线

问题描述

我希望我的快速代码绘制水平直线。现在,它选择一个点,用户将锚定在第一个点上的线延伸。我只希望用户能够向左或向右画线。我尝试了交替使用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是起点的位置。这将导致一条水平线。


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

  1. 如果您致电UIGraphicsBeginImageContext,则必须致电UIGraphicsEndImageContext。您应该在touchesMoved内执行此操作,而不要在此调用之后继续使用上下文。

  2. 如果要执行此操作,那么今天通常会使用UIGraphicsImageRenderer

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

  4. 我不太确定为什么要遍历所有触摸。我只拿一个就用。

  5. 我可能建议您使用预测性触摸来最大程度地减少延迟感。

  6. startTouch实际上是CGPoint,而不是UITouch,因此我可以改称为startPoint

  7. 如果要制作快照图像,我会在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

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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...