平移手势(按住/拖动)缩放相机,如 Snapchat

Posted

技术标签:

【中文标题】平移手势(按住/拖动)缩放相机,如 Snapchat【英文标题】:Pan gesture (hold/drag) zoom on camera like Snapchat 【发布时间】:2019-01-29 23:57:49 【问题描述】:

我正在尝试复制 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

    

【问题讨论】:

我认为 UIPanGesutureRecognizer 没有规模。相反,我认为您应该确定最大缩放系数,然后创建增量缩放级别(例如 5),当识别到 PanGesuture 时,只需将缩放系数增加到或减少到预定级别之一。如果你愿意在 github 上分享你的代码,我可以给你看。 嗯,我以前试过;我将发布我很快尝试过的代码,但我将它增加了 +1 缩放,但它没有按预期工作。 @DoesData 下面的答案解决了它 【参考方案1】:

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

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

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

【讨论】:

效果很好!一旦我进一步测试它,我会奖励赏金。 是的,它工作得很好,但是我怎样才能做到,一旦你已经点击了一个按钮,你就可以用同一个手指向上移动和缩放。就像您按住按钮的 snapchat 一样,您可以用按住 cam 按钮的同一根手指放大。 我明白了...您可以在 .began 和 .ended 事件中处理开始/停止录制...确保将手势识别器附加到您的按钮,但使用超级视图进行计算译文。查看我编辑的答案 好的,请检查代码并稍后回复...感谢您到目前为止的帮助。

以上是关于平移手势(按住/拖动)缩放相机,如 Snapchat的主要内容,如果未能解决你的问题,请参考以下文章

35three.js鼠标控制物体旋转缩放

捏手势不适用于 SKCameraNode

threeJS 导入模型(不确定尺寸)后如何确定相机位置及物体缩放比例

Sceneview 翻译/移动带有手势的视角相机

平移手势使视图在拖动时从手指跳开

缩放和平移仅适用于第一次尝试使用 Windows Phone 的手势监听器