播放器横竖屏方案

类似现在主流app的横竖切换的方式

  1. 原理 : 在播放器横屏时候, present一个新的视图控制器, 并在该新控制器中支持横竖屏. dismiss时候, 返回之前的播放器;
  2. 源码 :

// - 声明

#import 
#import "DYVideoPlayerView+Private.h"

#pragma mark - 横屏的控制器
@interface DYVideoPlayerVC : UIViewController

/** 初始化方法 */
- (instancetype)initWithVideoPlayerView:(UIView *)videoPlayerView preferredInterfaceOrientationForPresentation:(UIInterfaceOrientation)orientation;

@end

#pragma mark - 跳转横屏控制器的转场动画
typedef NS_ENUM(NSUInteger, DYVideoPlayerTransitionType){
    DYVideoPlayerTransitionTypePresent = 0,
    DYVideoPlayerTransitionTypeDismiss,
};

@interface DYVideoPlayerTransition : NSObject
+(instancetype)presentTransitionWithVideoPlayerView:(DYVideoPlayerView *)videoPlayerView;
+(instancetype)dismissTransitionWithVideoPlayerView:(DYVideoPlayerView *)videoPlayerView;
@end

// - DYVideoPlayerView+Private.h

#import "DYVideoPlayerView.h"

@interface DYVideoPlayerView ()

/** 全屏之前的父视图 */
@property (nonatomic, weak) UIView *originalSuperView;

/** 全屏之前的 frame */
@property (nonatomic, assign) CGRect originalFrameInSuperView;

/** 全屏之前的 frame */
@property (nonatomic, assign) CGRect originalFrameInWindow;

@end

// - 实现

#import "DYVideoPlayerVC.h"

#pragma mark - 横屏的控制器
@interface DYVideoPlayerVC ()
/** 播放器 */
@property (nonatomic, assign) UIView *videoPlayerView;

/** 跳转前播放器的父视图 */
@property (nonatomic, assign) UIView *videoPlayerViewOriginalSuperView;

/** 跳转的控制器的方向 */
@property (nonatomic, assign) UIInterfaceOrientation orientation;

@end

@implementation DYVideoPlayerVC
/** 初始化方法 */
- (instancetype)initWithVideoPlayerView:(UIView *)videoPlayerView preferredInterfaceOrientationForPresentation:(UIInterfaceOrientation)orientation
{
    self = [super init];
    if (self) {
        self.modalPresentationStyle = UIModalPresentationFullScreen;
        self.videoPlayerView = videoPlayerView;
        self.transitioningDelegate = self.videoPlayerView;
        self.videoPlayerViewOriginalSuperView = self.videoPlayerView .superview;
        self.orientation = orientation;
    }
    return self;
}

// - MARK: <-- 初始化设置的方法 -->
- (void)viewDidLoad {
    [super viewDidLoad];
}

-(void)viewWillAppear:(BOOL)animated{
    [[UIApplication sharedApplication] setStatusBarHidden:NO];
}

- (BOOL)shouldAutorotate{
    return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskLandscape;
}

-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    return self.orientation;
}

@end

#pragma mark - 跳转横屏控制器的转场动画
@interface DYVideoPlayerTransition ()

/** 跳转类型 */
@property (nonatomic, assign)DYVideoPlayerTransitionType transitionType;

/** present时候  originalRect->全屏, dismiss时候 : 全屏->originalRect*/
@property (nonatomic, weak) DYVideoPlayerView *videoPlayerView;

@end

@implementation DYVideoPlayerTransition

// - MARK: <-- 生成present和dismiss的转场动画 -->
+(instancetype)presentTransitionWithVideoPlayerView:(DYVideoPlayerView *)videoPlayerView{
    videoPlayerView.originalSuperView = videoPlayerView.superview;
    videoPlayerView.originalFrameInSuperView = videoPlayerView.frame;
    videoPlayerView.originalFrameInWindow = [videoPlayerView.originalSuperView convertRect:videoPlayerView.originalFrameInSuperView toView:[UIApplication sharedApplication].keyWindow];
    DYVideoPlayerTransition *transition = [[DYVideoPlayerTransition alloc] init];
    transition.videoPlayerView = videoPlayerView;
    transition.transitionType = DYVideoPlayerTransitionTypePresent;
    return transition;
}

+(instancetype)dismissTransitionWithVideoPlayerView:(DYVideoPlayerView *)videoPlayerView{
    DYVideoPlayerTransition *transition = [[DYVideoPlayerTransition alloc] init];
    transition.videoPlayerView = videoPlayerView;
    transition.transitionType = DYVideoPlayerTransitionTypeDismiss;
    return transition;
}

// - MARK: <-- 转场动画代理方法 -->
- (NSTimeInterval)transitionDuration:(id)transitionContext{
    return 3;
}

- (void)animateTransition:(id)transitionContext{
    
    if (_transitionType == DYVideoPlayerTransitionTypePresent) {
        [self presentAnimation:transitionContext];
    }else{
        [self dismissAnimation:transitionContext];
    }
}

/** present 的动画*/
- (void)presentAnimation:(id)transitionContext{
    // - 跳转的vc
    DYVideoPlayerVC *toVC = (DYVideoPlayerVC *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    // - 跳转的vc的view
    UIView *containerView = [transitionContext containerView];
    UIView *toView = toVC.view;
    [containerView addSubview:toView];

    // - 设置原始的位置
    CGRect originalRect;
    CGRect tmpRect = self.videoPlayerView.originalFrameInWindow;
    if (toVC.orientation == UIInterfaceOrientationLandscapeLeft) {
        toView.transform = CGAffineTransformMakeRotation(M_PI / 2);
        originalRect = CGRectMake(
                                  [UIApplication sharedApplication].keyWindow.frame.size.width -  - tmpRect.size.height,
                                  tmpRect.origin.x,
                                  tmpRect.size.height,
                                  tmpRect.size.width);
    }else{
        toView.transform = CGAffineTransformMakeRotation(-M_PI / 2);
        originalRect = CGRectMake(tmpRect.origin.y, tmpRect.origin.x, tmpRect.size.height, tmpRect.size.width);

    }
    
    // - 更换父视图并设置位置
    [toView addSubview:self.videoPlayerView];
    toView.frame = originalRect;
    self.videoPlayerView.frame = toView.bounds;
    [self.videoPlayerView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.left.right.top.bottom.equalTo(toView);
    }];

    // - 跳转动画
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    [UIView animateWithDuration:duration animations:^{
        toView.transform = CGAffineTransformIdentity;
        toView.frame = [UIApplication sharedApplication].keyWindow.bounds;
        [toView layoutIfNeeded];
    } completion:^(BOOL finished) {
        toView.transform = CGAffineTransformIdentity;
        toView.frame = [UIApplication sharedApplication].keyWindow.bounds;
        [transitionContext completeTransition:YES];
    }];
}

/** dismiss的动画 */
- (void)dismissAnimation:(id)transitionContext{
    // - 当前的vc
    DYVideoPlayerVC *fromVC = (DYVideoPlayerVC *)[transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    // - 当前的view
    UIView *containerView = [transitionContext containerView];
    UIView *fromView = fromVC.view;
    UIView *toView = toVC.view;
    [containerView addSubview:fromView];
    
    toView.frame = [UIApplication sharedApplication].keyWindow.bounds;
    [containerView insertSubview:toView belowSubview:fromView];
    
    // - 返回的动画
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    [UIView animateWithDuration:duration animations:^{
        fromView.transform = CGAffineTransformIdentity;
        fromView.frame = self.videoPlayerView.originalFrameInWindow;
        [fromView layoutIfNeeded];
    } completion:^(BOOL finished) {
        fromView.transform = CGAffineTransformIdentity;
        fromView.frame = self.videoPlayerView.originalFrameInWindow;
        
        // - 更换父视图并设置位置
        [fromVC.videoPlayerViewOriginalSuperView addSubview:fromVC.videoPlayerView];
        fromView.frame = self.videoPlayerView.originalFrameInSuperView;
        [fromVC.videoPlayerView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.left.mas_equalTo(fromVC.videoPlayerViewOriginalSuperView).offset(self.videoPlayerView.originalFrameInSuperView.origin.x);
            make.top.mas_equalTo(fromVC.videoPlayerViewOriginalSuperView).offset(self.videoPlayerView.originalFrameInSuperView.origin.y);
            make.width.mas_equalTo(self.videoPlayerView.originalFrameInSuperView.size.width);
            make.height.mas_equalTo(self.videoPlayerView.originalFrameInSuperView.size.height);
        }];
        [transitionContext completeTransition:YES];
    }];
}


@end

// - 使用

//
//  DYVideoPlayerView.m
//  QEZB
//
//  Created by 李超群 on 2018/4/23.
//Copyright © 2018年 zhou. All rights reserved.
//

#pragma mark ************************************ 短视频的播放器的 view ************************************

#import "DYVideoPlayerView.h"
#import "DYVideoPlayerVC.h"

@interface DYVideoPlayerView () 

/** <#注释#> */
@property (nonatomic, weak) UIViewController *videoPlayerVC;

@end

@implementation DYVideoPlayerView

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    [self toRightScreenModel];
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIDeviceOrientationDidChangeNotification object:nil];

    }
    return self;
}

- (void)statusBarOrientationChange:(NSNotification *)notification {
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
    if (orientation == UIDeviceOrientationLandscapeLeft ) {
        [self toLeftScreenModel];
    }else if (orientation == UIDeviceOrientationLandscapeRight) {
        [self toRightScreenModel];
    }else if (orientation == UIDeviceOrientationPortrait) {
        [self toSmallScreenModel];
    }
}

-(void)toSmallScreenModel{
    self.videoPlayerVC.transitioningDelegate = self;
    [self.videoPlayerVC dismissViewControllerAnimated:YES completion:nil];
    self.videoPlayerVC = nil;
}


-(void)toLeftScreenModel{
    // - 如果已经在全屏模式, 不操作
    if (self.videoPlayerVC) return;

    // - 旋转到大屏回调
    if ([self.delegate respondsToSelector:@selector(playerView:willRotateToFullScreen:)]) {
        [self.delegate playerView:self willRotateToFullScreen:YES];
    }

    // - 跳转到大屏
    DYVideoPlayerVC *videoPlayerVC = [[DYVideoPlayerVC alloc]initWithVideoPlayerView:self preferredInterfaceOrientationForPresentation:UIInterfaceOrientationLandscapeRight];
    UIImageView *tempV = [[UIImageView alloc]initWithImage:[UIImage imageCaptureTheFullScreen]];
    [[UIApplication sharedApplication].keyWindow.rootViewController.view addSubview:tempV];
    [[ControllerTool getCurrentVC] presentViewController:videoPlayerVC animated:YES completion:^{
        [tempV removeFromSuperview];
    }];
    self.videoPlayerVC = videoPlayerVC;
}
/** 旋转到大屏模式(右边) */
-(void)toRightScreenModel{
    // - 如果已经在全屏模式, 不操作
    if (self.videoPlayerVC) return;

    // - 旋转到大屏回调
    if ([self.delegate respondsToSelector:@selector(playerView:willRotateToFullScreen:)]) {
        [self.delegate playerView:self willRotateToFullScreen:YES];
    }

    // - 跳转到大屏
    DYVideoPlayerVC *videoPlayerVC = [[DYVideoPlayerVC alloc]initWithVideoPlayerView:self preferredInterfaceOrientationForPresentation:UIInterfaceOrientationLandscapeLeft];
    UIImageView *tempV = [[UIImageView alloc]initWithImage:[UIImage imageCaptureTheFullScreen]];
    [[UIApplication sharedApplication].keyWindow.rootViewController.view addSubview:tempV];
    [[ControllerTool getCurrentVC] presentViewController:videoPlayerVC animated:YES completion:^{
        [tempV removeFromSuperview];
    }];
    self.videoPlayerVC = videoPlayerVC;
}

- (id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source{
    return [DYVideoPlayerTransition presentTransitionWithVideoPlayerView:self];
}

- (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed{
    return [DYVideoPlayerTransition dismissTransitionWithVideoPlayerView:self];
}

@end

你可能感兴趣的:(项目中使用的技巧,#,横竖屏旋转)