ZFLandScapeControlView.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. //
  2. // ZFLandScapeControlView.m
  3. // ZFPlayer
  4. //
  5. // Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. #import "ZFLandScapeControlView.h"
  25. #import "UIView+ZFFrame.h"
  26. #import "ZFUtilities.h"
  27. #import "ZFPlayerStatusBar.h"
  28. #if __has_include(<ZFPlayer/ZFPlayer.h>)
  29. #import <ZFPlayer/ZFPlayerConst.h>
  30. #else
  31. #import "ZFPlayerConst.h"
  32. #endif
  33. @interface ZFLandScapeControlView () <ZFSliderViewDelegate>
  34. @property (nonatomic, strong) ZFPlayerStatusBar *statusBarView;
  35. /// 顶部工具栏
  36. @property (nonatomic, strong) UIView *topToolView;
  37. /// 返回按钮
  38. @property (nonatomic, strong) UIButton *backBtn;
  39. /// 标题
  40. @property (nonatomic, strong) UILabel *titleLabel;
  41. /// 底部工具栏
  42. @property (nonatomic, strong) UIView *bottomToolView;
  43. /// 播放或暂停按钮
  44. @property (nonatomic, strong) UIButton *playOrPauseBtn;
  45. /// 播放的当前时间
  46. @property (nonatomic, strong) UILabel *currentTimeLabel;
  47. /// 滑杆
  48. @property (nonatomic, strong) ZFSliderView *slider;
  49. /// 视频总时间
  50. @property (nonatomic, strong) UILabel *totalTimeLabel;
  51. /// 锁定屏幕按钮
  52. @property (nonatomic, strong) UIButton *lockBtn;
  53. @property (nonatomic, assign) BOOL isShow;
  54. @end
  55. @implementation ZFLandScapeControlView
  56. - (void)dealloc {
  57. [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
  58. }
  59. - (instancetype)initWithFrame:(CGRect)frame {
  60. if (self = [super initWithFrame:frame]) {
  61. [self addSubview:self.topToolView];
  62. [self.topToolView addSubview:self.statusBarView];
  63. [self.topToolView addSubview:self.backBtn];
  64. [self.topToolView addSubview:self.titleLabel];
  65. [self addSubview:self.bottomToolView];
  66. [self.bottomToolView addSubview:self.playOrPauseBtn];
  67. [self.bottomToolView addSubview:self.currentTimeLabel];
  68. [self.bottomToolView addSubview:self.slider];
  69. [self.bottomToolView addSubview:self.totalTimeLabel];
  70. [self addSubview:self.lockBtn];
  71. // 设置子控件的响应事件
  72. [self makeSubViewsAction];
  73. [self resetControlView];
  74. /// statusBarFrame changed
  75. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutControllerViews) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
  76. }
  77. return self;
  78. }
  79. - (void)layoutSubviews {
  80. [super layoutSubviews];
  81. CGFloat min_x = 0;
  82. CGFloat min_y = 0;
  83. CGFloat min_w = 0;
  84. CGFloat min_h = 0;
  85. CGFloat min_view_w = self.bounds.size.width;
  86. CGFloat min_view_h = self.bounds.size.height;
  87. CGFloat min_margin = 9;
  88. min_x = 0;
  89. min_y = 0;
  90. min_w = min_view_w;
  91. min_h = iPhoneX ? 110 : 80;
  92. self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  93. min_x = 0;
  94. min_y = 0;
  95. min_w = min_view_w;
  96. min_h = 20;
  97. self.statusBarView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  98. min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
  99. if (@available(iOS 13.0, *)) {
  100. if (self.showCustomStatusBar) {
  101. min_y = self.statusBarView.zf_bottom;
  102. } else {
  103. min_y = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) ? 10 : (iPhoneX ? 40 : 20);
  104. }
  105. } else {
  106. min_y = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 10: (iPhoneX ? 40 : 20);
  107. }
  108. min_w = 40;
  109. min_h = 40;
  110. self.backBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
  111. min_x = self.backBtn.zf_right + 5;
  112. min_y = 0;
  113. min_w = min_view_w - min_x - 15 ;
  114. min_h = 30;
  115. self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
  116. self.titleLabel.zf_centerY = self.backBtn.zf_centerY;
  117. min_h = iPhoneX ? 100 : 73;
  118. min_x = 0;
  119. min_y = min_view_h - min_h;
  120. min_w = min_view_w;
  121. self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
  122. min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
  123. min_y = 32;
  124. min_w = 30;
  125. min_h = 30;
  126. self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
  127. min_x = self.playOrPauseBtn.zf_right + 4;
  128. min_y = 0;
  129. min_w = 62;
  130. min_h = 30;
  131. self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
  132. self.currentTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
  133. min_w = 62;
  134. min_x = self.bottomToolView.zf_width - min_w - ((iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: min_margin);
  135. min_y = 0;
  136. min_h = 30;
  137. self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
  138. self.totalTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
  139. min_x = self.currentTimeLabel.zf_right + 4;
  140. min_y = 0;
  141. min_w = self.totalTimeLabel.zf_left - min_x - 4;
  142. min_h = 30;
  143. self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
  144. self.slider.zf_centerY = self.playOrPauseBtn.zf_centerY;
  145. min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 50: 18;
  146. min_y = 0;
  147. min_w = 40;
  148. min_h = 40;
  149. self.lockBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
  150. self.lockBtn.zf_centerY = self.zf_centerY;
  151. if (!self.isShow) {
  152. self.topToolView.zf_y = -self.topToolView.zf_height;
  153. self.bottomToolView.zf_y = self.zf_height;
  154. self.lockBtn.zf_left = iPhoneX ? -82: -47;
  155. } else {
  156. self.lockBtn.zf_left = iPhoneX ? 50: 18;
  157. if (self.player.isLockedScreen) {
  158. self.topToolView.zf_y = -self.topToolView.zf_height;
  159. self.bottomToolView.zf_y = self.zf_height;
  160. } else {
  161. self.topToolView.zf_y = 0;
  162. self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
  163. }
  164. }
  165. }
  166. - (void)makeSubViewsAction {
  167. [self.backBtn addTarget:self action:@selector(backBtnClickAction:) forControlEvents:UIControlEventTouchUpInside];
  168. [self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
  169. [self.lockBtn addTarget:self action:@selector(lockButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
  170. }
  171. #pragma mark - action
  172. - (void)layoutControllerViews {
  173. [self layoutIfNeeded];
  174. [self setNeedsLayout];
  175. }
  176. - (void)backBtnClickAction:(UIButton *)sender {
  177. self.lockBtn.selected = NO;
  178. self.player.lockedScreen = NO;
  179. self.lockBtn.selected = NO;
  180. if (self.player.orientationObserver.supportInterfaceOrientation & ZFInterfaceOrientationMaskPortrait) {
  181. [self.player enterFullScreen:NO animated:YES];
  182. }
  183. if (self.backBtnClickCallback) {
  184. self.backBtnClickCallback();
  185. }
  186. }
  187. - (void)playPauseButtonClickAction:(UIButton *)sender {
  188. [self playOrPause];
  189. }
  190. /// 根据当前播放状态取反
  191. - (void)playOrPause {
  192. self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
  193. self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
  194. }
  195. - (void)playBtnSelectedState:(BOOL)selected {
  196. self.playOrPauseBtn.selected = selected;
  197. }
  198. - (void)lockButtonClickAction:(UIButton *)sender {
  199. sender.selected = !sender.selected;
  200. self.player.lockedScreen = sender.selected;
  201. }
  202. #pragma mark - ZFSliderViewDelegate
  203. - (void)sliderTouchBegan:(float)value {
  204. self.slider.isdragging = YES;
  205. }
  206. - (void)sliderTouchEnded:(float)value {
  207. if (self.player.totalTime > 0) {
  208. self.slider.isdragging = YES;
  209. if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
  210. @zf_weakify(self)
  211. [self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
  212. @zf_strongify(self)
  213. self.slider.isdragging = NO;
  214. if (finished) {
  215. if (self.sliderValueChanged) self.sliderValueChanged(value);
  216. if (self.seekToPlay) {
  217. [self.player.currentPlayerManager play];
  218. }
  219. }
  220. }];
  221. } else {
  222. self.slider.isdragging = NO;
  223. self.slider.value = 0;
  224. }
  225. }
  226. - (void)sliderValueChanged:(float)value {
  227. if (self.player.totalTime == 0) {
  228. self.slider.value = 0;
  229. return;
  230. }
  231. self.slider.isdragging = YES;
  232. NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
  233. self.currentTimeLabel.text = currentTimeString;
  234. if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
  235. }
  236. - (void)sliderTapped:(float)value {
  237. [self sliderTouchEnded:value];
  238. NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
  239. self.currentTimeLabel.text = currentTimeString;
  240. }
  241. #pragma mark - public method
  242. /// 重置ControlView
  243. - (void)resetControlView {
  244. self.slider.value = 0;
  245. self.slider.bufferValue = 0;
  246. self.currentTimeLabel.text = @"00:00";
  247. self.totalTimeLabel.text = @"00:00";
  248. self.backgroundColor = [UIColor clearColor];
  249. self.playOrPauseBtn.selected = YES;
  250. self.titleLabel.text = @"";
  251. self.topToolView.alpha = 1;
  252. self.bottomToolView.alpha = 1;
  253. self.isShow = NO;
  254. self.lockBtn.selected = self.player.isLockedScreen;
  255. }
  256. - (void)showControlView {
  257. self.lockBtn.alpha = 1;
  258. self.isShow = YES;
  259. if (self.player.isLockedScreen) {
  260. self.topToolView.zf_y = -self.topToolView.zf_height;
  261. self.bottomToolView.zf_y = self.zf_height;
  262. } else {
  263. self.topToolView.zf_y = 0;
  264. self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
  265. }
  266. self.lockBtn.zf_left = iPhoneX ? 50: 18;
  267. self.player.statusBarHidden = NO;
  268. if (self.player.isLockedScreen) {
  269. self.topToolView.alpha = 0;
  270. self.bottomToolView.alpha = 0;
  271. } else {
  272. self.topToolView.alpha = 1;
  273. self.bottomToolView.alpha = 1;
  274. }
  275. }
  276. - (void)hideControlView {
  277. self.isShow = NO;
  278. self.topToolView.zf_y = -self.topToolView.zf_height;
  279. self.bottomToolView.zf_y = self.zf_height;
  280. self.lockBtn.zf_left = iPhoneX ? -82: -47;
  281. self.player.statusBarHidden = YES;
  282. self.topToolView.alpha = 0;
  283. self.bottomToolView.alpha = 0;
  284. self.lockBtn.alpha = 0;
  285. }
  286. - (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
  287. CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
  288. if (CGRectContainsPoint(sliderRect, point)) {
  289. return NO;
  290. }
  291. if (self.player.isLockedScreen && type != ZFPlayerGestureTypeSingleTap) { // 锁定屏幕方向后只相应tap手势
  292. return NO;
  293. }
  294. return YES;
  295. }
  296. - (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
  297. self.lockBtn.hidden = self.player.orientationObserver.fullScreenMode == ZFFullScreenModePortrait;
  298. }
  299. /// 视频view即将旋转
  300. - (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationWillChange:(ZFOrientationObserver *)observer {
  301. if (self.showCustomStatusBar) {
  302. if (self.hidden) {
  303. [self.statusBarView destoryTimer];
  304. } else {
  305. [self.statusBarView startTimer];
  306. }
  307. }
  308. }
  309. - (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
  310. if (!self.slider.isdragging) {
  311. NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
  312. self.currentTimeLabel.text = currentTimeString;
  313. NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
  314. self.totalTimeLabel.text = totalTimeString;
  315. self.slider.value = videoPlayer.progress;
  316. }
  317. }
  318. - (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
  319. self.slider.bufferValue = videoPlayer.bufferProgress;
  320. }
  321. - (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
  322. self.titleLabel.text = title;
  323. self.player.orientationObserver.fullScreenMode = fullScreenMode;
  324. self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
  325. }
  326. /// 调节播放进度slider和当前时间更新
  327. - (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
  328. self.slider.value = value;
  329. self.currentTimeLabel.text = timeString;
  330. self.slider.isdragging = YES;
  331. [UIView animateWithDuration:0.3 animations:^{
  332. self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
  333. }];
  334. }
  335. /// 滑杆结束滑动
  336. - (void)sliderChangeEnded {
  337. self.slider.isdragging = NO;
  338. [UIView animateWithDuration:0.3 animations:^{
  339. self.slider.sliderBtn.transform = CGAffineTransformIdentity;
  340. }];
  341. }
  342. #pragma mark - setter
  343. - (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
  344. _fullScreenMode = fullScreenMode;
  345. self.player.orientationObserver.fullScreenMode = fullScreenMode;
  346. self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
  347. }
  348. - (void)setShowCustomStatusBar:(BOOL)showCustomStatusBar {
  349. _showCustomStatusBar = showCustomStatusBar;
  350. self.statusBarView.hidden = !showCustomStatusBar;
  351. }
  352. #pragma mark - getter
  353. - (ZFPlayerStatusBar *)statusBarView {
  354. if (!_statusBarView) {
  355. _statusBarView = [[ZFPlayerStatusBar alloc] init];
  356. _statusBarView.hidden = YES;
  357. }
  358. return _statusBarView;
  359. }
  360. - (UIView *)topToolView {
  361. if (!_topToolView) {
  362. _topToolView = [[UIView alloc] init];
  363. UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
  364. _topToolView.layer.contents = (id)image.CGImage;
  365. }
  366. return _topToolView;
  367. }
  368. - (UIButton *)backBtn {
  369. if (!_backBtn) {
  370. _backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  371. [_backBtn setImage:ZFPlayer_Image(@"ZFPlayer_back_full") forState:UIControlStateNormal];
  372. }
  373. return _backBtn;
  374. }
  375. - (UILabel *)titleLabel {
  376. if (!_titleLabel) {
  377. _titleLabel = [[UILabel alloc] init];
  378. _titleLabel.textColor = [UIColor whiteColor];
  379. _titleLabel.font = [UIFont systemFontOfSize:15.0];
  380. }
  381. return _titleLabel;
  382. }
  383. - (UIView *)bottomToolView {
  384. if (!_bottomToolView) {
  385. _bottomToolView = [[UIView alloc] init];
  386. UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
  387. _bottomToolView.layer.contents = (id)image.CGImage;
  388. }
  389. return _bottomToolView;
  390. }
  391. - (UIButton *)playOrPauseBtn {
  392. if (!_playOrPauseBtn) {
  393. _playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  394. [_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_play") forState:UIControlStateNormal];
  395. [_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_pause") forState:UIControlStateSelected];
  396. }
  397. return _playOrPauseBtn;
  398. }
  399. - (UILabel *)currentTimeLabel {
  400. if (!_currentTimeLabel) {
  401. _currentTimeLabel = [[UILabel alloc] init];
  402. _currentTimeLabel.textColor = [UIColor whiteColor];
  403. _currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
  404. _currentTimeLabel.textAlignment = NSTextAlignmentCenter;
  405. }
  406. return _currentTimeLabel;
  407. }
  408. - (ZFSliderView *)slider {
  409. if (!_slider) {
  410. _slider = [[ZFSliderView alloc] init];
  411. _slider.delegate = self;
  412. _slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
  413. _slider.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
  414. _slider.minimumTrackTintColor = [UIColor whiteColor];
  415. [_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
  416. _slider.sliderHeight = 2;
  417. }
  418. return _slider;
  419. }
  420. - (UILabel *)totalTimeLabel {
  421. if (!_totalTimeLabel) {
  422. _totalTimeLabel = [[UILabel alloc] init];
  423. _totalTimeLabel.textColor = [UIColor whiteColor];
  424. _totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
  425. _totalTimeLabel.textAlignment = NSTextAlignmentCenter;
  426. }
  427. return _totalTimeLabel;
  428. }
  429. - (UIButton *)lockBtn {
  430. if (!_lockBtn) {
  431. _lockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  432. [_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_unlock-nor") forState:UIControlStateNormal];
  433. [_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_lock-nor") forState:UIControlStateSelected];
  434. }
  435. return _lockBtn;
  436. }
  437. @end