概述

最近在做有关音视频的项目,项目中涉及到全屏播放切换的问题,最近研究了一下。在此做个记录,实现全屏效果我目前能够用两种方法实现,一种是让App需要进行全屏的页面随着设备进行旋转,另外一种是把需要全屏的view放到window上面,为window添加旋转动画。在这介绍的是使用window实现全屏功能。

效果

#import "VideoFullScreenController.h"static CGFloat AnimationDuration = 0.3;//旋转动画执行时间@interface VideoFullScreenController ()@property (nonatomic, nullable, strong) UIView *playerView;//播放器视图
@property (nonatomic, nullable, strong) UIButton *btnFullScreen;
@property (nonatomic, nullable, strong) UIView *playerSuperView;//记录播放器父视图
@property (nonatomic, assign) CGRect playerFrame;//记录播放器原始frame
@property (nonatomic, assign) BOOL isFullScreen;//记录是否全屏@property (nonatomic, assign) UIInterfaceOrientation lastInterfaceOrientation;
@property (nonatomic, nullable, strong) UIWindow *mainWindow;@end@implementation VideoFullScreenController- (void)viewDidLoad {[super viewDidLoad];[self.playerView addSubview:self.btnFullScreen];[self.view addSubview:self.playerView];if (@available(iOS 13.0, *)) {_lastInterfaceOrientation = [UIApplication sharedApplication].windows.firstObject.windowScene.interfaceOrientation;} else {_lastInterfaceOrientation = [UIApplication sharedApplication].statusBarOrientation;}//开启和监听 设备旋转的通知if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];}[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(handleDeviceOrientationChange:)name:UIDeviceOrientationDidChangeNotification object:nil];
}//设备方向改变的处理
- (void)handleDeviceOrientationChange:(NSNotification *)notification{UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;switch (deviceOrientation) {case UIDeviceOrientationFaceUp:NSLog(@"屏幕朝上平躺");break;case UIDeviceOrientationFaceDown:NSLog(@"屏幕朝下平躺");break;case UIDeviceOrientationUnknown:NSLog(@"未知方向");break;case UIDeviceOrientationLandscapeLeft:if (self.isFullScreen) {[self interfaceOrientation:UIInterfaceOrientationLandscapeRight];}NSLog(@"屏幕向左横置");break;case UIDeviceOrientationLandscapeRight:if (self.isFullScreen) {[self interfaceOrientation:UIInterfaceOrientationLandscapeLeft];}NSLog(@"屏幕向右橫置");break;case UIDeviceOrientationPortrait:NSLog(@"屏幕直立");break;case UIDeviceOrientationPortraitUpsideDown:NSLog(@"屏幕直立,上下顛倒");break;default:NSLog(@"无法辨识");break;}
}
//最后在dealloc中移除通知 和结束设备旋转的通知
- (void)dealloc{[[NSNotificationCenter defaultCenter]removeObserver:self];[[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications];
}- (BOOL)shouldAutorotate {return NO;
}- (BOOL)prefersStatusBarHidden {if (@available(iOS 13.0, *)) {return self.isFullScreen;}return NO;
}- (UIInterfaceOrientationMask)supportedInterfaceOrientations {return UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskLandscapeLeft|UIInterfaceOrientationMaskLandscapeRight;
}#pragma mark - private method- (void)fullScreenAction:(UIButton *)sender {if (self.isFullScreen) {//如果是全屏,点击按钮进入小屏状态[self changeToOriginalFrame];} else {//不是全屏,点击按钮进入全屏状态[self changeToFullScreen];}}- (void)changeToOriginalFrame {if (!self.isFullScreen) {return;}[UIView animateWithDuration:AnimationDuration animations:^{[self interfaceOrientation:UIInterfaceOrientationPortrait];self.playerView.frame = self.playerFrame;} completion:^(BOOL finished) {[self.playerView removeFromSuperview];[self.playerSuperView addSubview:self.playerView];self.isFullScreen = NO;//调用以下方法后,系统会在合适的时间调用prefersStatusBarHidden方法,控制状态栏的显示和隐藏,可根据自己的产品控制显示逻辑[self setNeedsStatusBarAppearanceUpdate];}];}- (void)changeToFullScreen {if (self.isFullScreen) {return;}//记录播放器视图的父视图和原始frame值,在实际项目中,可能会嵌套子视图,所以播放器的superView有可能不是self.view,所以需要记录父视图self.playerSuperView = self.playerView.superview;self.playerFrame = self.playerView.frame;CGRect rectInWindow = [self.playerView convertRect:self.playerView.bounds toView:self.mainWindow];[self.playerView removeFromSuperview];self.playerView.frame = rectInWindow;[self.mainWindow addSubview:self.playerView];//执行旋转动画[UIView animateWithDuration:AnimationDuration animations:^{UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;if (orientation == UIDeviceOrientationLandscapeRight) {[self interfaceOrientation:UIInterfaceOrientationLandscapeLeft];} else {[self interfaceOrientation:UIInterfaceOrientationLandscapeRight];}self.playerView.bounds = CGRectMake(0, 0, CGRectGetHeight(self.mainWindow.bounds), CGRectGetWidth(self.mainWindow.bounds));self.playerView.center = CGPointMake(CGRectGetMidX(self.mainWindow.bounds), CGRectGetMidY(self.mainWindow.bounds));} completion:^(BOOL finished) {self.isFullScreen = YES;//调用以下方法后,系统会在合适的时间调用prefersStatusBarHidden方法,控制状态栏的显示和隐藏,可根据自己的产品控制显示逻辑[self setNeedsStatusBarAppearanceUpdate];}];
}- (void)interfaceOrientation:(UIInterfaceOrientation)orientation {if (orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft) {// 设置横屏[self setOrientationLandscapeConstraint:orientation];} else if (orientation == UIInterfaceOrientationPortrait) {// 设置竖屏[self setOrientationPortraitConstraint];}
}- (void)setOrientationLandscapeConstraint:(UIInterfaceOrientation)orientation {[self toOrientation:orientation];
}- (void)setOrientationPortraitConstraint {[self toOrientation:UIInterfaceOrientationPortrait];
}- (void)toOrientation:(UIInterfaceOrientation)orientation {// 获取到当前状态条的方向------iOS13已经废弃,所以不能根据状态栏的方向判断是否旋转,手动记录最后一次的旋转方向
//    UIInterfaceOrientation currentOrientation = [UIApplication sharedApplication].statusBarOrientation;// 判断如果当前方向和要旋转的方向一致,那么不做任何操作if (self.lastInterfaceOrientation == orientation) { return; }if (@available(iOS 13.0, *)) {//iOS 13已经将setStatusBarOrientation废弃,调用此方法无效} else {[[UIApplication sharedApplication] setStatusBarOrientation:orientation animated:NO];}self.lastInterfaceOrientation = orientation;// 获取旋转状态条需要的时间:[UIView animateWithDuration:AnimationDuration animations:^{// 更改了状态条的方向,但是设备方向UIInterfaceOrientation还是正方向的,这就要设置给你播放视频的视图的方向设置旋转// 给你的播放视频的view视图设置旋转self.playerView.transform = CGAffineTransformIdentity;self.playerView.transform = [self getTransformRotationAngleWithOrientation:self.lastInterfaceOrientation];// 开始旋转} completion:^(BOOL finished) {}];
}- (CGAffineTransform)getTransformRotationAngleWithOrientation:(UIInterfaceOrientation)orientation {// 根据要进行旋转的方向来计算旋转的角度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;
}#pragma mark - setter- (void)setIsFullScreen:(BOOL)isFullScreen {_isFullScreen = isFullScreen;[self.btnFullScreen setTitle:isFullScreen?@"退出全屏":@"全屏" forState:UIControlStateNormal];
}#pragma mark - getter- (UIView *)playerView {if (!_playerView) {_playerView = [[UIView alloc]init];_playerView.backgroundColor = [UIColor redColor];if (@available(iOS 11.0, *)) {_playerView.frame = CGRectMake(0, self.view.safeAreaInsets.top, CGRectGetWidth(self.view.bounds), CGRectGetWidth(self.view.bounds) * 9 / 16.f);} else {_playerView.frame = CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetWidth(self.view.bounds) * 9 / 16.f);}}return _playerView;
}- (UIButton *)btnFullScreen {if (!_btnFullScreen) {_btnFullScreen = [UIButton buttonWithType:UIButtonTypeCustom];[_btnFullScreen setTitle:@"全屏" forState:UIControlStateNormal];_btnFullScreen.backgroundColor = [UIColor orangeColor];[_btnFullScreen addTarget:self action:@selector(fullScreenAction:) forControlEvents:UIControlEventTouchUpInside];_btnFullScreen.frame = CGRectMake(50, 80, 150, 50);}return _btnFullScreen;
}- (UIWindow *)mainWindow {if (!_mainWindow) {if (@available(iOS 13.0, *)) {_mainWindow = [UIApplication sharedApplication].windows.firstObject;} else {_mainWindow = [UIApplication sharedApplication].keyWindow;}}return _mainWindow;
}@end

