XZ_iOS 之监听屏幕方向

使用系统通知 orientationDidChangeNotification  获取屏幕方向,前提是:手机不能设置强制竖屏,如果设置了强制竖屏,是不会调用这个通知的。本文是在用户手机设置了强制竖屏的情况下,将用户竖屏录制的视频,根据屏幕旋转方向,将视频旋转成横屏显示。比如:如下图,拍摄的视频/图片是横着拍的

无论是摄像头在左边/右边/上边/下边拍摄的视频或图片,在播放视频或显示图片的时候,如下图显示:

代码实现

屏幕旋转方向监听,使用 CoreMotion 每隔一秒钟获取一次视频的方向,视频方向改变时,发送通知。

import Foundation
import CoreMotion

class XZDeviceOrientation: NSObject {
    
    private let sensitive = 0.77
    
    private let motionManager = CMMotionManager()
    
    private var direction: UIInterfaceOrientation = .portrait
    
    // 每隔一个间隔做轮询
    func start() {
        
        print("------走了start")
        
        motionManager.deviceMotionUpdateInterval = 1.0
        
        if motionManager.isDeviceMotionAvailable {
            
            motionManager.startDeviceMotionUpdates(to: OperationQueue.current!) {[weak self] (motion, error) in
                
                self?.performSelector(onMainThread: #selector(self?.deviceMotion(motion:)), with: motion, waitUntilDone: true)
            }
            
        }
    }
    
    @objc func deviceMotion(motion: CMDeviceMotion) {
        
        let x = motion.gravity.x
        let y = motion.gravity.y
        
        if y < 0 {
            if fabs(y) < sensitive {
                
                if direction != .portrait {
                    direction = .portrait
                    
                    NotificationCenter.default.post(name: UIDevice.orientationDidChangeNotification, object: nil, userInfo: ["direction": direction])
                }
            }
        }else {
            
            if y > sensitive {
                if direction != .portraitUpsideDown {
                    direction = .portraitUpsideDown
                    
                    NotificationCenter.default.post(name: UIDevice.orientationDidChangeNotification, object: nil, userInfo: ["direction": direction])
                    
                }
            }
        }
        
        
        if x < 0 {
            if fabs(x) > sensitive {
                if direction != .landscapeLeft {
                    direction = .landscapeLeft
                    
                    NotificationCenter.default.post(name: UIDevice.orientationDidChangeNotification, object: nil, userInfo: ["direction": direction])
                }
            }
        }else {
            if x > sensitive {
                if direction != .landscapeRight {
                    direction = .landscapeRight
                    
                    NotificationCenter.default.post(name: UIDevice.orientationDidChangeNotification, object: nil, userInfo: ["direction": direction])
                }
            }
        }
        
        print("---------direction:", direction.rawValue)
    }
    
    func stop() {
        print("---------走了stop")
        motionManager.stopDeviceMotionUpdates()
    }
}

在进入控制器时,调用开始轮询的方法;页面不显示时,关闭轮询。

private let device = XZDeviceOrientation()

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
                
        device.start()
}


override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    
        device.stop()
}

接收到通知修改orientationValue的值,当点击开始录制视频时,使用 currentValue 记录点击开始拍摄时的屏幕方向。

/// 旋转方向 - 默认竖屏
private var orientationValue: UIInterfaceOrientation = .portrait
private var currentValue: UIInterfaceOrientation = .portrait


// 监听屏幕旋转通知
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
        
NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged(notification:)), name: UIDevice.orientationDidChangeNotification, object: nil)

   /// 监听屏幕旋转
    @objc func orientationChanged(notification: NSNotification) {
        
//        let orientation = UIDevice.current.orientation
        guard let userInfo = notification.userInfo, let orientation = userInfo["direction"] as? UIInterfaceOrientation else {
            return
        }
        
        print("---------orientation:", orientation)
        
        switch orientation {
        case .portrait:
            orientationValue = .portrait
        case .landscapeLeft:
            orientationValue = .landscapeLeft
        case .landscapeRight:
            orientationValue = .landscapeRight
        case .portraitUpsideDown:
            orientationValue = .portraitUpsideDown
        default:
            break
        }
    }


/// 开始录制视频
func startRecording() {
       
   currentValue = orientationValue
}
        

我使用的GPUImage拍摄的视频,给视频输出变量GPUImageMovieWriter,根据拍摄时方向设置transform来修改视频的横竖屏,代码如下:

 
        switch currentValue {

        case .landscapeLeft:
            // 旋转 90°
            movieWriter?.transform = CGAffineTransform(rotationAngle: -CGFloat(Double.pi) * 0.5)
        case .landscapeRight:
            // 旋转 -90°
            movieWriter?.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi) * 0.5)
        case .portraitUpsideDown:
            // 旋转 180°
            movieWriter?.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
        default:
            break
        }

竖屏,摄像头在上方时,不进行任何操作;横屏:摄像头在左侧、右侧和竖屏:摄像头在下方时,进行旋转。

获取视频的宽高时,根据currentValue的值,修改宽高值,代码如下:

// 获取视频尺寸
let asset = AVURLAsset(url: url)
let array = asset.tracks
var videoSize = CGSize.zero
        
for track in array {
    if track.mediaType == AVMediaType.video {
        videoSize = track.naturalSize
        // 横屏
        if currentValue == .landscapeLeft || currentValue == .landscapeRight {
                    
           videoSize = CGSize(width: track.naturalSize.height, height: track.naturalSize.width)
         }
         print("---------:", videoSize)
     }
}
        
发布了208 篇原创文章 · 获赞 52 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/understand_XZ/article/details/89847209
今日推荐