0

I am trying to zoom a view horizontally using UIScrollView. My code almost gives me what I want except that it also scales the view vertically. What I want to achieve is that the image only gets scaled in the horizontal direction and that the ScrollView takes care of the horizontal scrolling.

When I remove the .flexibleHeight option from the autoresizingMask of the hostedView the image doesn't show anymore. Why is that? How can I get my desired behaviour?

struct ContentView: View {

    var body: some View {
        ZoomableScrollView {
            Image(systemName: "star")
                .resizable()
                .scaledToFit()
          }
    }
}

struct ZoomableScrollView<Content: View>: UIViewRepresentable {
  private var content: Content

  init(@ViewBuilder content: () -> Content) {
    self.content = content()
  }

  func makeUIView(context: Context) -> UIScrollView {
    // set up the UIScrollView
    let scrollView = UIScrollView()
    scrollView.delegate = context.coordinator  // for viewForZooming(in:)
    scrollView.maximumZoomScale = 20
    scrollView.minimumZoomScale = 1
    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))
  }

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

  // MARK: - Coordinator

  class Coordinator: NSObject, UIScrollViewDelegate {
    var hostingController: UIHostingController<Content>

    init(hostingController: UIHostingController<Content>) {
      self.hostingController = hostingController
    }

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

1 Answer 1

0

This does it in pure SwiftUI:

struct HorizontalScaleView<Content: View>: View {

    @ViewBuilder var content: Content

    @State private var currentAmount: CGFloat = 0
    @State private var finalAmount: CGFloat = 1

    var body: some View {
        GeometryReader { geo in
            ScrollView(.horizontal) {
                content
                    .scaledToFit()
                    .scaleEffect(x: finalAmount + currentAmount, y: 1)
                    .frame(width: (finalAmount + currentAmount) * geo.size.width, height: geo.size.width)
                    .gesture(
                        MagnificationGesture()
                            .onChanged { amount in
                                self.currentAmount = amount - 1
                            }
                            .onEnded { _ in
                                if self.finalAmount + self.currentAmount >= 1 {
                                    self.finalAmount += self.currentAmount
                                } else {
                                    self.finalAmount = 1
                                }
                                self.currentAmount = 0
                            }
                    )
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.