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





Это был бы ответ.
Интересная часть, которую я добавляю, заключается в том, что масштаб увеличенного представления можно контролировать извне с помощью свойства привязки. Таким образом, нам не нужно зависеть только от жеста сжатия, но можно добавить двойное касание, чтобы получить максимальный масштаб, вернуться к нормальному масштабу или иметь ползунок (например), который изменяет масштаб по своему усмотрению.
Я обязан большей частью этого кода 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.
Что касается двойного нажатия, поведение можно очень легко изменить в зависимости от того, что вы предпочитаете.
Прикрепляю видео, чтобы показать все сразу:
Я надеюсь, что это поможет всем, кто ищет эту функцию.
Ставьте ответ как, ну и ответьте stackoverflow.com/help/self-answer