SwiftUI 中的 PencilKit
PencilKit in SwiftUI
我正在尝试在 SwiftUI 中使用 PencilKit
。
- 如何在
updateUIView
- 函数中检测更新了哪个 Binding
- 变量?例如,我不想在更改颜色时清除 canvas。
- 有没有比切换布尔值更好的方法来清除 canvas?切换布尔值会强制执行
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)
}
}
这样做就可以了:
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
世界之间进行相互交流......并且有人试图将所有东西从一个放到另一个,或者反之亦然...
我有一个想法,可能最好保留每个性质并在两者之间有一些调解者或演员......所以对于你的用例,我认为我会采取不同的方式, say (scratchy, 未测试, 供考虑):
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
}
当然,我在 中针对类似情况提出了简单的方法...但上面的方法对我来说更可取。
备注:有人可能会说 Coordinator 就是为了这个目的,但它的生命周期是由 SwiftUI-internals 管理的,它参与那些内部工作流,所以我会避免侵入这些关系...
我正在尝试在 SwiftUI 中使用 PencilKit
。
- 如何在
updateUIView
- 函数中检测更新了哪个Binding
- 变量?例如,我不想在更改颜色时清除 canvas。 - 有没有比切换布尔值更好的方法来清除 canvas?切换布尔值会强制执行
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)
}
}
这样做就可以了:
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
世界之间进行相互交流......并且有人试图将所有东西从一个放到另一个,或者反之亦然...
我有一个想法,可能最好保留每个性质并在两者之间有一些调解者或演员......所以对于你的用例,我认为我会采取不同的方式, say (scratchy, 未测试, 供考虑):
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
}
当然,我在
备注:有人可能会说 Coordinator 就是为了这个目的,但它的生命周期是由 SwiftUI-internals 管理的,它参与那些内部工作流,所以我会避免侵入这些关系...