TZImagePickerController.m 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. //
  2. // TZImagePickerController.m
  3. // TZImagePickerController
  4. //
  5. // Created by 谭真 on 15/12/24.
  6. // Copyright © 2015年 谭真. All rights reserved.
  7. // version 3.2.1 - 2019.05.29
  8. // 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
  9. #import "TZImagePickerController.h"
  10. #import "TZPhotoPickerController.h"
  11. #import "TZPhotoPreviewController.h"
  12. #import "TZAssetModel.h"
  13. #import "TZAssetCell.h"
  14. #import "UIView+Layout.h"
  15. #import "TZImageManager.h"
  16. @interface TZImagePickerController () {
  17. NSTimer *_timer;
  18. UILabel *_tipLabel;
  19. UIButton *_settingBtn;
  20. BOOL _pushPhotoPickerVc;
  21. BOOL _didPushPhotoPickerVc;
  22. UIButton *_progressHUD;
  23. UIView *_HUDContainer;
  24. UIActivityIndicatorView *_HUDIndicatorView;
  25. UILabel *_HUDLabel;
  26. UIStatusBarStyle _originStatusBarStyle;
  27. }
  28. /// Default is 4, Use in photos collectionView in TZPhotoPickerController
  29. /// 默认4列, TZPhotoPickerController中的照片collectionView
  30. @property (nonatomic, assign) NSInteger columnNumber;
  31. @end
  32. @implementation TZImagePickerController
  33. - (instancetype)init {
  34. self = [super init];
  35. if (self) {
  36. self = [self initWithMaxImagesCount:9 delegate:nil];
  37. }
  38. return self;
  39. }
  40. #pragma clang diagnostic push
  41. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  42. - (void)viewDidLoad {
  43. [super viewDidLoad];
  44. self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden;
  45. self.view.backgroundColor = [UIColor whiteColor];
  46. self.navigationBar.barStyle = UIBarStyleBlack;
  47. self.navigationBar.translucent = YES;
  48. self.modalPresentationStyle = UIModalPresentationFullScreen;
  49. [TZImageManager manager].shouldFixOrientation = NO;
  50. // Default appearance, you can reset these after this method
  51. // 默认的外观,你可以在这个方法后重置
  52. self.oKButtonTitleColorNormal = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0];
  53. self.oKButtonTitleColorDisabled = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:0.5];
  54. self.navigationBar.barTintColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:1.0];
  55. self.navigationBar.tintColor = [UIColor whiteColor];
  56. self.automaticallyAdjustsScrollViewInsets = NO;
  57. if (self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
  58. }
  59. - (void)setNaviBgColor:(UIColor *)naviBgColor {
  60. _naviBgColor = naviBgColor;
  61. self.navigationBar.barTintColor = naviBgColor;
  62. }
  63. - (void)setNaviTitleColor:(UIColor *)naviTitleColor {
  64. _naviTitleColor = naviTitleColor;
  65. [self configNaviTitleAppearance];
  66. }
  67. - (void)setNaviTitleFont:(UIFont *)naviTitleFont {
  68. _naviTitleFont = naviTitleFont;
  69. [self configNaviTitleAppearance];
  70. }
  71. - (void)configNaviTitleAppearance {
  72. NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
  73. if (self.naviTitleColor) {
  74. textAttrs[NSForegroundColorAttributeName] = self.naviTitleColor;
  75. }
  76. if (self.naviTitleFont) {
  77. textAttrs[NSFontAttributeName] = self.naviTitleFont;
  78. }
  79. self.navigationBar.titleTextAttributes = textAttrs;
  80. }
  81. - (void)setBarItemTextFont:(UIFont *)barItemTextFont {
  82. _barItemTextFont = barItemTextFont;
  83. [self configBarButtonItemAppearance];
  84. }
  85. - (void)setBarItemTextColor:(UIColor *)barItemTextColor {
  86. _barItemTextColor = barItemTextColor;
  87. [self configBarButtonItemAppearance];
  88. }
  89. - (void)setIsStatusBarDefault:(BOOL)isStatusBarDefault {
  90. _isStatusBarDefault = isStatusBarDefault;
  91. if (isStatusBarDefault) {
  92. self.statusBarStyle = UIStatusBarStyleDefault;
  93. } else {
  94. self.statusBarStyle = UIStatusBarStyleLightContent;
  95. }
  96. }
  97. - (void)configBarButtonItemAppearance {
  98. UIBarButtonItem *barItem;
  99. if (@available(iOS 9, *)) {
  100. barItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
  101. } else {
  102. barItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil];
  103. }
  104. NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
  105. textAttrs[NSForegroundColorAttributeName] = self.barItemTextColor;
  106. textAttrs[NSFontAttributeName] = self.barItemTextFont;
  107. [barItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
  108. }
  109. - (void)viewWillAppear:(BOOL)animated {
  110. [super viewWillAppear:animated];
  111. _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
  112. [UIApplication sharedApplication].statusBarStyle = self.statusBarStyle;
  113. }
  114. - (void)viewWillDisappear:(BOOL)animated {
  115. [super viewWillDisappear:animated];
  116. [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
  117. [self hideProgressHUD];
  118. }
  119. - (UIStatusBarStyle)preferredStatusBarStyle {
  120. return self.statusBarStyle;
  121. }
  122. - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate {
  123. return [self initWithMaxImagesCount:maxImagesCount columnNumber:4 delegate:delegate pushPhotoPickerVc:YES];
  124. }
  125. - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate {
  126. return [self initWithMaxImagesCount:maxImagesCount columnNumber:columnNumber delegate:delegate pushPhotoPickerVc:YES];
  127. }
  128. - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc {
  129. _pushPhotoPickerVc = pushPhotoPickerVc;
  130. TZAlbumPickerController *albumPickerVc = [[TZAlbumPickerController alloc] init];
  131. albumPickerVc.isFirstAppear = YES;
  132. albumPickerVc.columnNumber = columnNumber;
  133. self = [super initWithRootViewController:albumPickerVc];
  134. if (self) {
  135. self.maxImagesCount = maxImagesCount > 0 ? maxImagesCount : 9; // Default is 9 / 默认最大可选9张图片
  136. self.pickerDelegate = delegate;
  137. self.selectedAssets = [NSMutableArray array];
  138. // Allow user picking original photo and video, you also can set No after this method
  139. // 默认准许用户选择原图和视频, 你也可以在这个方法后置为NO
  140. self.allowPickingOriginalPhoto = YES;
  141. self.allowPickingVideo = YES;
  142. self.allowPickingImage = YES;
  143. self.allowTakePicture = YES;
  144. self.allowTakeVideo = YES;
  145. self.videoMaximumDuration = 10 * 60;
  146. self.sortAscendingByModificationDate = YES;
  147. self.autoDismiss = YES;
  148. self.columnNumber = columnNumber;
  149. [self configDefaultSetting];
  150. if (![[TZImageManager manager] authorizationStatusAuthorized]) {
  151. _tipLabel = [[UILabel alloc] init];
  152. _tipLabel.frame = CGRectMake(8, 120, self.view.tz_width - 16, 60);
  153. _tipLabel.textAlignment = NSTextAlignmentCenter;
  154. _tipLabel.numberOfLines = 0;
  155. _tipLabel.font = [UIFont systemFontOfSize:16];
  156. _tipLabel.textColor = [UIColor blackColor];
  157. NSDictionary *infoDict = [TZCommonTools tz_getInfoDictionary];
  158. NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"];
  159. if (!appName) appName = [infoDict valueForKey:@"CFBundleName"];
  160. NSString *tipText = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Allow %@ to access your album in \"Settings -> Privacy -> Photos\""],appName];
  161. _tipLabel.text = tipText;
  162. [self.view addSubview:_tipLabel];
  163. _settingBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  164. [_settingBtn setTitle:self.settingBtnTitleStr forState:UIControlStateNormal];
  165. _settingBtn.frame = CGRectMake(0, 180, self.view.tz_width, 44);
  166. _settingBtn.titleLabel.font = [UIFont systemFontOfSize:18];
  167. [_settingBtn addTarget:self action:@selector(settingBtnClick) forControlEvents:UIControlEventTouchUpInside];
  168. [self.view addSubview:_settingBtn];
  169. if ([PHPhotoLibrary authorizationStatus] == 0) {
  170. _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO];
  171. }
  172. } else {
  173. [self pushPhotoPickerVc];
  174. }
  175. }
  176. return self;
  177. }
  178. /// This init method just for previewing photos / 用这个初始化方法以预览图片
  179. - (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index{
  180. TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init];
  181. self = [super initWithRootViewController:previewVc];
  182. if (self) {
  183. self.selectedAssets = [NSMutableArray arrayWithArray:selectedAssets];
  184. self.allowPickingOriginalPhoto = self.allowPickingOriginalPhoto;
  185. [self configDefaultSetting];
  186. previewVc.photos = [NSMutableArray arrayWithArray:selectedPhotos];
  187. previewVc.currentIndex = index;
  188. __weak typeof(self) weakSelf = self;
  189. [previewVc setDoneButtonClickBlockWithPreviewType:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  190. __strong typeof(weakSelf) strongSelf = weakSelf;
  191. [strongSelf dismissViewControllerAnimated:YES completion:^{
  192. if (!strongSelf) return;
  193. if (strongSelf.didFinishPickingPhotosHandle) {
  194. strongSelf.didFinishPickingPhotosHandle(photos,assets,isSelectOriginalPhoto);
  195. }
  196. }];
  197. }];
  198. }
  199. return self;
  200. }
  201. /// This init method for crop photo / 用这个初始化方法以裁剪图片
  202. - (instancetype)initCropTypeWithAsset:(PHAsset *)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,PHAsset *asset))completion {
  203. TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init];
  204. self = [super initWithRootViewController:previewVc];
  205. if (self) {
  206. self.maxImagesCount = 1;
  207. self.allowPickingImage = YES;
  208. self.allowCrop = YES;
  209. self.selectedAssets = [NSMutableArray arrayWithArray:@[asset]];
  210. [self configDefaultSetting];
  211. previewVc.photos = [NSMutableArray arrayWithArray:@[photo]];
  212. previewVc.isCropImage = YES;
  213. previewVc.currentIndex = 0;
  214. __weak typeof(self) weakSelf = self;
  215. [previewVc setDoneButtonClickBlockCropMode:^(UIImage *cropImage, id asset) {
  216. __strong typeof(weakSelf) strongSelf = weakSelf;
  217. [strongSelf dismissViewControllerAnimated:YES completion:^{
  218. if (completion) {
  219. completion(cropImage,asset);
  220. }
  221. }];
  222. }];
  223. }
  224. return self;
  225. }
  226. - (void)configDefaultSetting {
  227. self.timeout = 15;
  228. self.photoWidth = 828.0;
  229. self.photoPreviewMaxWidth = 600;
  230. self.naviTitleColor = [UIColor whiteColor];
  231. self.naviTitleFont = [UIFont systemFontOfSize:17];
  232. self.barItemTextFont = [UIFont systemFontOfSize:15];
  233. self.barItemTextColor = [UIColor whiteColor];
  234. self.allowPreview = YES;
  235. // 2.2.26版本,不主动缩放图片,降低内存占用
  236. self.notScaleImage = YES;
  237. self.needFixComposition = NO;
  238. self.statusBarStyle = UIStatusBarStyleLightContent;
  239. self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
  240. self.allowCameraLocation = YES;
  241. self.iconThemeColor = [UIColor colorWithRed:31 / 255.0 green:185 / 255.0 blue:34 / 255.0 alpha:1.0];
  242. [self configDefaultBtnTitle];
  243. CGFloat cropViewWH = MIN(self.view.tz_width, self.view.tz_height) / 3 * 2;
  244. self.cropRect = CGRectMake((self.view.tz_width - cropViewWH) / 2, (self.view.tz_height - cropViewWH) / 2, cropViewWH, cropViewWH);
  245. }
  246. - (void)configDefaultImageName {
  247. self.takePictureImageName = @"takePicture80";
  248. self.photoSelImageName = @"photo_sel_photoPickerVc";
  249. self.photoDefImageName = @"photo_def_photoPickerVc";
  250. self.photoNumberIconImage = [self createImageWithColor:nil size:CGSizeMake(24, 24) radius:12]; // @"photo_number_icon";
  251. self.photoPreviewOriginDefImageName = @"preview_original_def";
  252. self.photoOriginDefImageName = @"photo_original_def";
  253. self.photoOriginSelImageName = @"photo_original_sel";
  254. }
  255. - (void)setTakePictureImageName:(NSString *)takePictureImageName {
  256. _takePictureImageName = takePictureImageName;
  257. _takePictureImage = [UIImage tz_imageNamedFromMyBundle:takePictureImageName];
  258. }
  259. - (void)setPhotoSelImageName:(NSString *)photoSelImageName {
  260. _photoSelImageName = photoSelImageName;
  261. _photoSelImage = [UIImage tz_imageNamedFromMyBundle:photoSelImageName];
  262. }
  263. - (void)setPhotoDefImageName:(NSString *)photoDefImageName {
  264. _photoDefImageName = photoDefImageName;
  265. _photoDefImage = [UIImage tz_imageNamedFromMyBundle:photoDefImageName];
  266. }
  267. - (void)setPhotoNumberIconImageName:(NSString *)photoNumberIconImageName {
  268. _photoNumberIconImageName = photoNumberIconImageName;
  269. _photoNumberIconImage = [UIImage tz_imageNamedFromMyBundle:photoNumberIconImageName];
  270. }
  271. - (void)setPhotoPreviewOriginDefImageName:(NSString *)photoPreviewOriginDefImageName {
  272. _photoPreviewOriginDefImageName = photoPreviewOriginDefImageName;
  273. _photoPreviewOriginDefImage = [UIImage tz_imageNamedFromMyBundle:photoPreviewOriginDefImageName];
  274. }
  275. - (void)setPhotoOriginDefImageName:(NSString *)photoOriginDefImageName {
  276. _photoOriginDefImageName = photoOriginDefImageName;
  277. _photoOriginDefImage = [UIImage tz_imageNamedFromMyBundle:photoOriginDefImageName];
  278. }
  279. - (void)setPhotoOriginSelImageName:(NSString *)photoOriginSelImageName {
  280. _photoOriginSelImageName = photoOriginSelImageName;
  281. _photoOriginSelImage = [UIImage tz_imageNamedFromMyBundle:photoOriginSelImageName];
  282. }
  283. - (void)setIconThemeColor:(UIColor *)iconThemeColor {
  284. _iconThemeColor = iconThemeColor;
  285. [self configDefaultImageName];
  286. }
  287. - (void)configDefaultBtnTitle {
  288. self.doneBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Done"];
  289. self.cancelBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Cancel"];
  290. self.previewBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Preview"];
  291. self.fullImageBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Full image"];
  292. self.settingBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Setting"];
  293. self.processHintStr = [NSBundle tz_localizedStringForKey:@"Processing..."];
  294. }
  295. - (void)setShowSelectedIndex:(BOOL)showSelectedIndex {
  296. _showSelectedIndex = showSelectedIndex;
  297. if (showSelectedIndex) {
  298. self.photoSelImage = [self createImageWithColor:nil size:CGSizeMake(24, 24) radius:12];
  299. }
  300. [TZImagePickerConfig sharedInstance].showSelectedIndex = showSelectedIndex;
  301. }
  302. - (void)setShowPhotoCannotSelectLayer:(BOOL)showPhotoCannotSelectLayer {
  303. _showPhotoCannotSelectLayer = showPhotoCannotSelectLayer;
  304. [TZImagePickerConfig sharedInstance].showPhotoCannotSelectLayer = showPhotoCannotSelectLayer;
  305. }
  306. - (void)setNotScaleImage:(BOOL)notScaleImage {
  307. _notScaleImage = notScaleImage;
  308. [TZImagePickerConfig sharedInstance].notScaleImage = notScaleImage;
  309. }
  310. - (void)setNeedFixComposition:(BOOL)needFixComposition {
  311. _needFixComposition = needFixComposition;
  312. [TZImagePickerConfig sharedInstance].needFixComposition = needFixComposition;
  313. }
  314. - (void)observeAuthrizationStatusChange {
  315. [_timer invalidate];
  316. _timer = nil;
  317. if ([PHPhotoLibrary authorizationStatus] == 0) {
  318. _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO];
  319. }
  320. if ([[TZImageManager manager] authorizationStatusAuthorized]) {
  321. [_tipLabel removeFromSuperview];
  322. [_settingBtn removeFromSuperview];
  323. [self pushPhotoPickerVc];
  324. TZAlbumPickerController *albumPickerVc = (TZAlbumPickerController *)self.visibleViewController;
  325. if ([albumPickerVc isKindOfClass:[TZAlbumPickerController class]]) {
  326. [albumPickerVc configTableView];
  327. }
  328. }
  329. }
  330. - (void)pushPhotoPickerVc {
  331. _didPushPhotoPickerVc = NO;
  332. // 1.6.8 判断是否需要push到照片选择页,如果_pushPhotoPickerVc为NO,则不push
  333. if (!_didPushPhotoPickerVc && _pushPhotoPickerVc) {
  334. TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init];
  335. photoPickerVc.isFirstAppear = YES;
  336. photoPickerVc.columnNumber = self.columnNumber;
  337. [[TZImageManager manager] getCameraRollAlbum:self.allowPickingVideo allowPickingImage:self.allowPickingImage needFetchAssets:NO completion:^(TZAlbumModel *model) {
  338. photoPickerVc.model = model;
  339. [self pushViewController:photoPickerVc animated:YES];
  340. self->_didPushPhotoPickerVc = YES;
  341. }];
  342. }
  343. }
  344. - (UIAlertController *)showAlertWithTitle:(NSString *)title {
  345. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
  346. [alertController addAction:[UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"OK"] style:UIAlertActionStyleDefault handler:nil]];
  347. [self presentViewController:alertController animated:YES completion:nil];
  348. return alertController;
  349. }
  350. - (void)hideAlertView:(UIAlertController *)alertView {
  351. [alertView dismissViewControllerAnimated:YES completion:nil];
  352. alertView = nil;
  353. }
  354. - (void)showProgressHUD {
  355. if (!_progressHUD) {
  356. _progressHUD = [UIButton buttonWithType:UIButtonTypeCustom];
  357. [_progressHUD setBackgroundColor:[UIColor clearColor]];
  358. _HUDContainer = [[UIView alloc] init];
  359. _HUDContainer.layer.cornerRadius = 8;
  360. _HUDContainer.clipsToBounds = YES;
  361. _HUDContainer.backgroundColor = [UIColor darkGrayColor];
  362. _HUDContainer.alpha = 0.7;
  363. _HUDIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
  364. _HUDLabel = [[UILabel alloc] init];
  365. _HUDLabel.textAlignment = NSTextAlignmentCenter;
  366. _HUDLabel.text = self.processHintStr;
  367. _HUDLabel.font = [UIFont systemFontOfSize:15];
  368. _HUDLabel.textColor = [UIColor whiteColor];
  369. [_HUDContainer addSubview:_HUDLabel];
  370. [_HUDContainer addSubview:_HUDIndicatorView];
  371. [_progressHUD addSubview:_HUDContainer];
  372. }
  373. [_HUDIndicatorView startAnimating];
  374. UIWindow *applicationWindow;
  375. if ([[[UIApplication sharedApplication] delegate] respondsToSelector:@selector(window)]) {
  376. applicationWindow = [[[UIApplication sharedApplication] delegate] window];
  377. } else {
  378. applicationWindow = [[UIApplication sharedApplication] keyWindow];
  379. }
  380. [applicationWindow addSubview:_progressHUD];
  381. [self.view setNeedsLayout];
  382. // if over time, dismiss HUD automatic
  383. __weak typeof(self) weakSelf = self;
  384. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  385. __strong typeof(weakSelf) strongSelf = weakSelf;
  386. [strongSelf hideProgressHUD];
  387. });
  388. }
  389. - (void)hideProgressHUD {
  390. if (_progressHUD) {
  391. [_HUDIndicatorView stopAnimating];
  392. [_progressHUD removeFromSuperview];
  393. }
  394. }
  395. - (void)setMaxImagesCount:(NSInteger)maxImagesCount {
  396. _maxImagesCount = maxImagesCount;
  397. if (maxImagesCount > 1) {
  398. _showSelectBtn = YES;
  399. _allowCrop = NO;
  400. }
  401. }
  402. - (void)setShowSelectBtn:(BOOL)showSelectBtn {
  403. _showSelectBtn = showSelectBtn;
  404. // 多选模式下,不允许让showSelectBtn为NO
  405. if (!showSelectBtn && _maxImagesCount > 1) {
  406. _showSelectBtn = YES;
  407. }
  408. }
  409. - (void)setAllowCrop:(BOOL)allowCrop {
  410. _allowCrop = _maxImagesCount > 1 ? NO : allowCrop;
  411. if (allowCrop) { // 允许裁剪的时候,不能选原图和GIF
  412. self.allowPickingOriginalPhoto = NO;
  413. self.allowPickingGif = NO;
  414. }
  415. }
  416. - (void)setCircleCropRadius:(NSInteger)circleCropRadius {
  417. _circleCropRadius = circleCropRadius;
  418. self.cropRect = CGRectMake(self.view.tz_width / 2 - circleCropRadius, self.view.tz_height / 2 - _circleCropRadius, _circleCropRadius * 2, _circleCropRadius * 2);
  419. }
  420. - (void)setCropRect:(CGRect)cropRect {
  421. _cropRect = cropRect;
  422. _cropRectPortrait = cropRect;
  423. CGFloat widthHeight = cropRect.size.width;
  424. _cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, cropRect.origin.x, widthHeight, widthHeight);
  425. }
  426. - (void)setTimeout:(NSInteger)timeout {
  427. _timeout = timeout;
  428. if (timeout < 5) {
  429. _timeout = 5;
  430. } else if (_timeout > 60) {
  431. _timeout = 60;
  432. }
  433. }
  434. - (void)setPickerDelegate:(id<TZImagePickerControllerDelegate>)pickerDelegate {
  435. _pickerDelegate = pickerDelegate;
  436. [TZImageManager manager].pickerDelegate = pickerDelegate;
  437. }
  438. - (void)setColumnNumber:(NSInteger)columnNumber {
  439. _columnNumber = columnNumber;
  440. if (columnNumber <= 2) {
  441. _columnNumber = 2;
  442. } else if (columnNumber >= 6) {
  443. _columnNumber = 6;
  444. }
  445. TZAlbumPickerController *albumPickerVc = [self.childViewControllers firstObject];
  446. albumPickerVc.columnNumber = _columnNumber;
  447. [TZImageManager manager].columnNumber = _columnNumber;
  448. }
  449. - (void)setMinPhotoWidthSelectable:(NSInteger)minPhotoWidthSelectable {
  450. _minPhotoWidthSelectable = minPhotoWidthSelectable;
  451. [TZImageManager manager].minPhotoWidthSelectable = minPhotoWidthSelectable;
  452. }
  453. - (void)setMinPhotoHeightSelectable:(NSInteger)minPhotoHeightSelectable {
  454. _minPhotoHeightSelectable = minPhotoHeightSelectable;
  455. [TZImageManager manager].minPhotoHeightSelectable = minPhotoHeightSelectable;
  456. }
  457. - (void)setHideWhenCanNotSelect:(BOOL)hideWhenCanNotSelect {
  458. _hideWhenCanNotSelect = hideWhenCanNotSelect;
  459. [TZImageManager manager].hideWhenCanNotSelect = hideWhenCanNotSelect;
  460. }
  461. - (void)setPhotoPreviewMaxWidth:(CGFloat)photoPreviewMaxWidth {
  462. _photoPreviewMaxWidth = photoPreviewMaxWidth;
  463. if (photoPreviewMaxWidth > 800) {
  464. _photoPreviewMaxWidth = 800;
  465. } else if (photoPreviewMaxWidth < 500) {
  466. _photoPreviewMaxWidth = 500;
  467. }
  468. [TZImageManager manager].photoPreviewMaxWidth = _photoPreviewMaxWidth;
  469. }
  470. - (void)setPhotoWidth:(CGFloat)photoWidth {
  471. _photoWidth = photoWidth;
  472. [TZImageManager manager].photoWidth = photoWidth;
  473. }
  474. - (void)setSelectedAssets:(NSMutableArray *)selectedAssets {
  475. _selectedAssets = selectedAssets;
  476. _selectedModels = [NSMutableArray array];
  477. _selectedAssetIds = [NSMutableArray array];
  478. for (PHAsset *asset in selectedAssets) {
  479. TZAssetModel *model = [TZAssetModel modelWithAsset:asset type:[[TZImageManager manager] getAssetType:asset]];
  480. model.isSelected = YES;
  481. [self addSelectedModel:model];
  482. }
  483. }
  484. - (void)setAllowPickingImage:(BOOL)allowPickingImage {
  485. _allowPickingImage = allowPickingImage;
  486. [TZImagePickerConfig sharedInstance].allowPickingImage = allowPickingImage;
  487. if (!allowPickingImage) {
  488. _allowTakePicture = NO;
  489. }
  490. }
  491. - (void)setAllowPickingVideo:(BOOL)allowPickingVideo {
  492. _allowPickingVideo = allowPickingVideo;
  493. [TZImagePickerConfig sharedInstance].allowPickingVideo = allowPickingVideo;
  494. if (!allowPickingVideo) {
  495. _allowTakeVideo = NO;
  496. }
  497. }
  498. - (void)setPreferredLanguage:(NSString *)preferredLanguage {
  499. _preferredLanguage = preferredLanguage;
  500. [TZImagePickerConfig sharedInstance].preferredLanguage = preferredLanguage;
  501. [self configDefaultBtnTitle];
  502. }
  503. - (void)setLanguageBundle:(NSBundle *)languageBundle {
  504. _languageBundle = languageBundle;
  505. [TZImagePickerConfig sharedInstance].languageBundle = languageBundle;
  506. [self configDefaultBtnTitle];
  507. }
  508. - (void)setSortAscendingByModificationDate:(BOOL)sortAscendingByModificationDate {
  509. _sortAscendingByModificationDate = sortAscendingByModificationDate;
  510. [TZImageManager manager].sortAscendingByModificationDate = sortAscendingByModificationDate;
  511. }
  512. - (void)settingBtnClick {
  513. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  514. }
  515. - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
  516. viewController.automaticallyAdjustsScrollViewInsets = NO;
  517. [super pushViewController:viewController animated:animated];
  518. }
  519. - (void)dealloc {
  520. // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
  521. }
  522. - (void)addSelectedModel:(TZAssetModel *)model {
  523. [_selectedModels addObject:model];
  524. [_selectedAssetIds addObject:model.asset.localIdentifier];
  525. }
  526. - (void)removeSelectedModel:(TZAssetModel *)model {
  527. [_selectedModels removeObject:model];
  528. [_selectedAssetIds removeObject:model.asset.localIdentifier];
  529. }
  530. - (UIImage *)createImageWithColor:(UIColor *)color size:(CGSize)size radius:(CGFloat)radius {
  531. if (!color) {
  532. color = self.iconThemeColor;
  533. }
  534. CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
  535. UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
  536. CGContextRef context = UIGraphicsGetCurrentContext();
  537. CGContextSetFillColorWithColor(context, [color CGColor]);
  538. UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
  539. CGContextAddPath(context, path.CGPath);
  540. CGContextFillPath(context);
  541. UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  542. UIGraphicsEndImageContext();
  543. return image;
  544. }
  545. #pragma mark - UIContentContainer
  546. - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  547. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  548. if (![UIApplication sharedApplication].statusBarHidden) {
  549. if (self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
  550. }
  551. });
  552. if (size.width > size.height) {
  553. _cropRect = _cropRectLandscape;
  554. } else {
  555. _cropRect = _cropRectPortrait;
  556. }
  557. }
  558. #pragma mark - Layout
  559. - (void)viewDidLayoutSubviews {
  560. [super viewDidLayoutSubviews];
  561. CGFloat progressHUDY = CGRectGetMaxY(self.navigationBar.frame);
  562. _progressHUD.frame = CGRectMake(0, progressHUDY, self.view.tz_width, self.view.tz_height - progressHUDY);
  563. _HUDContainer.frame = CGRectMake((self.view.tz_width - 120) / 2, (_progressHUD.tz_height - 90 - progressHUDY) / 2, 120, 90);
  564. _HUDIndicatorView.frame = CGRectMake(45, 15, 30, 30);
  565. _HUDLabel.frame = CGRectMake(0,40, 120, 50);
  566. }
  567. #pragma mark - Public
  568. - (void)cancelButtonClick {
  569. if (self.autoDismiss) {
  570. [self dismissViewControllerAnimated:YES completion:^{
  571. [self callDelegateMethod];
  572. }];
  573. } else {
  574. [self callDelegateMethod];
  575. }
  576. }
  577. - (void)callDelegateMethod {
  578. if ([self.pickerDelegate respondsToSelector:@selector(tz_imagePickerControllerDidCancel:)]) {
  579. [self.pickerDelegate tz_imagePickerControllerDidCancel:self];
  580. }
  581. if (self.imagePickerControllerDidCancelHandle) {
  582. self.imagePickerControllerDidCancelHandle();
  583. }
  584. }
  585. @end
  586. @interface TZAlbumPickerController ()<UITableViewDataSource,UITableViewDelegate> {
  587. UITableView *_tableView;
  588. }
  589. @property (nonatomic, strong) NSMutableArray *albumArr;
  590. @end
  591. @implementation TZAlbumPickerController
  592. - (void)viewDidLoad {
  593. [super viewDidLoad];
  594. self.isFirstAppear = YES;
  595. self.view.backgroundColor = [UIColor whiteColor];
  596. TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  597. self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:imagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:imagePickerVc action:@selector(cancelButtonClick)];
  598. }
  599. - (void)viewWillAppear:(BOOL)animated {
  600. [super viewWillAppear:animated];
  601. TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  602. [imagePickerVc hideProgressHUD];
  603. if (imagePickerVc.allowPickingImage) {
  604. self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Photos"];
  605. } else if (imagePickerVc.allowPickingVideo) {
  606. self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Videos"];
  607. }
  608. if (self.isFirstAppear && !imagePickerVc.navLeftBarButtonSettingBlock) {
  609. self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Back"] style:UIBarButtonItemStylePlain target:nil action:nil];
  610. }
  611. [self configTableView];
  612. }
  613. - (void)configTableView {
  614. if (![[TZImageManager manager] authorizationStatusAuthorized]) {
  615. return;
  616. }
  617. if (self.isFirstAppear) {
  618. TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  619. [imagePickerVc showProgressHUD];
  620. }
  621. TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  622. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  623. [[TZImageManager manager] getAllAlbums:imagePickerVc.allowPickingVideo allowPickingImage:imagePickerVc.allowPickingImage needFetchAssets:!self.isFirstAppear completion:^(NSArray<TZAlbumModel *> *models) {
  624. dispatch_async(dispatch_get_main_queue(), ^{
  625. self->_albumArr = [NSMutableArray arrayWithArray:models];
  626. for (TZAlbumModel *albumModel in self->_albumArr) {
  627. albumModel.selectedModels = imagePickerVc.selectedModels;
  628. }
  629. [imagePickerVc hideProgressHUD];
  630. if (self.isFirstAppear) {
  631. self.isFirstAppear = NO;
  632. [self configTableView];
  633. }
  634. if (!self->_tableView) {
  635. self->_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
  636. self->_tableView.backgroundColor = [UIColor colorWithRed:30/255.0 green:30/255.0 blue:42/255.0 alpha:1.0];
  637. self->_tableView.separatorColor = [UIColor colorWithRed:48.0/255.0 green:48.0/255.0 blue:59.0/255.0 alpha:1.0];
  638. self->_tableView.rowHeight = 84;
  639. self->_tableView.tableFooterView = [[UIView alloc] init];
  640. self->_tableView.dataSource = self;
  641. self->_tableView.delegate = self;
  642. [self->_tableView registerClass:[TZAlbumCell class] forCellReuseIdentifier:@"TZAlbumCell"];
  643. [self.view addSubview:self->_tableView];
  644. } else {
  645. [self->_tableView reloadData];
  646. }
  647. });
  648. }];
  649. });
  650. }
  651. - (void)dealloc {
  652. // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
  653. }
  654. - (UIStatusBarStyle)preferredStatusBarStyle {
  655. TZImagePickerController *tzImagePicker = (TZImagePickerController *)self.navigationController;
  656. if (tzImagePicker && [tzImagePicker isKindOfClass:[TZImagePickerController class]]) {
  657. return tzImagePicker.statusBarStyle;
  658. }
  659. return [super preferredStatusBarStyle];
  660. }
  661. #pragma mark - Layout
  662. - (void)viewDidLayoutSubviews {
  663. [super viewDidLayoutSubviews];
  664. CGFloat top = 0;
  665. CGFloat tableViewHeight = 0;
  666. CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height;
  667. BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
  668. if (self.navigationController.navigationBar.isTranslucent) {
  669. top = naviBarHeight;
  670. if (!isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight];
  671. tableViewHeight = self.view.tz_height - top;
  672. } else {
  673. tableViewHeight = self.view.tz_height;
  674. }
  675. _tableView.frame = CGRectMake(0, top, self.view.tz_width, tableViewHeight);
  676. }
  677. #pragma mark - UITableViewDataSource && Delegate
  678. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  679. return _albumArr.count;
  680. }
  681. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  682. TZAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TZAlbumCell"];
  683. TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  684. cell.albumCellDidLayoutSubviewsBlock = imagePickerVc.albumCellDidLayoutSubviewsBlock;
  685. cell.albumCellDidSetModelBlock = imagePickerVc.albumCellDidSetModelBlock;
  686. cell.selectedCountButton.backgroundColor = imagePickerVc.iconThemeColor;
  687. cell.model = _albumArr[indexPath.row];
  688. cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  689. return cell;
  690. }
  691. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  692. TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init];
  693. photoPickerVc.columnNumber = self.columnNumber;
  694. TZAlbumModel *model = _albumArr[indexPath.row];
  695. photoPickerVc.model = model;
  696. [self.navigationController pushViewController:photoPickerVc animated:YES];
  697. [tableView deselectRowAtIndexPath:indexPath animated:NO];
  698. }
  699. #pragma clang diagnostic pop
  700. @end
  701. @implementation UIImage (MyBundle)
  702. + (UIImage *)tz_imageNamedFromMyBundle:(NSString *)name {
  703. NSBundle *imageBundle = [NSBundle tz_imagePickerBundle];
  704. name = [name stringByAppendingString:@"@2x"];
  705. NSString *imagePath = [imageBundle pathForResource:name ofType:@"png"];
  706. UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
  707. if (!image) {
  708. // 兼容业务方自己设置图片的方式
  709. name = [name stringByReplacingOccurrencesOfString:@"@2x" withString:@""];
  710. image = [UIImage imageNamed:name];
  711. }
  712. return image;
  713. }
  714. @end
  715. @implementation TZCommonTools
  716. + (BOOL)tz_isIPhoneX {
  717. return (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||
  718. CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)) ||
  719. CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(414, 896)) ||
  720. CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(896, 414)));
  721. }
  722. + (CGFloat)tz_statusBarHeight {
  723. return [self tz_isIPhoneX] ? 44 : 20;
  724. }
  725. // 获得Info.plist数据字典
  726. + (NSDictionary *)tz_getInfoDictionary {
  727. NSDictionary *infoDict = [NSBundle mainBundle].localizedInfoDictionary;
  728. if (!infoDict || !infoDict.count) {
  729. infoDict = [NSBundle mainBundle].infoDictionary;
  730. }
  731. if (!infoDict || !infoDict.count) {
  732. NSString *path = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"];
  733. infoDict = [NSDictionary dictionaryWithContentsOfFile:path];
  734. }
  735. return infoDict ? infoDict : @{};
  736. }
  737. + (BOOL)tz_isRightToLeftLayout {
  738. if (@available(iOS 9.0, *)) {
  739. if ([UIView userInterfaceLayoutDirectionForSemanticContentAttribute:UISemanticContentAttributeUnspecified] == UIUserInterfaceLayoutDirectionRightToLeft) {
  740. return YES;
  741. }
  742. } else {
  743. NSString *preferredLanguage = [NSLocale preferredLanguages].firstObject;
  744. if ([preferredLanguage hasPrefix:@"ar-"]) {
  745. return YES;
  746. }
  747. }
  748. return NO;
  749. }
  750. @end
  751. @implementation TZImagePickerConfig
  752. + (instancetype)sharedInstance {
  753. static dispatch_once_t onceToken;
  754. static TZImagePickerConfig *config = nil;
  755. dispatch_once(&onceToken, ^{
  756. if (config == nil) {
  757. config = [[TZImagePickerConfig alloc] init];
  758. config.preferredLanguage = nil;
  759. config.gifPreviewMaxImagesCount = 50;
  760. }
  761. });
  762. return config;
  763. }
  764. - (void)setPreferredLanguage:(NSString *)preferredLanguage {
  765. _preferredLanguage = preferredLanguage;
  766. if (!preferredLanguage || !preferredLanguage.length) {
  767. preferredLanguage = [NSLocale preferredLanguages].firstObject;
  768. }
  769. if ([preferredLanguage rangeOfString:@"zh-Hans"].location != NSNotFound) {
  770. preferredLanguage = @"zh-Hans";
  771. } else if ([preferredLanguage rangeOfString:@"zh-Hant"].location != NSNotFound) {
  772. preferredLanguage = @"zh-Hant";
  773. } else if ([preferredLanguage rangeOfString:@"vi"].location != NSNotFound) {
  774. preferredLanguage = @"vi";
  775. } else {
  776. preferredLanguage = @"en";
  777. }
  778. _languageBundle = [NSBundle bundleWithPath:[[NSBundle tz_imagePickerBundle] pathForResource:preferredLanguage ofType:@"lproj"]];
  779. }
  780. @end