如何设置此代码以从图像的任何位置放大?

How can I set this code up to zoom in from anywhere on the image?

我正在编写一些代码,允许用户在应用程序的图像上使用各种手势。我想要的是了解如何允许用户捏合或双击图像中的特定位置。现在,他们只能从中心缩放,否则缩放会得到意想不到的结果。我选择这条路径是因为它同时使用了 SwiftUI 和拖动关闭功能。谢谢!

import SwiftUI

public struct SampleZoom {
    @ObservedObject
    private var viewModel: ViewModel

    @State private var currentZoom: CGFloat = 0
    @State private var endingZoom: CGFloat = 1

    @State private var isZoomed = false
    @State private var pointTapped: CGPoint = .zero

    @GestureState var swipeOffset: CGSize = .zero

    public init(viewModel: ViewModel) {
        self.viewModel = viewModel
    }
}

extension SampleZoom: View {
    public var body: some View {
        if viewModel.isVisible {
            ZStack {
                Color.black
                    .opacity(viewModel.bgOpacity)
                    .edgesIgnoringSafeArea(.all)
                image(imageData: viewModel.image)
            }
            .onAppear {
                endingZoom = 1
                isZoomed = false
            }
            .overlay(
                /// Close Button
                Button(action: {
                    viewModel.isVisible.toggle()
                }, label: {
                    Image(systemName: "xmark")
                        .foregroundColor(.white)
                        .padding()
                        .background(Color.white.opacity(0.33))
                        .clipShape(Circle())
                })
                    .padding(Spacing.standard), alignment: .topLeading
            )
        } else {
            Spacer()
        }
    }
}

private extension SampleZoom {
    /// Creates card Image
    func image(imageData: Data) -> some View {
        GeometryReader { reader in
            Image("Your Image Here!")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .offset(y: viewModel.imageOffset.height)
                .animation(.default)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .scaleEffect(endingZoom + currentZoom > 1 ? endingZoom + currentZoom : 1, anchor: UnitPoint(
                    x: pointTapped.x / reader.frame(in: .global).maxX,
                    y: pointTapped.y / reader.frame(in: .global).maxY
                ))
                /// Double tap to zoom
                .gesture(
                    TapGesture(count: 2).onEnded {
                        withAnimation {
                            isZoomed.toggle()
                            endingZoom = endingZoom > 1 ? 1 : 2
                        }
                    }
                    .simultaneously(
                        with: DragGesture(minimumDistance: 0, coordinateSpace: .global).onChanged { value in
                            if !isZoomed {
                                pointTapped = value.startLocation
                            }
                        }
                        /// Swipe & close interactions
                        .updating($swipeOffset) { value, outValue, _ in
                            outValue = value.translation
                            viewModel.onChange(imagePosition: swipeOffset)
                        }
                        .onEnded(viewModel.onEnd(swipeDistance:))
                    )
                )
                /// Pinch & zoom interactions
                .gesture(
                    MagnificationGesture()
                        .onChanged { amount in
                            currentZoom = amount - 1
                        }
                        .onEnded { _ in
                            endingZoom += currentZoom
                            currentZoom = 0
                            isZoomed = endingZoom + currentZoom > 1 ? true : false
                        }
                )
        }
    }
}

public extension SampleZoom {
    final class ViewModel: ObservableObject {
        let image: Data

        @Published
        var isVisible: Bool

        @Published
        var imageOffset: CGSize = .zero

        @Published
        var bgOpacity: Double = 1

        func onChange(imagePosition: CGSize) {
            imageOffset = imagePosition

            let halfScreenHeight = UIScreen.main.bounds.height / 2
            let progress = imagePosition.height / halfScreenHeight

            withAnimation(.default) {
                bgOpacity = Double(1 - (progress < 0 ? -progress : progress))
            }
        }

        func onEnd(swipeDistance: DragGesture.Value) {
            withAnimation(.easeOut) {
                var translation = swipeDistance.translation.height

                if translation < Spacing.none {
                    translation = -translation
                }

                if translation < Spacing.doubleExtraLarge * 3 {
                    imageOffset.height = Spacing.none
                    bgOpacity = 1
                } else {
                    isVisible.toggle()
                    imageOffset.height = Spacing.none
                    bgOpacity = 1
                }
            }
        }

        init(image: Data, isVisible: Bool) {
            self.image = image
            self.isVisible = isVisible
        }
    }
}

在 UIScrollView 的帮助下,您可以非常轻松地缩放到您的 imageView。添加 UIScrollView 并在内部添加 imageView。然后实现 UIScrollViewDelegate 和函数 viewForZooming

override func viewDidLoad() {
    super.viewDidLoad()

    scrollView.minimumZoomScale = 1.0
    scrollView.maximumZoomScale = 10.0        
    scrollView.delegate = self
}  

extension YourVC: UIScrollViewDelegate {
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return image
    }
}