视图旋转 AVPlayer视频播放视图旋转

淳于熙云
2023-12-01
/*
 
当在做视频播放器的时候 , 需要对播放视频的那个view进行旋转操作 , 当控制中心 ( 上拉的那个菜单 ) 开启旋转屏幕 , 点击全屏按钮或把手机横屏 视图都会全屏 , 全屏状态下 , 点击退出全屏按钮或将屏幕旋转到正方向 , 视图都会退出全屏 ; 如果控制中心关闭旋转屏幕 , 旋转屏幕不再能用 , 但进入和退出全屏按钮都是能用的
 
在这期间 , 状态条也是要改变方向的 , 而且是一直显示的 , 现在专业做视频的 APP 都是这样的 , 下面是怎样实现的屏幕旋转的这一块 :
 1.
方案 1 : 强制旋转屏幕 + SizeClasses 这个需要调用私有 API( 审核可能被拒绝 ), 而且现在私有 API 有的也不能用了 , 无法强制退出横屏 , 所以这个方案不可以 ;
 2.
方案 2 : 这就是我即将说的这个 , 主流视频 APP 都是这么做的 , 一开始我做播放器的时候先就差这一点没有解决 , 蛋疼了好几天 , 现在终于全都解决了 , 以后可能会发 AVPlayer 视频播放的博客 , 包括音量 . 亮度 . 手势等等 不过下一篇我还是会总结一些旋转屏幕时遇到的各种问题 ;
(首先确定你的程序info.plist添加了要旋转的方向)
 */


@interface LRLAVPlayerController ()

//用来播放视频的view
@property ( nonatomic , strong ) LRLAVPlayerView * avplayerView;
//用来存储这个view的尺寸, 为了模拟存储视频信息的的model
@property ( nonatomic , strong ) AVPlayerModel * avModel;
//view的高度
@property ( nonatomic , assign ) CGFloat videoHeight;

@end

@implementation LRLAVPlayerController

// 懒加载的方式来获取一个默认的 model, 用来模拟视频的尺寸 ;
-(
AVPlayerModel *)avModel{
   
if (! _avModel ) {
       
_avModel = [[ AVPlayerModel alloc ] init ];
       
_avModel . videoSize = CGSizeMake ( SCREEN_WIDTH , 200 );
    }
   
return _avModel ;
}

// 实例化 , 一个模拟播放视频的view
-(
void )initAVPlayerView{
   
self . avplayerView = [[ NSBundle mainBundle ] loadNibNamed : @"LRLAVPlayerView" owner : self options : nil ]. lastObject ;
    [
self . view addSubview : self . avplayerView ];
   
self . videoHeight = SCREEN_WIDTH * ( self . avModel . videoSize . height / self . avModel . videoSize . width );
   
// 使用 masonry 给视图加限制 (autoLayout)
    [
self . avplayerView mas_makeConstraints :^( MASConstraintMaker *make) {
        make.
top . equalTo ( self . view ). with . offset ( 40 );
        make.
left . equalTo ( self . view );
        make.
right . equalTo ( self . view );
        make.
height . equalTo ( @( self . videoHeight ) );
    }];
}

// 点击进入全屏按钮
- (
IBAction )toLaunch:( id )sender {
    [
self toOrientation : UIInterfaceOrientationLandscapeLeft ];
}

// 点击退出全屏按钮
- (
IBAction )toPra:( id )sender {
    [
self toOrientation : UIInterfaceOrientationPortrait ];
}

