使用 Core Graphics 在 UIImageView 上绘制一个矩形

Posted

技术标签:

【中文标题】使用 Core Graphics 在 UIImageView 上绘制一个矩形【英文标题】:Drawing a rectangle on UIImageView using Core Graphics 【发布时间】:2017-08-27 14:57:16 【问题描述】:

我想让用户在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 touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) 
    if let touch = touches.first 
        firstTouchLocation = touch.location(in: self.view)            
    


override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) 
    if let touch = touches.first 
        lastTouchLocation = touch.location(in: self.view)
        draw(from: firstTouchLocation, to: lastTouchLocation)
    


override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) 
    if let touch = touches.first 
        lastTouchLocation = touch.location(in: self.view)
        draw(from: firstTouchLocation, to: lastTouchLocation)
    

我想让用户在touchMoved 时扩展矩形并在touchEnded 时绘制。

【问题讨论】:

【参考方案1】:

您正在将 image 替换为由以前的 image 加上在其上绘制的矩形组成的新图像。不要从图像视图中绘制图像,而是绘制原始图像。

或者,您可以将矩形渲染为形状图层,然后更新该形状图层的路径:

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
    

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

产生:

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

【讨论】:

在哪里可以找到有关“预测性触摸”的信息,您知道在哪里可以找到一些教程或其他东西吗? @ReinierMelian - 参见 WWDC 2015 Advanced Touch Input on ios。或者只是谷歌“predictedTouches 教程”,你会看到很多链接。 非常感谢。但是它会绘制一个矩形,当一个新的 touchBegan 事件时,它会开始一个新的矩形并删除前一个矩形。我想在触摸结束后保存一个绘图并开始一个新的 @ReinierMelian - 没关系。然后在那时(在touchesEnded)执行“构建新图像”过程。或者为下一个手势添加一个新的形状图层,将旧的保留在那里。关键是避免在每个touchesMoved期间更改图像。 @MohmedShowekh - 在UIView 上查看带有snapshot 扩展名的修订答案。

以上是关于使用 Core Graphics 在 UIImageView 上绘制一个矩形的主要内容,如果未能解决你的问题,请参考以下文章

使用 Core Graphics 在 UIImageView 上绘制一个矩形

如何使用 Core Graphics 绘制箭头?

带有 Core Graphics 绘图的 Core Animation

使用 Core Graphics 制作类似画笔的纹理

使用 Core Graphics 绘制带有减去文本的路径

在 iOS 中使用 Core Graphics 绘制 VU 表