zumzum
zumzum

Reputation: 20198

Cannot pan image in zoomed ScrollView?

I would like to build a simple view that allows me to show an image in a scroll view and let the user pinch to zoom on the image, and pan.

I've looked around and started with thisScrollView:

struct TestView: View {
    
    var body: some View {
        
        ScrollView {
            Image("test")
                .border(Color(.yellow))
        }
        .border(Color(.red))
        
    }
}

That would not handle zooming.

I then did this:

struct TestView: View {


    /// https://wp.usatodaysports.com/wp-content/uploads/sites/88/2014/03/sunset-in-the-dolos-mikadun.jpg
    var image = UIImage(named: "test")!
    @State var scale: CGFloat = 1.0
    @State var lastScaleValue: CGFloat = 1.0

    var body: some View {


        GeometryReader { geo in

            ScrollView([.vertical, .horizontal], showsIndicators: false){

                ZStack{

                    Image(uiImage: image)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: geo.size.width, height: geo.size.width)
                        .scaleEffect(scale)
                        .gesture(MagnificationGesture().onChanged { val in
                            let delta = val / self.lastScaleValue
                            self.lastScaleValue = val
                            var newScale = self.scale * delta
                            if newScale < 1.0 {
                                newScale =  1.0
                            }
                            scale = newScale
                        }.onEnded{val in
                            lastScaleValue = 1
                        })

                }

            }
            .frame(width: geo.size.width, height: geo.size.width)
            .border(Color(.red))
            .background(Color(.systemBackground).edgesIgnoringSafeArea(.all))

        }

    }

}

This allows me to zoom in and out, however, I cannot pan the image:

enter image description here

How can I code up things so I can support zoom and panning?

Upvotes: 2

Views: 1724

Answers (1)

Francisco D. Hurtado
Francisco D. Hurtado

Reputation: 129

in order to get the panning functionality you will have to change the size of your Image container, in this case the ZStack. So first we need a variable to save the current latest scale value.

@State var scaledFrame: CGFloat = 1.0

Then just change the size of the container each time the gesture ends.

 ZStack{
        Image(uiImage: image)
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: geo.size.width, height: geo.size.width )
            .scaleEffect(scale)
            .gesture(MagnificationGesture().onChanged { val in
                let delta = val / self.lastScaleValue
                self.lastScaleValue = val
                var newScale = self.scale * delta
                if newScale < 1.0 {
                    newScale =  1.0
                }
                scale = newScale
            }.onEnded{val in
                scaledFrame = scale//Update the value once the gesture is over
                lastScaleValue = 1
                
            })
            .draggable()
    }
    .frame(width: geo.size.width * scaledFrame, height: geo.size.width * scaledFrame)
    //change the size of the frame once the drag is complete

This is due to the way ScrollView works, when you were zooming in, the real size of the container was not changing, therefore the ScrollView was only moving accordingly.

Upvotes: 1

Related Questions