4.全屏播放
全屏播放是每一个视屏播放器的标配。切换横竖屏有两种方式,视频播放器的画面随着手机的旋转而旋转和点击按钮切换。我们先将第一种方式,所以必须要监测手机的旋转。
监测手机的旋转很简单,苹果通过通知的方式告诉我们。
// 开启监听设备旋转的通知(不开启的话,设备方向一直是UIInterfaceOrientationUnknown)
// ioS11.4.1 不开启也能检测到
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
deviceOrientationDidChange
是回调方法,设备只要发生旋转就会调用这个方法。
- (void)deviceOrientationDidChange:(NSNotification *)noti
{
// 设备方向
UIInterfaceOrientation deviceOrientation =(UIInterfaceOrientation)[[UIDevice currentDevice] orientation];
// 界面方向
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (deviceOrientation == interfaceOrientation || !UIDeviceOrientationIsValidInterfaceOrientation(deviceOrientation)) {
NSLog(@"UIDeviceOrientationUnknown");
return;
}
[self changeInterfaceOrientation:deviceOrientation];
}
[[UIDevice currentDevice] orientation];返回的是设置的方向,值的类型是
UIDeviceOrientatin`,它是一个枚举,一个有7个值。
typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
UIDeviceOrientationUnknown, // 未知
UIDeviceOrientationPortrait, // 竖屏,HOME键在下面
UIDeviceOrientationPortraitUpsideDown, // 竖屏,HOME键在上面
UIDeviceOrientationLandscapeLeft, // 横屏,HOME键在左面
UIDeviceOrientationLandscapeRight, // 横屏,HOME键在右面
UIDeviceOrientationFaceUp, // 平放,屏幕朝上
UIDeviceOrientationFaceDown // 平放,屏幕朝下
}
需要注意的是屏幕横放的时候,是不能区分横竖屏的。[[UIApplication sharedApplication] statusBarOrientation];
返回值是界面的方向,类型是UIInterfaceOrientation,也是一个枚举值,一共有5个值。
UIInterfaceOrientationUnknown, // 未知
UIInterfaceOrientationPortrait , // 竖屏,HOME键在下面
UIInterfaceOrientationPortraitUpsideDown, // 竖屏,HOME键在上面
UIInterfaceOrientationLandscapeLeft, // 横屏,HOME键在左面
UIInterfaceOrientationLandscapeRight // 横屏,HOME键在右面
我们监听到手机旋转后,第一步要检验一下设备的方向是否可以转化为有效的界面方向。UIDeviceOrientationIsValidInterfaceOrientation(deviceOrientation)
。因为如果是UIDeviceOrientationUnknown、UIDeviceOrientationFaceUp、UIDeviceOrientationFaceDown,我们没办法分清横竖屏,就没办法旋转界面的方向。第二步判断两种方向是否一致,不一致在旋转。
// 旋转屏幕,interfaceOrientation要旋转的方向
- (void)changeInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// 父视图
UIView *superView = nil;
// 旋转的角度,默认值是恢复原来的样式
CGAffineTransform transform = CGAffineTransformIdentity;
// 竖屏 -> 横屏
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
// 父视图是keyWindow
superView = [[UIApplication sharedApplication] keyWindow];
// HOME键在左边,逆时针旋转90°
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
transform = CGAffineTransformMakeRotation(-M_PI_2);
}else if(interfaceOrientation == UIInterfaceOrientationLandscapeRight){
// HOME键在右边,顺时针旋转90°
transform = CGAffineTransformMakeRotation(M_PI_2);
}
// 记录界面的状态
self.isFullScreen = YES;
}else{
// 横屏 -> 竖屏
superView = self.containerView;
transform = CGAffineTransformIdentity;
self.isFullScreen = NO;
}
[superView addSubview:self.presentView];
// 修改界面的方向
[UIApplication sharedApplication].statusBarOrientation = interfaceOrientation;
// 标记界面的方向需要更改
[self setNeedsStatusBarAppearanceUpdate];
// 旋转动画
[UIView animateWithDuration:0.25 animations:^{
// 旋转
self.presentView.transform = transform;
[UIView animateWithDuration:0.25 animations:^{
// 修改尺寸
self.presentView.frame = superView.bounds;
}];
} completion:^(BOOL finished) {
// 修改控制视图的约束
[self updateControlViewConstraint];
}];
}
- (void)updateControlViewConstraint
{
// 当屏幕旋转后,屏幕的长宽也发生了变化,现在长的值变为了原来的宽的值
if (self.isFullScreen) {
CGFloat width = self.presentView.bounds.size.width;
CGFloat height = self.presentView.bounds.size.height;
self.controlView.frame = CGRectMake(0, height - 40, width, 40);
}else{
CGFloat width = SCREEN_WIDTH;
CGFloat height = SCREEN_WIDTH / 7 * 4;
self.controlView.frame = CGRectMake(0, height - 40, width, 40);
}
// 如果不执行下面的两个方法, 上面的设置无效
// 标记更新约束
[self.controlView setNeedsUpdateConstraints];
// 更新约束
[self.controlView updateConstraintsIfNeeded];
}
当横屏的时候,presentView(layer是AVPlayerLayer,视频播放器的界面)的父视图的就变成了keyWindow。我们选择界面的时候,也需要修改statusBarOrientation的值,[UIApplication sharedApplication].statusBarOrientation = interfaceOrientation;
。因为还要和设备的方向做比较。
你以为上面的方法执行完之后,就能横竖屏切换了嘛?当然不是,结尾有彩蛋奥。执行方上面的方法,可以由竖屏转化为横屏,确转化不回来了。因为[UIApplication sharedApplication].statusBarOrientation = interfaceOrientation;
这个方法设置无效,[UIApplication sharedApplication].statusBarOrientation
的值一直是UIDeviceOrientationPortrait。当设备由横屏转化为竖屏的时候,设备的方向和屏幕的方向分别是UIDeviceOrientationPortrait和UIInterfaceOrientationPortrait是相等的,所以不会执行旋转的方法。所以我们还要加一个方法。
// 界面是否可以跟随手机自动旋转
// if yes, [UIApplication sharedApplication].statusBarOrientation = deviceOrientation; 设置无效;
// if yes, - (UIInterfaceOrientationMask)supportedInterfaceOrientations;支持的屏幕方向一定要和Deployment Info -> Device Orientation 一致, 否则会报 Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and [FHNavigationController shouldAutorotate] is returning YES'
- (BOOL)shouldAutorotate {
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
if (self.isFullScreen) {
return UIInterfaceOrientationMaskLandscape;
}
return UIInterfaceOrientationMaskPortrait;
}
这个方法shouldAutorotate
默认返回YES,表明界面可以随着视频自动旋转,不要我们设置什么了。那当然不行,那样UI就会乱,大家可以试一试。所以我们要返回NO,由我们自己控制界面的旋转supportedInterfaceOrientations
返回的是界面支持的旋转方向,返回值得类型是UIInterfaceOrientationMask。