Saturday, April 20, 2024
HomeiOS Developmentios - Pan and zoom assist wanted

ios – Pan and zoom assist wanted


I simply began my journey to study coding and doing it on the iPad with Swift playground.

I’ve an audio waveform to which I apply zoom and pan gestures. I’m having a little bit of hassle. Once I zoom in and pan all the way in which to the tip of the waveform, if I strive zooming out, the waveform tends to pan as an alternative, and it disappears. As a substitute of the tip of the waveform being hooked up to the background traces, I can see it shifting. Might you additionally assist implement a method to zoom between my finger?

Here’s a YouTube of the problem https://youtu.be/RrP39Fv-_oc?si=sca_ys0vOnihLFGs and right here is the code:

import SwiftUI

struct WaveformView: View {
    @Binding var waveform: [Float]
    @State personal var zoomFactor: CGFloat = 1.0
    @State personal var lastZoomFactor: CGFloat = 1.0
    @State personal var offset: CGSize = .zero
    @State personal var lastOffset: CGSize = .zero
    @State personal var selectionStart: CGFloat = 0.0
    @State personal var selectionEnd: CGFloat = 1.0

    var physique: some View {
        ZStack {
            Coloration.grey.opacity(0.3).edgesIgnoringSafeArea(.all)
            GeometryReader { geometry in
                ZStack(alignment: .main) {
                    Canvas { context, measurement in
                        let middleY = measurement.top / 2
                        let maxAmplitude = measurement.top / 3 - 1
                        var path = Path()
                        path.transfer(to: CGPoint(x: 0, y: middleY))
                        var previousPoint = CGPoint(x: 0, y: middleY)
                        for (index, pattern) in waveform.enumerated() {
                            let x = (measurement.width * CGFloat(index) / CGFloat(waveform.depend)) * zoomFactor - offset.width
                            let amplitude = max(min(CGFloat(pattern) * maxAmplitude, maxAmplitude), -maxAmplitude)
                            let level = CGPoint(x: x, y: middleY - amplitude)
                            let controlPoint1 = CGPoint(x: (previousPoint.x + level.x) / 2, y: previousPoint.y)
                            let controlPoint2 = CGPoint(x: (previousPoint.x + level.x) / 2, y: level.y)
                            path.addCurve(to: level, control1: controlPoint1, control2: controlPoint2)
                            previousPoint = level
                        }
                        context.stroke(path, with: .colour(.blue), lineWidth: 1)
                        
                        // Playhead line
                      
                    }
                    
                    // Choice overlay and handles
                    Rectangle()
                        .fill(Coloration.blue.opacity(0.3)) // Choice overlay colour
                        .body(width: geometry.measurement.width * (selectionEnd - selectionStart), top: geometry.measurement.top)
                        .offset(x: geometry.measurement.width * selectionStart, y: 0)
                    
                    Circle() // Begin deal with
                        .fill(Coloration.blue)
                        .body(width: 30, top: 30)
                        .offset(x: geometry.measurement.width * selectionStart - 15, y: geometry.measurement.top / 2 - 15)
                        .gesture(
                            DragGesture()
                                .onChanged { worth in
                                    selectionStart = min(max(0, worth.location.x / geometry.measurement.width), selectionEnd)
                                }
                        )
                    
                    Circle() // Finish deal with
                        .fill(Coloration.blue)
                        .body(width: 30, top: 30)
                        .offset(x: geometry.measurement.width * selectionEnd - 15, y: geometry.measurement.top / 2 - 15)
                        .gesture(
                            DragGesture()
                                .onChanged { worth in
                                    selectionEnd = max(min(1, worth.location.x / geometry.measurement.width), selectionStart)
                                }
                        )
                }
                .gesture(
                    SimultaneousGesture(
                        MagnificationGesture().onChanged { worth in
                            let newZoomFactor = lastZoomFactor * worth
                            self.zoomFactor = max(1.0, newZoomFactor)
                        }.onEnded { worth in
                            if abs(self.zoomFactor - 1.0) < 0.05 {
                                self.zoomFactor = 1.0
                                self.offset = .zero
                                self.lastOffset = .zero
                            } else {
                                self.lastZoomFactor = self.zoomFactor
                                let adjustmentFactor = self.zoomFactor / self.lastZoomFactor
                                self.offset.width *= adjustmentFactor
                                self.lastOffset = self.offset
                            }
                        },
                        DragGesture().onChanged { worth in
                            let proposedOffset = lastOffset.width - worth.translation.width
                            let maxOffset = max((geometry.measurement.width * zoomFactor) - geometry.measurement.width, 0)
                            self.offset.width = min(max(proposedOffset, 0), maxOffset)
                        }.onEnded { worth in
                            self.lastOffset = self.offset
                        }
                    )
                )
                .onChange(of: waveform) { _ in
                    resetSelection()
                    resetZoomAndOffset()
                }
                .gesture(TapGesture(depend: 2).onEnded {
                    resetSelection()
                    resetZoomAndOffset()
                })
            }
        }
    }
    
    personal func resetSelection() {
        selectionStart = 0.0
        selectionEnd = 1.0
    }
    
    personal func resetZoomAndOffset() {
        zoomFactor = 1.0
        lastZoomFactor = 1.0
        offset = .zero
        lastOffset = .zero
    }
}

I zoom in, pan to the tip of waveform, then attempt to zoom out.
Waveform detaches from background body, pans as an alternative of zooming out.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments