【问题标题】:PencilKit in SwiftUISwiftUI 中的 PencilKit
【发布时间】:2019-12-20 18:53:36
【问题描述】:

我正在尝试在 SwiftUI 中使用 PencilKit

  1. 如何在updateUIView-函数中检测到Binding-variable 已更新?例如,我不想在更改颜色时清除画布。
  2. 还有比切换布尔值更好的方法来清除画布吗?切换布尔值会强制执行 updateUIView-函数。
import SwiftUI
import UIKit
import PencilKit

struct ContentView: View {
    @State var color = UIColor.black
    @State var clear = false

    var body: some View {
        VStack{
            PKCanvas(color: $color, clear:$clear)
            VStack(){
                Button("Change to BLUE"){ self.color = UIColor.blue }
                Button("Change to GREEN"){ self.color = UIColor.green }
                Button("Clear Canvas"){ self.clear.toggle() }
            }
        }
    }
}

struct PKCanvas: UIViewRepresentable {
    class Coordinator: NSObject, PKCanvasViewDelegate {
        var pkCanvas: PKCanvas

        init(_ pkCanvas: PKCanvas) {
            self.pkCanvas = pkCanvas
        }
    }

    @Binding var color:UIColor
    @Binding var clear:Bool

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> PKCanvasView {
        let canvas = PKCanvasView()
        canvas.tool = PKInkingTool(.pen, color: color, width: 10)

        canvas.delegate = context.coordinator
        return canvas
    }

    func updateUIView(_ canvasView: PKCanvasView, context: Context) {
        // clears the canvas
        canvasView.drawing = PKDrawing()

        // sets a new color
        canvasView.tool = PKInkingTool(.pen, color: color, width: 10)
    }
}

【问题讨论】:

    标签: ios swift swiftui uiviewrepresentable pencilkit


    【解决方案1】:

    这样就可以了:

        func updateUIView(_ canvasView: PKCanvasView, context: Context) {
            if clear != context.coordinator.pkCanvas.clear{
                canvasView.drawing = PKDrawing()
            }
            canvasView.tool = PKInkingTool(.pen, color: color, width: 10)
        }
    

    【讨论】:

      【解决方案2】:

      我多次观察到类似的模式,在这里我们得到了SwiftUI-value-declarative-state-managedworld 和xKit-OOP-imperative-action-managedworld 之间的相互通信......并且有人尝试将所有内容从一个到另一个,反之亦然......

      我有一个想法,可能最好为每个人保留每个性质并在两者之间有一些调解人或演员......所以对于你的用例,我认为我会采取不同的方式,比如说(粗糙,未测试,供考虑):

      struct ContentView: View {
          //@State var color = UIColor.black // < both these have nothing to ContentView
          //@State var clear = false
      
          let pkActor = PKCanvasActor() // < mediator, reference type
      
          var body: some View {
              VStack{
                  PKCanvas(actor: pkActor)
                  VStack(){
                      Button("Change to BLUE"){ self.pkActor.use(color: UIColor.blue) }
                      Button("Change to GREEN"){ self.pkActor.use(color: UIColor.green) }
                      Button("Clear Canvas"){ self.pkActor.clear() }
                  }
              }
          }
      }
      

      这里的某个地方

      func makeUIView(context: Context) -> PKCanvasView {
          let canvas = PKCanvasView()
          self.actor.canvas = canvas // but think to avoid cycle reference
      

      和纯 OOP 部分

      class PKCanvasActor {
        var canvas: PKCanvasView
      
         func use(color: Color) {
            // do anything with canvas color
         }
      
         func clear() {
            canvas.drawing = PKDrawing()
         }
      
         // ... any more actions 
      }
      

      当然,我在SwiftUI Button interact with Map 中为类似场景提出了简单的方法......但上面的方法对我来说看起来更可取。

      备注:有人可能会说 Coordinator 就是为了这个目的,但它的生命周期由 SwiftUI-internals 管理,并且它参与那些内部工作流,所以我会避免侵入这些关系...

      【讨论】:

      • 我明白你的意思,我喜欢你将演员和视图分开的方法。但我的问题更多,如何清除画布作为PencilKit 的一部分。基本上,如何处理updateView-函数中的事件。切换布尔值很可能不是处理它的正确方法。
      • 使用actor 方法,您只需将动作直接传递给画布,它将根据需要进行处理。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-20
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 1970-01-01
      • 1970-01-01
      • 2019-11-05
      相关资源
      最近更新 更多