更新:2017.11.14
更新內容:
1.可以由在指定區域播放,并切換到全屏模式,然后點擊切換按鈕切換到以前指定區域
2.優化橫豎屏切換的代碼以及WLPlayerControlView內存管理引起的崩潰問題
要點說明:WLPlayerView新增了父視圖和父視圖原尺寸的屬性,在初始化播放器的時候,只需要將父視圖以及父視圖原尺寸保存起來,在橫豎屏切換的時候調用分類提供的
- (void)makeScreenToLandscape;
- (void)makeScreenToPortrait;
這兩個方法就可以實現所需要的功能,具體的調用邏輯可以查看源碼
做這款播放器還是因為項目需要,關于播放器的需求,大都相同,要么是可以小屏全屏切換,要么是一開始播放就默認橫屏,由于下一個版本項目需求變化,需要的是一開始播放就默認全屏播放,之前我所用的是ZFPlayer,這個庫很強大,基本上囊括了常用的功能點,特別是全屏切換這塊,這個庫處理的很好,但是遺憾的是這款播放器沒有提供自動全屏的功能,我在這個庫的源碼中修改之后能實現所要的效果,但是改動了源碼總歸是不美的,于是我就花費一些時間,參考這個庫,依據需求,先實現自己項目中的需要為準:實現已進入就橫屏播放的需要。項目中用了RAC,以及Masnory布局方式。
我寫的這個庫目前還是初級階段,許多功能都不完善,主要包括以下幾個要點:
1.present以及push進入播放控制器,一進入就橫屏
2.可以控制暫停/播放,雙擊屏幕暫停/播放,單擊屏幕顯示控制皮膚/隱藏控制皮膚等
3.滑動播放進度條可以控制播放時間,跳轉到指定位置播放
4.橫屏豎屏切換功能,狀態欄方向跟著橫屏豎屏而變化等
5.左右滑動屏幕,實現快進/快退功能
6.上下滑動右邊半屏,控制系統音量,滑動左半屏控制系統亮度
具體的功能模塊就以上幾個,是一個功能單一,比較簡單的播放控制器,我會在以后慢慢完善它的功能
下面我簡要說一下如何去引用,并且對去全屏這塊做簡要描述(只針對presetn下)
我先放兩張效果圖:
項目默認是豎屏顯示,只有在播放界面才默認橫屏:
從首頁進入到播放界面如下處理:
@weakify(self);
[[self.playButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
@strongify(self);
WLPlayerController *playerC = [[WLPlayerController alloc] init];
[self presentViewController:playerC animated:YES completion:nil];
}];
在播放界面主要是控制進入就橫屏顯示,我是這樣處理的:
進入播放器有兩種模式,一種是present,一種是push,我這里用的是tabbar+navigation+控制器的模式,默認整個項目界面是豎屏,只有在播放界面才是橫屏,下面我簡要說明一下對于這兩種模式下的控制,我搜索資料有對這兩種區別去控制的,我也嘗試了下網上給的方法,發現present很好弄,但是Push的坑很多,我這里是直接對兩種模式都有效果的,摘要代碼配置如下:
1.設置tabbarController分類,在分類中實現以下幾個方法
// 是否支持自動轉屏
- (BOOL)shouldAutorotate {
UIViewController *vc = self.viewControllers[self.selectedIndex];
if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.topViewController shouldAutorotate];
} else {
return [vc shouldAutorotate];
}
}
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
UIViewController *vc = self.viewControllers[self.selectedIndex];
if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.topViewController supportedInterfaceOrientations];
} else {
return [vc supportedInterfaceOrientations];
}
}
// 默認的屏幕方向(當前ViewController必須是通過模態出來的UIViewController(模態帶導航的無效)方式展現出來的,才會調用這個方法)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
UIViewController *vc = self.viewControllers[self.selectedIndex];
if ([vc isKindOfClass:[UINavigationController class]]) {
UINavigationController *nav = (UINavigationController *)vc;
return [nav.topViewController preferredInterfaceOrientationForPresentation];
} else {
return [vc preferredInterfaceOrientationForPresentation];
}
}
2.設置導航控制器分類,實現如下幾個方法:
- (BOOL)shouldAutorotate {
return self.topViewController.shouldAutorotate;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return self.topViewController.supportedInterfaceOrientations;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return self.topViewController.preferredInterfaceOrientationForPresentation;
}
3.所有的控制器繼承于這個基類,在視頻播放控制器中單獨設置:
基類中默認豎屏模式:
return YES;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleDefault;
}
- (BOOL)prefersStatusBarHidden {
return NO;
}
播放器中如下設置:
// 支持哪些屏幕方向
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeRight;
}
- (BOOL)prefersStatusBarHidden {
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
- (BOOL)shouldAutorotate {
return YES;
}
另外我在UIViewController的分類中提供了present和Push下實現橫屏和豎屏切換的方法,具體的方法如下:
- (void)makeScreenToLandscape {
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationLandscapeRight;
CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
if (self.navigationController) {
self.view.transform = CGAffineTransformMakeRotation(M_PI*(90)/180.0);
self.view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
}else {
self.view.transform = CGAffineTransformIdentity;
self.view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
}
[UIView commitAnimations];
[[NSNotificationCenter defaultCenter] postNotificationName:wl_makeScreenToLandscapeNotificationName object:nil];
}
- (void)makeScreenToPortrait {
[UIApplication sharedApplication].statusBarOrientation = UIInterfaceOrientationPortrait;
CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
if (self.navigationController) {
self.view.transform = CGAffineTransformIdentity;
self.view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
}else {
self.view.transform = CGAffineTransformMakeRotation(-M_PI*(90)/180.0);
self.view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
}
[UIView commitAnimations];
[[NSNotificationCenter defaultCenter] postNotificationName:wl_makeScreenToPortraitNotificationName object:nil];
}
在這里我遇到一個坑,改變狀態欄方向之后,我一開始改變的是self.navigationController.view.bounds,結果會發現切換之間存在布局錯亂,后來查了許久,發現frame的x,y值出現負值,導致整體布局錯亂,于是我改成了改變frame值就解決了
具體的調用方式,demo中有介紹,可以下載demo進行嘗試與驗證
關于其他的控制邏輯,在后續會進一步實現,下面附上我的github源碼地址,有需要的伙伴們可以自行下載,使用過程遇到問題的歡迎留言評論,謝謝
特別說明:在適配iPad的時候,發現了一個重大問題,我所有設置強制豎屏的條件都不管用了,而且,在橫屏豎屏的時候混亂了,經查閱資料,最終解決了,解決方法是,將General->Deployment Info中的Requires Full Screen勾選選中