Есть ли простой способ масштабировать и перетаскивать любой вид в SwiftUI?

Я искал короткий, повторно используемый фрагмент кода, который позволяет масштабировать и перетаскивать любое представление в SwiftUI, а также независимо изменять масштаб.

Ставьте ответ как, ну и ответьте stackoverflow.com/help/self-answer

Martheen 28.10.2022 18:45

Совершенно нормально публиковать ответ на свой вопрос, но напрямую публиковать такой ответ — это не то, как работает stackoverflow. Пожалуйста, отредактируйте это, чтобы задать вопрос, а затем опубликовать ответ на вопрос.

Joakim Danielson 28.10.2022 18:45

Хорошо, я собираюсь изменить его. Моя ошибка.

Antonio Calvo 28.10.2022 18:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это был бы ответ.

Интересная часть, которую я добавляю, заключается в том, что масштаб увеличенного представления можно контролировать извне с помощью свойства привязки. Таким образом, нам не нужно зависеть только от жеста сжатия, но можно добавить двойное касание, чтобы получить максимальный масштаб, вернуться к нормальному масштабу или иметь ползунок (например), который изменяет масштаб по своему усмотрению.

Я обязан большей частью этого кода jtbandes в его ответе на этот вопрос.

Здесь у вас есть в одном файле код масштабируемого и прокручиваемого представления и тестового представления, чтобы показать, как это работает:

`

import SwiftUI

let maxAllowedScale = 4.0

struct TestZoomableScrollView: View {

    @State private var scale: CGFloat = 1.0
    
    var doubleTapGesture: some Gesture {
        TapGesture(count: 2).onEnded {
            if scale < maxAllowedScale / 2 {
                scale = maxAllowedScale
            } else {
                scale = 1.0
            }
        }
    }
    
    var body: some View {
            VStack(alignment: .center) {
                Spacer()
                ZoomableScrollView(scale: $scale) {
                    Image("foto_producto")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 200, height: 200)
                }
                .frame(width: 300, height: 300)
                .border(.black)
                .gesture(doubleTapGesture)
                Spacer()
                Text("Change the scale")
                Slider(value: $scale, in: 0.5...maxAllowedScale + 0.5)
                .padding(.horizontal)
                Spacer()
            }
    }
}

struct ZoomableScrollView<Content: View>: UIViewRepresentable {
    
    private var content: Content
    @Binding private var scale: CGFloat

    init(scale: Binding<CGFloat>, @ViewBuilder content: () -> Content) {
        self._scale = scale
        self.content = content()
    }

    func makeUIView(context: Context) -> UIScrollView {
        // set up the UIScrollView
        let scrollView = UIScrollView()
        scrollView.delegate = context.coordinator  // for viewForZooming(in:)
        scrollView.maximumZoomScale = maxAllowedScale
        scrollView.minimumZoomScale = 1
        scrollView.showsVerticalScrollIndicator = false
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.bouncesZoom = true

//      Create a UIHostingController to hold our SwiftUI content
        let hostedView = context.coordinator.hostingController.view!
        hostedView.translatesAutoresizingMaskIntoConstraints = true
        hostedView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        hostedView.frame = scrollView.bounds
        scrollView.addSubview(hostedView)

        return scrollView
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(hostingController: UIHostingController(rootView: self.content), scale: $scale)
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        // update the hosting controller's SwiftUI content
        context.coordinator.hostingController.rootView = self.content
        uiView.zoomScale = scale
        assert(context.coordinator.hostingController.view.superview == uiView)
    }
    
    class Coordinator: NSObject, UIScrollViewDelegate {

        var hostingController: UIHostingController<Content>
        @Binding var scale: CGFloat

        init(hostingController: UIHostingController<Content>, scale: Binding<CGFloat>) {
            self.hostingController = hostingController
            self._scale = scale
        }

        func viewForZooming(in scrollView: UIScrollView) -> UIView? {
            return hostingController.view
        }

        func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
            self.scale = scale
        }
    }
}

`

Я думаю, что это самый короткий и простой способ получить желаемое поведение. Кроме того, он отлично работает, чего я не нашел в других предлагаемых здесь решениях. Например, уменьшение масштаба происходит плавно и обычно может быть рывками, если вы не используете этот подход.

Ползунок имеет этот диапазон, чтобы показать, как соблюдаются минимальные и максимальные значения, в реальном приложении диапазон будет 1 ... maxAllowedScale.

Что касается двойного нажатия, поведение можно очень легко изменить в зависимости от того, что вы предпочитаете.

Прикрепляю видео, чтобы показать все сразу:

Я надеюсь, что это поможет всем, кто ищет эту функцию.

Другие вопросы по теме