Added zoom gesture to expanded view
This commit is contained in:
parent
ccdf7db12e
commit
565d80910d
@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
46410F842C3D12B100FFBF7E /* ZoomableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46410F832C3D12B100FFBF7E /* ZoomableScrollView.swift */; };
|
||||
466989C72C34DC7A009884D1 /* JustScanItApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 466989C62C34DC7A009884D1 /* JustScanItApp.swift */; };
|
||||
466989CB2C34DC7B009884D1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 466989CA2C34DC7B009884D1 /* Assets.xcassets */; };
|
||||
466989CE2C34DC7B009884D1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 466989CD2C34DC7B009884D1 /* Preview Assets.xcassets */; };
|
||||
@ -19,6 +20,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
46410F832C3D12B100FFBF7E /* ZoomableScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZoomableScrollView.swift; sourceTree = "<group>"; };
|
||||
466989C32C34DC7A009884D1 /* JustScanIt.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JustScanIt.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
466989C62C34DC7A009884D1 /* JustScanItApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JustScanItApp.swift; sourceTree = "<group>"; };
|
||||
466989C82C34DC7A009884D1 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||
@ -83,6 +85,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
466989D52C34DCE4009884D1 /* VNDocumentCameraViewControllerR.swift */,
|
||||
46410F832C3D12B100FFBF7E /* ZoomableScrollView.swift */,
|
||||
);
|
||||
path = Controllers;
|
||||
sourceTree = "<group>";
|
||||
@ -182,6 +185,7 @@
|
||||
466989D92C35206E009884D1 /* Scan.swift in Sources */,
|
||||
466989DF2C353FEC009884D1 /* SettingsView.swift in Sources */,
|
||||
466989D62C34DCE4009884D1 /* VNDocumentCameraViewControllerR.swift in Sources */,
|
||||
46410F842C3D12B100FFBF7E /* ZoomableScrollView.swift in Sources */,
|
||||
466989DD2C35299D009884D1 /* ScanItemView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
162
JustScanIt/Controllers/ZoomableScrollView.swift
Normal file
162
JustScanIt/Controllers/ZoomableScrollView.swift
Normal file
@ -0,0 +1,162 @@
|
||||
//
|
||||
// ZoomableScrollView.swift
|
||||
// JustScanIt
|
||||
//
|
||||
// Created by Pradyun Setti on 09/07/2024.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
class PinchZoomView: UIView {
|
||||
|
||||
weak var delegate: PinchZoomViewDelgate?
|
||||
|
||||
private(set) var scale: CGFloat = 0 {
|
||||
didSet {
|
||||
delegate?.pinchZoomView(self, didChangeScale: scale)
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var anchor: UnitPoint = .center {
|
||||
didSet {
|
||||
delegate?.pinchZoomView(self, didChangeAnchor: anchor)
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var offset: CGSize = .zero {
|
||||
didSet {
|
||||
delegate?.pinchZoomView(self, didChangeOffset: offset)
|
||||
}
|
||||
}
|
||||
|
||||
private(set) var isPinching: Bool = false {
|
||||
didSet {
|
||||
delegate?.pinchZoomView(self, didChangePinching: isPinching)
|
||||
}
|
||||
}
|
||||
|
||||
private var startLocation: CGPoint = .zero
|
||||
private var location: CGPoint = .zero
|
||||
private var numberOfTouches: Int = 0
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
|
||||
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinch(gesture:)))
|
||||
pinchGesture.cancelsTouchesInView = false
|
||||
addGestureRecognizer(pinchGesture)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
@objc private func pinch(gesture: UIPinchGestureRecognizer) {
|
||||
|
||||
switch gesture.state {
|
||||
case .began:
|
||||
isPinching = true
|
||||
startLocation = gesture.location(in: self)
|
||||
anchor = UnitPoint(x: startLocation.x / bounds.width, y: startLocation.y / bounds.height)
|
||||
numberOfTouches = gesture.numberOfTouches
|
||||
|
||||
case .changed:
|
||||
if gesture.numberOfTouches != numberOfTouches {
|
||||
// If the number of fingers being used changes, the start location needs to be adjusted to avoid jumping.
|
||||
let newLocation = gesture.location(in: self)
|
||||
let jumpDifference = CGSize(width: newLocation.x - location.x, height: newLocation.y - location.y)
|
||||
startLocation = CGPoint(x: startLocation.x + jumpDifference.width, y: startLocation.y + jumpDifference.height)
|
||||
|
||||
numberOfTouches = gesture.numberOfTouches
|
||||
}
|
||||
|
||||
scale = gesture.scale
|
||||
|
||||
location = gesture.location(in: self)
|
||||
offset = CGSize(width: location.x - startLocation.x, height: location.y - startLocation.y)
|
||||
|
||||
case .ended, .cancelled, .failed:
|
||||
isPinching = false
|
||||
scale = 1.0
|
||||
anchor = .center
|
||||
offset = .zero
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protocol PinchZoomViewDelgate: AnyObject {
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangePinching isPinching: Bool)
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeScale scale: CGFloat)
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeAnchor anchor: UnitPoint)
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeOffset offset: CGSize)
|
||||
}
|
||||
|
||||
struct PinchZoom: UIViewRepresentable {
|
||||
|
||||
@Binding var scale: CGFloat
|
||||
@Binding var anchor: UnitPoint
|
||||
@Binding var offset: CGSize
|
||||
@Binding var isPinching: Bool
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(self)
|
||||
}
|
||||
|
||||
func makeUIView(context: Context) -> PinchZoomView {
|
||||
let pinchZoomView = PinchZoomView()
|
||||
pinchZoomView.delegate = context.coordinator
|
||||
return pinchZoomView
|
||||
}
|
||||
|
||||
func updateUIView(_ pageControl: PinchZoomView, context: Context) { }
|
||||
|
||||
class Coordinator: NSObject, PinchZoomViewDelgate {
|
||||
var pinchZoom: PinchZoom
|
||||
|
||||
init(_ pinchZoom: PinchZoom) {
|
||||
self.pinchZoom = pinchZoom
|
||||
}
|
||||
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangePinching isPinching: Bool) {
|
||||
pinchZoom.isPinching = isPinching
|
||||
}
|
||||
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeScale scale: CGFloat) {
|
||||
pinchZoom.scale = scale
|
||||
}
|
||||
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeAnchor anchor: UnitPoint) {
|
||||
pinchZoom.anchor = anchor
|
||||
}
|
||||
|
||||
func pinchZoomView(_ pinchZoomView: PinchZoomView, didChangeOffset offset: CGSize) {
|
||||
pinchZoom.offset = offset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PinchToZoom: ViewModifier {
|
||||
@State var scale: CGFloat = 1.0
|
||||
@State var anchor: UnitPoint = .center
|
||||
@State var offset: CGSize = .zero
|
||||
@State var isPinching: Bool = false
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.scaleEffect(scale, anchor: anchor)
|
||||
.offset(offset)
|
||||
.animation(.spring, value: isPinching)
|
||||
.overlay(PinchZoom(scale: $scale, anchor: $anchor, offset: $offset, isPinching: $isPinching))
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func pinchToZoom() -> some View {
|
||||
self.modifier(PinchToZoom())
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ struct MainView: View {
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
ScrollView {
|
||||
// newScanButton
|
||||
ForEach(scans, id: \.self) { scan in
|
||||
ScanItemView(scan)
|
||||
}
|
||||
@ -72,6 +73,18 @@ struct MainView: View {
|
||||
}
|
||||
}
|
||||
|
||||
var newScanButton: some View {
|
||||
Button { showVNDocumentCameraView() } label: {
|
||||
Text("New Scan")
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(12)
|
||||
.foregroundStyle(.white)
|
||||
.background(.blue)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 15))
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
|
||||
private func showVNDocumentCameraView() {
|
||||
Task { guard await isAuthorized else { return } }
|
||||
|
||||
@ -95,5 +108,11 @@ struct MainView: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
MainView()
|
||||
let config = ModelConfiguration(isStoredInMemoryOnly: true)
|
||||
let container = try! ModelContainer(for: Scan.self, configurations: config)
|
||||
|
||||
let scan = Scan(images: [UIImage(systemName: "questionmark")!])
|
||||
container.mainContext.insert(scan)
|
||||
|
||||
return MainView().modelContainer(container)
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ struct ScanItemView: View {
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(maxHeight: 400)
|
||||
.pinchToZoom()
|
||||
.onTapGesture {
|
||||
withAnimation(.easeInOut(duration: 0.3)) {
|
||||
isZoomed = false
|
||||
|
Loading…
x
Reference in New Issue
Block a user