项目中,也写过类似"视频全屏"的功能, 前一阵子读到今日头条 的一篇技术文章,详细介绍三种旋转方法差异优劣最终择取。文章从技术角度看写的非常好,从用户角度看,也用过多家有视频功能的app,今日头条的体验的确很优。特别值得学习特此参考写了一个视频全屏小功能

实现方法:配合重写当前的ViewController的shouldAutorotate方法,返回NO 并且控制 状态栏的展示  然后 通过 animation旋转动画处理UI相对布局

(1)组织类别方法 UINavigationController+Rotation 目的视频旋转 状态栏也要旋转

//
// UINavigationController+Rotation.h
// SectionDemo
//
// Created by HF on 17/4/1.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import <UIKit/UIKit.h> @interface UINavigationController (Rotation) @end
//
// UINavigationController+Rotation.m
// SectionDemo
//
// Created by HF on 17/4/1.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import "UINavigationController+Rotation.h" @implementation UINavigationController (Rotation) - (BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
} - (NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
} - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
} @end

(2)视频UI HFMovieView

//
// HFMovieView.h
// SectionDemo
//
// Created by HF on 17/4/1.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import <UIKit/UIKit.h>
#import "HFPlayerView.h" typedef NS_ENUM(NSUInteger, MovieViewState) {
MovieViewStateSmall,
MovieViewStateAnimating,
MovieViewStateFullscreen,
}; @interface HFMovieView : UIView /**
视频播放对象
*/
@property (nonatomic, strong)HFPlayerView *videoView; /**
记录小屏时的parentView
*/
@property (nonatomic, weak) UIView *movieViewParentView; /**
记录小屏时的frame
*/
@property (nonatomic, assign) CGRect movieViewFrame; @property (nonatomic, assign) MovieViewState state; @end
//
// HFMovieView.m
// SectionDemo
//
// Created by HF on 17/4/1.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import "HFMovieView.h" @implementation HFMovieView - (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) { //videoView
[self addSubview:self.videoView]; //others
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)];
[self.videoView addGestureRecognizer:tapGestureRecognizer]; }
return self;
} #pragma mark - event - (void)handleTapGesture:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
if (self.state == MovieViewStateSmall) {
[self enterFullscreen];
}
else if (self.state == MovieViewStateFullscreen) {
[self exitFullscreen];
}
}
} #pragma mark - private #pragma mark -- 全屏 animation
- (void)enterFullscreen { if (self.state != MovieViewStateSmall) {
return;
} self.state = MovieViewStateAnimating; /*
* 记录进入全屏前的parentView和frame
*/
self.movieViewParentView = self.videoView.superview;
self.movieViewFrame = self.videoView.frame; /*
* movieView移到window上
*/
CGRect rectInWindow = [self convertRect:self.videoView.bounds toView:[UIApplication sharedApplication].keyWindow];
[self.videoView removeFromSuperview];
self.videoView.frame = rectInWindow;
[[UIApplication sharedApplication].keyWindow addSubview:self.videoView]; /*
* 执行动画
*/
[UIView animateWithDuration:0.5 animations:^{
self.videoView.transform = CGAffineTransformMakeRotation(M_PI_2);
self.videoView.bounds = CGRectMake(0, 0, CGRectGetHeight(self.videoView.superview.bounds), CGRectGetWidth(self.videoView.superview.bounds));
self.videoView.center = CGPointMake(CGRectGetMidX(self.videoView.superview.bounds), CGRectGetMidY(self.videoView.superview.bounds));
} completion:^(BOOL finished) {
self.state = MovieViewStateFullscreen;
}]; [self refreshStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
} #pragma mark -- 退出全屏 animation - (void)exitFullscreen
{
if (self.state != MovieViewStateFullscreen) {
return;
} self.state = MovieViewStateAnimating; CGRect frame = [self.movieViewParentView convertRect:self.movieViewFrame toView:[UIApplication sharedApplication].keyWindow]; [UIView animateWithDuration:0.5 animations:^{
self.videoView.transform = CGAffineTransformIdentity;
self.videoView.frame = frame;
} completion:^(BOOL finished) {
/*
* movieView回到小屏位置
*/
[self.videoView removeFromSuperview];
self.videoView.frame = self.movieViewFrame;
[self.movieViewParentView addSubview:self.videoView];
self.state = MovieViewStateSmall;
}]; [self refreshStatusBarOrientation:UIInterfaceOrientationPortrait];
} #pragma mark -- 更新状态栏方向 - (void)refreshStatusBarOrientation:(UIInterfaceOrientation)interfaceOrientation {
[[UIApplication sharedApplication] setStatusBarOrientation:interfaceOrientation animated:YES];
} #pragma mark - setter and getter - (HFPlayerView *)videoView
{
if (!_videoView) {
_videoView = [[HFPlayerView alloc]initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
_videoView.backgroundColor = [UIColor blackColor];
}
return _videoView;
} @end

(3)视图控制器

//
// MethodDetailViewController.h
// SectionDemo
//
// Created by HF on 17/4/1.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import <UIKit/UIKit.h>
#import "HFMovieView.h" @interface MethodDetailViewController : UIViewController @property (nonatomic, strong) HFMovieView *moviewView; @end
//
// MethodDetailViewController.m
// SectionDemo
//
// Created by HF on 17/4/1.
// Copyright © 2017年 HF-Liqun. All rights reserved.
// #import "MethodDetailViewController.h" @interface MethodDetailViewController () @property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) UIView *headView; @end @implementation MethodDetailViewController - (void)viewDidLoad {
[super viewDidLoad]; [self.view addSubview:self.tableView];
[self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}]; self.tableView.tableHeaderView = self.headView;
[self.headView addSubview:self.moviewView]; } - (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
} #pragma mark - 旋转配置 - (BOOL)shouldAutorotate {
return NO;
} #pragma mark - setter/getter - (UITableView *)tableView
{
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.backgroundColor = [UIColor clearColor];
// _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; }
return _tableView;
} - (UIView *)headView
{
if (!_headView) {
_headView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 200)];;
_headView.backgroundColor = [UIColor lightGrayColor];
}
return _headView;
} - (HFMovieView *)moviewView
{
if (!_moviewView) {
_moviewView = [[HFMovieView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 200)];
_moviewView.backgroundColor = [UIColor yellowColor];
}
return _moviewView;
}
@end