结尾

如果你的rootViewController是UIViewController的话,那么用上面的代码实现全屏效果没有问题,如果你的rootViewController是UINavigationController或者UITabBarController的话,那么还要增加两个分类文件。文件内容如下:

一、定义分类UINavigationController+Rotation.h

@implementation UINavigationController (Rotation)- (BOOL)shouldAutorotate {return [self.topViewController shouldAutorotate];
}- (UIInterfaceOrientationMask)supportedInterfaceOrientations {return [self.topViewController supportedInterfaceOrientations];
}- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {return [self.topViewController preferredInterfaceOrientationForPresentation];
}

二、定义分类UITabBarController+Rotation.h

@implementation UITabBarController (Rotation)- (BOOL)shouldAutorotate {return [self.selectedViewController shouldAutorotate];
}- (UIInterfaceOrientationMask)supportedInterfaceOrientations {return [self.selectedViewController supportedInterfaceOrientations];
}- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}

iOS视频播放全屏效果实现相关推荐

  1. H5案例分享:微信视频播放全屏问题

    2019独角兽企业重金招聘Python工程师标准>>> 微信视频播放全屏问题 在ios和安卓手机里的微信下播放视频时,会遇到不少问题,例如需要手动点击,视频才会播放,并且视频会跳出微 ...

  2. Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮...

    Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮 前言 之前写过屏蔽系统导航栏功能的文章,具体可看Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP) ...

  3. html实现全屏效果原理,HTML5 实现全屏效果

    HTML5 实现全屏效果 点击进入全屏和点击退出全屏方法: //进入全屏 function requestFullScreen() { var de = document.documentElemen ...

  4. Leaflet中使用Leaflet.fullscreen插件实现全屏效果

    场景 Vue+Leaflet实现加载OSM显示地图: Vue+Leaflet实现加载OSM显示地图_BADAO_LIUMANG_QIZHI的博客-CSDN博客 在上面的基础上,怎样实现地图全屏效果. ...

  5. js如何设置浏览器全屏效果?

    现在很多网页游戏进入游戏界面后都是全屏显示的效果,很多人问我这个要怎么实现,其实这个只要调用Fullscreen API就可以实现了作为一个比较新的 API,目前只有 Safari.Chrome 和 ...

  6. Android学习之Android 5.0分享动画实现微信点击全屏效果

    Android5.0过渡动画,请看 http://blog.csdn.net/qq_16131393/article/details/51112772 今天用分享动画实现微信点击全屏效果 本文源代码下 ...

  7. android 点击图片动画效果,Android仿微信图片点击全屏效果

    废话不多说,先看下Android图片点击全屏效果: 先是微信的 再是模仿的 先说下实现原理,再一步步分析 这里总共有2个Activity一个就是主页,一个就是显示我们图片效果的页面,参数通过Inten ...

  8. android视频播放处理,安卓版微信视频播放全屏处理

    问题 在安卓版微信里,video在播放的时候,如果在没有做任何处理的情况下,微信会全屏播放你的视频,会严重影响一些例如直播之类的边看视频边交互的H5应用(注:在iOS里可以通过playsinline( ...

  9. iOS视频播放横竖屏切换技巧

    一.需求:横竖屏切换. 二.效果:                       三.实现: 如上图,点击工具栏的第四个按钮进行横屏切换: - (void)toolTabButtonPressed:(A ...

最新文章

  1. mysql文件头标记_通过文件头准确识别PHP上传的文件类型 ( 一 )
  2. Redis 限流的 3 种方式,还有谁不会!
  3. Disruptor 线程间共享数据无需竞争
  4. 8道Java经典面试题
  5. 会签 数据库表设计_关于数据库表设计和实体类设计的思考
  6. dnf剑魂buff等级上限_DNF:又是随机大坑?8月新护石装备可升级,但升3个需要刷半年...
  7. Spark源码分析之DAGScheduler以及stage的划分
  8. cv2作图cv2.polylines,cv2.fillPoly,cv2.fillConvexPoly多边形时需要注意的地方
  9. 升级到android studio 4.1后检测不到flutter、Dart插件
  10. mysql 优化count_MySQL优化之COUNT(*)效率
  11. 基于springboot助学贷款管理毕业设计源码061528
  12. cefsharp修改html,CefSharp v62修改方法(支持.net4.0)
  13. JavaWeb后端代码自动生成工具
  14. 程序设计与数据结构_周立功【读书笔记】
  15. Neo4j 图数据库高级应用系列 / 服务器扩展指南 APOC 8.5 - 图生成 / 随机图
  16. 伽马函数公式 ∫x^ne^{-x}dx=n!
  17. IIS启动失败,发生意外错误 0x8ffe2740的解决方法
  18. 和平精英服务器为什么老是无响应,和平精英触控失灵怎么回事 操作触屏有时候没反应介绍...
  19. css 文字超出三行展示省略号
  20. 推荐系统中learning to rank(学习排名)

热门文章

  1. 【论文解读--MPC控制】Dynamic Locomotion in the MIT Cheetah 3 Through Convex Model-Predictive Control
  2. SQL SERVER学习记录
  3. AI算法工程师 | 02人工智能基础-Python基础(四)os模块_打开读取文件
  4. [原创]WIA 学习笔记
  5. zabbix5.0-06-报警媒介
  6. LeetCode:数组刷题(17道经典题目)
  7. 小米网卡驱动linux,小米笔记本pro 15.6寸安装ubuntu16.04无法使用wifi的解决方法
  8. CF1155F Delivery Oligopoly
  9. 现在还没多少人知道的商业模式,月入百万不是梦——消费盲返模式
  10. 互联网营销新模式,泰山众筹sun4.0模式了解一下