DFPlayerUIManager.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. //
  2. // DFPlayerUIManager.m
  3. // DFPlayer
  4. //
  5. // Created by ihoudf on 2017/7/20.
  6. // Copyright © 2017年 ihoudf. All rights reserved.
  7. //
  8. #import "DFPlayerUIManager.h"
  9. #import "DFPlayer.h"
  10. #import "DFPlayerTool.h"
  11. #import "DFPlayerLyricsTableview.h"
  12. #import <MediaPlayer/MediaPlayer.h>
  13. #pragma mark - DFPlayerSlider
  14. @interface DFPlayerSlider : UISlider
  15. @property (nonatomic, assign) CGFloat trackHeight;
  16. @end
  17. @implementation DFPlayerSlider
  18. - (CGRect)trackRectForBounds:(CGRect)bounds{
  19. return CGRectMake(0, (CGRectGetHeight(self.frame)-self.trackHeight) / 2, CGRectGetWidth(self.frame), self.trackHeight);
  20. }
  21. @end
  22. #pragma mark - DFPlayer控制管理器
  23. //KEY
  24. NSString * const DFStateKey = @"state";
  25. NSString * const DFBufferProgressKey = @"bufferProgress";
  26. NSString * const DFProgressKey = @"progress";
  27. NSString * const DFCurrentTimeKey = @"currentTime";
  28. NSString * const DFTotalTimeKey = @"totalTime";
  29. typedef void(^DFPlayerLyricsBlock)(NSString *onPlayingLyrics);
  30. @interface DFPlayerUIManager() <DFPlayerLyricsTableviewDelegate>
  31. {
  32. BOOL _stopUpdate;
  33. BOOL _isSeek;
  34. }
  35. @property (nonatomic, strong) UIButton *playBtn;
  36. @property (nonatomic, strong) UIButton *typeBtn;
  37. @property (nonatomic, strong) UIProgressView *bufferProgressView;
  38. @property (nonatomic, strong) DFPlayerSlider *progressSlider;
  39. @property (nonatomic, strong) UILabel *currentTimeLabel;
  40. @property (nonatomic, strong) UILabel *totalTimeLabel;
  41. @property (nonatomic, strong) DFPlayerLyricsTableview *lyricsTableView;
  42. @property (nonatomic, copy) DFPlayerLyricsBlock lyricsBlock;
  43. @property (nonatomic, strong) UIImage *playImage;
  44. @property (nonatomic, strong) UIImage *pauseImage;
  45. @property (nonatomic, strong) UIImage *singleImage;
  46. @property (nonatomic, strong) UIImage *circleImage;
  47. @property (nonatomic, strong) UIImage *shuffleImage;
  48. @end
  49. @implementation DFPlayerUIManager
  50. + (DFPlayerUIManager *)sharedManager{
  51. static DFPlayerUIManager *manager = nil;
  52. static dispatch_once_t predicate;
  53. dispatch_once(&predicate, ^{
  54. manager = [[[self class] alloc] init];
  55. });
  56. return manager;
  57. }
  58. - (UIButton *)button:(CGRect)frame
  59. image:(UIImage *)image
  60. superView:(UIView *)superView
  61. block:(nullable void (^)(void))block
  62. action:(nullable void(^)(void))action{
  63. UIButton *btn = [UIButton buttonWithType:(UIButtonTypeSystem)];
  64. btn.frame = frame;
  65. [btn setBackgroundImage:image forState:(UIControlStateNormal)];
  66. btn.handleButtonActionBlock = ^(UIButton * _Nullable sender) {
  67. if (block) {
  68. block();
  69. }
  70. if (action) {
  71. action();
  72. }
  73. };
  74. [superView addSubview:btn];
  75. return btn;
  76. }
  77. - (UILabel *)label:(CGRect)frame
  78. textColor:(UIColor *)textColor
  79. textAlignment:(NSTextAlignment)textAlignment
  80. font:(UIFont *)font
  81. superView:(UIView *)superView
  82. observerKey:(NSString *)observerKey{
  83. UILabel *label = [[UILabel alloc] initWithFrame:frame];
  84. label.text = @"00:00";
  85. label.textColor = textColor;
  86. label.textAlignment = textAlignment;
  87. label.font = font;
  88. [superView addSubview:label];
  89. [[DFPlayer sharedPlayer] addObserver:self forKeyPath:observerKey options:NSKeyValueObservingOptionNew context:nil];
  90. return label;
  91. }
  92. - (void)df_stopUpdate{
  93. _stopUpdate = YES;
  94. self.lyricsTableView.stopUpdate = YES;
  95. }
  96. - (void)df_resumeUpdate{
  97. _stopUpdate = NO;
  98. self.lyricsTableView.stopUpdate = NO;
  99. }
  100. #pragma mark - 播放暂停按钮
  101. - (UIButton *)df_playPauseBtnWithFrame:(CGRect)frame
  102. playImage:(UIImage *)playImage
  103. pauseImage:(UIImage *)pauseImage
  104. superView:(UIView *)superView
  105. block:(nullable void (^)(void))block{
  106. self.playImage = playImage;
  107. self.pauseImage = pauseImage;
  108. UIImage *img = [DFPlayer sharedPlayer].state == DFPlayerStatePlaying ? self.playImage : self.pauseImage;
  109. self.playBtn = [self button:frame image:img superView:superView block:block action:^{
  110. if ([DFPlayer sharedPlayer].state == DFPlayerStatePlaying) {
  111. [[DFPlayer sharedPlayer] df_pause];
  112. }else{
  113. [[DFPlayer sharedPlayer] df_play];
  114. }
  115. }];
  116. [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFStateKey options:NSKeyValueObservingOptionNew context:nil];
  117. return self.playBtn;
  118. }
  119. #pragma mark - 上一首按钮
  120. - (UIButton *)df_lastBtnWithFrame:(CGRect)frame
  121. image:(UIImage *)image
  122. superView:(UIView *)superView
  123. block:(void (^)(void))block{
  124. return [self button:frame image:image superView:superView block:block action:^{
  125. [[DFPlayer sharedPlayer] df_last];
  126. }];
  127. }
  128. #pragma mark - 下一首按钮
  129. - (UIButton *)df_nextBtnWithFrame:(CGRect)frame
  130. image:(UIImage *)image
  131. superView:(UIView *)superView
  132. block:(void (^)(void))block{
  133. return [self button:frame image:image superView:superView block:block action:^{
  134. [[DFPlayer sharedPlayer] df_next];
  135. }];
  136. }
  137. #pragma mark - 播放模式设置按钮
  138. - (UIButton *)df_typeBtnWithFrame:(CGRect)frame
  139. singleImage:(UIImage *)singleImage
  140. circleImage:(UIImage *)circleImage
  141. shuffleImage:(UIImage *)shuffleImage
  142. superView:(UIView *)superView
  143. block:(void (^)(void))block{
  144. if ([DFPlayer sharedPlayer].playMode == DFPlayerModeOnlyOnce) {
  145. return nil;
  146. }
  147. self.singleImage = singleImage;
  148. self.circleImage = circleImage;
  149. self.shuffleImage = shuffleImage;
  150. UIImage *img = [UIImage new];
  151. if ([DFPlayer sharedPlayer].playMode == DFPlayerModeSingleCycle) {
  152. img = self.singleImage;
  153. }else if ([DFPlayer sharedPlayer].playMode == DFPlayerModeOrderCycle){
  154. img = self.circleImage;
  155. }else{
  156. img = self.shuffleImage;
  157. }
  158. UIButton *btn = [self button:frame image:img superView:superView block:block action:nil];
  159. btn.handleButtonActionBlock = ^(UIButton * _Nullable sender) {
  160. switch ([DFPlayer sharedPlayer].playMode) {
  161. case DFPlayerModeSingleCycle:
  162. [DFPlayer sharedPlayer].playMode = DFPlayerModeOrderCycle;
  163. [sender setBackgroundImage:self.circleImage forState:(UIControlStateNormal)];
  164. break;
  165. case DFPlayerModeOrderCycle:
  166. [DFPlayer sharedPlayer].playMode = DFPlayerModeShuffleCycle;
  167. [sender setBackgroundImage:self.shuffleImage forState:(UIControlStateNormal)];
  168. break;
  169. case DFPlayerModeShuffleCycle:
  170. [DFPlayer sharedPlayer].playMode = DFPlayerModeSingleCycle;
  171. [sender setBackgroundImage:self.singleImage forState:(UIControlStateNormal)];
  172. break;
  173. default:
  174. break;
  175. }
  176. };
  177. return btn;
  178. }
  179. #pragma mark - 音频当前时间
  180. - (UILabel *)df_currentTimeLabelWithFrame:(CGRect)frame
  181. textColor:(UIColor *)textColor
  182. textAlignment:(NSTextAlignment)textAlignment
  183. font:(UIFont *)font
  184. superView:(UIView *)superView{
  185. self.currentTimeLabel = [self label:frame textColor:textColor textAlignment:textAlignment font:font superView:superView observerKey:DFCurrentTimeKey];
  186. return self.currentTimeLabel;
  187. }
  188. #pragma mark - 音频总时长
  189. - (UILabel *)df_totalTimeLabelWithFrame:(CGRect)frame
  190. textColor:(UIColor *)textColor
  191. textAlignment:(NSTextAlignment)textAlignment
  192. font:(UIFont *)font
  193. superView:(UIView *)superView{
  194. self.totalTimeLabel = [self label:frame textColor:textColor textAlignment:textAlignment font:font superView:superView observerKey:DFTotalTimeKey];
  195. return self.totalTimeLabel;
  196. }
  197. #pragma mark - 缓冲进度条
  198. - (UIProgressView *)df_bufferViewWithFrame:(CGRect)frame
  199. trackTintColor:(UIColor *)trackTintColor
  200. progressTintColor:(UIColor *)progressTintColor
  201. superView:(UIView *)superView{
  202. self.bufferProgressView = [[UIProgressView alloc] initWithFrame:frame];
  203. self.bufferProgressView.trackTintColor = trackTintColor;
  204. self.bufferProgressView.progressTintColor = progressTintColor;
  205. [superView addSubview:self.bufferProgressView];
  206. [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFBufferProgressKey options:NSKeyValueObservingOptionNew context:nil];
  207. return self.bufferProgressView;
  208. }
  209. #pragma mark - 播放进度条
  210. - (UISlider *)df_sliderWithFrame:(CGRect)frame
  211. minimumTrackTintColor:(UIColor *)minimumTrackTintColor
  212. maximumTrackTintColor:(UIColor *)maximumTrackTintColor
  213. trackHeight:(CGFloat)trackHeight
  214. thumbImage:(UIImage *)thumbImage
  215. superView:(UIView *)superView{
  216. self.progressSlider = [[DFPlayerSlider alloc] initWithFrame:frame];
  217. self.progressSlider.trackHeight = trackHeight;
  218. [self.progressSlider setThumbImage:thumbImage forState:UIControlStateNormal];
  219. self.progressSlider.minimumValue = 0;
  220. self.progressSlider.maximumValue = 1;
  221. self.progressSlider.minimumTrackTintColor = minimumTrackTintColor;
  222. self.progressSlider.maximumTrackTintColor = maximumTrackTintColor;
  223. [superView addSubview:self.progressSlider];
  224. [[DFPlayer sharedPlayer] addObserver:self forKeyPath:DFProgressKey options:NSKeyValueObservingOptionNew context:nil];
  225. //开始滑动
  226. [self.progressSlider addTarget:self action:@selector(progressSliderTouchBegan:) forControlEvents:UIControlEventTouchDown];
  227. //滑动中
  228. [self.progressSlider addTarget:self action:@selector(progressSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
  229. //滑动结束
  230. [self.progressSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchUpOutside];
  231. //点击slider
  232. UITapGestureRecognizer *sliderTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapSliderAction:)];
  233. [self.progressSlider addGestureRecognizer:sliderTap];
  234. return self.progressSlider;
  235. }
  236. #pragma mark 刷新总时长
  237. - (void)RefreshTotalTimeLabelFun
  238. {
  239. [self configTimeLabel:self.totalTimeLabel time:[DFPlayer sharedPlayer].totalTime];
  240. }
  241. - (void)progressSliderTouchBegan:(UISlider *)sender{
  242. _isSeek = YES;
  243. }
  244. - (void)progressSliderValueChanged:(UISlider *)sender{
  245. CGFloat time = [DFPlayer sharedPlayer].totalTime * self.progressSlider.value;
  246. [self configTimeLabel:self.currentTimeLabel time:time];
  247. }
  248. - (void)progressSliderTouchEnded:(UISlider *)sender{
  249. [self seek:self.progressSlider.value];
  250. }
  251. - (void)handleTapSliderAction:(UITapGestureRecognizer *)tap{
  252. if ([tap.view isKindOfClass:[UISlider class]]) {
  253. _isSeek = YES;
  254. UISlider *slider = (UISlider *)tap.view;
  255. CGPoint point = [tap locationInView:slider];
  256. CGFloat value = point.x / slider.frame.size.width;
  257. [self seek:value];
  258. }
  259. }
  260. - (void)seek:(CGFloat)value{
  261. [[DFPlayer sharedPlayer] df_seekToTime:value completionBlock:^{
  262. [[NSNotificationCenter defaultCenter] postNotificationName:DFPlayerNotificationSeekEnd object:nil];
  263. self->_isSeek = NO;
  264. }];
  265. }
  266. #pragma mark - KVO
  267. - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
  268. if (object == [DFPlayer sharedPlayer]) {
  269. dispatch_async(dispatch_get_main_queue(), ^{
  270. if ([keyPath isEqualToString:DFStateKey]) {
  271. if (!self->_isSeek) {
  272. UIImage *img = [DFPlayer sharedPlayer].state == (DFPlayerStateBuffering | DFPlayerStatePlaying) ? self.pauseImage : self.playImage;
  273. [self.playBtn setBackgroundImage:img forState:(UIControlStateNormal)];
  274. }
  275. }else{
  276. if (self->_stopUpdate) {
  277. return;
  278. }
  279. if ([keyPath isEqualToString:DFBufferProgressKey]){
  280. [self.bufferProgressView setProgress:[DFPlayer sharedPlayer].bufferProgress];
  281. }else if ([keyPath isEqualToString:DFProgressKey]){
  282. if (!self->_isSeek) {
  283. if (self.progressSlider.state != UIControlStateHighlighted) {
  284. self.progressSlider.value = [DFPlayer sharedPlayer].progress;
  285. }
  286. }
  287. }else if ([keyPath isEqualToString:DFCurrentTimeKey]){
  288. if (!self->_isSeek) {
  289. [self configTimeLabel:self.currentTimeLabel time:[DFPlayer sharedPlayer].currentTime];
  290. }
  291. }else if ([keyPath isEqualToString:DFTotalTimeKey]){
  292. [self configTimeLabel:self.totalTimeLabel time:[DFPlayer sharedPlayer].totalTime];
  293. }
  294. }
  295. });
  296. }
  297. }
  298. - (void)configTimeLabel:(UILabel *)label time:(CGFloat)time{
  299. NSInteger seconds = (NSInteger)time % 60;
  300. NSInteger minutes = ((NSInteger)time / 60) % 60;
  301. dispatch_async(dispatch_get_main_queue(), ^{
  302. label.text = [NSString stringWithFormat:@"%02ld:%02ld",(long)minutes,(long)seconds];
  303. });
  304. }
  305. - (void)dealloc{
  306. [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFStateKey];
  307. [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFBufferProgressKey];
  308. [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFProgressKey];
  309. [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFCurrentTimeKey];
  310. [[DFPlayer sharedPlayer] removeObserver:self forKeyPath:DFTotalTimeKey];
  311. }
  312. #pragma mark - 歌词tableview
  313. - (UITableView *)df_lyricTableViewWithFrame:(CGRect)frame
  314. cellRowHeight:(CGFloat)cellRowHeight
  315. cellBackgroundColor:(UIColor *)cellBackgroundColor
  316. currentLineLrcForegroundTextColor:(nullable UIColor *)currentLineLrcForegroundTextColor
  317. currentLineLrcBackgroundTextColor:(UIColor *)currentLineLrcBackgroundTextColor
  318. otherLineLrcBackgroundTextColor:(UIColor *)otherLineLrcBackgroundTextColor
  319. currentLineLrcFont:(UIFont *)currentLineLrcFont
  320. otherLineLrcFont:(UIFont *)otherLineLrcFont
  321. superView:(UIView *)superView
  322. block:(nullable void (^)(NSString * onPlayingLyrics))block{
  323. self.lyricsTableView = [[DFPlayerLyricsTableview alloc] init];
  324. self.lyricsTableView.frame = frame;
  325. self.lyricsTableView.backgroundColor = cellBackgroundColor;
  326. self.lyricsTableView.cellRowHeight = cellRowHeight;
  327. self.lyricsTableView.cellBackgroundColor = cellBackgroundColor;
  328. self.lyricsTableView.currentLineLrcForegroundTextColor = currentLineLrcForegroundTextColor;
  329. self.lyricsTableView.currentLineLrcBackgroundTextColor = currentLineLrcBackgroundTextColor;
  330. self.lyricsTableView.otherLineLrcBackgroundTextColor = otherLineLrcBackgroundTextColor;
  331. self.lyricsTableView.currentLineLrcFont = currentLineLrcFont;
  332. self.lyricsTableView.otherLineLrcFont = otherLineLrcFont;
  333. self.lyricsTableView.lrcTableViewSuperview = superView;
  334. self.lyricsTableView.lyricsDelegate = self;
  335. [superView addSubview:self.lyricsTableView];
  336. if (block) { self.lyricsBlock = block; }
  337. return self.lyricsTableView;
  338. }
  339. - (void)df_lyricsTableview:(DFPlayerLyricsTableview *)lyricsTableview
  340. onPlayingLyrics:(NSString *)onPlayingLyrics{
  341. if (self.lyricsBlock) {
  342. self.lyricsBlock(onPlayingLyrics);
  343. }
  344. }
  345. /**释放播放器UI*/
  346. - (void)dfUI_deallocPlayer
  347. {
  348. if(_playBtn){
  349. _playBtn = nil;
  350. }
  351. if(_typeBtn){
  352. _typeBtn = nil;
  353. }
  354. if(_bufferProgressView){
  355. _bufferProgressView = nil;
  356. }
  357. if(_progressSlider){
  358. _progressSlider = nil;
  359. }
  360. if(_currentTimeLabel){
  361. _currentTimeLabel = nil;
  362. }
  363. if(_totalTimeLabel){
  364. _totalTimeLabel = nil;
  365. }
  366. if(_lyricsTableView){
  367. _lyricsTableView = nil;
  368. }
  369. if(_playImage){
  370. _playImage = nil;
  371. }
  372. if(_pauseImage){
  373. _pauseImage = nil;
  374. }
  375. if(_singleImage){
  376. _singleImage = nil;
  377. }
  378. if(_circleImage){
  379. _circleImage = nil;
  380. }
  381. if(_shuffleImage){
  382. _shuffleImage = nil;
  383. }
  384. }
  385. @end