SelectImageHandler.m 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. //
  2. // SelectImageHandler.m
  3. // Starbuds
  4. //
  5. // Created by 翟玉磊 on 2020/1/7.
  6. // Copyright © 2020 翟玉磊. All rights reserved.
  7. //
  8. #import "SelectImageHandler.h"
  9. #import <Photos/Photos.h>
  10. #import "BottomBasePopupController.h"
  11. @interface SelectImageHandler ()<UIImagePickerControllerDelegate,UIAlertViewDelegate, TZImagePickerControllerDelegate, UINavigationControllerDelegate>
  12. @property (nonatomic, strong) UIImagePickerController *imagePickerVc;
  13. @property (strong, nonatomic) CLLocation *location;
  14. @end
  15. @implementation SelectImageHandler
  16. - (instancetype)init {
  17. if (self = [super init]) {
  18. }
  19. return self;
  20. }
  21. #pragma mark — Public
  22. /// 显示图片选择控制器
  23. /// @param maxCount 能选择的最大数量
  24. /// @param parentController 父控制器且支持代理
  25. - (void)showImagePickerControllerWithMaxCount:(NSInteger)maxCount parentController:(UIViewController*)parentController; {
  26. self.maxImagesCount = maxCount;
  27. self.parentController = parentController;
  28. CustomActionSheetController *sheet = [[CustomActionSheetController alloc] initWithTitle:nil categoryTitles:@[kLocalizedString(@"拍照"), kLocalizedString(@"从手机相册选择")] cancel:kLocalizedString(@"取消") selctedBlock:^(NSInteger index, NSString * _Nonnull title) {
  29. if (index == 1) {
  30. [self takePhoto];
  31. }
  32. if (index == 2) {
  33. [self pushTZImagePickerController];
  34. }
  35. }];
  36. [sheet show];
  37. }
  38. /// 预览图片
  39. /// @param selectedPhotos 选中的图片数组
  40. /// @param selectedAssets 选中图片数组的相册数据
  41. /// @param index 选中的索引
  42. /// @param parentController 父控制器
  43. - (void)previewImagePickerWithSelectedPhotos:(NSArray *)selectedPhotos selectedAssets:(NSArray *)selectedAssets index:(NSInteger)index parentController:(UIViewController*)parentController {
  44. self.parentController = parentController;
  45. TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithSelectedAssets:[selectedAssets copy] selectedPhotos:[selectedPhotos copy] index:index];
  46. imagePickerVc.maxImagesCount = self.maxImagesCount;
  47. imagePickerVc.allowPickingOriginalPhoto = YES;
  48. imagePickerVc.showSelectedIndex = YES;
  49. imagePickerVc.modalPresentationStyle = UIModalPresentationFullScreen;
  50. [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  51. if (self.delegate && [self.delegate respondsToSelector:@selector(previewImageDidFinishPhotos:sourceAssets:isSelectOriginalPhoto:)]) {
  52. [self.delegate previewImageDidFinishPhotos:photos sourceAssets:assets isSelectOriginalPhoto:isSelectOriginalPhoto];
  53. }
  54. }];
  55. [self.parentController presentViewController:imagePickerVc animated:YES completion:nil];
  56. }
  57. #pragma mark — 相机操作
  58. - (void)takePhoto {
  59. AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  60. if (authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied) {
  61. // 无相机权限 做一个友好的提示
  62. UIAlertController *al = [BlockAlertController alertWithTitle:kLocalizedString(@"无法使用相机") message:kLocalizedString(@"请在iPhone的""设置-隐私-相机""中允许访问相机") cancelTitle:kLocalizedString(@"取消") sureTitle:kLocalizedString(@"设置") clickAction:^(UIAlertAction *action) {
  63. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  64. }];
  65. [self.parentController presentViewController:al animated:YES completion:nil];
  66. } else if (authStatus == AVAuthorizationStatusNotDetermined) {
  67. // fix issue 466, 防止用户首次拍照拒绝授权时相机页黑屏
  68. [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
  69. if (granted) {
  70. dispatch_async(dispatch_get_main_queue(), ^{
  71. [self takePhoto];
  72. });
  73. }
  74. }];
  75. // 拍照之前还需要检查相册权限
  76. } else if ([PHPhotoLibrary authorizationStatus] == 2) { // 已被拒绝,没有相册权限,将无法保存拍的照片
  77. UIAlertController *al = [BlockAlertController alertWithTitle:kLocalizedString(@"无法使用相机") message:kLocalizedString(@"请在iPhone的""设置-隐私-相机""中允许访问相机") cancelTitle:kLocalizedString(@"取消") sureTitle:kLocalizedString(@"设置") clickAction:^(UIAlertAction *action) {
  78. if ([action.title isEqualToString:@"设置"]) {
  79. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  80. }
  81. }];
  82. [self.parentController presentViewController:al animated:YES completion:nil];
  83. } else if ([PHPhotoLibrary authorizationStatus] == 0) { // 未请求过相册权限
  84. [[TZImageManager manager] requestAuthorizationWithCompletion:^{
  85. [self takePhoto];
  86. }];
  87. } else {
  88. [self pushImagePickerController];
  89. }
  90. }
  91. // 调用相机
  92. - (void)pushImagePickerController {
  93. // 提前定位
  94. __weak typeof(self) weakSelf = self;
  95. [[TZLocationManager manager] startLocationWithSuccessBlock:^(NSArray<CLLocation *> *locations) {
  96. __strong typeof(weakSelf) strongSelf = weakSelf;
  97. strongSelf.location = [locations firstObject];
  98. } failureBlock:^(NSError *error) {
  99. __strong typeof(weakSelf) strongSelf = weakSelf;
  100. strongSelf.location = nil;
  101. }];
  102. UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
  103. if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) {
  104. self.imagePickerVc.sourceType = sourceType;
  105. [self.parentController presentViewController:_imagePickerVc animated:YES completion:nil];
  106. } else {
  107. NSLog(@"模拟器中无法打开照相机,请在真机中使用");
  108. }
  109. }
  110. #pragma mark - UIImagePickerController
  111. - (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
  112. [picker dismissViewControllerAnimated:YES completion:nil];
  113. NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
  114. TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:self];
  115. // 对照片排序,按修改时间升序,默认是YES
  116. tzImagePickerVc.sortAscendingByModificationDate = YES;
  117. [tzImagePickerVc showProgressHUD];
  118. if ([type isEqualToString:@"public.image"]) {
  119. UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
  120. // save photo and get asset / 保存图片,获取到asset
  121. [[TZImageManager manager] savePhotoWithImage:image location:self.location completion:^(PHAsset *asset, NSError *error) {
  122. [tzImagePickerVc hideProgressHUD];
  123. if (error) {
  124. NSLog(@"图片保存失败 %@",error);
  125. } else {
  126. TZAssetModel *assetModel = [[TZImageManager manager] createModelWithAsset:asset];
  127. if (self.allowCrop) { // 允许裁剪,去裁剪
  128. TZImagePickerController *imagePicker = [[TZImagePickerController alloc] initCropTypeWithAsset:assetModel.asset photo:image completion:^(UIImage *cropImage, id asset) {
  129. [self didFinishWithAddedAsset:asset image:cropImage];
  130. }];
  131. imagePicker.allowPickingImage = YES;
  132. imagePicker.needCircleCrop = self.needCircleCrop;
  133. imagePicker.circleCropRadius = 100;
  134. [self.parentController presentViewController:imagePicker animated:YES completion:nil];
  135. } else {
  136. [self didFinishWithAddedAsset:assetModel.asset image:image];
  137. }
  138. }
  139. }];
  140. } else if ([type isEqualToString:@"public.movie"]) {
  141. NSURL *videoUrl = [info objectForKey:UIImagePickerControllerMediaURL];
  142. if (videoUrl) {
  143. [[TZImageManager manager] saveVideoWithUrl:videoUrl location:self.location completion:^(PHAsset *asset, NSError *error) {
  144. [tzImagePickerVc hideProgressHUD];
  145. if (!error) {
  146. TZAssetModel *assetModel = [[TZImageManager manager] createModelWithAsset:asset];
  147. [[TZImageManager manager] getPhotoWithAsset:assetModel.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  148. if (!isDegraded && photo) {
  149. [self didFinishWithAddedAsset:assetModel.asset image:photo];
  150. }
  151. }];
  152. }
  153. }];
  154. }
  155. }
  156. }
  157. - (void)didFinishWithAddedAsset:(PHAsset *)asset image:(UIImage *)image {
  158. PHAsset *phAsset;
  159. if ([asset isKindOfClass:[PHAsset class]]) {
  160. phAsset = asset;
  161. NSLog(@"location:%@",phAsset.location);
  162. }
  163. if (self.delegate && [self.delegate respondsToSelector:@selector(didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:)]) {
  164. [self.delegate didFinishPickingPhotos:@[image] sourceAssets:@[phAsset] isSelectOriginalPhoto:NO];
  165. }
  166. }
  167. - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
  168. if ([picker isKindOfClass:[UIImagePickerController class]]) {
  169. [picker dismissViewControllerAnimated:YES completion:nil];
  170. }
  171. }
  172. - (UIImagePickerController *)imagePickerVc {
  173. if (_imagePickerVc == nil) {
  174. _imagePickerVc = [[UIImagePickerController alloc] init];
  175. _imagePickerVc.delegate = self;
  176. UIBarButtonItem *tzBarItem, *BarItem;
  177. if (@available(iOS 9, *)) {
  178. tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
  179. BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]];
  180. } else {
  181. tzBarItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil];
  182. BarItem = [UIBarButtonItem appearanceWhenContainedIn:[UIImagePickerController class], nil];
  183. }
  184. NSDictionary *titleTextAttributes = [tzBarItem titleTextAttributesForState:UIControlStateNormal];
  185. [BarItem setTitleTextAttributes:titleTextAttributes forState:UIControlStateNormal];
  186. }
  187. return _imagePickerVc;
  188. }
  189. #pragma mark - UIAlertViewDelegate
  190. - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  191. if (buttonIndex == 1) { // 去设置界面,开启相机访问权限
  192. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  193. }
  194. }
  195. #pragma mark - TZImagePickerController
  196. - (void)pushTZImagePickerController {
  197. if (self.maxImagesCount <= 0) {
  198. return;
  199. }
  200. TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:self.maxImagesCount columnNumber:4 delegate:self pushPhotoPickerVc:YES];
  201. imagePickerVc.allowTakePicture = YES; // 在内部显示拍照按钮
  202. imagePickerVc.allowTakeVideo = NO; // 在内部显示拍视频按
  203. imagePickerVc.allowPickingVideo = NO;
  204. imagePickerVc.showSelectBtn = self.showSelectBtn;
  205. imagePickerVc.allowCrop = self.allowCrop;
  206. imagePickerVc.needCircleCrop = self.needCircleCrop;
  207. if (self.allowSquareCrop) {
  208. imagePickerVc.allowCrop = YES;
  209. imagePickerVc.cropRect = CGRectMake(0, (SCREEN_HEIGHT - SCREEN_WIDTH)/2, SCREEN_WIDTH, SCREEN_WIDTH);
  210. }
  211. if (self.allowHorizontalCrop) {
  212. imagePickerVc.allowCrop = YES;
  213. float height = SCREEN_WIDTH*0.5;
  214. imagePickerVc.cropRect = CGRectMake(0, (SCREEN_HEIGHT - height)/2, SCREEN_WIDTH, height);
  215. }
  216. [self.parentController presentViewController:imagePickerVc animated:YES completion:nil];
  217. }
  218. #pragma mark - TZImagePickerControllerDelegate
  219. /// User click cancel button
  220. /// 用户点击了取消
  221. - (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker {
  222. // NSLog(@"cancel");
  223. }
  224. // The picker should dismiss itself; when it dismissed these handle will be called.
  225. // You can also set autoDismiss to NO, then the picker don't dismiss itself.
  226. // If isOriginalPhoto is YES, user picked the original photo.
  227. // You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:].
  228. // The UIImage Object in photos default width is 828px, you can set it by photoWidth property.
  229. // 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的代理方法
  230. // 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了
  231. // 如果isSelectOriginalPhoto为YES,表明用户选择了原图
  232. // 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:]
  233. // photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它
  234. - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray<NSDictionary *> *)infos {
  235. if (self.delegate && [self.delegate respondsToSelector:@selector(didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:)]) {
  236. [self.delegate didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:isSelectOriginalPhoto];
  237. }
  238. }
  239. @end