Ios 使用核心图形在UIImageView上绘制矩形

Ios 使用核心图形在UIImageView上绘制矩形,ios,uiimageview,core-graphics,Ios,Uiimageview,Core Graphics,我想让用户在UIImageView 我为第一个和最后一个触摸位置添加了两个变量 我增加了这个功能:- func draw(from: CGPoint, to: CGPoint) { UIGraphicsBeginImageContext(imageView.frame.size) context = UIGraphicsGetCurrentContext() context?.setStrokeColor(UIColor(red: 0, green: 0, blue: 0

我想让用户在
UIImageView
我为第一个和最后一个触摸位置添加了两个变量 我增加了这个功能:-

func draw(from: CGPoint, to: CGPoint) {
    UIGraphicsBeginImageContext(imageView.frame.size)
    context = UIGraphicsGetCurrentContext()
    context?.setStrokeColor(UIColor(red: 0, green: 0, blue: 0, alpha: 1.0).cgColor)
    context?.setLineWidth(5.0)
    let currentRect = CGRect(x: from.x,
                             y: from.y,
                             width: to.x - from.x,
                             height: to.y - from.y)
    context?.addRect(currentRect)
    context?.drawPath(using: .stroke)
    context?.strokePath()
    imageView.image?.draw(in: self.imageView.frame)
    imageView.image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
}
我将该方法添加到(
touchMoved
)中,它绘制了许多矩形

我将该方法添加到(
touchEnded
)中,它会绘制一个,但当用户移动触摸时,它不会出现

override func touchsbegind(touch:Set,带有事件:UIEvent?){
如果让触摸=先触摸{
firstTouchLocation=touch.location(在:self.view中)
}
}
覆盖功能触摸移动(touchs:Set,带有事件:UIEvent?){
如果让触摸=先触摸{
lastTouchLocation=touch.location(在:self.view中)
绘制(从:firstTouchLocation到:lastTouchLocation)
}
}
覆盖函数touchesend(touchs:Set,带有事件:UIEvent?){
如果让触摸=先触摸{
lastTouchLocation=touch.location(在:self.view中)
绘制(从:firstTouchLocation到:lastTouchLocation)
}
}

我想让用户在触摸移动时扩展矩形,并在触摸结束时绘制,您将用一个新的图像替换您的
图像,该图像由先前的
图像
加上在其上绘制的矩形组成。绘制原始图像,而不是从图像视图中绘制图像

或者,可以将矩形渲染为形状层,只需更新该形状层的路径:

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    private let shapeLayer: CAShapeLayer = {
        let _shapeLayer = CAShapeLayer()
        _shapeLayer.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
        _shapeLayer.strokeColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
        _shapeLayer.lineWidth = 3
        return _shapeLayer
    }()

    private var startPoint: CGPoint!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.layer.addSublayer(shapeLayer)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        startPoint = touches.first?.location(in: imageView)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let startPoint = startPoint, let touch = touches.first else { return }

        let point: CGPoint

        if let predictedTouch = event?.predictedTouches(for: touch)?.last {
            point = predictedTouch.location(in: imageView)
        } else {
            point = touch.location(in: imageView)
        }

        updatePath(from: startPoint, to: point)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let startPoint = startPoint, let touch = touches.first else { return }

        let point = touch.location(in: imageView)

        updatePath(from: startPoint, to: point)
        imageView.image = imageView.snapshot(afterScreenUpdates: true)
        shapeLayer.path = nil
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        shapeLayer.path = nil
    }

    private func updatePath(from startPoint: CGPoint, to point: CGPoint) {
        let size = CGSize(width: point.x - startPoint.x, height: point.y - startPoint.y)
        let rect = CGRect(origin: startPoint, size: size)
        shapeLayer.path = UIBezierPath(rect: rect).cgPath
    }

}
这不仅简单,而且效率更高

这将产生:


顺便说一下,我可能建议在
touchsmoved
中使用预测性触摸。在一个可以产生稍微更具响应性的UI的设备(而不是模拟器)上。

在哪里我可以找到关于“预测触摸”的信息?你知道在哪里我可以找到一些教程或东西吗?@ReinierMelian-见WWDC 2015。或者只是谷歌“predictedTouches教程”,你会看到很多链接。非常感谢。但是它会绘制一个矩形,当一个新的触摸开始时,它会开始一个新的矩形并删除上一个。我想在触摸结束后保存一个图形并开始新的one@ReinierMelian-那很好。然后在该点执行“构建新图像”过程(在
touchesend
)。或者为下一个手势添加新的形状层,保留旧的形状层。关键是要避免在每次触摸移动时更改图像
@MohmedShowekh-请参见
UIView
上带有
快照
扩展名的修订答案。
class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    private let shapeLayer: CAShapeLayer = {
        let _shapeLayer = CAShapeLayer()
        _shapeLayer.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
        _shapeLayer.strokeColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
        _shapeLayer.lineWidth = 3
        return _shapeLayer
    }()

    private var startPoint: CGPoint!

    override func viewDidLoad() {
        super.viewDidLoad()

        imageView.layer.addSublayer(shapeLayer)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        startPoint = touches.first?.location(in: imageView)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let startPoint = startPoint, let touch = touches.first else { return }

        let point: CGPoint

        if let predictedTouch = event?.predictedTouches(for: touch)?.last {
            point = predictedTouch.location(in: imageView)
        } else {
            point = touch.location(in: imageView)
        }

        updatePath(from: startPoint, to: point)
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let startPoint = startPoint, let touch = touches.first else { return }

        let point = touch.location(in: imageView)

        updatePath(from: startPoint, to: point)
        imageView.image = imageView.snapshot(afterScreenUpdates: true)
        shapeLayer.path = nil
    }

    override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        shapeLayer.path = nil
    }

    private func updatePath(from startPoint: CGPoint, to point: CGPoint) {
        let size = CGSize(width: point.x - startPoint.x, height: point.y - startPoint.y)
        let rect = CGRect(origin: startPoint, size: size)
        shapeLayer.path = UIBezierPath(rect: rect).cgPath
    }

}
extension UIView {
    func snapshot(afterScreenUpdates: Bool = false) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(bounds.size, isOpaque, 0)
        drawHierarchy(in: bounds, afterScreenUpdates: afterScreenUpdates)
        let image = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }
}