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/

2. iOS AVPlayer 学习

原文地址:https://www.cnblogs.com/someonelikeyou/p/6890256.html