Как я могу настроить этот код для увеличения масштаба из любого места изображения?

#swift #swiftui #gesture

Вопрос:

Я работаю над некоторым кодом, в котором пользователям должно быть разрешено использовать различные жесты на изображении приложения. Я хотел бы понять, как я могу разрешить пользователям нажимать или дважды нажимать на определенное место на изображении. Прямо сейчас они могут масштабироваться только от центра, иначе я получаю неожиданные результаты с увеличением. Я выбрал этот путь, так как для этого используется как 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 amp; close interactions
                        .updating($swipeOffset) { value, outValue, _ in
                            outValue = value.translation
                            viewModel.onChange(imagePosition: swipeOffset)
                        }
                        .onEnded(viewModel.onEnd(swipeDistance:))
                    )
                )
                /// Pinch amp; 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
        }
    }
}
 

Ответ №1:

Вы можете очень легко щелкнуть, чтобы увеличить изображение с помощью UIScrollView. Добавьте UIScrollView и внутри добавьте изображение. Затем реализуйте 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
    }
}