iOS屏幕旋转之为横屏视频播放增加竖屏模式

在App Store上的大部分视频播放App中,都实现了竖屏小屏播放以显示更多相关信息,横屏切换到全屏播放,这样的交互显得优雅而大方。最近项目里有个这样的需求,为全屏视频播放加上竖屏模式。下面,让我们一起来实现这个需求。


iOS中的方向

iOS设备中有两种方向,一种是设备方向,一种是屏幕视图方向。我们可以直接调用

[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPartrait];

强制更改设备方向,但该方法已经在iOS6中废止。另外一种更改设备方向的方法是通过重力感应触发。

那么视图方向是又什么决定的呢?

  1. 全局Info.plist
  2. iOS6+在UIApplicationDelegate中增加了 - (NSUInteger)supportedInterfaceOrientationsForWindow:(UIWindow *)window;回调
  3. UIViewController。并且只在UIWindow的rootViewController或model状态下的UIViewController有效

最终的视图方向取决于 (全局控制 ∩ UIWindow 中的回调 ∩ 单个界面控制) 的交集,如果交集为空,iOS6下抛出 UIApplicationInvalidInterfaceOrientationException 异常后崩溃。

UIController中对视图方向变化的响应

iOS5:

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return ((toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) |
           (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft));
}
iOS6+:

// 支持转屏?
(BOOL)shouldAutorotate
{
    return YES;
}
// 支持的屏幕方向
- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

实现前后的效果

竖屏:


横屏:


两张横竖屏的图片中,菜单、标题大小都发生了改变。下面我们就来讨论下实现的方法。

实现细节

  1. 首先在视频播放所在UIViewController支持横竖屏,并在设备旋转的回调中,通知菜单当前的设备方向发生了改变,代码如下:
    //设备旋转前
    - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    {
    //横竖屏变更菜单等
    if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
    //竖屏状态
    }
     
    //设备旋转前
    - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
    {
    //对视图进行旋转处理,这里通过present一个新的UIViewController,暂不需要处理
    }
     
    //设备旋转完
    - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
    {
    //设备旋转完的处理
    }
    // 支持转屏
    (BOOL)shouldAutorotate
    {
        return YES;
    }
    // 支持的屏幕方向
    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIDeviceOrientationLandscapeLeft | UIInterfaceOrientationPortrait ;
    }
    -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
    {
        return ((toInterfaceOrientation == UIInterfaceOrientationPortrait) ||
               (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft));
    }
    willRotateToInterfaceOrientation:duration: 和 willAnimateRotationToInterfaceOrientation:duration:的区别在于调用的顺序。前者在旋转前调用,并且屏幕方向、设备原点、视图大小等都未改变,后者在旋转的动画block中调用,并且屏幕方向、设备原点、视图大小等都已改变。因此在willRotateToInterfaceOrientation:duration:中,应当做变量的更改;在willAnimateRotationToInterfaceOrientation:duration:中,适合做一些重绘工作。
  2. 考虑到原来的视频播放器只支持横屏播放,这里采用的方案如下:竖屏状态下,先present一个只支持横屏的UIViewController,再将视频播放器作为横屏UIViewController的子控制器添加进来。这样可以触发iOS进行横竖屏检测。
  3. 当竖屏切到横屏时,旋转的动画设置。代码如下:
    [portraitViewController presentViewController:landscapeViewController animated:NO completion:^{
    
                //mvPlayer原先是作为protraitViewController的子UIViewController
                [mvPlayer.view removeFromSuperview]; 
                [mvPlayer removeFromParentViewController];
    
                //改为作为landscapeViewController的子UIViewController
    	    [landscapeViewController addChildViewController:mvPlayer];
                [landscapeViewController.view addSubview:mvPlayer.view]; 
                
                //改变状态栏方向
                [[UIApplication sharedApplication] setStatusBarHidden:YES];
                [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft animated:NO];
                
                //旋转前
                CGAffineTransform transform = CGAffineTransformMakeRotation(-M_PI_2);
                transform = CGAffineTransformScale(transform, scale, scale);
                mvPlayer.view.transform = transform;
                
                //旋转动画
                [UIView animateWithDuration:[[UIApplication sharedApplication] statusBarOrientationAnimationDuration] animations:^{
                    mvPlayer.view.transform = CGAffineTransformIdentity;
                    mvPlayer.view.frame = landscapeViewController.view.bounds;
                }completion:^(BOOL finished) {
                    
                    [[UIApplication sharedApplication] setStatusBarHidden:NO];
                    
                }];
            }];

  4. 横屏切换到竖屏的动画实现如下:
    //更改mvPlayer的父UIController
    [mvPlayer.view removeFromSuperview];
    UIViewController *viewController = strongSelf.player.presentingViewController;
    [mvPlayer removeFromParentViewController];
    [viewController dismissModalViewControllerAnimated:NO];
    
    [portraitViewController addChildViewController:mvPlayer];
    [portraitViewController.view addSubview:mvPlayer.view];
            
    //缩放动画
    CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
    mvPlayer.view.transform = transform;
    mvPlayer.view.frame = CGRectMake(0, 0, CGRectGetWidth(mvPlayer.view.frame), CGRectGetHeight(mvPlayer.view.frame));
    mvPlayer.view.transform = CGAffineTransformRotate(transform, M_PI_2);
            
         [UIView animateWithDuration:[[UIApplication sharedApplication] statusBarOrientationAnimationDuration]
                          animations:^{
                              mvPlayer.view.transform = CGAffineTransformMakeScale(scale, scale);
                          }
                          completion:^(BOOL finished) {
                              mvPlayer.view.frame = CGRectMake(0, 0, CGRectGetWidth(mvPlayer.view.frame), CGRectGetHeight(mvPlayer.view.frame));
                                  
                          }];

  5. 以上是手动旋转过程。还有一种方法是直接旋转portraitViewController.view。人为旋转过程中,设备的原点并未发生改变,这需要考虑横竖屏布局问题。

总结

本文介绍横竖屏切换的一些基础知识,并实践了类似腾讯视频的横竖屏人为切换方式,达到不同状态下显示不同视图的交互方式。



  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值