XG_MediaCell.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. //
  2. // XG_MediaCell.m
  3. // MyApp
  4. //
  5. // Created by huxinguang on 2018/10/30.
  6. // Copyright © 2018年 huxinguang. All rights reserved.
  7. //
  8. #import "XG_MediaCell.h"
  9. #import "XG_PickerMacro.h"
  10. #import "UIView+XGAdd.h"
  11. #import "XG_AssetPickerManager.h"
  12. #import "XG_AssetModel.h"
  13. @interface XG_MediaCell()<UIScrollViewDelegate,XG_PlayerManagerDelegate,BottomBarDelegate>
  14. @end
  15. @implementation XG_MediaCell
  16. - (instancetype)initWithFrame:(CGRect)frame
  17. {
  18. self = [super initWithFrame:frame];
  19. if (self) {
  20. [self setupSubViews];
  21. }
  22. return self;
  23. }
  24. - (void)setupSubViews{
  25. [self.contentView addSubview:self.scrollView];
  26. [self.scrollView addSubview:self.mediaContainerView];
  27. [self.mediaContainerView addSubview:self.imageView];
  28. [self.mediaContainerView addSubview:self.playBtn];
  29. [self.contentView addSubview:self.bottomBar];
  30. }
  31. #pragma mark - Getter
  32. - (UIScrollView *)scrollView {
  33. if (!_scrollView) {
  34. _scrollView = [[UIScrollView alloc] init];
  35. _scrollView.frame = self.contentView.bounds;
  36. _scrollView.bouncesZoom = YES;
  37. _scrollView.multipleTouchEnabled = YES;
  38. _scrollView.alwaysBounceVertical = NO;
  39. _scrollView.showsVerticalScrollIndicator = YES;
  40. _scrollView.delegate = self;
  41. }
  42. return _scrollView;
  43. }
  44. -(UIView *)mediaContainerView{
  45. if (!_mediaContainerView) {
  46. _mediaContainerView = [UIView new];
  47. _mediaContainerView.clipsToBounds = YES;
  48. }
  49. return _mediaContainerView;
  50. }
  51. - (FLAnimatedImageView *)imageView {
  52. if (!_imageView) {
  53. _imageView = [FLAnimatedImageView new];
  54. _imageView.backgroundColor = [UIColor blackColor];
  55. _imageView.contentMode = UIViewContentModeScaleAspectFill;
  56. }
  57. return _imageView;
  58. }
  59. - (UIButton *)playBtn{
  60. if (!_playBtn) {
  61. _playBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  62. [_playBtn setImage:ImageWithFile(@"player_play") forState:UIControlStateNormal];
  63. [_playBtn addTarget:self action:@selector(playAction) forControlEvents:UIControlEventTouchUpInside];
  64. }
  65. return _playBtn;
  66. }
  67. -(BottomBar *)bottomBar{
  68. if (!_bottomBar) {
  69. _bottomBar = [[BottomBar alloc]initWithFrame:CGRectMake(0, kAppScreenHeight-30-kAppTabbarSafeBottomMargin, kAppScreenWidth, 30)];
  70. _bottomBar.delegate = self;
  71. }
  72. return _bottomBar;
  73. }
  74. #pragma mark - Setter
  75. - (void)setItem:(XG_AssetModel *)item{
  76. _item = item;
  77. if (item.asset.mediaType == PHAssetMediaTypeVideo) {
  78. self.playBtn.hidden = NO;
  79. }else{
  80. self.playBtn.hidden = YES;
  81. }
  82. self.bottomBar.hidden = YES;
  83. self.bottomBar.rightTimeLabel.text = [self getNewTimeFromSecond:item.asset.duration];
  84. [self.scrollView setZoomScale:1.0 animated:NO];
  85. self.scrollView.maximumZoomScale = 1.0;
  86. __weak typeof (self) weakSelf = self;
  87. [[XG_AssetPickerManager manager]getPhotoWithAsset:item.asset completion:^(id photo, NSDictionary *info) {
  88. dispatch_async(dispatch_get_main_queue(), ^{
  89. if (item.asset.mediaType == PHAssetMediaTypeImage) {
  90. weakSelf.scrollView.maximumZoomScale = 3;
  91. }
  92. if (photo) {
  93. if (@available(iOS 11.0, *)) {
  94. if (item.asset.playbackStyle == PHAssetPlaybackStyleImageAnimated) {
  95. FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:photo];
  96. weakSelf.imageView.animatedImage = image;
  97. [weakSelf resizeSubviewSize];
  98. return;
  99. }
  100. }
  101. weakSelf.imageView.image = photo;
  102. [weakSelf resizeSubviewSize];
  103. }
  104. });
  105. }];
  106. [self resizeSubviewSize];
  107. }
  108. - (void)resizeSubviewSize {
  109. _mediaContainerView.origin = CGPointZero;
  110. _mediaContainerView.width = self.width;
  111. UIImage *image = _imageView.image;
  112. if (image.size.height / image.size.width > self.height / self.width) {
  113. _mediaContainerView.height = floor(image.size.height / (image.size.width / self.width));
  114. } else {
  115. CGFloat height = image.size.height / image.size.width * self.width;
  116. if (height < 1 || isnan(height)) height = self.height;
  117. height = floor(height);
  118. _mediaContainerView.height = height;
  119. _mediaContainerView.centerY = self.height / 2;
  120. }
  121. if (_mediaContainerView.height > self.height && _mediaContainerView.height - self.height <= 1) {
  122. _mediaContainerView.height = self.height;
  123. }
  124. self.scrollView.contentSize = CGSizeMake(self.width, MAX(_mediaContainerView.height, self.height));
  125. [self.scrollView scrollRectToVisible:self.scrollView.bounds animated:NO];
  126. if (_mediaContainerView.height <= self.height) {
  127. self.scrollView.alwaysBounceVertical = NO;
  128. } else {
  129. self.scrollView.alwaysBounceVertical = YES;
  130. }
  131. [CATransaction begin];
  132. [CATransaction setDisableActions:YES];
  133. self.imageView.frame = _mediaContainerView.bounds;
  134. self.playBtn.size = CGSizeMake(42, 42);
  135. self.playBtn.center = self.imageView.center;
  136. [CATransaction commit];
  137. }
  138. #pragma mark - UIScrollViewDelegate
  139. - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
  140. return self.mediaContainerView;
  141. }
  142. - (void)scrollViewDidZoom:(UIScrollView *)scrollView {
  143. CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)?
  144. (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
  145. CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)?
  146. (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
  147. self.mediaContainerView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX,
  148. scrollView.contentSize.height * 0.5 + offsetY);
  149. }
  150. #pragma mark - player
  151. - (void)playAction{
  152. self.bottomBar.hidden = NO;
  153. self.playBtn.hidden = YES;
  154. /*
  155. 在这里设置代理,解决cell复用引起的部分视频播放时slider进度和播放时间不更新的问题
  156. */
  157. [XG_PlayerManager shareInstance].delegate = self;
  158. __weak typeof (self) weakSelf = self;
  159. [[XG_AssetPickerManager manager]getVideoWithAsset:self.item.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
  160. if (playerItem) {
  161. dispatch_async(dispatch_get_main_queue(), ^{
  162. [[XG_PlayerManager shareInstance] playWithItem:playerItem onLayer:weakSelf.imageView.layer];
  163. });
  164. }
  165. }];
  166. }
  167. - (void)showOrHidePlayerControls{
  168. if (self.item.asset.mediaType == PHAssetMediaTypeImage) {
  169. return;
  170. }
  171. }
  172. - (void)pauseAndResetPlayer{
  173. self.playBtn.hidden = NO;
  174. self.bottomBar.leftTimeLabel.text = @"00:00";
  175. self.bottomBar.hidden = YES;
  176. self.bottomBar.slider.value = 0;
  177. self.sliderIsSliding = NO;
  178. [XG_PlayerManager shareInstance].delegate = nil;//一定要在这里置为nil
  179. [[XG_PlayerManager shareInstance] resetPlayer];
  180. }
  181. - (void)pausePlayer{
  182. self.playBtn.hidden = NO;
  183. self.bottomBar.hidden = YES;
  184. [[XG_PlayerManager shareInstance] pause];
  185. }
  186. #pragma mark - XG_PlayerManagerDelegate
  187. - (void)playerDidFinishPlay:(XG_PlayerManager *)manager{
  188. self.playBtn.hidden = NO;
  189. self.bottomBar.hidden = YES;
  190. self.bottomBar.slider.value = 0.0;
  191. self.bottomBar.leftTimeLabel.text = @"00:00";
  192. self.sliderIsSliding = NO;
  193. [manager resetPlayer];
  194. }
  195. - (void)playerDidPlayToTime:(CMTime)currentTime totalTime:(CMTime)totalTime{
  196. if (!self.sliderIsSliding) {
  197. self.bottomBar.leftTimeLabel.text = [self getNewTimeFromSecond:CMTimeGetSeconds(currentTime)];
  198. self.bottomBar.slider.value = CMTimeGetSeconds(currentTime)/CMTimeGetSeconds(totalTime);
  199. }
  200. }
  201. - (NSString *)getNewTimeFromSecond:(int)seconds {
  202. NSString *newTime;
  203. if (seconds < 10) {
  204. newTime = [NSString stringWithFormat:@"00:0%d",seconds];
  205. } else if (seconds < 60) {
  206. newTime = [NSString stringWithFormat:@"00:%d",seconds];
  207. } else {
  208. int min = seconds / 60;
  209. int sec = seconds - (min * 60);
  210. if (sec < 10) {
  211. if (min < 10) {
  212. newTime = [NSString stringWithFormat:@"0%d:0%d",min,sec];
  213. }else{
  214. newTime = [NSString stringWithFormat:@"%d:0%d",min,sec];
  215. }
  216. } else {
  217. if (min < 10) {
  218. newTime = [NSString stringWithFormat:@"0%d:%d",min,sec];
  219. }else{
  220. newTime = [NSString stringWithFormat:@"%d:%d",min,sec];
  221. }
  222. }
  223. }
  224. return newTime;
  225. }
  226. #pragma mark - BottomBarDelegate
  227. - (void)sliderDidSlide{
  228. self.sliderIsSliding = YES;
  229. }
  230. - (void)slideDidEndWithValue:(float)value{
  231. CMTime duration = [XG_PlayerManager shareInstance].playerItem.duration;
  232. Float64 totalSeconds = CMTimeGetSeconds(duration);
  233. Float64 currentSeconds = totalSeconds*value;
  234. CMTimeScale timescale = [XG_PlayerManager shareInstance].playerItem.currentTime.timescale;
  235. CMTime current = CMTimeMake(currentSeconds*timescale, timescale);
  236. [[XG_PlayerManager shareInstance] seekSmoothlyToTime:current];
  237. self.sliderIsSliding = NO;
  238. }
  239. @end
  240. @implementation BottomBar
  241. - (instancetype)initWithFrame:(CGRect)frame
  242. {
  243. self = [super initWithFrame:frame];
  244. if (self) {
  245. self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.65];
  246. [self addSubview:self.leftTimeLabel];
  247. [self addSubview:self.slider];
  248. [self addSubview:self.rightTimeLabel];
  249. [self addConstraints];
  250. }
  251. return self;
  252. }
  253. - (void)addConstraints{
  254. self.leftTimeLabel.translatesAutoresizingMaskIntoConstraints = NO;
  255. self.slider.translatesAutoresizingMaskIntoConstraints = NO;
  256. self.rightTimeLabel.translatesAutoresizingMaskIntoConstraints = NO;
  257. [NSLayoutConstraint activateConstraints:@[
  258. [NSLayoutConstraint constraintWithItem:self.leftTimeLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0],
  259. [NSLayoutConstraint constraintWithItem:self.leftTimeLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0],
  260. [NSLayoutConstraint constraintWithItem:self.leftTimeLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:60],
  261. [NSLayoutConstraint constraintWithItem:self.leftTimeLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0],
  262. [NSLayoutConstraint constraintWithItem:self.slider attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.leftTimeLabel attribute:NSLayoutAttributeRight multiplier:1.0 constant:0],
  263. [NSLayoutConstraint constraintWithItem:self.slider attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:20],
  264. [NSLayoutConstraint constraintWithItem:self.slider attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0],
  265. [NSLayoutConstraint constraintWithItem:self.slider attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.rightTimeLabel attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0],
  266. [NSLayoutConstraint constraintWithItem:self.rightTimeLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0],
  267. [NSLayoutConstraint constraintWithItem:self.rightTimeLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0],
  268. [NSLayoutConstraint constraintWithItem:self.rightTimeLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0],
  269. [NSLayoutConstraint constraintWithItem:self.rightTimeLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.leftTimeLabel attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]
  270. ]];
  271. }
  272. -(UILabel *)leftTimeLabel{
  273. if (!_leftTimeLabel) {
  274. _leftTimeLabel = [UILabel new];
  275. _leftTimeLabel.font = [UIFont systemFontOfSize:12];
  276. _leftTimeLabel.textColor = [UIColor whiteColor];
  277. _leftTimeLabel.textAlignment = NSTextAlignmentCenter;
  278. _leftTimeLabel.text = @"00:00";
  279. }
  280. return _leftTimeLabel;
  281. }
  282. -(UISlider *)slider{
  283. if (!_slider) {
  284. _slider = [UISlider new];
  285. _slider.value = 0.0;
  286. _slider.minimumValue = 0.0;
  287. _slider.maximumValue = 1.0;
  288. _slider.minimumTrackTintColor = [UIColor colorWithRed:36/255.0 green:160/255.0 blue:252/255.0 alpha:1];
  289. _slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.5];
  290. _slider.backgroundColor = [UIColor clearColor];
  291. [_slider setThumbImage:ImageWithFile(@"dot") forState:UIControlStateNormal];
  292. [_slider addTarget:self action:@selector(slideDidEnd:) forControlEvents:UIControlEventTouchUpInside];
  293. [_slider addTarget:self action:@selector(sliderDidSlide:) forControlEvents:UIControlEventValueChanged];
  294. }
  295. return _slider;
  296. }
  297. -(UILabel *)rightTimeLabel{
  298. if (!_rightTimeLabel) {
  299. _rightTimeLabel = [UILabel new];
  300. _rightTimeLabel.font = [UIFont systemFontOfSize:12];
  301. _rightTimeLabel.textColor = [UIColor whiteColor];
  302. _rightTimeLabel.textAlignment = NSTextAlignmentCenter;
  303. _rightTimeLabel.text = @"00:00";
  304. }
  305. return _rightTimeLabel;
  306. }
  307. - (void)slideDidEnd:(UISlider *)slider{
  308. if ([self.delegate respondsToSelector:@selector(slideDidEndWithValue:)]) {
  309. [self.delegate slideDidEndWithValue:slider.value];
  310. }
  311. }
  312. - (void)sliderDidSlide:(UISlider *)slider{
  313. if ([self.delegate respondsToSelector:@selector(sliderDidSlide)]) {
  314. [self.delegate sliderDidSlide];
  315. }
  316. }
  317. @end