我能够利用每个 ViewController 来编辑 Original ImageView。有没有什么办法解决这一问题?

I am able to draw on each ViewController to edit Original ImageView. Is there any way to fix this?

我正在开发一个动画应用程序,并且彼此之间 ViewController 我可以在当前显示在原始 ImageView 上的图像上绘图。有什么办法可以解决这个问题吗?

这正是正在发生的事情。我真的不知道问题存在于代码的哪个位置。 https://drive.google.com/file/d/1M7qWKMugaqeDjGls3zvVitoRmwpOUJFY/view?usp=sharing

预计只能在 DrawingFrame 上绘图 ViewController。但是,我可以在我的应用程序

中利用每个 ViewController

问题似乎是您的手势识别器仍在运行,即使您在当前视图之上呈现了另一个视图。

这有点不寻常。通常,当您呈现这样的视图时,旧视图(及其手势识别器)将从视图层次结构中删除。我猜你只是将第二个视图滑动到另一个视图之上。有几个解决方案:

  • 一个解决方案是确保定义这个新视图,以便 (a) 它接受用户交互; (b) 编写代码以处理这些手势。这将避免其背后的视图接收这些手势。

  • 另一个解决方案是在显示菜单视图时禁用手势识别器识别器,并在关闭菜单时re-enable禁用它。

  • 第三种解决方案是更改显示该菜单视图的方式,确保在执行此操作时从视图层次结构中删除当前视图。不过,标准的 show/present 转换通常会执行此操作,因此我们可能需要查看您如何呈现此菜单视图以进一步发表评论。


话虽如此,但还有一些不相关的观察:

  • 你应该使用UIGraphicsBeginImageContextWithOptions而不是UIGraphicsBeginImageContext

  • 而不是

    if pencil.eraser == true { ... }
    

    你可以

    if pencil.eraser { ... }
    
  • 我建议给 pencil 计算 属性:

    var color: UIColor { return UIColor(red: red, green: green, blue: blue, alpha: opacity) }
    

    那你可以参考一下pencil.color;

  • 属性 名称应以小写字母开头;和

  • drawingFrame 是一个令人困惑的名字,恕我直言,因为它不是一个“框架”,而是一个 UIImageView。我会称之为 drawingImageView 或类似的东西。

产量:

func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
    guard let pencil = pencil else { return }

    //begins current context (and defer the ending of the context)
    UIGraphicsBeginImageContextWithOptions(drawingImageView.bounds.size, false, 0)
    defer { UIGraphicsEndImageContext() }

    //where to draw
    drawingImageView.image?.draw(in: drawingImageView.bounds)
    //saves context
    guard let context = UIGraphicsGetCurrentContext() else { return }

    //drawing the line
    context.move(to: fromPoint)
    context.addLine(to: toPoint)
    context.setLineCap(.round)

    if pencil.eraser {
        //Eraser
        context.setBlendMode(.clear)
        context.setLineWidth(10)
        context.setStrokeColor(UIColor.white.cgColor)
    } else {
        //opacity, brush width, etc.
        context.setBlendMode(.normal)
        context.setLineWidth(pencil.pencilWidth)
        context.setStrokeColor(pencil.color.cgColor)
    }

    context.strokePath()

    //storing context back into the imageView
    drawingImageView.image = UIGraphicsGetImageFromCurrentImageContext()
}

或者,更好的是,完全退出 UIGraphicsBeginImageContext 并使用现代 UIGraphicsImageRenderer:

func drawLine(from fromPoint: CGPoint, to toPoint: CGPoint) {
    guard let pencil = pencil else { return }

    drawingImageView.image = UIGraphicsImageRenderer(size: drawingImageView.bounds.size).image { _ in
        drawingImageView.image?.draw(in: drawingImageView.bounds)

        let path = UIBezierPath()
        path.move(to: fromPoint)
        path.addLine(to: toPoint)
        path.lineCapStyle = .round

        if pencil.eraser {
            path.lineWidth = 10
            UIColor.white.setStroke()
        } else {
            path.lineWidth = pencil.pencilWidth
            pencil.color.setStroke()
        }

        path.stroke()
    }
}

有关 UIGraphicsImageRenderer 的详细信息,请参阅 WWDC 2018 图像和图形最佳实践 的“绘图 off-screen”部分。

顺便说一句,一旦你解决了这个问题,你可能想重新审视这个“从点 a 到点 b 和 re-snapshot” 的逻辑来捕获点数组并从中构建路径整个系列,不要 re-snapshot 点,但只有在添加了一大堆之后。这个快照过程很慢,你会发现用户体验比它需要的更卡顿。我个人 re-snapshot 在 100 点左右之后(此时重新绘制整个路径的时间量足够慢以至于它不会比快照过程快多少,所以如果我快照并从我离开的地方重新启动路径关闭,然后再次加速)。

但是你说:

Expected to be able to draw only on the DrawingFrame ViewController. However, I can draw on every single ViewController in my app.

上面只画了drawingImageViewimagefromPointtoPoint的笔划。关于“每一个ViewController”的绘图问题在别处。我们真的需要看看您如何精确地呈现这个菜单场景。