TZAssetCell.m 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. //
  2. // TZAssetCell.m
  3. // TZImagePickerController
  4. //
  5. // Created by 谭真 on 15/12/24.
  6. // Copyright © 2015年 谭真. All rights reserved.
  7. //
  8. #import "TZAssetCell.h"
  9. #import "TZAssetModel.h"
  10. #import "UIView+TZLayout.h"
  11. #import "TZImageManager.h"
  12. #import "TZImagePickerController.h"
  13. #import "TZProgressView.h"
  14. @interface TZAssetCell ()
  15. @property (weak, nonatomic) UIImageView *imageView; // The photo / 照片
  16. @property (weak, nonatomic) UIImageView *selectImageView;
  17. @property (weak, nonatomic) UILabel *indexLabel;
  18. @property (weak, nonatomic) UIView *bottomView;
  19. @property (weak, nonatomic) UILabel *timeLength;
  20. @property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
  21. @property (nonatomic, weak) UIImageView *videoImgView;
  22. @property (nonatomic, strong) TZProgressView *progressView;
  23. @property (nonatomic, assign) int32_t bigImageRequestID;
  24. @end
  25. @implementation TZAssetCell
  26. - (instancetype)initWithFrame:(CGRect)frame {
  27. self = [super initWithFrame:frame];
  28. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reload:) name:@"TZ_PHOTO_PICKER_RELOAD_NOTIFICATION" object:nil];
  29. return self;
  30. }
  31. - (void)setModel:(TZAssetModel *)model {
  32. _model = model;
  33. self.representedAssetIdentifier = model.asset.localIdentifier;
  34. int32_t imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  35. // Set the cell's thumbnail image if it's still showing the same asset.
  36. if ([self.representedAssetIdentifier isEqualToString:model.asset.localIdentifier]) {
  37. self.imageView.image = photo;
  38. [self setNeedsLayout];
  39. } else {
  40. // NSLog(@"this cell is showing other asset");
  41. [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
  42. }
  43. if (!isDegraded) {
  44. [self hideProgressView];
  45. self.imageRequestID = 0;
  46. }
  47. } progressHandler:nil networkAccessAllowed:NO];
  48. if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) {
  49. [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
  50. // NSLog(@"cancelImageRequest %d",self.imageRequestID);
  51. }
  52. self.imageRequestID = imageRequestID;
  53. self.selectPhotoButton.selected = model.isSelected;
  54. self.selectImageView.image = self.selectPhotoButton.isSelected ? self.photoSelImage : self.photoDefImage;
  55. self.indexLabel.hidden = !self.selectPhotoButton.isSelected;
  56. self.type = (NSInteger)model.type;
  57. // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中
  58. if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) {
  59. if (_selectImageView.hidden == NO) {
  60. self.selectPhotoButton.hidden = YES;
  61. _selectImageView.hidden = YES;
  62. }
  63. }
  64. // 如果用户选中了该图片,提前获取一下大图
  65. if (model.isSelected) {
  66. [self requestBigImage];
  67. } else {
  68. [self cancelBigImageRequest];
  69. }
  70. [self setNeedsLayout];
  71. if (self.assetCellDidSetModelBlock) {
  72. self.assetCellDidSetModelBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView);
  73. }
  74. }
  75. - (void)setIndex:(NSInteger)index {
  76. _index = index;
  77. self.indexLabel.text = [NSString stringWithFormat:@"%zd", index];
  78. [self.contentView bringSubviewToFront:self.indexLabel];
  79. }
  80. - (void)setShowSelectBtn:(BOOL)showSelectBtn {
  81. _showSelectBtn = showSelectBtn;
  82. BOOL selectable = [[TZImageManager manager] isPhotoSelectableWithAsset:self.model.asset];
  83. if (!self.selectPhotoButton.hidden) {
  84. self.selectPhotoButton.hidden = !showSelectBtn || !selectable;
  85. }
  86. if (!self.selectImageView.hidden) {
  87. self.selectImageView.hidden = !showSelectBtn || !selectable;
  88. }
  89. }
  90. - (void)setType:(TZAssetCellType)type {
  91. _type = type;
  92. if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif) || self.allowPickingMultipleVideo) {
  93. _selectImageView.hidden = NO;
  94. _selectPhotoButton.hidden = NO;
  95. _bottomView.hidden = YES;
  96. } else { // Video of Gif
  97. _selectImageView.hidden = YES;
  98. _selectPhotoButton.hidden = YES;
  99. }
  100. if (type == TZAssetCellTypeVideo) {
  101. self.bottomView.hidden = NO;
  102. self.timeLength.text = _model.timeLength;
  103. self.videoImgView.hidden = NO;
  104. _timeLength.tz_left = self.videoImgView.tz_right;
  105. _timeLength.textAlignment = NSTextAlignmentRight;
  106. } else if (type == TZAssetCellTypePhotoGif && self.allowPickingGif) {
  107. self.bottomView.hidden = NO;
  108. self.timeLength.text = @"GIF";
  109. self.videoImgView.hidden = YES;
  110. _timeLength.tz_left = 5;
  111. _timeLength.textAlignment = NSTextAlignmentLeft;
  112. }
  113. }
  114. - (void)setAllowPreview:(BOOL)allowPreview {
  115. _allowPreview = allowPreview;
  116. if (allowPreview) {
  117. _imageView.userInteractionEnabled = NO;
  118. _tapGesture.enabled = NO;
  119. } else {
  120. _imageView.userInteractionEnabled = YES;
  121. _tapGesture.enabled = YES;
  122. }
  123. }
  124. - (void)selectPhotoButtonClick:(UIButton *)sender {
  125. if (self.didSelectPhotoBlock) {
  126. self.didSelectPhotoBlock(sender.isSelected);
  127. }
  128. self.selectImageView.image = sender.isSelected ? self.photoSelImage : self.photoDefImage;
  129. if (sender.isSelected) {
  130. [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger];
  131. // 用户选中了该图片,提前获取一下大图
  132. [self requestBigImage];
  133. } else { // 取消选中,取消大图的获取
  134. [self cancelBigImageRequest];
  135. }
  136. }
  137. /// 只在单选状态且allowPreview为NO时会有该事件
  138. - (void)didTapImageView {
  139. if (self.didSelectPhotoBlock) {
  140. self.didSelectPhotoBlock(NO);
  141. }
  142. }
  143. - (void)hideProgressView {
  144. if (_progressView) {
  145. self.progressView.hidden = YES;
  146. self.imageView.alpha = 1.0;
  147. }
  148. }
  149. - (void)requestBigImage {
  150. if (_bigImageRequestID) {
  151. [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
  152. }
  153. _bigImageRequestID = [[TZImageManager manager] requestImageDataForAsset:_model.asset completion:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  154. BOOL iCloudSyncFailed = !imageData && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
  155. self.model.iCloudFailed = iCloudSyncFailed;
  156. if (iCloudSyncFailed && self.didSelectPhotoBlock) {
  157. self.didSelectPhotoBlock(YES);
  158. self.selectImageView.image = self.photoDefImage;
  159. }
  160. [self hideProgressView];
  161. } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  162. if (self.model.isSelected) {
  163. progress = progress > 0.02 ? progress : 0.02;;
  164. self.progressView.progress = progress;
  165. self.progressView.hidden = NO;
  166. self.imageView.alpha = 0.4;
  167. if (progress >= 1) {
  168. [self hideProgressView];
  169. }
  170. } else {
  171. // 快速连续点几次,会EXC_BAD_ACCESS...
  172. // *stop = YES;
  173. [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
  174. [self cancelBigImageRequest];
  175. }
  176. }];
  177. if (_model.type == TZAssetCellTypeVideo) {
  178. [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
  179. BOOL iCloudSyncFailed = !playerItem && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]];
  180. self.model.iCloudFailed = iCloudSyncFailed;
  181. if (iCloudSyncFailed && self.didSelectPhotoBlock) {
  182. dispatch_async(dispatch_get_main_queue(), ^{
  183. self.didSelectPhotoBlock(YES);
  184. self.selectImageView.image = self.photoDefImage;
  185. });
  186. }
  187. }];
  188. }
  189. }
  190. - (void)cancelBigImageRequest {
  191. if (_bigImageRequestID) {
  192. [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
  193. }
  194. [self hideProgressView];
  195. }
  196. #pragma mark - Notification
  197. - (void)reload:(NSNotification *)noti {
  198. TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)noti.object;
  199. UIViewController *parentViewController = nil;
  200. UIResponder *responder = self.nextResponder;
  201. do {
  202. if ([responder isKindOfClass:[UIViewController class]]) {
  203. parentViewController = (UIViewController *)responder;
  204. break;
  205. }
  206. responder = responder.nextResponder;
  207. } while (responder);
  208. if (parentViewController.navigationController != tzImagePickerVc) {
  209. return;
  210. }
  211. if (self.model.isSelected && tzImagePickerVc.showSelectedIndex) {
  212. self.index = [tzImagePickerVc.selectedAssetIds indexOfObject:self.model.asset.localIdentifier] + 1;
  213. }
  214. self.indexLabel.hidden = !self.selectPhotoButton.isSelected;
  215. BOOL notSelectable = [TZCommonTools isAssetNotSelectable:self.model tzImagePickerVc:tzImagePickerVc];
  216. if (notSelectable && tzImagePickerVc.showPhotoCannotSelectLayer && !self.model.isSelected) {
  217. self.cannotSelectLayerButton.backgroundColor = tzImagePickerVc.cannotSelectLayerColor;
  218. self.cannotSelectLayerButton.hidden = NO;
  219. } else {
  220. self.cannotSelectLayerButton.hidden = YES;
  221. }
  222. }
  223. #pragma mark - Lazy load
  224. - (UIButton *)selectPhotoButton {
  225. if (_selectPhotoButton == nil) {
  226. UIButton *selectPhotoButton = [[UIButton alloc] init];
  227. [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside];
  228. [self.contentView addSubview:selectPhotoButton];
  229. _selectPhotoButton = selectPhotoButton;
  230. }
  231. return _selectPhotoButton;
  232. }
  233. - (UIImageView *)imageView {
  234. if (_imageView == nil) {
  235. UIImageView *imageView = [[UIImageView alloc] init];
  236. imageView.contentMode = UIViewContentModeScaleAspectFill;
  237. imageView.clipsToBounds = YES;
  238. [self.contentView addSubview:imageView];
  239. _imageView = imageView;
  240. _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapImageView)];
  241. [_imageView addGestureRecognizer:_tapGesture];
  242. self.allowPreview = self.allowPreview;
  243. }
  244. return _imageView;
  245. }
  246. - (UIImageView *)selectImageView {
  247. if (_selectImageView == nil) {
  248. UIImageView *selectImageView = [[UIImageView alloc] init];
  249. selectImageView.contentMode = UIViewContentModeCenter;
  250. selectImageView.clipsToBounds = YES;
  251. [self.contentView addSubview:selectImageView];
  252. _selectImageView = selectImageView;
  253. }
  254. return _selectImageView;
  255. }
  256. - (UIView *)bottomView {
  257. if (_bottomView == nil) {
  258. UIView *bottomView = [[UIView alloc] init];
  259. static NSInteger rgb = 0;
  260. bottomView.userInteractionEnabled = NO;
  261. bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8];
  262. [self.contentView addSubview:bottomView];
  263. _bottomView = bottomView;
  264. }
  265. return _bottomView;
  266. }
  267. - (UIButton *)cannotSelectLayerButton {
  268. if (_cannotSelectLayerButton == nil) {
  269. UIButton *cannotSelectLayerButton = [[UIButton alloc] init];
  270. [self.contentView addSubview:cannotSelectLayerButton];
  271. _cannotSelectLayerButton = cannotSelectLayerButton;
  272. }
  273. return _cannotSelectLayerButton;
  274. }
  275. - (UIImageView *)videoImgView {
  276. if (_videoImgView == nil) {
  277. UIImageView *videoImgView = [[UIImageView alloc] init];
  278. [videoImgView setImage:[UIImage tz_imageNamedFromMyBundle:@"VideoSendIcon"]];
  279. [self.bottomView addSubview:videoImgView];
  280. _videoImgView = videoImgView;
  281. }
  282. return _videoImgView;
  283. }
  284. - (UILabel *)timeLength {
  285. if (_timeLength == nil) {
  286. UILabel *timeLength = [[UILabel alloc] init];
  287. timeLength.font = [UIFont boldSystemFontOfSize:11];
  288. timeLength.textColor = [UIColor whiteColor];
  289. timeLength.textAlignment = NSTextAlignmentRight;
  290. [self.bottomView addSubview:timeLength];
  291. _timeLength = timeLength;
  292. }
  293. return _timeLength;
  294. }
  295. - (UILabel *)indexLabel {
  296. if (_indexLabel == nil) {
  297. UILabel *indexLabel = [[UILabel alloc] init];
  298. indexLabel.font = [UIFont systemFontOfSize:14];
  299. indexLabel.adjustsFontSizeToFitWidth = YES;
  300. indexLabel.textColor = [UIColor whiteColor];
  301. indexLabel.textAlignment = NSTextAlignmentCenter;
  302. [self.contentView addSubview:indexLabel];
  303. _indexLabel = indexLabel;
  304. }
  305. return _indexLabel;
  306. }
  307. - (TZProgressView *)progressView {
  308. if (_progressView == nil) {
  309. _progressView = [[TZProgressView alloc] init];
  310. _progressView.hidden = YES;
  311. [self addSubview:_progressView];
  312. }
  313. return _progressView;
  314. }
  315. - (void)layoutSubviews {
  316. [super layoutSubviews];
  317. _cannotSelectLayerButton.frame = self.bounds;
  318. if (self.allowPreview) {
  319. _selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44);
  320. } else {
  321. _selectPhotoButton.frame = self.bounds;
  322. }
  323. _selectImageView.frame = CGRectMake(self.tz_width - 27, 3, 24, 24);
  324. if (_selectImageView.image.size.width <= 27) {
  325. _selectImageView.contentMode = UIViewContentModeCenter;
  326. } else {
  327. _selectImageView.contentMode = UIViewContentModeScaleAspectFit;
  328. }
  329. _indexLabel.frame = _selectImageView.frame;
  330. _imageView.frame = self.bounds;
  331. static CGFloat progressWH = 20;
  332. CGFloat progressXY = (self.tz_width - progressWH) / 2;
  333. _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH);
  334. _bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17);
  335. _videoImgView.frame = CGRectMake(8, 0, 17, 17);
  336. _timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17);
  337. self.type = (NSInteger)self.model.type;
  338. self.showSelectBtn = self.showSelectBtn;
  339. [self.contentView bringSubviewToFront:_bottomView];
  340. [self.contentView bringSubviewToFront:_cannotSelectLayerButton];
  341. [self.contentView bringSubviewToFront:_selectPhotoButton];
  342. [self.contentView bringSubviewToFront:_selectImageView];
  343. [self.contentView bringSubviewToFront:_indexLabel];
  344. if (self.assetCellDidLayoutSubviewsBlock) {
  345. self.assetCellDidLayoutSubviewsBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView);
  346. }
  347. }
  348. - (void)dealloc {
  349. [[NSNotificationCenter defaultCenter] removeObserver:self];
  350. }
  351. @end
  352. @interface TZAlbumCell ()
  353. @property (weak, nonatomic) UIImageView *posterImageView;
  354. @property (weak, nonatomic) UILabel *titleLabel;
  355. @end
  356. @implementation TZAlbumCell
  357. - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
  358. self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  359. self.backgroundColor = [UIColor whiteColor];
  360. self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  361. return self;
  362. }
  363. - (void)setModel:(TZAlbumModel *)model {
  364. _model = model;
  365. UIColor *nameColor = UIColor.blackColor;
  366. if (@available(iOS 13.0, *)) {
  367. nameColor = UIColor.labelColor;
  368. }
  369. NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:nameColor}];
  370. NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
  371. [nameString appendAttributedString:countString];
  372. self.titleLabel.attributedText = nameString;
  373. [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) {
  374. self.posterImageView.image = postImage;
  375. [self setNeedsLayout];
  376. }];
  377. if (model.selectedCount) {
  378. self.selectedCountButton.hidden = NO;
  379. [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal];
  380. } else {
  381. self.selectedCountButton.hidden = YES;
  382. }
  383. if (self.albumCellDidSetModelBlock) {
  384. self.albumCellDidSetModelBlock(self, _posterImageView, _titleLabel);
  385. }
  386. }
  387. - (void)layoutSubviews {
  388. [super layoutSubviews];
  389. _selectedCountButton.frame = CGRectMake(self.contentView.tz_width - 24, 23, 24, 24);
  390. NSInteger titleHeight = ceil(self.titleLabel.font.lineHeight);
  391. self.titleLabel.frame = CGRectMake(80, (self.tz_height - titleHeight) / 2, self.tz_width - 80 - 50, titleHeight);
  392. self.posterImageView.frame = CGRectMake(0, 0, 70, 70);
  393. if (self.albumCellDidLayoutSubviewsBlock) {
  394. self.albumCellDidLayoutSubviewsBlock(self, _posterImageView, _titleLabel);
  395. }
  396. }
  397. - (void)layoutSublayersOfLayer:(CALayer *)layer {
  398. [super layoutSublayersOfLayer:layer];
  399. }
  400. #pragma mark - Lazy load
  401. - (UIImageView *)posterImageView {
  402. if (_posterImageView == nil) {
  403. UIImageView *posterImageView = [[UIImageView alloc] init];
  404. posterImageView.contentMode = UIViewContentModeScaleAspectFill;
  405. posterImageView.clipsToBounds = YES;
  406. [self.contentView addSubview:posterImageView];
  407. _posterImageView = posterImageView;
  408. }
  409. return _posterImageView;
  410. }
  411. - (UILabel *)titleLabel {
  412. if (_titleLabel == nil) {
  413. UILabel *titleLabel = [[UILabel alloc] init];
  414. titleLabel.font = [UIFont boldSystemFontOfSize:17];
  415. if (@available(iOS 13.0, *)) {
  416. titleLabel.textColor = UIColor.labelColor;
  417. } else {
  418. titleLabel.textColor = [UIColor blackColor];
  419. }
  420. titleLabel.textAlignment = NSTextAlignmentLeft;
  421. [self.contentView addSubview:titleLabel];
  422. _titleLabel = titleLabel;
  423. }
  424. return _titleLabel;
  425. }
  426. - (UIButton *)selectedCountButton {
  427. if (_selectedCountButton == nil) {
  428. UIButton *selectedCountButton = [[UIButton alloc] init];
  429. selectedCountButton.titleLabel.adjustsFontSizeToFitWidth = YES;
  430. selectedCountButton.layer.cornerRadius = 12;
  431. selectedCountButton.clipsToBounds = YES;
  432. selectedCountButton.backgroundColor = [UIColor redColor];
  433. [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  434. selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15];
  435. [self.contentView addSubview:selectedCountButton];
  436. _selectedCountButton = selectedCountButton;
  437. }
  438. return _selectedCountButton;
  439. }
  440. @end
  441. @implementation TZAssetCameraCell
  442. - (instancetype)initWithFrame:(CGRect)frame {
  443. self = [super initWithFrame:frame];
  444. if (self) {
  445. self.backgroundColor = [UIColor whiteColor];
  446. _imageView = [[UIImageView alloc] init];
  447. _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
  448. _imageView.contentMode = UIViewContentModeScaleAspectFill;
  449. [self.contentView addSubview:_imageView];
  450. self.clipsToBounds = YES;
  451. }
  452. return self;
  453. }
  454. - (void)layoutSubviews {
  455. [super layoutSubviews];
  456. _imageView.frame = self.bounds;
  457. }
  458. @end