如何在SwiftUI中使PKCanvasView可缩放?

huangapple go评论110阅读模式
英文:

How to make PKCanvasView zoomable in SwiftUI?

问题

有一个像这样设置的PKCanvasView

    struct CanvasView {
      @Binding var canvasView: PKCanvasView
      let onSaved: () -> Void
      @State var toolPicker = PKToolPicker()
    }
    
    
    extension CanvasView: UIViewRepresentable {
      func makeUIView(context: Context) -> PKCanvasView {
          canvasView.tool = PKInkingTool(.pencil, color: .gray, width: 20)
    //    #if targetEnvironment(simulator)
          canvasView.drawingPolicy = .anyInput
    //    #endif
        canvasView.delegate = context.coordinator
        showToolPicker()
        return canvasView
      }
    
      func updateUIView(_ uiView: PKCanvasView, context: Context) {}
    
      func makeCoordinator() -> Coordinator {
        Coordinator(canvasView: $canvasView, onSaved: onSaved)
      }
    }

然后我在SwiftUI中使用它,就像这样:

            VStack {
                Spacer()
                CanvasView(canvasView: $canvasView, onSaved: saveDrawing)
                    .aspectRatio(1.0, contentMode: .fit)
                Spacer()
            }

但是,一旦我将它放入ScrollView以添加平移和缩放功能,就像这样:

    ScrollView {    //prevents drawing with finger
            VStack {
                Spacer()
                CanvasView(canvasView: $canvasView, onSaved: saveDrawing)
                    .aspectRatio(1.0, contentMode: .fit)
                Spacer()
            }
    }

它停止允许我用手指绘制,假设是在尝试滚动。我正在寻找类似于Apple的自由应用程序的行为。用手指绘制,捏合缩放,两个手指平移。
英文:

There a PKCanvasView setup like this:

struct CanvasView {
  @Binding var canvasView: PKCanvasView
  let onSaved: () -> Void
  @State var toolPicker = PKToolPicker()
}


extension CanvasView: UIViewRepresentable {
  func makeUIView(context: Context) -> PKCanvasView {
      canvasView.tool = PKInkingTool(.pencil, color: .gray, width: 20)
//    #if targetEnvironment(simulator)
      canvasView.drawingPolicy = .anyInput
//    #endif
    canvasView.delegate = context.coordinator
    showToolPicker()
    return canvasView
  }

  func updateUIView(_ uiView: PKCanvasView, context: Context) {}

  func makeCoordinator() -> Coordinator {
    Coordinator(canvasView: $canvasView, onSaved: onSaved)
  }
}

And then I use it in SwiftUI Like this:

        VStack {
            Spacer()
            CanvasView(canvasView: $canvasView, onSaved: saveDrawing)
                .aspectRatio(1.0, contentMode: .fit)
            Spacer()
        }

But the second I put it in the ScrollView to add the pan and zoom ability like this

ScrollView {    //prevents drawing with finger
        VStack {
            Spacer()
            CanvasView(canvasView: $canvasView, onSaved: saveDrawing)
                .aspectRatio(1.0, contentMode: .fit)
            Spacer()
        }
}

It stops allowing me to draw with finger, presuming that it's trying to scroll instead. I'm looking for a behaviour like the Apple's freeform app. Finger to draw and pinch to zoom, 2 fingers to pan.

答案1

得分: 2

更新

经过一些澄清,我已经添加了将整个绘图区域缩小到小于屏幕尺寸的功能。

Pencil Kit的画布功能强大,内置了缩放和平移。因此,无需添加滚动视图或平移手势,只需设置画布内容的大小、缩放比例和插图。

要进行滚动和平移,请为绘图区域设置较大的画布内容大小:

canvasView.contentSize = CGSize(width: 1500, height: 1000)

要进行缩放,请设置所需的缩放比例:

canvasView.minimumZoomScale = 0.2
canvasView.maximumZoomScale = 4.0

要允许整个绘图区域缩小到小于滚动视图框架尺寸,请添加内容插图:

canvasView.contentInset = UIEdgeInsets(top: 500, left: 500, bottom: 500, right: 500)

以下是一个带有工具选择器的基本SwiftUI铅笔应用程序。该应用程序支持捏合缩放、双指平移和用手指绘制:

import SwiftUI
import PencilKit

struct ContentView: View {
    var body: some View {
        CanvasView()
    }
}

struct CanvasView {
    @State var canvasView: PKCanvasView = PKCanvasView()
    @State var toolPicker = PKToolPicker()
}

extension CanvasView: UIViewRepresentable {
    func makeUIView(context: Context) -> PKCanvasView {
        // 画布
        canvasView.contentSize = CGSize(width: 1500, height: 1000)
        canvasView.drawingPolicy = .anyInput
        canvasView.minimumZoomScale = 0.2
        canvasView.maximumZoomScale = 4.0
        canvasView.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0)
        canvasView.contentInset = UIEdgeInsets(top: 500, left: 500, bottom: 500, right: 500)
        canvasView.becomeFirstResponder()

        // 工具选择器
        toolPicker.setVisible(true, forFirstResponder: canvasView)
        toolPicker.addObserver(canvasView)

        return canvasView
    }

    func updateUIView(_ uiView: PKCanvasView, context: Context) {}
}
英文:

Updated

After some clarification, I've included the ability to shrink the entire drawing area smaller than the screen size.

Pencil Kit's canvas is robust with built-in zooming and panning. So there's no need to add scroll views or pan gestures, just set the canvas content's size, zoom scales and insets.

For scrolling and panning, set a large canvas content size for the drawing area:

canvasView.contentSize = CGSize(width: 1500, height: 1000)

For zooming, set the desired zoom scales:

canvasView.minimumZoomScale = 0.2
canvasView.maximumZoomScale = 4.0

For allowing the full drawing area to shrink smaller than the scrollview's frame size, add content insets:

canvasView.contentInset = UIEdgeInsets(top: 500, left: 500, bottom: 500, right: 500)

The following is a basic SwiftUI pencil app with toolpicker. This has the pinch-to-zoom, two-finger panning and finger-to-draw:

import SwiftUI
import PencilKit

struct ContentView: View {
	var body: some View {
		CanvasView()
	}
}

struct CanvasView {
	@State var canvasView: PKCanvasView = PKCanvasView()
	@State var toolPicker = PKToolPicker()
}

extension CanvasView: UIViewRepresentable {
	func makeUIView(context: Context) -> PKCanvasView {
			// canvas
		canvasView.contentSize = CGSize(width: 1500, height: 1000)
		canvasView.drawingPolicy = .anyInput
		canvasView.minimumZoomScale = 0.2
		canvasView.maximumZoomScale = 4.0
		canvasView.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1.0)
		canvasView.contentInset = UIEdgeInsets(top: 500, left: 500, bottom: 500, right: 500)
		canvasView.becomeFirstResponder()
		
			//toolpicker
		toolPicker.setVisible(true, forFirstResponder: canvasView)
		toolPicker.addObserver(canvasView)
		
		return canvasView
	}
	
	func updateUIView(_ uiView: PKCanvasView, context: Context) {}
}

Note: The gif below was created using the code above on an iPad with the toolpicker moved to the side. The background color(white) was manually painted on the drawing area with the toolpicker's marker to better demonstrate the zooming and panning. Setting the scollview's background color independently of the drawing area is a needed enhancement.

The resulting app looks like this:

如何在SwiftUI中使PKCanvasView可缩放?

huangapple
  • 本文由 发表于 2023年3月12日 10:11:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75710708.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定