iOS 视频全屏功能 学习
项目中,也写过类似"视频全屏"的功能, 前一阵子读到今日头条 的一篇技术文章,详细介绍三种旋转方法差异优劣最终择取。文章从技术角度看写的非常好,从用户角度看,也用过多家有视频功能的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/
iOS 视频全屏功能 学习的更多相关文章
- iOS端一次视频全屏需求的实现(转)
对于一个带有视频播放功能的app产品来说,视频全屏是一个基本且重要的需求.虽然这个需求看起来很简单,但是在实现上,我们前后迭代了三套技术方案.这篇文章将介绍这三种实现方案中的利弊和坑点,以及实现过程中 ...
- js 实现操作浏览器或者元素的全屏与退出全屏功能
<!DOCTYPE html> <html lang="en" id="div1"> <head> <meta cha ...
- Chrome71版本使用screenfull.js全屏功能时报参数错误
在生产环境长期使用的一个“全屏”功能突然失效了,查看Console 如下报错: Failed to execute 'requestFullscreen' on 'Element': paramete ...
- 富文本编辑器vue2-editor实现全屏功能
vue2-editor非常不错,可惜并未带全屏功能,自己实现了一个,供大家参考. 实现思路:自定义模块. 1. 定义全屏模块Fullscreen /** * 编辑器的全屏实现 */ import no ...
- iOS的录屏功能
iOS的录屏功能其实没什么好说的,因为网上的教程很多,但是网上的Demo无一例外几乎都有一个bug,那就是iPad上会出现闪退,这也体现了国内的教程文档的一个特点,就是抄袭,教程几乎千篇一律,bug也 ...
- JS实现元素的全屏、退出全屏功能
在实际开发中,我们很可能需要实现某一元素的全屏和退出全屏功能,如canvas.所幸的是,js提供了相关api用来处理这一问题,只需简单的调用requestFullScreen.exitFullScr ...
- H5项目常见问题及注意事项,视频全屏,定位,屏幕旋转和触摸,偏页面重构向 来源joacycode的github
Meta基础知识: H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 //一.HTML页面结构 <meta name="viewport" content="wi ...
- iOS自定义全屏返回与tableView左划删除手势冲突解决
当自定义一个navigationController实现全屏右划返回时, 使用起来是不是很爽, 代码如下: - (void)viewDidLoad { [super viewDidLoad]; UIG ...
- C#窗体全屏功能
最近有朋友让我给他弄个应用程序全屏的功能,例如银行的取号程序界面.所以我从网上查询了一些实现的方法. C#应用程序中如何实现全屏幕显示功能? 效果就像windows自带的屏幕保护程序和众多的游戏那样, ...
随机推荐
- 学习笔记 - Unity是如何将你的项目发布到如此多的平台的?
很多Unity的开发者是不是都会觉得Unity能把项目导出发布到那么多不同的平台上运行是件很牛X的事情?那么你有没有想过Unity是如何做到的呢?本文就来大体的聊一聊Unity做的这件神奇的事情. 概 ...
- python 开发技巧(2)-- Django的安装与使用
一.安装Django pip3 install django 或者直接使用PyCharm安装 参考 二.添加环境变量 将 "(python安装路径)\Scripts" 添加到环境变 ...
- Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights
第一次提交遇到这样的情况,怎么回事呢,我在github上提交了ssh key 的啊. 排查先看看能不能解析, 1.先 ping https://github.com 把ip添加到 host : ...
- 我的第八个java程序--读取word内容
package World; import java.io.FileNotFoundException; import java.io.IOException; import org.apache.p ...
- SlidingMenu——使用前的配置
一: 首先下载lib:SlidingMenu.然后将起导入eclipse中,然后将其clean一下,重新生成R文件. 二: 因为SlidingMenu依赖ActionBarSherlock,所以需要下 ...
- TP数据查询
[数据查询] select()是数据模型的一个指定方法,可以获得数据表的数据信息 返回一个二维数组信息,当前数据表的全部数据信息 $obj = D(); 创建对象 $obj -> select ...
- php通过post将表单数据保存到数据库实例
html的form表单 <form id="contact-form" method="POST" action="../php/msg.php ...
- tomcat ; nginx ;mysql
[说明]上午在服务器上部署了自己的web目录(tomcat虚拟目录),下午安装并了解了nginx(出了点问题,后来解决了),晚上尝试nginx和tomcat配置(一头雾水) 一:今日完成 1)配置to ...
- 【BZOJ1731】[Usaco2005 dec]Layout 排队布局 差分约束
[BZOJ1731][Usaco2005 dec]Layout 排队布局 Description Like everyone else, cows like to stand close to the ...
- Xtrabackup 使用方法
简介:Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品.本文测试使用的是1.3版本,X ...