效果图:

(4)参考之前 写过视频播放的相关方法 优化架构分工

参考 SectionDemo

参考:

1. https://techblog.toutiao.com/2017/03/28/fullscreen/

2. iOS AVPlayer 学习

iOS 视频全屏功能 学习的更多相关文章

  1. iOS端一次视频全屏需求的实现(转)

    对于一个带有视频播放功能的app产品来说,视频全屏是一个基本且重要的需求.虽然这个需求看起来很简单,但是在实现上,我们前后迭代了三套技术方案.这篇文章将介绍这三种实现方案中的利弊和坑点,以及实现过程中 ...

  2. js 实现操作浏览器或者元素的全屏与退出全屏功能

    <!DOCTYPE html> <html lang="en" id="div1"> <head> <meta cha ...

  3. Chrome71版本使用screenfull.js全屏功能时报参数错误

    在生产环境长期使用的一个“全屏”功能突然失效了,查看Console 如下报错: Failed to execute 'requestFullscreen' on 'Element': paramete ...

  4. 富文本编辑器vue2-editor实现全屏功能

    vue2-editor非常不错,可惜并未带全屏功能,自己实现了一个,供大家参考. 实现思路:自定义模块. 1. 定义全屏模块Fullscreen /** * 编辑器的全屏实现 */ import no ...

  5. iOS的录屏功能

    iOS的录屏功能其实没什么好说的,因为网上的教程很多,但是网上的Demo无一例外几乎都有一个bug,那就是iPad上会出现闪退,这也体现了国内的教程文档的一个特点,就是抄袭,教程几乎千篇一律,bug也 ...

  6. JS实现元素的全屏、退出全屏功能

     在实际开发中,我们很可能需要实现某一元素的全屏和退出全屏功能,如canvas.所幸的是,js提供了相关api用来处理这一问题,只需简单的调用requestFullScreen.exitFullScr ...

  7. H5项目常见问题及注意事项,视频全屏,定位,屏幕旋转和触摸,偏页面重构向 来源joacycode的github

    Meta基础知识: H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 //一.HTML页面结构 <meta name="viewport" content="wi ...

  8. iOS自定义全屏返回与tableView左划删除手势冲突解决

    当自定义一个navigationController实现全屏右划返回时, 使用起来是不是很爽, 代码如下: - (void)viewDidLoad { [super viewDidLoad]; UIG ...

  9. C#窗体全屏功能

    最近有朋友让我给他弄个应用程序全屏的功能,例如银行的取号程序界面.所以我从网上查询了一些实现的方法. C#应用程序中如何实现全屏幕显示功能? 效果就像windows自带的屏幕保护程序和众多的游戏那样, ...

随机推荐

  1. Python 中,matplotlib绘图无法显示中文的问题

    在python中,默认情况下是无法显示中文的,如下代码: import matplotlib.pyplot as plt # 定义文本框和箭头格式 decisionNode = dict(boxsty ...

  2. OSX: bash的更新

    本文尽量详述眼下来说的bash补丁的进展,从以下4个方面解释: 最全最新的更新安装包,:Oct 5为止的 測试已知的bash漏洞的脚本:更新后能够用来检測已知bash漏洞的情况 脚本编译更新版本号:也 ...

  3. 大数据(4) - HDFS常用的shell操作

    注意:这次使用的是第二部分安装的集群,不是高可用集群 为了方便,开发,必须写集群脚本,试想集群的机器是100台以上,而不是3台的情况.... 集群启动脚本 vim /home/admin/tools/ ...

  4. php 按条件进行计算的方法

    $isin = in_array($sheng,$s_sheng);//post过来的省的编码是否在s_sheng(自定义的数组)里,如果在,则加一,如果不在则不加一 if($isin){ //ech ...

  5. references non-existing project XXX, launch configuration问题的解决办法

    Go to Project->properties In properties window's left pane select "Run/Debug Settings". ...

  6. jQuery 和其他 JavaScript 框架

    正如您已经了解到的,jQuery 使用 $ 符号作为 jQuery 的简写. 如果其他 JavaScript 框架也使用 $ 符号作为简写怎么办? 其他一些 JavaScript 框架包括:MooTo ...

  7. 【转载】C#时间差的计算,精确输出“年月天时分秒”

    ======================== 感谢“不忘初心”大神的分享======================== 原博地址:http://www.cnblogs.com/IT-Bear/a ...

  8. Ionic 取消自带动画效果

    $ionicConfigProvider.views.transition('none'); 或: <ion-view view-title="个人中心" animation ...

  9. 椭圆参数方程中的θ(离心角Theta)

    椭圆参数方程中的离心角θ是交以其x轴对应外接圆上点的角度(或是交以其y轴对应内接圆上点的角度) 椭圆的参数程为:x=acosθy=bsinθ.M(x,y)椭圆上一点.过M作直线⊥X轴,交以O为圆心,以 ...

  10. php的下载

    前言:你的坚持,终将美好! 今天给大家说一下,php的下载,由于php的下载本身就是一个压缩包,解压缩后即可使用.所以,解压缩的过程不再赘述. 第一步:在浏览器的地址栏输入:http://www.ph ...