PencilKit в SwiftUI
Я пытаюсь использовать PencilKit
в SwiftUI.
- Как я могу обнаружить в
updateUIView
-функция, котораяBinding
-переменная была обновлена? Например, я не хочу очищать холст при изменении цвета. - И есть ли лучший способ очистить холст, чем переключение логического значения? Переключение логического значения заставляет
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)
}
}
2 ответа
Это поможет:
func updateUIView(_ canvasView: PKCanvasView, context: Context) {
if clear != context.coordinator.pkCanvas.clear{
canvasView.drawing = PKDrawing()
}
canvasView.tool = PKInkingTool(.pen, color: color, width: 10)
}
Я наблюдал подобную картину много раз, и здесь мы получаем взаимосвязь между SwiftUI-value-declarative-state-managed
мир и xKit-OOP-imperative-action-managed
мир... и есть попытки либо все переставить из одного в другое, либо наоборот...
У меня есть мнение, что, вероятно, было бы лучше сохранить каждую природу для каждой и иметь какого-то посредника или актера между двумя... поэтому для вашего варианта использования я бы подумал, что я пошел бы другим путем, скажем (колючий, не тестировался, к сведению):
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
и чисто-ООП часть
class PKCanvasActor {
var canvas: PKCanvasView
func use(color: Color) {
// do anything with canvas color
}
func clear() {
canvas.drawing = PKDrawing()
}
// ... any more actions
}
Конечно, есть простой подход, который я предложил для аналогичного сценария в SwiftUI Button, взаимодействовать с картой... но для меня способ выше выглядит более предпочтительным.
Примечание: можно сказать, что Координатор предназначен для этой цели, но его время жизни управляется SwiftUI-internals, и он участвует в этих внутренних рабочих процессах, поэтому я бы избегал вторжения в эти отношения...