Isn't there an easy way to pinch to zoom in an image in Swiftui?

前端 未结 7 1528
自闭症患者
自闭症患者 2020-12-28 08:07

I want to be able to resize and move an image in SwiftUI (like if it were a map) with pinch to zoom and drag it around.

With UIKit I embedded the image into a

7条回答
  •  忘掉有多难
    2020-12-28 08:56

    I am also struggle with this issue. But some working sample is made with the this video-(https://www.youtube.com/watch?v=p0SwXJYJp2U)

    This is not completed. It's difficult to scale with anchor point. Hope this is hint to someone else.

    struct ContentView: View {
    
        let maxScale: CGFloat = 3.0
        let minScale: CGFloat = 1.0
    
        @State var lastValue: CGFloat = 1.0
        @State var scale: CGFloat = 1.0
        @State var draged: CGSize = .zero
        @State var prevDraged: CGSize = .zero
        @State var tapPoint: CGPoint = .zero
        @State var isTapped: Bool = false
    
        var body: some View {
            let magnify = MagnificationGesture(minimumScaleDelta: 0.2)
                .onChanged { value in
                    let resolvedDelta = value / self.lastValue
                    self.lastValue = value
                    let newScale = self.scale * resolvedDelta
                    self.scale = min(self.maxScale, max(self.minScale, newScale))
    
                    print("delta=\(value) resolvedDelta=\(resolvedDelta)  newScale=\(newScale)")
            }
    
            let gestureDrag = DragGesture(minimumDistance: 0, coordinateSpace: .local)
                .onChanged { (value) in
                    self.tapPoint = value.startLocation
                    self.draged = CGSize(width: value.translation.width + self.prevDraged.width,
                                         height: value.translation.height + self.prevDraged.height)
            }
    
            return GeometryReader { geo in
                    Image("dooli")
                        .resizable().scaledToFit().animation(.default)
                        .offset(self.draged)
                        .scaleEffect(self.scale)
    //                    .scaleEffect(self.isTapped ? 2 : 1,
    //                                 anchor: UnitPoint(x: self.tapPoint.x / geo.frame(in: .local).maxX,
    //                                                   y: self.tapPoint.y / geo.frame(in: .local).maxY))
                        .gesture(
                            TapGesture(count: 2).onEnded({
                                self.isTapped.toggle()
                                if self.scale > 1 {
                                    self.scale = 1
                                } else {
                                    self.scale = 2
                                }
                                let parent = geo.frame(in: .local)
                                self.postArranging(translation: CGSize.zero, in: parent)
                            })
                            .simultaneously(with: gestureDrag.onEnded({ (value) in
                                let parent = geo.frame(in: .local)
                                self.postArranging(translation: value.translation, in: parent)
                            })
                        ))
                        .gesture(magnify.onEnded { value in
                            // without this the next gesture will be broken
                            self.lastValue = 1.0
                            let parent = geo.frame(in: .local)
                            self.postArranging(translation: CGSize.zero, in: parent)
                        })
                }
                .frame(height: 300)
                .clipped()
                .background(Color.gray)
    
        }
    
        private func postArranging(translation: CGSize, in parent: CGRect) {
            let scaled = self.scale
            let parentWidth = parent.maxX
            let parentHeight = parent.maxY
            let offset = CGSize(width: (parentWidth * scaled - parentWidth) / 2,
                                height: (parentHeight * scaled - parentHeight) / 2)
    
            print(offset)
            var resolved = CGSize()
            let newDraged = CGSize(width: self.draged.width * scaled,
                                   height: self.draged.height * scaled)
            if newDraged.width > offset.width {
                resolved.width = offset.width / scaled
            } else if newDraged.width < -offset.width {
                resolved.width = -offset.width / scaled
            } else {
                resolved.width = translation.width + self.prevDraged.width
            }
            if newDraged.height > offset.height {
                resolved.height = offset.height / scaled
            } else if newDraged.height < -offset.height {
                resolved.height = -offset.height / scaled
            } else {
                resolved.height = translation.height + self.prevDraged.height
            }
            self.draged = resolved
            self.prevDraged = resolved
        }
    
    }
    

提交回复
热议问题