项目中,也写过类似"视频全屏"的功能, 前一阵子读到今日头条 的一篇技术文章,详细介绍三种旋转方法差异优劣最终择取。文章从技术角度看写的非常好,从用户角度看,也用过多家有视频功能的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. C++注释规范

      1 源文件头部注释 列出:版权.作者.编写日期和描述. /************************************************* Copyright:bupt Auth ...

  2. 百度UEditor 用require 引入 Thinkphp5 ,图片上传问题

    用require引入,用了10分钟:上传图片,用了一个早上(吐血一地.....) 重点:require引入成功后,在需要引用UEditor的文件开头加入(ue的文件夹路径) window.UEDITO ...

  3. java 定时器

    import java.io.IOException; import java.util.Timer; public class TimerTest { public static void main ...

  4. python 左移右移 2个数交换

    左移右移的能够使得数字*2或者/2 那*3怎么办,就左移一位然后再+ 经典面试题: 1.交换2个数,不用temp   a=10  b=12 1.1 a = a + b = 22 b = a - b = ...

  5. dm8148 开发之---sii9022a hdmi传输器

    SiI9022A -HDMI 发送器    照相机.摄影机和便携式媒体播放器的高清解决方案   SiI9022a是一款超低功耗的HDMI发送器,集成度更高, 电源管理特性也更强,适用于手提式消费电子设 ...

  6. 浅谈IM软件怎样建立安全socket连接、登录

    ----------------------------------------------------欢迎查看IM软件业务知识<专栏>-------------------------- ...

  7. sqoop1.4.4从oracle导数据到hive中

    sqoop从oracle定时增量导入数据到hive 感谢: http://blog.sina.com.cn/s/blog_3fe961ae01019a4l.htmlhttp://f.dataguru. ...

  8. Spark OOM:java heap space,OOM:GC overhead limit exceeded解决方法

    问题描述: 在使用spark过程中,有时会因为数据增大,而出现下面两种错误: java.lang.OutOfMemoryError: Java heap space java.lang.OutOfMe ...

  9. C++中的return返回值:return0 or return -1?

    C++98 中定义了如下两种 main 函数的定义方式: int main( ) int main( int argc, char *argv[] )   (参考资料:ISO/IEC 14882(19 ...

  10. hdu 2460(tarjan求边双连通分量+LCA)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2460 思路:题目的意思是要求在原图中加边后桥的数量,首先我们可以通过Tarjan求边双连通分量,对于边 ...