SwiftUI: 在图像上使用捏合手势进行缩放

12
我想允许用户在SwiftUI中用捏合手势进行图像缩放。我觉得最好的方法是使用MagnificationGesture,并且根据这里的答案进行操作,最终得到了以下代码:
// outside of `var body: some View`
@State private var scale: Int = 1.0
@State private var lastScale: Int = 1.0

// Image 
Image("dog")
.resizable()
.aspectRatio(contentMode: .fit)
.gesture(MagnificationGesture()
    .onChanged { val in
        let delta = val / self.lastScale
        self.lastScale = val
        let newScale = self.scale * delta
        self.scale = newScale
    }
    .onEnded { _ in
        self.lastScale = 1.0
    }
)
.scaleEffect(scale)

这段代码可以很好地处理放大,但不能让用户在特定区域进行缩放。相反,它总是在图像的中间进行缩放。
在SwiftUI中,我该如何处理图像的捏合缩放行为?

1
这个有任何更新吗? - Ruchi Makadia
2个回答

2
我发现实现这个的最简单方法是使用由苹果提供的PDFKit。

1.首先创建PDFView。

    import SwiftUI
    import PDFKit

    struct PhotoDetailView: UIViewRepresentable {
    let image: UIImage
    func makeUIView(context: Context) -> PDFView {
        let view = PDFView()
        view.document = PDFDocument()
        guard let page = PDFPage(image: image) else { return view }
        view.document?.insert(page, at: 0)
        view.autoScales = true
        view.backgroundColor = .clear
        return view
    }
    
    func updateUIView(_ uiView: PDFView, context: Context) {
        
    }
    }

2.在SwiftUI视图中使用,像这样

TabView(selection: $index,
                content:  {
                //this line
                PhotoDetailView(image: images[index])
                    .offset(imageViewerOffset)
                
        })
        .tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))

这个解决方案实际上是有效的。它可以放大图像,而且缩放手势也是可用的,并且按预期工作。 - Darkwonder

1
该代码通过添加拖动手势和放大手势来创建了一种捏合缩放效果。使用viewState允许在使用拖动手势时改变偏移位置。
struct ContentView: View {

    @State private var scale: CGFloat = 1.0
    @State private var lastScale: CGFloat = 1.0
    @State private var viewState = CGSize.zero

    var body: some View {

    Image("dog")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .animation(.spring())
        .offset(x: viewState.width, y: viewState.height)
        .gesture(DragGesture()
            .onChanged { val in
                self.viewState = val.translation
            }
        )
        .gesture(MagnificationGesture()
            .onChanged { val in
                let delta = val / self.lastScale
                self.lastScale = val
                if delta > 0.94 { // if statement to minimize jitter
                    let newScale = self.scale * delta
                    self.scale = newScale
                }
            }
            .onEnded { _ in
                self.lastScale = 1.0
            }
        )
        .scaleEffect(scale)
        }
}

“if”语句的添加是为了减少频繁更新所导致的抖动。0.94的数值并没有特别之处,只是通过试错设置的。
“.animation(spring())”语句的添加是为了实现更自然的拖拽效果。

3
我不知道为什么,但这段代码让我的应用完全没有响应。甚至无法点击导航栏中的返回按钮。 - swiftyboi
内存出问题了。公式有误。 - Ryan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接