// 点击进入 , 退出全屏 , 或者监测到屏幕旋转去调用的方法
-(
void )toOrientation:( UIInterfaceOrientation )orientation{
   
// 获取到当前状态条的方向
   
UIInterfaceOrientation currentOrientation = [ UIApplication sharedApplication ]. statusBarOrientation ;
   
// 判断如果当前方向和要旋转的方向一致 , 那么不做任何操作
   
if (currentOrientation == orientation) {
       
return ;
    }
   
   
// 根据要旋转的方向 , 使用 Masonry 重新修改限制
   
if (orientation == UIInterfaceOrientationPortrait ) {
        [
self . avplayerView mas_remakeConstraints :^( MASConstraintMaker *make) {
            make.
top . equalTo ( self . view ). with . offset ( 40 );
            make.
left . equalTo ( self . view );
            make.
right . equalTo ( self . view );
            make.
height . equalTo ( @( self . videoHeight ) );
        }];
    }
else {
       
// 这个地方加判断是为了从全屏的一侧 , 直接到全屏的另一侧不用修改限制 , 否则会出错 ;
       
if (currentOrientation == UIInterfaceOrientationPortrait ) {
            [
self . avplayerView mas_remakeConstraints :^( MASConstraintMaker *make) {
                make.
width . equalTo ( @( SCREEN_HEIGHT ) );
                make.
height . equalTo ( @( SCREEN_WIDTH ) );
                make.
center . equalTo ( self . avplayerView . superview );
            }];
        }
    }
   
//iOS6.0 之后 , 设置状态条的方法能使用的前提是 shouldAutorotate NO, 也就是说这个视图控制器内 , 旋转要关掉 ;
   
// 也就是说在实现这个方法的时候 -(BOOL)shouldAutorotate 返回值要为 NO
    [[
UIApplication sharedApplication ] setStatusBarOrientation :orientation animated : NO ];
   
// 获取旋转状态条需要的时间 :
   
CGFloat duration = [ UIApplication sharedApplication ]. statusBarOrientation ;
    [
UIView beginAnimations : nil context : nil ];
   
// 更改了状态条的方向 , 但是设备方向 UIInterfaceOrientation 还是正方向的 , 这就要设置给你播放视频的视图的方向设置旋转
   
// 给你的播放视频的 view 视图设置旋转
   
self . avplayerView . transform = [ self getOrientation ];
    [
UIView setAnimationDuration :duration];
   
// 开始旋转
    [
UIView commitAnimations ];
}

// 根据想要旋转的方向来设置旋转
-(
CGAffineTransform )getOrientation{
   
// 状态条的方向已经设置过 , 所以这个就是你想要旋转的方向
   
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ]. statusBarOrientation ;
   
// 根据要进行旋转的方向来计算旋转的角度
   
if (orientation == UIInterfaceOrientationPortrait ) {
       
return CGAffineTransformIdentity ;
    }
else if (orientation == UIInterfaceOrientationLandscapeLeft ){
       
return CGAffineTransformMakeRotation (- M_PI_2 );
    }
else if (orientation == UIInterfaceOrientationLandscapeRight ){
       
return CGAffineTransformMakeRotation ( M_PI_2 );
    }
   
return CGAffineTransformIdentity ;
}

// 视图控制器实现的方法
-(
BOOL )shouldAutorotate{        //iOS6.0 之后 , 要想让状态条可以旋转 , 必须设置视图不能自动旋转
   
return NO ;
}

// 这就遇到一个问题 , 可以手动进行设置旋转的方向 , 但我们关掉了自动旋转的开关 , 那么如果我想要既可以手动操作又想自动旋转呢 , 可现在我已经把自动旋转关了呀 , 别急 , 系统提供了一个通知 , 即使不开启旋转也能监测到旋转
- (
void )viewDidLoad {
    [
super viewDidLoad ];
   
self . view . backgroundColor = [ UIColor whiteColor ];
   
// 实例化播放视频的视图 , 实现在最上边
    [
self initAVPlayerView ];
   
   
// 获取设备旋转方向的通知 , 即使关闭了自动旋转 , 一样可以监测到设备的旋转方向
    [[
UIDevice currentDevice ] beginGeneratingDeviceOrientationNotifications ];
    [[
NSNotificationCenter defaultCenter ] addObserver : self selector : @selector (orientationChanged:) name : UIDeviceOrientationDidChangeNotification object : nil ];
}

// 获取设备的旋转方向 , 然后进行判断如何旋转 UI
-(
void )orientationChanged:( NSNotification *)notification{
   
UIDeviceOrientation orientation = [[ UIDevice currentDevice ] orientation ];
   
// 根据监测到的旋转方向 , 进行旋转
   
switch (orientation) {
       
case UIDeviceOrientationPortrait :
            [
self toOrientation : UIInterfaceOrientationPortrait ];
           
break ;
       
case UIDeviceOrientationLandscapeLeft :
           
//UIDeviceOrientation UIInterfaceOrientation 在左右方向上是翻着的
            [
self toOrientation : UIInterfaceOrientationLandscapeRight ];
           
break ;
       
case UIDeviceOrientationLandscapeRight :
            [
self toOrientation : UIInterfaceOrientationLandscapeLeft ];
           
break ;
       
default :
           
break ;
    }
}

@end
 类似资料: