使用系统通知 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)
}
}