平移手势(按住/拖动)像Snapchat一样在相机上缩放



我正在尝试复制Snapchat相机的缩放功能,一旦您开始录制,您就可以向上或向下拖动手指,它会相应地放大或缩小。我已经成功地缩放了捏合,但一直坚持使用PanGestureRecognizer缩放。

这是我尝试过的代码,问题是我不知道如何替换用于捏手势识别器缩放的sender.scale。我正在使用AVFoundation。基本上,我问我如何才能像在 TikTok 或 Snapchat 中那样正确进行保持缩放(一指拖动)。

let minimumZoom: CGFloat = 1.0
let maximumZoom: CGFloat = 15.0
var lastZoomFactor: CGFloat = 1.0
var latestDirection: Int = 0
@objc func panGesture(_ sender: UIPanGestureRecognizer) {
    let velocity = sender.velocity(in: doubleTapSwitchCamButton)
    var currentDirection: Int = 0
    if velocity.y > 0 || velocity.y < 0 {
                let originalCapSession = captureSession
                var devitce : AVCaptureDevice!
                let videoDeviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInDuoCamera], mediaType: AVMediaType.video, position: .unspecified)
                let devices = videoDeviceDiscoverySession.devices
                devitce = devices.first!
                guard let device = devitce else { return }
                    // Return zoom value between the minimum and maximum zoom values
                    func minMaxZoom(_ factor: CGFloat) -> CGFloat {
                        return min(min(max(factor, minimumZoom), maximumZoom), device.activeFormat.videoMaxZoomFactor)
                        }
                        func update(scale factor: CGFloat) {
                            do {
                                try device.lockForConfiguration()
                                defer { device.unlockForConfiguration() }
                                device.videoZoomFactor = factor
                            } catch {
                                print("(error.localizedDescription)")
                            }
                        }
//These 2 lines below are the problematic ones, pinch zoom uses this one below, and the newScaleFactor below that is a testing one that did not work.
                let newScaleFactor = minMaxZoom(sender.scale * lastZoomFactor)
                       //let newScaleFactor = CGFloat(exactly: number + lastZoomFactor)

                    switch sender.state {
                    case .began: fallthrough                
                    case .changed: update(scale: newScaleFactor!)                
                    case .ended:
                        lastZoomFactor = minMaxZoom(newScaleFactor!)
                        update(scale: lastZoomFactor)
                    default: break
                    }
        } else {
        }
        latestDirection = currentDirection
    }

您可以使用手势识别器的平移属性来计算以点为单位的位移,并将此位移归一化为缩放因子。

将其放入您的代码中,您可以尝试:

 ... somewhere in your view setup code, i.e. viewDidLoad.... 
     let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGesture))
     button.addGestureRecognizer(panGestureRecognizer)
 private var initialZoom: CGFloat = 1.0
 @objc func panGesture(_ sender: UIPanGestureRecognizer) {
    // note that 'view' here is the overall video preview
    let velocity = sender.velocity(in: view)
    if velocity.y > 0 || velocity.y < 0 {
       let originalCapSession = captureSession
       var devitce : AVCaptureDevice!
       let videoDeviceDiscoverySession = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInDuoCamera], mediaType: AVMediaType.video, position: .unspecified)
       let devices = videoDeviceDiscoverySession.devices
       devitce = devices.first!
       guard let device = devitce else { return }
        let minimumZoomFactor: CGFloat = 1.0
        let maximumZoomFactor: CGFloat = min(device.activeFormat.videoMaxZoomFactor, 10.0) // artificially set a max useable zoom of 10x
        // clamp a zoom factor between minimumZoom and maximumZoom
        func clampZoomFactor(_ factor: CGFloat) -> CGFloat {
            return min(max(factor, minimumZoomFactor), maximumZoomFactor)
        }
        func update(scale factor: CGFloat) {
            do {
                try device.lockForConfiguration()
                defer { device.unlockForConfiguration() }
                device.videoZoomFactor = factor
            } catch {
                print("(error.localizedDescription)")
            }
        }
        switch sender.state {
        case .began:
            initialZoom = device.videoZoomFactor
            startRecording() /// call to start recording your video
        case .changed:
            // distance in points for the full zoom range (e.g. min to max), could be view.frame.height
            let fullRangeDistancePoints: CGFloat = 300.0
            // extract current distance travelled, from gesture start
            let currentYTranslation: CGFloat = sender.translation(in: view).y
            // calculate a normalized zoom factor between [-1,1], where up is positive (ie zooming in)
            let normalizedZoomFactor = -1 * max(-1,min(1,currentYTranslation / fullRangeDistancePoints))
            // calculate effective zoom scale to use
            let newZoomFactor = clampZoomFactor(initialZoom + normalizedZoomFactor * (maximumZoomFactor - minimumZoomFactor))
            // update device's zoom factor'
            update(scale: newZoomFactor)
        case .ended, .cancelled:
            stopRecording() /// call to start recording your video
            break
        default:
            break
        }
    }
}

最新更新