I am very new to Swift and mobile development and am trying to create my first simple application for macOS and iPad use.
I am trying to create an application that initially displays an image and allows the user to write on it. I have an elementary example working, but I am having a problem.
Currently, the background image I load is larger than the viewable screen.
- I'd like it so that the image is scaled to the viewable screen by default but can then be zoomed with standard pinch gestures and panned with 2-finger gestures.
- The whole image can be written on top of.
I have searched and tried a few things, but I am obviously still missing something about how everything fits together.
Any help/pointers would be much appreciated.
import SwiftUI
import SwiftData
import PencilKit
struct ContentView: View {
@Environment(\.undoManager) private var undoManager
@State private var canvasView = PKCanvasView()
var body: some View {
VStack{
HStack(spacing: 5) {
Spacer(minLength: 1)
Button("Clear") {
canvasView.drawing = PKDrawing()
}.buttonStyle(.borderedProminent)
Spacer(minLength: 1)
Button("Undo") {
undoManager?.undo()
}.buttonStyle(.borderedProminent)
Spacer(minLength: 1)
Button("Redo") {
undoManager?.redo()
}.buttonStyle(.borderedProminent)
Spacer(minLength: 1)
Button("Remove Object") {
self.canvasView.tool = PKEraserTool(.vector);
}.buttonStyle(.borderedProminent)
Spacer(minLength: 1)
Button("Erase") {
self.canvasView.tool = PKEraserTool(.bitmap, width: 3);
}.buttonStyle(.borderedProminent)
Button("Draw") {
let color = PKInkingTool.convertColor(.black, from: .dark, to: .light)
self.canvasView.tool = PKInkingTool(.monoline, color: color, width: 3)
}.buttonStyle(.borderedProminent)
Spacer(minLength: 1)
}
GeometryReader { proxy in
VStack {MyCanvas(canvasView: $canvasView)}
.frame(width: proxy.size.width, height: proxy.size.height)
.background(.black)
}
}
}
}
struct MyCanvas: UIViewRepresentable {
@Binding var canvasView: PKCanvasView
//let picker = PKToolPicker()
let screenSize: CGRect = UIScreen.main.bounds
func makeUIView(context: Context) -> PKCanvasView {
//canvasView.contentSize = CGSize(width: 1500, height: 1000)
canvasView.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
canvasView.minimumZoomScale = 0.2
canvasView.maximumZoomScale = 4.0
canvasView.drawingPolicy = .anyInput
canvasView.isOpaque = false
canvasView.backgroundColor = UIColor.clear
canvasView.frame(forAlignmentRect: screenSize)
canvasView.becomeFirstResponder()
let imageView = UIImageView(image: UIImage(named: "tracker"))
imageView.frame(forAlignmentRect: screenSize)
imageView.contentMode = UIView.ContentMode.scaleAspectFit
let contentView = canvasView.subviews[0]
contentView.addSubview(imageView)
contentView.sendSubviewToBack(imageView)
//picker.addObserver(canvasView)
//picker.setVisible(true, forFirstResponder: canvasView)
let color = PKInkingTool.convertColor(.black, from: .dark, to: .light)
canvasView.tool = PKInkingTool(.monoline, color: color, width: 3)
return canvasView
}
func updateUIView(_ uiView: PKCanvasView, context: Context) {
}
}
#Preview {
ContentView()
.modelContainer(for: Item.self, inMemory: true)
}
struct Landscape_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewInterfaceOrientation(.landscapeLeft)
}
}
Preview of the current implementation: