preface

  • Recently I am writing the player case, which involves full-screen/half-screen conversion, here I share the problems and processing ideas I met, interested elder brother can download and play, feel useful and helpful, please point a little star!!

The Demo address:KJPlayerDemo


Effect preview,

Share ideas

As far as I know about full screen, here are a few options:

  • Native page rotation, forced rotation device rotation, player controller rotation to landscape state

  • The player’s View is rotated by 90 degrees using UIView’s Transform property. In fact, this is not a true landscape. The system menu bar and system controls remain in the original portrait state

baseView.transform = CGAffineTransformMakeRotation(M_PI_2);
Copy the code
  • Rotate View + landscape Window, this way to solve the second kind of rotation system control problem

Third way of thinking scheme

1, storage,frame, the back cut back to small screen time use

static CGRect _originalFrame;
+ (CGRect)originalFrame{
    return _originalFrame;
}
+ (void)setOriginalFrame:(CGRect)originalFrame{
    _originalFrame = originalFrame;
}
Copy the code

2. Rotate the status bar

id<KJPlayerRotateAppDelegate> delegate = (id<KJPlayerRotateAppDelegate>)[[UIApplication sharedApplication] delegate]; NSAssert([delegate conformsToProtocol:@protocol(KJPlayerRotateAppDelegate)], @"Please see the usage documentation!!!" ); [delegate kj_transmitCurrentRotateOrientation:UIInterfaceOrientationMaskLandscape]; KJRotateViewController *vc = [[KJRotateViewController alloc] init]; vc.interfaceOrientationMask = UIInterfaceOrientationMaskLandscape; UIWindow *videoWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; videoWindow.rootViewController = vc;Copy the code

This configuration ViewController to support the direction of rotation, call the Window’s rootViewcontroller supportedInterfaceOrientations and shouldAutorotate direction to determine the direction of the current page support

@implementation KJRotateViewController
- (BOOL)shouldAutorotate{
    return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
    return self.interfaceOrientationMask;
}
@end
Copy the code

3. Rotate the View

baseView.transform = CGAffineTransformMakeRotation(M_PI_2);
baseView.bounds = [UIScreen mainScreen].bounds;
baseView.center = baseView.superview.center;
[baseView setValue:@(YES) forKey:@"isFullScreen"];
Copy the code

There is a detail that we need to fix the screen to portrait after the rotation animation is completed

id<KJPlayerRotateAppDelegate> delegate = (id<KJPlayerRotateAppDelegate>)[[UIApplication sharedApplication] delegate];
[delegate kj_transmitCurrentRotateOrientation:UIInterfaceOrientationMaskPortrait];
Copy the code

To the full screen mode ideas came out the same, the specific need to pay attention to is the need to realize KJPlayerRotateAppDelegate Appdelegate

Reference document, the implementation of full-screen video requirements on iOS terminal,

I’ve packaged it as a tool

Post the implementation code directly

#import <Foundation/ foundation. h> #import <UIKit/ uikit. h> NS_ASSUME_NONNULL_BEGIN /* This protocol must be implemented in the Appdelegate */ @protocol KJPlayerRotateAppDelegate < NSObject > / * transfer current * / - rotating direction (void)kj_transmitCurrentRotateOrientation:(UIInterfaceOrientationMask)rotateOrientation; @end @class KJBasePlayerView; @ interface KJRotateManager: NSObject / * to switch to full screen * / + (void) kj_rotateFullScreenBasePlayerView (baseView UIView *); / * to switch to the small screen * / + (void) kj_rotateSmallScreenBasePlayerView (baseView UIView *); / * to switch to the floating window screen * / + (void) kj_rotateFloatingWindowBasePlayerView (baseView UIView *); @end NS_ASSUME_NONNULL_ENDCopy the code
#import "KJRotateManager.h" #define kRotate_KeyWindow \ ({UIWindow *window; \ if (@available(iOS 13.0, *)) {\ window = [UIApplication sharedApplication].Windows.firstObject; \ }else{\ window = [UIApplication sharedApplication].keyWindow; \ }\ window; }) // Rotate the middle controller @interface KJRotateViewController: UIViewController @property (nonatomic, assign) UIInterfaceOrientationMask interfaceOrientationMask; @end @implementation KJRotateViewController - (BOOL)shouldAutorotate{ return YES; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations{ return self.interfaceOrientationMask; } @ the end / * * * * * * * * * * * * * * * * * * * * * * * * * * gold line * * * * * * * * * * * * * * * * * * * * * * * * * * * / @ interface KJRotateManager () @property(nonatomic,assign,class)CGRect originalFrame; @ end @ implementation KJRotateManager / * to switch to full screen * / + (void) kj_rotateFullScreenBasePlayerView baseView: (UIView *) { self.originalFrame = baseView.frame; UIColor *temp = baseView.superview.backgroundColor; baseView.superview.backgroundColor = UIColor.blackColor; baseView.layer.zPosition = 1; id<KJPlayerRotateAppDelegate> delegate = (id<KJPlayerRotateAppDelegate>)[[UIApplication sharedApplication] delegate]; NSAssert([delegate conformsToProtocol:@protocol(KJPlayerRotateAppDelegate)], @"Please see the usage documentation!!!" ); [delegate kj_transmitCurrentRotateOrientation:UIInterfaceOrientationMaskLandscape]; KJRotateViewController *vc = [[KJRotateViewController alloc] init]; vc.interfaceOrientationMask = UIInterfaceOrientationMaskLandscape; UIWindow *videoWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; videoWindow.rootViewController = vc; [UIView animateWithDuration: 0.3 f animations: ^ {baseView. Transform = CGAffineTransformMakeRotation (M_PI_2);  baseView.bounds = [UIScreen mainScreen].bounds; baseView.center = baseView.superview.center;  [baseView setValue:@(YES) forKey:@"isFullScreen"];  } completion:^(BOOL finished) { baseView.superview.backgroundColor = temp;  id<KJPlayerRotateAppDelegate> delegate = (id<KJPlayerRotateAppDelegate>)[[UIApplication sharedApplication] delegate];  [delegate kj_transmitCurrentRotateOrientation:UIInterfaceOrientationMaskPortrait]; }]; } / * to switch to the small screen * / + (void) kj_rotateSmallScreenBasePlayerView: (UIView *) baseView {baseView. Layer. ZPosition = 0; id<KJPlayerRotateAppDelegate> delegate = (id<KJPlayerRotateAppDelegate>)[[UIApplication sharedApplication] delegate]; NSAssert([delegate conformsToProtocol:@protocol(KJPlayerRotateAppDelegate)], @"Please see the usage documentation!!!" ); [delegate kj_transmitCurrentRotateOrientation:UIInterfaceOrientationMaskPortrait]; KJRotateViewController *vc = [[KJRotateViewController alloc] init]; vc.interfaceOrientationMask = UIInterfaceOrientationMaskPortrait; UIWindow *videoWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; videoWindow.rootViewController = vc; baseView.transform = CGAffineTransformIdentity; baseView.frame = self.originalFrame; [baseView setValue:@(NO) forKey:@"isFullScreen"]; } / * to switch to the floating window screen * / + (void) kj_rotateFloatingWindowBasePlayerView baseView: (UIView *) {/ / TODO: } #pragma mark - getter/setter static CGRect _originalFrame; + (CGRect)originalFrame{ return _originalFrame; } + (void)setOriginalFrame:(CGRect)originalFrame{ _originalFrame = originalFrame; } + (UIViewController*)topViewController{ UIViewController *result = nil; UIWindow * window = kRotate_KeyWindow; if (window.windowLevel ! = UIWindowLevelNormal){ NSArray *windows = [[UIApplication sharedApplication] windows]; for(UIWindow * tmpWin in windows){ if (tmpWin.windowLevel == UIWindowLevelNormal){ window = tmpWin; break; } } } UIViewController *vc = window.rootViewController; while (vc.presentedViewController) { vc = vc.presentedViewController; } if ([vc isKindOfClass:[UITabBarController class]]){ UITabBarController * tabbar = (UITabBarController *)vc; UINavigationController * nav = (UINavigationController *)tabbar.viewControllers[tabbar.selectedIndex]; result = nav.childViewControllers.lastObject; }else if ([vc isKindOfClass:[UINavigationController class]]){ UIViewController * nav = (UIViewController *)vc; result = nav.childViewControllers.lastObject; }else{ result = vc; } return result; } @endCopy the code

Here, about the full screen mode of train of thought introduction is almost, as for the details, I Dmeo inside write also very detailed, interested friends can go to download the Demo address: KJPlayerDemo

Precautions for Use

About full-screen/half-screen configuration information

Please implement the agreement of the Appdelegate KJPlayerRotateAppDelegate

@interface AppDelegate ()<KJPlayerRotateAppDelegate> @property(nonatomic,assign) UIInterfaceOrientationMask rotateOrientation; @implementation AppDelegate /* pass the current rotation direction */ - (void)kj_transmitCurrentRotateOrientation:(UIInterfaceOrientationMask)rotateOrientation{ self.rotateOrientation = rotateOrientation; } - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{ if (self.rotateOrientation) { return self.rotateOrientation;  }else{ return UIInterfaceOrientationMaskPortrait; } } @endCopy the code

Eight elder brother summary

As expected, the code is not able to withstand the test debugging, as always, there are bugs

1. View hierarchy display problem

The control KJBasePlayerView takes precedence over the following button to Add to self.view, so when I press the full screen button the following problem occurs 😓😓-!

ZPosition is 0 by default, so just set the layer. ZPosition of the control to 1

- (instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        self.layer.zPosition = 1;
        [self kj_initializeConfiguration];
    }
    return self;
}
Copy the code

2, the top navigation bar problem

There is also a problem with the navigation bar. The only stupid way I can think of is to call back the current full-screen/half-screen state and hide/show it in the callback

PLAYER_WEAKSELF; self.basePlayerView.kVideoChangeScreenState = ^(KJPlayerVideoScreenState state) { if (state == KJPlayerVideoScreenStateFullScreen) { [weakself.navigationController setNavigationBarHidden:YES animated:YES]; }else{ [weakself.navigationController setNavigationBarHidden:NO animated:YES]; }};Copy the code

I do not know which god or better and more convenient solution, welcome to point out, thank ~ 😁

The article related

Other articles about player

  • Develop full screen processing of player frame
  • The development of the player frame side down play side storage scheme sharing

Later, I will gradually supplement and improve the case of the player. If my brother thinks it is good, please help me to point a **Little stars* * portal