Skip to content

Instantly share code, notes, and snippets.

@no13bus
Created October 17, 2023 13:27
Show Gist options
  • Save no13bus/dba6c7248df31ca41d548c8ae5003281 to your computer and use it in GitHub Desktop.
Save no13bus/dba6c7248df31ca41d548c8ae5003281 to your computer and use it in GitHub Desktop.
zoomanddrag
import SwiftUI
struct Line {
var points: [CGPoint]
}
struct ZoomDragView: View {
@State private var scale = 1.0
@State private var lastScale = 1.0
@State var offset: CGSize = .zero
@State var lastOffset: CGSize = .zero
@State private var lines: [Line] = []
private let minScale = 1.0
private let maxScale = 5.0
@State private var editing = false
var body: some View {
ZStack {
Color.black.ignoresSafeArea(.all)
ZStack {
Image("test")
.resizable()
.aspectRatio(contentMode: .fit)
.border(.green, width: 1)
Canvas { context, _ in
for line in lines {
var path = Path()
path.addLines(line.points)
context.stroke(path, with: .color(Color.red), style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
}
}
.border(.red, width: 1)
}
//topLeading will ok. but it is not good. if chang to center, it will wrong
.scaleEffect(scale, anchor: .topLeading)
.offset(offset)
.gesture(
MagnificationGesture()
.onChanged { state in
let delta = state / lastScale
scale *= delta
lastScale = state
}
.onEnded { _ in
var tmp = max(scale, minScale)
tmp = min(tmp, maxScale)
withAnimation {
scale = tmp
}
lastScale = 1.0
}
.simultaneously(
with: DragGesture(minimumDistance: 0, coordinateSpace: .local)
.onChanged { value in
if editing {
let newPoint = CGPoint(x: (value.location.x - offset.width)/scale, y: (value.location.y-offset.height)/scale)
if value.translation == .zero {
lines.append(Line(points: [newPoint]))
} else {
let index = lines.count - 1
lines[index].points.append(newPoint)
}
} else {
var newOffset: CGSize = .zero
newOffset.width = value.translation.width + lastOffset.width
newOffset.height = value.translation.height + lastOffset.height
offset = newOffset
}
}
.onEnded { _ in
lastOffset = offset
}
)
.simultaneously(
with: TapGesture(count: 2)
.onEnded {
if !editing {
if scale == 1 {
withAnimation(.spring()) {
scale = maxScale
}
} else {
withAnimation(.spring()) {
scale = 1
offset = .zero
}
}
}
}
)
)
Button {
editing = !editing
} label: {
Text("edit")
.font(.system(size: 25))
.foregroundColor(editing ? .primary : .red)
}
}
}
}
struct ZoomDragView_Previews: PreviewProvider {
static var previews: some View {
NavigationStack{
ZoomDragView()
.navigationTitle("List")
.navigationBarTitleDisplayMode(.inline)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment