无法在缩放的 ScrollView 中平移图像?

Cannot pan image in zoomed ScrollView?

我想构建一个简单的视图,允许我在滚动视图中显示图像并让用户捏合以缩放和平移图像。

我环顾四周并从这个开始ScrollView:

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

那不会处理缩放。

然后我这样做了:

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))

        }

    }

}

这允许我放大和缩小,但是我不能平移图像:

如何编写代码才能支持缩放和平移?

为了获得平移功能,您必须更改图像容器的大小,在本例中为 ZStack。 所以首先我们需要一个变量来保存当前最新的刻度值

@State var scaledFrame: CGFloat = 1.0

然后每次手势结束时改变容器的大小。

 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

这是由于 ScrollView 的工作方式,当您放大时,容器的实际大小并没有改变,因此 ScrollView 只是相应地移动。