Commit 5abd0c150e207dc714955f949fcd1ef3e2fc789c

Authored by 梁星国
1 parent e69396e3

提交建立

Showing 60 changed files with 9683 additions and 0 deletions
CNLiveImagePickerController/Classes/CNEditVideoController.h 0 → 100755
  1 +//
  2 +// ZLEditVideoController.h
  3 +// ZLPhotoBrowser
  4 +//
  5 +// Created by long on 2017/9/15.
  6 +// Copyright © 2017年 long. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +
  13 +@interface CNEditVideoController : UIViewController
  14 +
  15 +@property (nonatomic, strong) TZAssetModel *model;
  16 +
  17 +@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组
  18 +@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组
  19 +@property (nonatomic, assign) NSInteger currentIndex;
  20 +@property (nonatomic, assign) BOOL isCropImage;
  21 +
  22 +/// Return the new selected photos / 返回最新的选中图片数组
  23 +@property (nonatomic, copy) void (^backButtonEditClickBlock)(BOOL isSelectOriginalPhoto);
  24 +@property (nonatomic, copy) void (^doneButtonEditClickBlock)(BOOL isSelectOriginalPhoto);
  25 +
  26 +
  27 +@end
... ...
CNLiveImagePickerController/Classes/CNEditVideoController.m 0 → 100755
  1 +//
  2 +// ZLEditVideoController.m
  3 +// ZLPhotoBrowser
  4 +//
  5 +// Created by long on 2017/9/15.
  6 +// Copyright © 2017年 long. All rights reserved.
  7 +//
  8 +
  9 +#import "CNEditVideoController.h"
  10 +#import <AVFoundation/AVFoundation.h>
  11 +#import "TZAssetModel.h"
  12 +#import <objc/runtime.h>
  13 +#import <AssetsLibrary/AssetsLibrary.h>
  14 +#import "TZImagePickerController.h"
  15 +#import "TZPhotoPreviewCell.h"
  16 +#import "TZImageCropManager.h"
  17 +
  18 +#define kItemWidth kItemHeight * 2/3
  19 +#define kItemHeight 50
  20 +#define kAPPName @"网家家"
  21 +
  22 +#pragma mark - 显示帧数的CNEditFrameView
  23 +
  24 +@interface CNEditVideoCell : UICollectionViewCell
  25 +
  26 +@property (nonatomic, strong) UIImageView *imageView;
  27 +
  28 +@end
  29 +
  30 +@implementation CNEditVideoCell
  31 +
  32 +- (UIImageView *)imageView
  33 +{
  34 + if (!_imageView) {
  35 + _imageView = [[UIImageView alloc] init];
  36 + _imageView.frame = self.bounds;
  37 + _imageView.contentMode = UIViewContentModeScaleAspectFill;
  38 + _imageView.clipsToBounds = YES;
  39 + [self.contentView addSubview:_imageView];
  40 + }
  41 + return _imageView;
  42 +}
  43 +
  44 +@end
  45 +
  46 +#pragma mark - 协议编辑帧数协议CNEditFrameViewDelegate
  47 +@protocol CNEditFrameViewDelegate <NSObject>
  48 +
  49 +- (void)editViewValidRectChanged;//有效范围更变
  50 +
  51 +- (void)editViewValidRectEndChanged;//有效范围更变结束
  52 +
  53 +@end
  54 +
  55 +#pragma mark - 编辑时视图CNEditFrameView
  56 +@interface CNEditFrameView : UIView
  57 +{
  58 + UIImageView *_leftView;//左视图
  59 + UIImageView *_rightView;//有视图
  60 +}
  61 +
  62 +@property (nonatomic, assign) CGRect validRect;
  63 +@property (nonatomic, weak) id<CNEditFrameViewDelegate> delegate;
  64 +
  65 +@end
  66 +
  67 +@implementation CNEditFrameView
  68 +
  69 +- (instancetype)init
  70 +{
  71 + self = [super init];
  72 + if (self) {
  73 + [self setupUI];
  74 + }
  75 + return self;
  76 +}
  77 +
  78 +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
  79 +{
  80 + //扩大下有效范围
  81 + CGRect left = _leftView.frame;
  82 + left.origin.x -= kItemWidth/2;
  83 + left.size.width += kItemWidth/2;
  84 + CGRect right = _rightView.frame;
  85 + right.size.width += kItemWidth/2;
  86 +
  87 + if (CGRectContainsPoint(left, point)) {
  88 + return _leftView;
  89 + }
  90 + if (CGRectContainsPoint(right, point)) {
  91 + return _rightView;
  92 + }
  93 + return nil;
  94 +}
  95 +
  96 +- (void)setupUI
  97 +{
  98 + self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5];
  99 + self.layer.borderWidth = 2;
  100 + self.layer.borderColor = [UIColor clearColor].CGColor;
  101 +
  102 + _leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"video_edit_left"]];
  103 + _leftView.userInteractionEnabled = YES;
  104 + _leftView.tag = 0;
  105 + UIPanGestureRecognizer *lg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  106 + [_leftView addGestureRecognizer:lg];
  107 + [self addSubview:_leftView];
  108 +
  109 + _rightView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"video_edit_right"]];
  110 + _rightView.userInteractionEnabled = YES;
  111 + _rightView.tag = 1;
  112 + UIPanGestureRecognizer *rg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  113 + [_rightView addGestureRecognizer:rg];
  114 + [self addSubview:_rightView];
  115 +}
  116 +
  117 +- (void)panAction:(UIGestureRecognizer *)pan //滑动收拾实现
  118 +{
  119 + self.layer.borderColor = [[UIColor whiteColor] colorWithAlphaComponent:.4].CGColor;
  120 + CGPoint point = [pan locationInView:self];
  121 +
  122 + CGRect rct = self.validRect;
  123 +
  124 + const CGFloat W = self.width;
  125 + CGFloat minX = 0;
  126 + CGFloat maxX = W;
  127 +
  128 + switch (pan.view.tag) {
  129 + case 0: {
  130 + //left视图响应
  131 + maxX = rct.origin.x + rct.size.width - kItemWidth;
  132 +
  133 + point.x = MAX(minX, MIN(point.x, maxX));
  134 + point.y = 0;
  135 +
  136 + rct.size.width -= (point.x - rct.origin.x);
  137 + rct.origin.x = point.x;
  138 + }
  139 + break;
  140 +
  141 + case 1:
  142 + {
  143 + //right视图响应
  144 + minX = rct.origin.x + kItemWidth/2;
  145 + maxX = W - kItemWidth/2;
  146 +
  147 + point.x = MAX(minX, MIN(point.x, maxX));
  148 + point.y = 0;
  149 +
  150 + rct.size.width = (point.x - rct.origin.x + kItemWidth/2);
  151 + }
  152 + break;
  153 + }
  154 +
  155 + switch (pan.state) {
  156 + case UIGestureRecognizerStateBegan:
  157 + case UIGestureRecognizerStateChanged:
  158 + if (self.delegate && [self.delegate respondsToSelector:@selector(editViewValidRectChanged)]) {
  159 + [self.delegate editViewValidRectChanged];//滑动响应实现
  160 + }
  161 + break;
  162 +
  163 + case UIGestureRecognizerStateEnded:
  164 + case UIGestureRecognizerStateCancelled:
  165 + self.layer.borderColor = [UIColor clearColor].CGColor;
  166 + if (self.delegate && [self.delegate respondsToSelector:@selector(editViewValidRectEndChanged)]) {
  167 + [self.delegate editViewValidRectEndChanged];//滑动结束响应实现
  168 + }
  169 + break;
  170 +
  171 + default:
  172 + break;
  173 + }
  174 +
  175 +
  176 + self.validRect = rct;
  177 +}
  178 +
  179 +- (void)setValidRect:(CGRect)validRect//根据范围
  180 +{
  181 + _validRect = validRect;
  182 + _leftView.frame = CGRectMake(validRect.origin.x - kItemWidth/4, 0, kItemWidth/2, kItemHeight);
  183 + _rightView.frame = CGRectMake(validRect.origin.x+validRect.size.width-kItemWidth/4, 0, kItemWidth/2, kItemHeight);
  184 +
  185 + [self setNeedsDisplay];
  186 +}
  187 +
  188 +- (void)drawRect:(CGRect)rect
  189 +{
  190 + CGContextRef context = UIGraphicsGetCurrentContext();
  191 +
  192 + CGContextClearRect(context, self.validRect);
  193 +
  194 + CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
  195 + CGContextSetLineWidth(context, 4.0);
  196 +
  197 + CGPoint topPoints[2];
  198 + topPoints[0] = CGPointMake(self.validRect.origin.x, 0);
  199 + topPoints[1] = CGPointMake(self.validRect.origin.x+self.validRect.size.width, 0);
  200 +
  201 + CGPoint bottomPoints[2];
  202 + bottomPoints[0] = CGPointMake(self.validRect.origin.x, kItemHeight);
  203 + bottomPoints[1] = CGPointMake(self.validRect.origin.x+self.validRect.size.width, kItemHeight);
  204 +
  205 + CGContextAddLines(context, topPoints, 2);
  206 + CGContextAddLines(context, bottomPoints, 2);
  207 +
  208 + CGContextDrawPath(context, kCGPathStroke);
  209 +}
  210 +
  211 +@end
  212 +
  213 +
  214 +#pragma mark - 编辑视频控制器CNEditVideoController
  215 +@interface CNEditVideoController () <UIScrollViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate, CNEditFrameViewDelegate>
  216 +{
  217 + UIView *_bottomView;
  218 + UIButton *_cancelBtn;
  219 + UIButton *_doneBtn;
  220 +
  221 + NSTimer *_timer;
  222 +
  223 + //下方collectionview偏移量
  224 + CGFloat _offsetX;
  225 + BOOL _orientationChanged;
  226 +
  227 + UIView *_indicatorLine;
  228 +
  229 + AVAsset *_avAsset;
  230 +
  231 + NSTimeInterval _interval;
  232 +
  233 + NSInteger _measureCount;
  234 + NSOperationQueue *_queue;
  235 + NSMutableDictionary<NSString *, UIImage *> *_imageCache;
  236 + NSMutableDictionary<NSString *, NSBlockOperation *> *_opCache;
  237 +}
  238 +
  239 +@property (nonatomic, strong) AVPlayerLayer *playerLayer;
  240 +@property (nonatomic, strong) UICollectionView *collectionView;
  241 +@property (nonatomic, strong) CNEditFrameView *editView;
  242 +@property (nonatomic, strong) AVAssetImageGenerator *generator;
  243 +
  244 +@end
  245 +
  246 +@implementation CNEditVideoController
  247 +
  248 +- (void)dealloc
  249 +{
  250 + [_queue cancelAllOperations];
  251 + [self stopTimer];
  252 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  253 +// NSLog(@"---- %s", __FUNCTION__);
  254 +}
  255 +
  256 +- (AVAssetImageGenerator *)generator
  257 +{
  258 + if (!_generator) {
  259 + _generator = [[AVAssetImageGenerator alloc] initWithAsset:_avAsset];
  260 + _generator.maximumSize = CGSizeMake(kItemWidth*4, kItemHeight*4);
  261 + _generator.appliesPreferredTrackTransform = YES;
  262 + _generator.requestedTimeToleranceBefore = kCMTimeZero;
  263 + _generator.requestedTimeToleranceAfter = kCMTimeZero;
  264 + _generator.apertureMode = AVAssetImageGeneratorApertureModeProductionAperture;
  265 + }
  266 + return _generator;
  267 +}
  268 +
  269 +- (void)viewDidLoad {
  270 + [super viewDidLoad];
  271 + [self setupUI];
  272 + [self analysisAssetImages];
  273 +
  274 + _queue = [[NSOperationQueue alloc] init];
  275 + _queue.maxConcurrentOperationCount = 3;
  276 +
  277 + _imageCache = [NSMutableDictionary dictionary];
  278 + _opCache = [NSMutableDictionary dictionary];
  279 +
  280 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationChanged:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
  281 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appResignActive) name:UIApplicationWillResignActiveNotification object:nil];
  282 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
  283 +}
  284 +
  285 +- (void)viewWillAppear:(BOOL)animated
  286 +{
  287 + [super viewWillAppear:animated];
  288 + [UIApplication sharedApplication].statusBarHidden = YES;
  289 + self.navigationController.navigationBar.hidden = YES;
  290 +}
  291 +
  292 +- (void)viewWillDisappear:(BOOL)animated
  293 +{
  294 + [super viewWillDisappear:animated];
  295 + self.navigationController.navigationBar.hidden = NO;
  296 +}
  297 +
  298 +- (void)viewDidLayoutSubviews
  299 +{
  300 + [super viewDidLayoutSubviews];
  301 +
  302 + UIEdgeInsets inset = UIEdgeInsetsZero;
  303 + if (@available(iOS 11, *)) {
  304 + inset = self.view.safeAreaInsets;
  305 + }
  306 +
  307 + self.playerLayer.frame = CGRectMake(15, inset.top>0?inset.top:30, KScreenWidth-30, KScreenHeight-160-inset.bottom);
  308 +
  309 + self.editView.frame = CGRectMake((KScreenWidth-kItemWidth*10)/2, KScreenHeight-100-inset.bottom, kItemWidth*10, kItemHeight);
  310 + self.editView.validRect = self.editView.bounds;
  311 + self.collectionView.frame = CGRectMake(inset.left, KScreenHeight-100-inset.bottom, KScreenWidth-inset.left-inset.right, kItemHeight);
  312 +
  313 + CGFloat leftOffset = ((KScreenWidth-kItemWidth*10)/2-inset.left);
  314 + CGFloat rightOffset = ((KScreenWidth-kItemWidth*10)/2-inset.right);
  315 + [self.collectionView setContentInset:UIEdgeInsetsMake(0, leftOffset, 0, rightOffset)];
  316 + [self.collectionView setContentOffset:CGPointMake(_offsetX-leftOffset, 0)];
  317 +
  318 + CGFloat bottomViewH = 44;
  319 + CGFloat bottomBtnH = 30;
  320 + _bottomView.frame = CGRectMake(0, KScreenHeight-bottomViewH-inset.bottom, KScreenWidth, kItemHeight);
  321 + _cancelBtn.frame = CGRectMake(10+inset.left, 7, 60, bottomBtnH);
  322 + _doneBtn.frame = CGRectMake(KScreenWidth-70-inset.right, 7, 60, bottomBtnH);
  323 +
  324 + [self.playerLayer setBackgroundColor:[UIColor clearColor].CGColor];
  325 +}
  326 +
  327 +#pragma mark - notifies
  328 +//设备旋转
  329 +- (void)deviceOrientationChanged:(NSNotification *)notify
  330 +{
  331 + _offsetX = self.collectionView.contentOffset.x + self.collectionView.contentInset.left;
  332 + _orientationChanged = YES;
  333 +}
  334 +
  335 +- (void)appResignActive
  336 +{
  337 + [self stopTimer];
  338 +}
  339 +
  340 +- (void)appBecomeActive
  341 +{
  342 + [self startTimer];
  343 +}
  344 +
  345 +- (void)setupUI
  346 +{
  347 + //禁用返回手势
  348 + if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
  349 + self.navigationController.interactivePopGestureRecognizer.delegate = nil;
  350 + self.navigationController.interactivePopGestureRecognizer.enabled = NO;
  351 + }
  352 +
  353 + self.view.backgroundColor = [UIColor blackColor];
  354 +
  355 + self.playerLayer = [[AVPlayerLayer alloc] init];
  356 + [self.view.layer addSublayer:self.playerLayer];
  357 +
  358 + UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
  359 + layout.itemSize = CGSizeMake(kItemWidth, kItemHeight);
  360 + layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  361 + layout.minimumInteritemSpacing = 0;
  362 + layout.minimumLineSpacing = 0;
  363 +
  364 + self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
  365 + self.collectionView.delegate = self;
  366 + self.collectionView.dataSource = self;
  367 + self.collectionView.backgroundColor = [UIColor clearColor];
  368 + self.collectionView.showsHorizontalScrollIndicator = NO;
  369 + [self.collectionView registerClass:CNEditVideoCell.class forCellWithReuseIdentifier:@"CNEditVideoCell"];
  370 +
  371 + [self.view addSubview:self.collectionView];
  372 +
  373 + [self creatBottomView];
  374 +
  375 + self.editView = [[CNEditFrameView alloc] init];
  376 + self.editView.delegate = self;
  377 + [self.view addSubview:self.editView];
  378 +
  379 + _indicatorLine = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2, kItemHeight)];
  380 + _indicatorLine.backgroundColor = [RGBOF(0x0BBE06) colorWithAlphaComponent:.7];
  381 +}
  382 +
  383 +- (void)creatBottomView
  384 +{
  385 + //下方视图
  386 + _bottomView = [[UIView alloc] init];
  387 + _bottomView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.7];
  388 + [self.view addSubview:_bottomView];
  389 +
  390 + _cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  391 + _cancelBtn.titleLabel.font = [UIFont systemFontOfSize:15];
  392 + [_cancelBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  393 + [_cancelBtn setTitle:@"取消" forState:UIControlStateNormal];
  394 + [_cancelBtn addTarget:self action:@selector(cancelBtn_click) forControlEvents:UIControlEventTouchUpInside];
  395 + [_bottomView addSubview:_cancelBtn];
  396 +
  397 + _doneBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  398 + [_doneBtn setTitle:@"完成" forState:UIControlStateNormal];
  399 + [_doneBtn setBackgroundColor:[UIColor clearColor]];
  400 + [_doneBtn setTitleColor:RGBOF(0x0BBE06) forState:UIControlStateNormal];
  401 + _doneBtn.titleLabel.font = [UIFont systemFontOfSize:15];
  402 + _doneBtn.layer.masksToBounds = YES;
  403 + _doneBtn.layer.cornerRadius = 3.0f;
  404 + [_doneBtn addTarget:self action:@selector(btnDone_click) forControlEvents:UIControlEventTouchUpInside];
  405 + [_bottomView addSubview:_doneBtn];
  406 +}
  407 +
  408 +#pragma mark - 解析视频每一帧图片
  409 +- (void)analysisAssetImages
  410 +{
  411 + NSTimeInterval duration = 0.0;
  412 + if ([self.model.asset isKindOfClass:[PHAsset class]]) {
  413 + PHAsset *asset = self.model.asset;
  414 + duration = asset.duration;
  415 + }else if([self.model.asset isKindOfClass:[ALAsset class]]){
  416 + duration = [[self.model.asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  417 + }
  418 +
  419 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  420 + _interval = _tzImagePickerVc.maxEditVideoTime/10.0;
  421 + _measureCount = (NSInteger)(duration / _interval);
  422 + ///播放视频的
  423 + if ([self.model.asset isKindOfClass:[PHAsset class]]) {//PHAsset
  424 + __weak typeof(self) weakSelf = self;
  425 + [[PHCachingImageManager defaultManager] requestPlayerItemForVideo:self.model.asset options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
  426 + dispatch_async(dispatch_get_main_queue(), ^{
  427 + __strong typeof(weakSelf) strongSelf = weakSelf;
  428 + if (!playerItem) return;
  429 + AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
  430 + strongSelf.playerLayer.player = player;
  431 + [strongSelf startTimer];
  432 + });
  433 +
  434 + }];
  435 +
  436 + ///截取视频帧数
  437 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  438 + options.version = PHVideoRequestOptionsVersionOriginal;
  439 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  440 + options.networkAccessAllowed = YES;
  441 + [[PHImageManager defaultManager] requestAVAssetForVideo:self.model.asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
  442 + __strong typeof(weakSelf) strongSelf = weakSelf;
  443 + strongSelf->_avAsset = asset;
  444 + dispatch_async(dispatch_get_main_queue(), ^{
  445 + [strongSelf.collectionView reloadData];
  446 + });
  447 + }];
  448 +
  449 + }else if([self.model.asset isKindOfClass:[ALAsset class]]){//ALAsset
  450 + ///播放视频的
  451 + ALAsset *alAsset = (ALAsset *)self.model.asset;
  452 + ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation];
  453 + NSString *uti = [defaultRepresentation UTI];
  454 + NSURL *videoURL = [[alAsset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
  455 + AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
  456 + AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
  457 + self.playerLayer.player = player;
  458 + [self startTimer];
  459 +
  460 + ///截取视频帧数
  461 + NSURL *videoURL_al =[self.model.asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs
  462 + AVAsset *videoAsset = [AVURLAsset assetWithURL:videoURL];
  463 + _avAsset = videoAsset ;
  464 + [self.collectionView reloadData];
  465 +
  466 + }
  467 +
  468 +}
  469 +
  470 +#pragma mark - action
  471 +- (void)cancelBtn_click
  472 +{
  473 + [self stopTimer];
  474 +
  475 + if (_playerLayer) {
  476 + [_playerLayer.player pause];
  477 + _playerLayer = nil;
  478 + }
  479 +
  480 + if (self.backButtonEditClickBlock) {
  481 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  482 + self.backButtonEditClickBlock(_tzImagePickerVc.isSelectOriginalPhoto);
  483 + }
  484 + UIViewController *vc = [self.navigationController popViewControllerAnimated:NO];
  485 + if (!vc) {
  486 + [self dismissViewControllerAnimated:YES completion:nil];
  487 + }
  488 +}
  489 +
  490 +- (void)stopPlay {
  491 + if (self.playerLayer) {
  492 + [self.playerLayer.player pause];
  493 + self.playerLayer = nil;
  494 + }
  495 +}
  496 +
  497 +- (void)btnDone_click
  498 +{
  499 + [self stopTimer];
  500 +
  501 +
  502 +
  503 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  504 + [_tzImagePickerVc showProgressHUD];
  505 + __weak typeof(self) weakSelf = self;
  506 +
  507 + [self exportEditVideoForAsset:_avAsset range:[self getTimeRange] complete:^(BOOL isSuc, id asset) {
  508 + [_tzImagePickerVc hideProgressHUD];
  509 + if (isSuc) {
  510 + [self stopPlay];
  511 + TZAssetModel *editModel = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypeVideo];
  512 +
  513 + // 如果没有选中过照片 点击确定时选中当前预览的照片
  514 + if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) {
  515 + [_tzImagePickerVc addSelectedModel:editModel];
  516 + }
  517 +
  518 + if (weakSelf.doneButtonEditClickBlock) {
  519 + weakSelf.doneButtonEditClickBlock(_tzImagePickerVc.isSelectOriginalPhoto);
  520 + }
  521 + [_tzImagePickerVc hideProgressHUD];
  522 + }else{
  523 + [_tzImagePickerVc showAlertWithTitle:@"编辑失败"];
  524 + }
  525 +
  526 + }];
  527 +}
  528 +#pragma mark - 截取视频
  529 +
  530 +- (void)exportEditVideoForAsset:(AVAsset *)asset range:(CMTimeRange)range complete:(void (^)(BOOL, id))complete
  531 +{
  532 + __weak typeof(self) weakSelf = self;
  533 + [self export:asset range:range presetName:AVAssetExportPresetPassthrough renderSize:CGSizeZero imageSize:CGSizeZero effectImage:nil birthRate:0 velocity:0 complete:^(NSString *exportFilePath, NSError *error) {
  534 + if (!error) {
  535 + [weakSelf saveVideoToAblum:[NSURL fileURLWithPath:exportFilePath] completion:^(BOOL isSuc, id asset) {
  536 + dispatch_async(dispatch_get_main_queue(), ^{
  537 + if (complete) complete(isSuc, asset);
  538 + });
  539 + }];
  540 + } else {
  541 + dispatch_async(dispatch_get_main_queue(), ^{
  542 + if (complete) complete(NO, nil);
  543 + });
  544 + }
  545 + }];
  546 +}
  547 +
  548 +///保存视频到相册
  549 +- (void)saveVideoToAblum:(NSURL *)url completion:(void (^)(BOOL, id))completion
  550 +{
  551 + if (iOS8Later) {
  552 + __weak typeof(self) weakSelf = self;
  553 + PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
  554 + if (status == PHAuthorizationStatusDenied) {
  555 + if (completion) completion(NO, nil);
  556 + } else if (status == PHAuthorizationStatusRestricted) {
  557 + if (completion) completion(NO, nil);
  558 + } else {
  559 + __block PHObjectPlaceholder *placeholderAsset=nil;
  560 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  561 + PHAssetChangeRequest *newAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
  562 + placeholderAsset = newAssetRequest.placeholderForCreatedAsset;
  563 + } completionHandler:^(BOOL success, NSError * _Nullable error) {
  564 + if (!success) {
  565 + if (completion) completion(NO, nil);
  566 + return;
  567 + }
  568 + PHAsset *asset = [self getAssetFromlocalIdentifier:placeholderAsset.localIdentifier];
  569 + PHAssetCollection *desCollection = [weakSelf getDestinationCollection];
  570 + if (!desCollection) completion(NO, nil);
  571 +
  572 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  573 + [[PHAssetCollectionChangeRequest changeRequestForAssetCollection:desCollection] addAssets:@[asset]];
  574 + } completionHandler:^(BOOL success, NSError * _Nullable error) {
  575 + if (completion) completion(success, asset);
  576 + }];
  577 + }];
  578 + }
  579 + }else{
  580 +
  581 + ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];
  582 + [assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) {
  583 + if (error) {
  584 + NSLog(@"保存视频出错:%@",error.localizedDescription);
  585 + if (completion) {
  586 + completion(NO,nil);
  587 + }
  588 + } else {
  589 + [assetLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
  590 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  591 + if (completion) {
  592 + completion(YES,asset);
  593 + }
  594 + });
  595 + } failureBlock:^(NSError *error) {
  596 +
  597 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  598 + if (completion) {
  599 + completion(NO,nil);
  600 + }
  601 + });
  602 +
  603 + }];
  604 + }
  605 + }];
  606 +
  607 + }
  608 +
  609 +}
  610 +
  611 +- (PHAsset *)getAssetFromlocalIdentifier:(NSString *)localIdentifier{
  612 + if(localIdentifier == nil){
  613 + NSLog(@"Cannot get asset from localID because it is nil");
  614 + return nil;
  615 + }
  616 + PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil];
  617 + if(result.count){
  618 + return result[0];
  619 + }
  620 + return nil;
  621 +}
  622 +
  623 +//获取自定义相册
  624 +- (PHAssetCollection *)getDestinationCollection
  625 +{
  626 + //找是否已经创建自定义相册
  627 + PHFetchResult<PHAssetCollection *> *collectionResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  628 + for (PHAssetCollection *collection in collectionResult) {
  629 + if ([collection.localizedTitle isEqualToString:kAPPName]) {
  630 + return collection;
  631 + }
  632 + }
  633 + //新建自定义相册
  634 + __block NSString *collectionId = nil;
  635 + NSError *error = nil;
  636 + [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
  637 + collectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:kAPPName].placeholderForCreatedAssetCollection.localIdentifier;
  638 + } error:&error];
  639 + if (error) {
  640 + return nil;
  641 + }
  642 + return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[collectionId] options:nil].lastObject;
  643 +}
  644 +
  645 +- (void)export:(AVAsset *)asset range:(CMTimeRange)range presetName:(NSString *)presetName renderSize:(CGSize)renderSize imageSize:(CGSize)imageSize effectImage:(UIImage *)effectImage birthRate:(NSInteger)birthRate velocity:(CGFloat)velocity complete:(void (^)(NSString *exportFilePath, NSError *error))complete
  646 +{
  647 + NSString *exportFilePath = [self getVideoExportFilePath];
  648 +
  649 + AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:presetName];
  650 +
  651 + NSURL *exportFileUrl = [NSURL fileURLWithPath:exportFilePath];
  652 +
  653 + exportSession.outputURL = exportFileUrl;
  654 + exportSession.outputFileType = AVFileTypeMPEG4;
  655 + exportSession.timeRange = range;
  656 + // exportSession.shouldOptimizeForNetworkUse = YES;
  657 + if (!CGSizeEqualToSize(renderSize, CGSizeZero)) {
  658 + AVMutableVideoComposition *com = [self getVideoComposition:asset renderSize:renderSize imageSize:imageSize effectImage:effectImage birthRate:birthRate velocity:velocity];
  659 + if (!com) {
  660 + if (complete) {
  661 + complete(nil, [NSError errorWithDomain:@"视频裁剪导出失败" code:-1 userInfo:@{@"message": @"视频对象格式可能有错误,没有检测到视频通道"}]);
  662 + }
  663 + return;
  664 + }
  665 + exportSession.videoComposition = com;
  666 + }
  667 +
  668 + [exportSession exportAsynchronouslyWithCompletionHandler:^{
  669 + BOOL suc = NO;
  670 + switch ([exportSession status]) {
  671 + case AVAssetExportSessionStatusFailed:
  672 + NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
  673 + break;
  674 + case AVAssetExportSessionStatusCancelled:
  675 + NSLog(@"Export canceled");
  676 + break;
  677 +
  678 + case AVAssetExportSessionStatusCompleted:{
  679 + NSLog(@"Export completed");
  680 + suc = YES;
  681 + }
  682 + break;
  683 +
  684 + default:
  685 + NSLog(@"Export other");
  686 + break;
  687 + }
  688 +
  689 + if (complete) {
  690 + complete(suc?exportFilePath:nil, suc?nil:exportSession.error);
  691 + if (!suc) {
  692 + [exportSession cancelExport];
  693 + }
  694 + }
  695 + }];
  696 +}
  697 +
  698 +- (NSString *)getVideoExportFilePath
  699 +{
  700 + NSString *format = @"mp4";
  701 +
  702 + NSString *exportFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self getUniqueStrByUUID], format]];
  703 +
  704 + return exportFilePath;
  705 +}
  706 +
  707 +- (NSString *)getUniqueStrByUUID
  708 +{
  709 + CFUUIDRef uuidObj = CFUUIDCreate(nil);//create a new UUID
  710 +
  711 + //get the string representation of the UUID
  712 + CFStringRef uuidString = CFUUIDCreateString(nil, uuidObj);
  713 +
  714 + NSString *str = [NSString stringWithString:(__bridge NSString *)uuidString];
  715 +
  716 + CFRelease(uuidObj);
  717 + CFRelease(uuidString);
  718 +
  719 + return [str lowercaseString];
  720 +}
  721 +
  722 +
  723 +- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset renderSize:(CGSize)renderSize imageSize:(CGSize)imageSize effectImage:(UIImage *)effectImage birthRate:(NSInteger)birthRate velocity:(CGFloat)velocity
  724 +{
  725 + AVMutableComposition *composition = [AVMutableComposition composition];
  726 + //视频通道
  727 + AVMutableCompositionTrack *assetVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
  728 + //音频通道
  729 + AVMutableCompositionTrack *assetAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  730 +
  731 + NSError *error = nil;
  732 + //裁剪时长
  733 + CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration);
  734 +
  735 + AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;//视频
  736 + AVAssetTrack *audioTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;//音频
  737 +
  738 + if (!videoTrack) {
  739 + return nil;
  740 + }
  741 + [assetVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:&error];
  742 + NSLog(@"%@", error);
  743 + if (audioTrack) {
  744 + [assetAudioTrack insertTimeRange:timeRange ofTrack:audioTrack atTime:kCMTimeZero error:&error];
  745 + NSLog(@"%@", error);
  746 + }
  747 +
  748 + if (error) {
  749 + return nil;
  750 + }
  751 +
  752 + AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  753 + instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration);
  754 +
  755 + //处理视频旋转
  756 + AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:assetVideoTrack];
  757 + [layerInstruction setOpacity:0.0 atTime:assetVideoTrack.timeRange.duration];
  758 + //视频旋转,获取视频旋转角度,然后旋转对应角度,保持视频方向正确
  759 + CGFloat degree = [self getVideoDegree:videoTrack];
  760 + CGSize naturalSize = assetVideoTrack.naturalSize;
  761 +
  762 + CGAffineTransform mixedTransform = CGAffineTransformIdentity;
  763 + //处理renderSize,不能大于视频宽高
  764 + CGFloat videoWidth = (degree==0 || degree==M_PI) ? naturalSize.width : naturalSize.height;
  765 + CGFloat videoHeight = (degree==0 || degree==M_PI) ? naturalSize.height : naturalSize.width;
  766 + CGSize cropSize = CGSizeMake(MIN(videoWidth, renderSize.width), MIN(videoHeight, renderSize.height));
  767 + CGFloat x, y;
  768 + if (degree == M_PI_2) {
  769 + //顺时针 90°
  770 + CGAffineTransform t = CGAffineTransformMakeTranslation(naturalSize.height,.0);
  771 + CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI_2);
  772 + //x为正向下 y为正向左
  773 + x = -(videoHeight-cropSize.height)/2;
  774 + y = (videoWidth-cropSize.width)/2;
  775 + mixedTransform = CGAffineTransformTranslate(t1, x, y);
  776 + } else if (degree == M_PI) {
  777 + //顺时针 180°
  778 + CGAffineTransform t = CGAffineTransformMakeTranslation(naturalSize.width, naturalSize.height);
  779 + CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI);
  780 + //x为正向左 y为正向上
  781 + x = (videoWidth-cropSize.width)/2;
  782 + y = (videoHeight-cropSize.height)/2;
  783 + mixedTransform = CGAffineTransformTranslate(t1, x, y);
  784 + } else if (degree == (M_PI_2 * 3)) {
  785 + //顺时针 270°
  786 + CGAffineTransform t = CGAffineTransformMakeTranslation(.0, naturalSize.width);
  787 + CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI_2*3);
  788 + //x为正向上 y为正向右
  789 + x = (videoHeight-cropSize.height)/2;
  790 + y = -(videoWidth-cropSize.width)/2;
  791 + mixedTransform = CGAffineTransformTranslate(t1, x, y);
  792 + } else {
  793 + //x为正向右 y为正向下
  794 + x = -(videoWidth-cropSize.width)/2;
  795 + y = -(videoHeight-cropSize.height)/2;
  796 + mixedTransform = CGAffineTransformMakeTranslation(x, y);
  797 + }
  798 +
  799 + [layerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  800 +
  801 + //管理所有需要处理的视频
  802 + AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  803 + videoComposition.frameDuration = CMTimeMake(1, 30);
  804 + videoComposition.renderScale = 1;
  805 + videoComposition.renderSize = cropSize;
  806 +
  807 + instruction.layerInstructions = @[layerInstruction];
  808 + videoComposition.instructions = @[instruction];
  809 +
  810 + return videoComposition;
  811 +}
  812 +
  813 +- (CGFloat)getVideoDegree:(AVAssetTrack *)videoTrack
  814 +{
  815 + CGAffineTransform tf = videoTrack.preferredTransform;
  816 +
  817 + CGFloat degree = 0;
  818 + if (tf.b == 1.0 && tf.c == -1.0) {
  819 + degree = M_PI_2;
  820 + } else if (tf.a == -1.0 && tf.d == -1.0) {
  821 + degree = M_PI;
  822 + } else if (tf.b == -1.0 && tf.c == 1.0) {
  823 + degree = M_PI_2 * 3;
  824 + }
  825 + return degree;
  826 +}
  827 +
  828 +
  829 +
  830 +#pragma mark - timer
  831 +- (void)startTimer
  832 +{
  833 + [self stopTimer];
  834 +
  835 + CGFloat duration = _interval * self.editView.validRect.size.width / (kItemWidth);
  836 + _timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(playPartVideo:) userInfo:nil repeats:YES];
  837 + [_timer fire];
  838 + [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
  839 +
  840 + _indicatorLine.frame = CGRectMake(self.editView.validRect.origin.x, 0, 4, kItemHeight);
  841 + [self.editView addSubview:_indicatorLine];
  842 + [UIView animateWithDuration:duration delay:.0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear animations:^{
  843 + _indicatorLine.frame = CGRectMake(CGRectGetMaxX(self.editView.validRect)-2, 0, 2, kItemHeight);
  844 + } completion:nil];
  845 +}
  846 +
  847 +- (void)stopTimer
  848 +{
  849 + [_timer invalidate];
  850 + _timer = nil;
  851 + [_indicatorLine removeFromSuperview];
  852 + [self.playerLayer.player pause];
  853 +}
  854 +
  855 +- (CMTime)getStartTime
  856 +{
  857 + CGRect rect = [self.collectionView convertRect:self.editView.validRect fromView:self.editView];
  858 + CGFloat s = MAX(0, _interval * rect.origin.x / (kItemWidth));
  859 + return CMTimeMakeWithSeconds(s, self.playerLayer.player.currentTime.timescale);
  860 +}
  861 +
  862 +- (CMTimeRange)getTimeRange
  863 +{
  864 + CMTime start = [self getStartTime];
  865 + CGFloat d = _interval * self.editView.validRect.size.width / (kItemWidth);
  866 + CMTime duration = CMTimeMakeWithSeconds(d, self.playerLayer.player.currentTime.timescale);
  867 + return CMTimeRangeMake(start, duration);
  868 +}
  869 +
  870 +- (void)playPartVideo:(NSTimer *)timer
  871 +{
  872 + [self.playerLayer.player play];
  873 + [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
  874 +}
  875 +
  876 +#pragma mark - edit view delegate
  877 +- (void)editViewValidRectChanged
  878 +{
  879 + [self stopTimer];
  880 + [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
  881 +}
  882 +
  883 +- (void)editViewValidRectEndChanged
  884 +{
  885 + [self startTimer];
  886 +}
  887 +
  888 +#pragma mark - scroll view delegate
  889 +- (void)scrollViewDidScroll:(UIScrollView *)scrollView
  890 +{
  891 + if (!self.playerLayer.player || _orientationChanged) {
  892 + _orientationChanged = NO;
  893 + return;
  894 + }
  895 + [self stopTimer];
  896 + [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];
  897 +}
  898 +
  899 +- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
  900 +{
  901 + if (!decelerate) {
  902 + [self startTimer];
  903 + }
  904 +}
  905 +
  906 +- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
  907 +{
  908 + [self startTimer];
  909 +}
  910 +
  911 +#pragma mark - collection view data sources
  912 +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  913 +{
  914 + return _measureCount;
  915 +}
  916 +
  917 +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  918 +{
  919 + CNEditVideoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CNEditVideoCell" forIndexPath:indexPath];
  920 +
  921 + UIImage *image = _imageCache[@(indexPath.row).stringValue];
  922 + if (image) {
  923 + cell.imageView.image = image;
  924 + }
  925 +
  926 + return cell;
  927 +}
  928 +
  929 +static const char _CNOperationCellKey;
  930 +- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
  931 +{
  932 + if (!_avAsset) return;
  933 +
  934 + if (_imageCache[@(indexPath.row).stringValue] || _opCache[@(indexPath.row).stringValue]) {
  935 + return;
  936 + }
  937 +
  938 + NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
  939 + NSInteger row = indexPath.row;
  940 + NSInteger i = row * _interval;
  941 +
  942 + CMTime time = CMTimeMake((i+0.35) * _avAsset.duration.timescale, _avAsset.duration.timescale);
  943 +
  944 + NSError *error = nil;
  945 + CGImageRef cgImg = [self.generator copyCGImageAtTime:time actualTime:NULL error:&error];
  946 + if (!error && cgImg) {
  947 + UIImage *image = [UIImage imageWithCGImage:cgImg];
  948 + CGImageRelease(cgImg);
  949 +
  950 + [_imageCache setValue:image forKey:@(row).stringValue];
  951 +
  952 + dispatch_async(dispatch_get_main_queue(), ^{
  953 +
  954 + NSIndexPath *nowIndexPath = [collectionView indexPathForCell:cell];
  955 + if (row == nowIndexPath.row) {
  956 + [(CNEditVideoCell *)cell imageView].image = image;
  957 + } else {
  958 + UIImage *cacheImage = _imageCache[@(nowIndexPath.row).stringValue];
  959 + if (cacheImage) {
  960 + [(CNEditVideoCell *)cell imageView].image = cacheImage;
  961 + }
  962 + }
  963 + });
  964 + [_opCache removeObjectForKey:@(row).stringValue];
  965 + }
  966 + objc_removeAssociatedObjects(cell);
  967 + }];
  968 + [_queue addOperation:op];
  969 + [_opCache setValue:op forKey:@(indexPath.row).stringValue];
  970 +
  971 + objc_setAssociatedObject(cell, &_CNOperationCellKey, op, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  972 +}
  973 +
  974 +- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
  975 +{
  976 + NSBlockOperation *op = objc_getAssociatedObject(cell, &_CNOperationCellKey);
  977 + if (op) {
  978 + [op cancel];
  979 + objc_removeAssociatedObjects(cell);
  980 + [_opCache removeObjectForKey:@(indexPath.row).stringValue];
  981 + }
  982 +}
  983 +
  984 +- (void)didReceiveMemoryWarning {
  985 + [super didReceiveMemoryWarning];
  986 + // Dispose of any resources that can be recreated.
  987 +}
  988 +
  989 +/*
  990 +#pragma mark - Navigation
  991 +
  992 +// In a storyboard-based application, you will often want to do a little preparation before navigation
  993 +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
  994 + // Get the new view controller using [segue destinationViewController].
  995 + // Pass the selected object to the new view controller.
  996 +}
  997 +*/
  998 +
  999 +@end
... ...
CNLiveImagePickerController/Classes/CNImagePickerController.h 0 → 100644
  1 +//
  2 +// CNTZImagePickerControllerViewController.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/8/22.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImagePickerController.h"
  10 +
  11 +@interface CNImagePickerController : TZImagePickerController
  12 +
  13 +/**
  14 + 配置
  15 + */
  16 +- (void)configTZImagePicker;
  17 +
  18 +@end
... ...
CNLiveImagePickerController/Classes/CNImagePickerController.m 0 → 100644
  1 +//
  2 +// CNTZImagePickerControllerViewController.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/8/22.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNImagePickerController.h"
  10 +
  11 +@interface CNImagePickerController ()
  12 +
  13 +@end
  14 +
  15 +@implementation CNImagePickerController
  16 +
  17 +- (void)viewDidLoad {
  18 + [super viewDidLoad];
  19 +
  20 +}
  21 +
  22 +/**
  23 + 配置
  24 + */
  25 +- (void)configTZImagePicker{
  26 +
  27 + // imagePickerVc.navigationBar.translucent = NO;
  28 +
  29 +#pragma mark - 五类个性化设置,这些参数都可以不传,此时会走默认设置
  30 + // 1.设置目前已经选中的图片数组
  31 + self.allowTakePicture = NO; // 在内部显示拍照按钮
  32 + self.allowTakeVideo = NO;// 在内部拍摄按钮
  33 + self.videoMaximumDuration = 10; // 视频最大拍摄时间
  34 + [self setUiImagePickerControllerSettingBlock:^(UIImagePickerController *imagePickerController) {
  35 + imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;//拍摄分辨率
  36 + }];
  37 + // imagePickerVc.photoWidth = 1000;
  38 +
  39 + // 2. Set the appearance
  40 + // 2. 在这里设置imagePickerVc的外观
  41 + // if (iOS7Later) {
  42 + // imagePickerVc.navigationBar.barTintColor = [UIColor greenColor];
  43 + // }
  44 + // imagePickerVc.oKButtonTitleColorDisabled = [UIColor lightGrayColor];
  45 + // imagePickerVc.oKButtonTitleColorNormal = [UIColor greenColor];
  46 + // imagePickerVc.navigationBar.translucent = NO;
  47 + self.iconThemeColor = RGBOF(0x00BBE06);// 主体颜色
  48 + self.showPhotoCannotSelectLayer = YES;//达到上限是否有浮层
  49 + self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];//设置达到上限的浮层
  50 + self.photoDefImage = [UIImage imageNamed:@"photo_cell_normal"];
  51 + self.photoSelImage = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06) size:CGSizeMake(22, 22) cornerRadius:11];
  52 + self.photoOriginDefImage = [UIImage imageNamed:@"photo_original_nor"];
  53 +
  54 + // 3. Set allow picking video & photo & originalPhoto or not
  55 + // 3. 设置是否可以选择视频/图片/原图/gif(未开放)
  56 + self.allowPickingVideo = YES;// 显示视频
  57 + self.allowPickingImage = YES;// 显示图片
  58 + self.allowPickingOriginalPhoto = YES; //显示原图
  59 + self.allowPickingGif = NO;// 显示GIF
  60 + self.allowPickingMultipleVideo = YES; // 是否可以多选视频
  61 +
  62 + // 4. 照片排列按修改时间升序
  63 + self.sortAscendingByModificationDate = YES;
  64 +
  65 + // imagePickerVc.minImagesCount = 3;
  66 + // imagePickerVc.alwaysEnableDoneBtn = YES;
  67 +
  68 + // imagePickerVc.minPhotoWidthSelectable = 3000;
  69 + // imagePickerVc.minPhotoHeightSelectable = 2000;
  70 +
  71 + /// 5. Single selection mode, valid when maxImagesCount = 1
  72 + /// 5. 单选模式,maxImagesCount为1时才生效
  73 + self.showSelectBtn = NO;
  74 + self.allowCrop = NO;
  75 + self.needCircleCrop = NO;
  76 + // 设置横屏下的裁剪尺寸
  77 + // imagePickerVc.cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, left, widthHeight, widthHeight);
  78 + /*
  79 + [imagePickerVc setCropViewSettingBlock:^(UIView *cropView) {
  80 + cropView.layer.borderColor = [UIColor redColor].CGColor;
  81 + cropView.layer.borderWidth = 2.0;
  82 + }];*/
  83 +
  84 + //imagePickerVc.allowPreview = NO;
  85 + // 自定义导航栏上的返回按钮
  86 + /*
  87 + [imagePickerVc setNavLeftBarButtonSettingBlock:^(UIButton *leftButton){
  88 + [leftButton setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
  89 + [leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 20)];
  90 + }];
  91 + imagePickerVc.delegate = self;
  92 + */
  93 +
  94 + self.statusBarStyle = UIStatusBarStyleDefault;//状态栏黑色
  95 +
  96 + self.showSelectedIndex = YES; // 设置是否显示图片序号
  97 +
  98 + self.naviBgColor = RGBOF(0xFFFFFF);//导航栏颜色
  99 + self.naviTitleColor = RGBOF(0x282828);//相册title
  100 + self.naviTitleFont = [UIFont fontWithName:@"PingFangSC-Medium" size:18];//title文字大小
  101 + [self setNavLeftBarButtonSettingBlock:^(UIButton *leftButton) {//设置返回按钮图标
  102 + [leftButton setImage:[UIImage imageNamed:@"photo_back"] forState:UIControlStateNormal];//返回按钮图片
  103 + [leftButton setTitle:@"返回" forState:UIControlStateNormal];//设置文字大小
  104 + [leftButton setTitleColor:RGBOF(0x282828) forState:UIControlStateNormal];//设置文字颜色
  105 + leftButton.titleLabel.font = [UIFont systemFontOfSize:15];//设置文字大小
  106 + leftButton.imageEdgeInsets = UIEdgeInsetsMake(0, -7, 0, +7);//设置图片边缘
  107 + }];
  108 + self.barItemTextColor = RGBOF(0x282828);//设置barItem文字颜色
  109 + self.barItemTextFont = [UIFont systemFontOfSize:15];
  110 +
  111 + // 设置首选语言 / Set preferred language
  112 + // imagePickerVc.preferredLanguage = @"zh-Hans";
  113 +
  114 + // 设置languageBundle以使用其它语言 / Set languageBundle to use other language
  115 + // imagePickerVc.languageBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"tz-ru" ofType:@"lproj"]];
  116 +
  117 + /// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等
  118 + //相册
  119 + [self setPhotoPickerPageUIConfigBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) {
  120 +
  121 + //底部栏
  122 + [bottomToolBar setBackgroundColor:RGBOF(0xFFFFFF)];
  123 +
  124 + //预览
  125 + previewButton.titleLabel.font = [UIFont systemFontOfSize:16];
  126 + [previewButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];//禁用
  127 + [previewButton setTitleColor:RGBOF(0x000000) forState:UIControlStateNormal];//默认
  128 +
  129 + //原图按钮
  130 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用
  131 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateNormal];//默认
  132 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_select"] forState:UIControlStateSelected];//选中
  133 + originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  134 + [originalPhotoButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];
  135 + [originalPhotoButton setTitleColor:RGBOF(0x000000) forState:UIControlStateNormal];
  136 +
  137 + //原图文字提示
  138 + originalPhotoLabel.font = [UIFont fontWithName:@"PingFang-SC-Regular" size:16];
  139 + originalPhotoLabel.textColor = RGBOF(0xB3B3B3);
  140 + originalPhotoLabel.hidden = YES;
  141 +
  142 + //选中提示
  143 + numberImageView = [UIImageView new];
  144 + numberLabel = [UILabel new];
  145 +
  146 + //完成按钮
  147 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  148 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  149 + [doneButton setTitleColor:RGBAOF(0xFFFFFF, 0.5) forState:UIControlStateDisabled];
  150 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  151 +
  152 + //颜色绘制成图片
  153 + UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  154 + [doneButton setBackgroundImage:dis_image forState:UIControlStateDisabled];
  155 + UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  156 + [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  157 + doneButton.layer.masksToBounds = YES;
  158 + doneButton.layer.cornerRadius = 5;
  159 +
  160 + //分割线
  161 + [divideLine setBackgroundColor:RGBOF(0xDEDEDE)];
  162 +
  163 + }];
  164 +
  165 + //图片预览
  166 + [self setPhotoPreviewPageUIConfigBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) {
  167 +
  168 + //返回按钮
  169 + [backButton setImage:[UIImage imageNamed:@"photo_original_back"] forState:UIControlStateNormal];
  170 + //选择按钮
  171 + [selectButton setImage:[UIImage imageNamed:@"photo_original_nor"] forState:UIControlStateNormal];
  172 + [selectButton setImage:[UIImage qmui_imageWithColor:RGBOF(0x0BBE06) size:CGSizeMake(28, 28) cornerRadius:14] forState:UIControlStateSelected];
  173 + [selectButton setTitle:@"" forState:UIControlStateDisabled];
  174 +
  175 + //原图按钮
  176 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用
  177 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateNormal];//默认
  178 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_select"] forState:UIControlStateSelected];//选中
  179 + originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  180 + [originalPhotoButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];
  181 + [originalPhotoButton setTitleColor:RGBAOF(0xFFFFFF, 0.7) forState:UIControlStateNormal];
  182 + //原图内容隐藏
  183 + originalPhotoLabel.hidden = YES;
  184 +
  185 + //完成按钮
  186 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  187 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  188 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  189 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  190 +
  191 + //颜色绘制成图片
  192 + UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  193 + [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  194 + UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  195 + [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  196 + doneButton.layer.masksToBounds = YES;
  197 + doneButton.layer.cornerRadius = 5;
  198 + }];
  199 +
  200 + //视频预览
  201 + [self setVideoPreviewPageUIConfigBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) {
  202 +
  203 + //完成按钮
  204 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  205 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  206 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  207 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  208 +
  209 + //颜色绘制成图片
  210 + UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  211 + [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  212 + UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  213 + [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  214 + doneButton.layer.masksToBounds = YES;
  215 + doneButton.layer.cornerRadius = 5;
  216 +
  217 + }];
  218 +
  219 + //gif预览
  220 + [self setGifPreviewPageUIConfigBlock:^(UIView *toolBar, UIButton *doneButton) {
  221 +
  222 + //完成按钮
  223 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  224 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  225 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  226 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  227 +
  228 + //颜色绘制成图片
  229 + UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  230 + [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  231 + UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  232 + [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  233 + doneButton.layer.masksToBounds = YES;
  234 + doneButton.layer.cornerRadius = 5;
  235 +
  236 + }];
  237 + //相册cell
  238 + [self setAssetCellDidSetModelBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
  239 +
  240 +
  241 + }];
  242 + //相簿
  243 + [self setAlbumCellDidSetModelBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) {
  244 + [posterImageView setBackgroundColor:[UIColor blueColor]];
  245 + [posterImageView setBackgroundColor:[UIColor blueColor]];
  246 +
  247 + }];
  248 +
  249 +
  250 + /// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等
  251 + //相册
  252 + [self setPhotoPickerPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) {
  253 +
  254 + CGRect frame = bottomToolBar.frame;
  255 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kVerticalBottomSafeHeight /2), 60, 30);
  256 +
  257 + CGRect originalPhotoLabelFrame = originalPhotoLabel.frame;
  258 + CGFloat originalX = (bottomToolBar.frame.size.width - originalPhotoLabelFrame.size.width) /2;
  259 + CGFloat originalY = originalPhotoLabelFrame.origin.y;
  260 + originalPhotoButton.frame = CGRectMake(originalX, originalY, originalPhotoLabelFrame.size.width, originalPhotoLabelFrame.size.height);
  261 +
  262 +
  263 + }];
  264 + //图片预览
  265 + [self setPhotoPreviewPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) {
  266 +
  267 + CGRect frame = toolBar.frame;
  268 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kVerticalBottomSafeHeight /2), 60, 30);
  269 +
  270 + }];
  271 + //视频预览
  272 + [self setVideoPreviewPageDidLayoutSubviewsBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) {
  273 +
  274 + CGRect frame = toolBar.frame;
  275 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kVerticalBottomSafeHeight /2), 60, 30);
  276 +
  277 + }];
  278 + //gif预览
  279 + [self setGifPreviewPageDidLayoutSubviewsBlock:^(UIView *toolBar, UIButton *doneButton) {
  280 +
  281 + CGRect frame = toolBar.frame;
  282 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kVerticalBottomSafeHeight /2), 60, 30);
  283 +
  284 + }];
  285 + //相册cell
  286 + [self setAssetCellDidLayoutSubviewsBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
  287 + }];
  288 + //相簿
  289 + [self setAlbumCellDidLayoutSubviewsBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) {
  290 +
  291 + }];
  292 +
  293 + //设置图片个数
  294 + self.photoNumberIconImage = [UIImage new];
  295 +
  296 +}
  297 +
  298 +- (void)didReceiveMemoryWarning {
  299 + [super didReceiveMemoryWarning];
  300 + // Dispose of any resources that can be recreated.
  301 +}
  302 +
  303 +
  304 +@end
... ...
CNLiveImagePickerController/Classes/CNImagePickerManager.h 0 → 100644
  1 +//
  2 +// CNImagePickerManager.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/10/8.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <Foundation/Foundation.h>
  11 +#import "CNImagePickerController.h"
  12 +
  13 +#pragma mark - TODO: 导出
  14 +typedef void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);//选着图片返回
  15 +
  16 +typedef void (^didNewFinishPickingPhotosHandle) (NSArray<UIImage *> *photos,NSArray<TZAssetModel *> *models,NSArray *assets,BOOL isSelectOriginalPhoto);
  17 +
  18 +//typedef void (^failureBlock)(NSMutableArray* errorArray, NSError *error);//失败数组,错误
  19 +
  20 +typedef NS_ENUM(NSUInteger, CNImagePickerEnterType) {
  21 + CNImagePickerEnterTypeFriendsCircle = 0,//朋友圈
  22 + CNImagePickerEnterTypeComment = 1,//评论
  23 + CNImagePickerEnterTypeSweepCode = 2,//扫码
  24 + CNImagePickerEnterTypeChat = 3,//聊天
  25 + CNImagePickerEnterTypeOther = 4,//其他
  26 + CNImagePickerEnterTypeWitness = 5, //目击者
  27 + CNImagePickedEnterTypeField = 6, //农业智能
  28 +
  29 +};
  30 +
  31 +@interface CNImagePickerManager : NSObject
  32 +
  33 +
  34 +
  35 +/**
  36 + 打开相册选择图片
  37 +
  38 + @param maxImagesCount 最大图片
  39 + @param columnNumber 列个数
  40 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  41 + @param pushPhotoPickerVc 是否跳转到相册
  42 + @param isSelectOriginalPhoto 是否原图
  43 + @param selectedAssets 选择图片
  44 + @param enterType 进入方式
  45 + @param pickingPhotosHandle 选择结束回调
  46 + */
  47 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto selectedAssets:(NSMutableArray *)selectedAssets enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle;
  48 +
  49 +/**
  50 + 预览图片
  51 +
  52 + @param maxImagesCount 最大限制
  53 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  54 + @param selectedAssets 选中Assets
  55 + @param selectedPhotos 选中Photos
  56 + @param index 选中第几个
  57 + @param isSelectOriginalPhoto 是否原图
  58 + @param enterType 进入方式
  59 + @param pickingPhotosHandle 回调参数
  60 + */
  61 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate selectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle;
  62 +
  63 +
  64 +/**
  65 + 预览单个视频
  66 +
  67 + @param selectedAsset 选择视频
  68 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  69 + */
  70 ++ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate;
  71 +
  72 +
  73 +/**
  74 + 保存图片
  75 +
  76 + @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>)
  77 + @param image 图片
  78 + @param location 地点
  79 + @param success 成功
  80 + @param failure 失败
  81 +
  82 + */
  83 ++(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure;
  84 +
  85 +
  86 +/**
  87 + 判断Asset类型
  88 +
  89 + @param asset asset
  90 + @return 返回类型
  91 + */
  92 ++ (TZAssetModelMediaType)getAssetType:(id)asset;
  93 +
  94 +
  95 +@end
  96 +
... ...
CNLiveImagePickerController/Classes/CNImagePickerManager.m 0 → 100644
  1 +//
  2 +// CNImagePickerManager.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/10/8.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNImagePickerManager.h"
  10 +#import <AssetsLibrary/AssetsLibrary.h>
  11 +
  12 +@implementation CNImagePickerManager
  13 +
  14 +/// 打开相册选择图片
  15 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto selectedAssets:(NSMutableArray *)selectedAssets enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle{
  16 +
  17 + if (![delegate isKindOfClass:[UIViewController class]]) {
  18 + return;
  19 + }
  20 + UIViewController *vc = (UIViewController *)delegate;
  21 +
  22 + CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithMaxImagesCount:maxImagesCount columnNumber:columnNumber delegate:delegate pushPhotoPickerVc:pushPhotoPickerVc];
  23 + [imagePickerVc configTZImagePicker];//基本配置
  24 + //特殊配置
  25 + switch (enterType) {
  26 + case CNImagePickerEnterTypeFriendsCircle:
  27 + imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度
  28 + imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度
  29 + // 3. 设置是否可以混选选择视频/图片/原图
  30 + imagePickerVc.allowPickingMultipleVideo = NO;
  31 + break;
  32 + case CNImagePickerEnterTypeComment:
  33 +#pragma mark - TODO:根据不同设置
  34 + break;
  35 + case CNImagePickerEnterTypeSweepCode:
  36 +
  37 + break;
  38 + case CNImagePickerEnterTypeChat:
  39 +
  40 + break;
  41 + case CNImagePickerEnterTypeWitness:
  42 + imagePickerVc.allowPickingImage = NO;// 显示图片
  43 + imagePickerVc.allowPickingMultipleVideo = NO;
  44 + imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度
  45 + imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度
  46 + break;
  47 + case CNImagePickedEnterTypeField:
  48 + imagePickerVc.allowPickingImage = YES;// 显示图片
  49 + imagePickerVc.allowPickingMultipleVideo = NO;
  50 + imagePickerVc.allowPickingVideo = NO;
  51 + imagePickerVc.allowPickingGif = NO;
  52 + break;
  53 + default://其他
  54 + break;
  55 + }
  56 +
  57 + imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;//是否选择原图
  58 + // 1.设置目前已经选中的图片数组
  59 + imagePickerVc.selectedAssets = selectedAssets; // 目前已经选中的图片数组
  60 + /// 5. Single selection mode, valid when maxImagesCount = 1
  61 + /// 5. 单选模式,maxImagesCount为1时才生效
  62 + // 设置竖屏下的裁剪尺寸
  63 + NSInteger left = 30;
  64 + NSInteger widthHeight = vc.view.width - 2 * left;
  65 + NSInteger top = (vc.view.height - widthHeight) / 2;
  66 + imagePickerVc.cropRect = CGRectMake(left, top, widthHeight, widthHeight);
  67 + // 你可以通过block或者代理,来得到用户选择的照片.
  68 + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  69 + // 回调参数
  70 + !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto);
  71 +
  72 + }];
  73 +
  74 + [imagePickerVc setDidFinishPickingPhotosWithInfosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto, NSArray<NSDictionary *> *infos) {
  75 +
  76 + NSLog(@"输出infos = %@",infos);
  77 + }];
  78 +
  79 + [imagePickerVc setDidNewFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray<TZAssetModel *> *models, NSArray *assets, BOOL isSelectOriginalPhoto) {
  80 + NSLog(@"输出models = %@",models);
  81 + }];
  82 +
  83 + [vc presentViewController:imagePickerVc animated:YES completion:nil];
  84 +}
  85 +
  86 +/// 预览图片
  87 ++ (void)ImagePickerWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate selectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto enterType:(CNImagePickerEnterType )enterType pickingPhotosHandle:(didFinishPickingPhotosHandle) pickingPhotosHandle {
  88 +
  89 + if (![delegate isKindOfClass:[UIViewController class]]) {
  90 + return;
  91 + }
  92 + UIViewController *vc = (UIViewController *)delegate;
  93 +
  94 + CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithSelectedAssets:selectedAssets selectedPhotos:selectedPhotos index:index];
  95 + [imagePickerVc configTZImagePicker];//基本配置
  96 + //特殊配置
  97 + switch (enterType) {
  98 + case CNImagePickerEnterTypeFriendsCircle:
  99 + imagePickerVc.allowPickingGif = NO;
  100 + imagePickerVc.allowPickingOriginalPhoto = YES;
  101 + imagePickerVc.allowPickingMultipleVideo = NO;
  102 + break;
  103 + case CNImagePickerEnterTypeComment:
  104 +#pragma mark - TODO:根据不同设置
  105 + break;
  106 + case CNImagePickerEnterTypeSweepCode:
  107 +
  108 + break;
  109 + case CNImagePickerEnterTypeChat:
  110 +
  111 + break;
  112 + case CNImagePickerEnterTypeOther:
  113 + break;
  114 + default://其他
  115 + break;
  116 + }
  117 +
  118 + imagePickerVc.maxImagesCount = maxImagesCount;
  119 + imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;
  120 +
  121 + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  122 + // 回调参数
  123 + !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto);
  124 +
  125 + }];
  126 +
  127 +
  128 +
  129 + [vc presentViewController:imagePickerVc animated:YES completion:nil];
  130 +
  131 +}
  132 +
  133 +/// 预览单个视频
  134 ++ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate {
  135 +
  136 + if (![delegate isKindOfClass:[UIViewController class]]) {
  137 + return;
  138 + }
  139 + UIViewController *vc = (UIViewController *)delegate;
  140 +
  141 + TZVideoPlayerController *videoVC = [[TZVideoPlayerController alloc] init];
  142 + TZAssetModel *model = [TZAssetModel modelWithAsset:selectedAsset type:TZAssetModelMediaTypeVideo timeLength:@""];
  143 + videoVC.isOther = YES;//(LXG)相册外进入
  144 + videoVC.model = model;
  145 + [vc presentViewController:videoVC animated:YES completion:nil];
  146 +
  147 +}
  148 +
  149 +/// 返回类型
  150 ++ (TZAssetModelMediaType)getAssetType:(id)asset {
  151 +
  152 + TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
  153 + if ([asset isKindOfClass:[PHAsset class]]) {
  154 + PHAsset *phAsset = (PHAsset *)asset;
  155 + if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
  156 + else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
  157 + else if (phAsset.mediaType == PHAssetMediaTypeImage) {
  158 + if (iOS9_1Later) {
  159 + if (@available(iOS 9.1, *)) {
  160 + if (phAsset.mediaSubtypes == PHAssetMediaSubtypePhotoLive)
  161 + {
  162 + type = TZAssetModelMediaTypeLivePhoto;
  163 + }
  164 + } else {
  165 + // Fallback on earlier versions
  166 + }
  167 + }
  168 + // Gif
  169 + if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  170 + type = TZAssetModelMediaTypePhotoGif;
  171 + }
  172 + }
  173 + } else {
  174 + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
  175 + type = TZAssetModelMediaTypeVideo;
  176 + }
  177 + }
  178 + return type;
  179 +}
  180 +
  181 +
  182 ++(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure {
  183 +
  184 + TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:delegate];
  185 + tzImagePickerVc.sortAscendingByModificationDate = YES;
  186 +
  187 + [tzImagePickerVc showProgressHUD];
  188 + // save photo and get asset / 保存图片,获取到asset
  189 + [[TZImageManager manager] savePhotoWithImage:image location:location completion:^(NSError *error){
  190 +
  191 + if (error) {
  192 + [tzImagePickerVc hideProgressHUD];
  193 + failure(error);
  194 + NSLog(@"图片保存失败 %@",error);
  195 + } else {
  196 +
  197 + [[TZImageManager manager] getCameraRollAlbum:NO allowPickingImage:YES needFetchAssets:YES completion:^(TZAlbumModel *model) {
  198 + [[TZImageManager manager] getAssetsFromFetchResult:model.result allowPickingVideo:NO allowPickingImage:YES completion:^(NSArray<TZAssetModel *> *models) {
  199 + [tzImagePickerVc hideProgressHUD];
  200 + TZAssetModel *assetModel = [models firstObject];
  201 + if (tzImagePickerVc.sortAscendingByModificationDate) {
  202 + assetModel = [models lastObject];
  203 + }
  204 + success(assetModel);
  205 + }];
  206 +
  207 + }];
  208 + }
  209 + }];
  210 +
  211 +}
  212 +
  213 +
  214 +@end
... ...
CNLiveImagePickerController/Classes/NSBundle+TZImagePicker.h 0 → 100755
  1 +//
  2 +// NSBundle+TZImagePicker.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/08/18.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface NSBundle (TZImagePicker)
  12 +
  13 ++ (NSBundle *)tz_imagePickerBundle;
  14 +
  15 ++ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value;
  16 ++ (NSString *)tz_localizedStringForKey:(NSString *)key;
  17 +
  18 +@end
  19 +
... ...
CNLiveImagePickerController/Classes/NSBundle+TZImagePicker.m 0 → 100755
  1 +//
  2 +// NSBundle+TZImagePicker.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/08/18.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "NSBundle+TZImagePicker.h"
  10 +#import "TZImagePickerController.h"
  11 +
  12 +@implementation NSBundle (TZImagePicker)
  13 +
  14 ++ (NSBundle *)tz_imagePickerBundle {
  15 + NSBundle *bundle = [NSBundle bundleForClass:[TZImagePickerController class]];
  16 + NSURL *url = [bundle URLForResource:@"TZImagePickerController" withExtension:@"bundle"];
  17 + bundle = [NSBundle bundleWithURL:url];
  18 + return bundle;
  19 +}
  20 +
  21 ++ (NSString *)tz_localizedStringForKey:(NSString *)key {
  22 + return [self tz_localizedStringForKey:key value:@""];
  23 +}
  24 +
  25 ++ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value {
  26 + NSBundle *bundle = [TZImagePickerConfig sharedInstance].languageBundle;
  27 + NSString *value1 = [bundle localizedStringForKey:key value:value table:nil];
  28 + return value1;
  29 +}
  30 +
  31 +@end
... ...
CNLiveImagePickerController/Classes/ReplaceMe.m deleted 100644 → 0
CNLiveImagePickerController/Classes/TZAssetCell.h 0 → 100755
  1 +//
  2 +// TZAssetCell.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <Photos/Photos.h>
  11 +
  12 +typedef enum : NSUInteger {
  13 + TZAssetCellTypePhoto = 0,
  14 + TZAssetCellTypeLivePhoto,
  15 + TZAssetCellTypePhotoGif,
  16 + TZAssetCellTypeVideo,
  17 + TZAssetCellTypeAudio,
  18 +} TZAssetCellType;
  19 +
  20 +@class TZAssetModel;
  21 +@interface TZAssetCell : UICollectionViewCell
  22 +@property (weak, nonatomic) UIButton *selectPhotoButton;
  23 +@property (weak, nonatomic) UIButton *cannotSelectLayerButton;
  24 +@property (nonatomic, strong) TZAssetModel *model;
  25 +@property (assign, nonatomic) NSInteger index;
  26 +@property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL);
  27 +@property (nonatomic, assign) TZAssetCellType type;
  28 +@property (nonatomic, assign) BOOL allowPickingGif;
  29 +@property (nonatomic, assign) BOOL allowPickingMultipleVideo;
  30 +@property (nonatomic, copy) NSString *representedAssetIdentifier;
  31 +@property (nonatomic, assign) int32_t imageRequestID;
  32 +
  33 +@property (nonatomic, strong) UIImage *photoSelImage;
  34 +@property (nonatomic, strong) UIImage *photoDefImage;
  35 +
  36 +@property (nonatomic, assign) BOOL showSelectBtn;
  37 +@property (assign, nonatomic) BOOL allowPreview;
  38 +@property (assign, nonatomic) BOOL useCachedImage;
  39 +
  40 +@property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  41 +@property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  42 +@end
  43 +
  44 +
  45 +@class TZAlbumModel;
  46 +@interface TZAlbumCell : UITableViewCell
  47 +@property (nonatomic, strong) TZAlbumModel *model;
  48 +@property (weak, nonatomic) UIButton *selectedCountButton;
  49 +
  50 +@property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  51 +@property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  52 +@end
  53 +
  54 +
  55 +@interface TZAssetCameraCell : UICollectionViewCell
  56 +@property (nonatomic, strong) UIImageView *imageView;
  57 +@end
... ...
CNLiveImagePickerController/Classes/TZAssetCell.m 0 → 100755
  1 +//
  2 +// TZAssetCell.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZAssetCell.h"
  10 +#import "TZAssetModel.h"
  11 +#import "UIView+TZLayout.h"
  12 +#import "TZImageManager.h"
  13 +#import "TZImagePickerController.h"
  14 +#import "TZProgressView.h"
  15 +
  16 +@interface TZAssetCell ()
  17 +@property (weak, nonatomic) UIImageView *imageView; // The photo / 照片
  18 +@property (weak, nonatomic) UIImageView *selectImageView;
  19 +@property (weak, nonatomic) UILabel *indexLabel;
  20 +@property (weak, nonatomic) UIView *bottomView;
  21 +@property (weak, nonatomic) UILabel *timeLength;
  22 +@property (strong, nonatomic) UITapGestureRecognizer *tapGesture;
  23 +
  24 +@property (nonatomic, weak) UIImageView *videoImgView;
  25 +@property (nonatomic, strong) TZProgressView *progressView;
  26 +@property (nonatomic, assign) int32_t bigImageRequestID;
  27 +@end
  28 +
  29 +@implementation TZAssetCell
  30 +
  31 +- (void)setModel:(TZAssetModel *)model {
  32 + _model = model;
  33 + if (iOS8Later) {
  34 + self.representedAssetIdentifier = [[TZImageManager manager] getAssetIdentifier:model.asset];
  35 + }
  36 + if (self.useCachedImage && model.cachedImage) {
  37 + self.imageView.image = model.cachedImage;
  38 + } else {
  39 + self.model.cachedImage = nil;
  40 + __weak typeof(self) weakSelf = self;
  41 + int32_t imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  42 +// NSLog(@"输出导出参数info = %@",info);
  43 + if (photo) {//lxg: 裂图
  44 + model.isExport = YES;
  45 + }else{
  46 + model.isExport = NO;
  47 + }
  48 +
  49 + // Set the cell's thumbnail image if it's still showing the same asset.
  50 + if (!iOS8Later) {
  51 + weakSelf.imageView.image = photo;
  52 + weakSelf.model.cachedImage = photo;
  53 + [weakSelf hideProgressView];
  54 + return;
  55 + }
  56 + if ([weakSelf.representedAssetIdentifier isEqualToString:[[TZImageManager manager] getAssetIdentifier:model.asset]]) {
  57 + weakSelf.imageView.image = photo;
  58 + weakSelf.model.cachedImage = photo;
  59 + } else {
  60 + // NSLog(@"this cell is showing other asset");
  61 + [[PHImageManager defaultManager] cancelImageRequest:weakSelf.imageRequestID];
  62 + }
  63 + if (!isDegraded) {
  64 + [weakSelf hideProgressView];
  65 + weakSelf.imageRequestID = 0;
  66 + }
  67 + } progressHandler:nil networkAccessAllowed:NO];
  68 +#pragma mark - warining: 本身应该在progressHandler中判断是否可导出
  69 + if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) {
  70 + [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
  71 + // NSLog(@"cancelImageRequest %d",self.imageRequestID);
  72 + }
  73 + self.imageRequestID = imageRequestID;
  74 + }
  75 +
  76 + /** 处理视频 */
  77 + if (model.type == TZAssetModelMediaTypeVideo) {
  78 +
  79 + if (model.isCheckICloudType) {//是否检测来源
  80 + NSLog(@"输出检测过来源");
  81 + }else {
  82 +
  83 + [[TZImageManager manager] getVideoWithAsset:self.model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
  84 + NSLog(@"输出识别后结果 = %@",info);
  85 + NSLog(@"Info:%@",info);
  86 + model.isCheckICloudType = YES;
  87 + if ([[info objectForKey: PHImageResultIsInCloudKey] boolValue])
  88 + {
  89 + model.isICloudType = YES;
  90 + }else {
  91 + model.isICloudType = NO;
  92 + }
  93 +
  94 + if (model.isICloudType) {//源是iCloud
  95 + if ([info objectForKey:@"PHImageFileSandboxExtensionTokenKey"]) {
  96 + model.isVideoICloudDownLoad = YES;
  97 + }else {
  98 + model.isVideoICloudDownLoad = NO;
  99 + }
  100 + }else {
  101 +
  102 + }
  103 +
  104 +
  105 + }];
  106 +
  107 +
  108 +
  109 +// PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  110 +// options.version = PHVideoRequestOptionsVersionOriginal;
  111 +// options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  112 +// options.networkAccessAllowed = YES;
  113 +// options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  114 +//
  115 +// if (progress >= 1) {
  116 +// model.isVideoICloudDownLoad = YES;
  117 +// } else {
  118 +// model.isVideoICloudDownLoad = NO;
  119 +// }
  120 +// NSLog(@"输出进度 = %f",progress);
  121 +// };
  122 +// /** requestPlayerItemForVideo */
  123 +// [[PHImageManager defaultManager] requestAVAssetForVideo:model.asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
  124 +// NSLog(@"Info:%@",info);
  125 +// model.isCheckICloudType = YES;
  126 +// if ([[info objectForKey: PHImageResultIsInCloudKey] boolValue])
  127 +// {
  128 +// model.isICloudType = YES;
  129 +//
  130 +// }else {
  131 +// model.isICloudType = NO;
  132 +// }
  133 +// BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  134 +// if (downloadFinined && avasset) {//成功
  135 +// model.isVideoICloudDownLoad = YES;
  136 +//
  137 +// }else {
  138 +// model.isVideoICloudDownLoad = NO;
  139 +//
  140 +// }
  141 +//
  142 +// }];
  143 +
  144 + }
  145 + }
  146 +
  147 +
  148 + self.selectPhotoButton.selected = model.isSelected;
  149 + self.selectImageView.image = self.selectPhotoButton.isSelected ? self.photoSelImage : self.photoDefImage;
  150 + self.indexLabel.hidden = !self.selectPhotoButton.isSelected;
  151 +
  152 + self.type = (NSInteger)model.type;
  153 + // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中
  154 + if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) {
  155 + if (_selectImageView.hidden == NO) {
  156 + self.selectPhotoButton.hidden = YES;
  157 + _selectImageView.hidden = YES;
  158 + }
  159 + }
  160 + // 如果用户选中了该图片,提前获取一下大图
  161 + if (model.isSelected) {
  162 + [self requestBigImage];
  163 + } else {
  164 + [self cancelBigImageRequest];
  165 + }
  166 + if (model.needOscillatoryAnimation) {
  167 + [UIView showOscillatoryAnimationWithLayer:self.selectImageView.layer type:TZOscillatoryAnimationToBigger];
  168 + }
  169 + model.needOscillatoryAnimation = NO;
  170 +
  171 + if (!model.isExport) {
  172 + self.imageView.image = [UIImage imageNamed:@"placeImg.png"];
  173 + }
  174 +
  175 +
  176 +
  177 + [self setNeedsLayout];
  178 +
  179 + if (self.assetCellDidSetModelBlock) {
  180 + self.assetCellDidSetModelBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView);
  181 + }
  182 +}
  183 +
  184 +- (void)setIndex:(NSInteger)index {
  185 + _index = index;
  186 + self.indexLabel.text = [NSString stringWithFormat:@"%zd", index];
  187 + [self.contentView bringSubviewToFront:self.indexLabel];
  188 +}
  189 +
  190 +- (void)setShowSelectBtn:(BOOL)showSelectBtn {
  191 + _showSelectBtn = showSelectBtn;
  192 + BOOL selectable = [[TZImageManager manager] isPhotoSelectableWithAsset:self.model.asset];
  193 + if (!self.selectPhotoButton.hidden) {
  194 + self.selectPhotoButton.hidden = !showSelectBtn || !selectable;
  195 + }
  196 + if (!self.selectImageView.hidden) {
  197 + self.selectImageView.hidden = !showSelectBtn || !selectable;
  198 + }
  199 +}
  200 +
  201 +- (void)setType:(TZAssetCellType)type {
  202 + _type = type;
  203 + if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif) || self.allowPickingMultipleVideo) {
  204 + _selectImageView.hidden = NO;
  205 + _selectPhotoButton.hidden = NO;
  206 + _bottomView.hidden = YES;
  207 + } else { // Video of Gif
  208 + _selectImageView.hidden = YES;
  209 + _selectPhotoButton.hidden = YES;
  210 + }
  211 +
  212 + if (type == TZAssetCellTypeVideo) {
  213 + self.bottomView.hidden = NO;
  214 + self.timeLength.text = _model.timeLength;
  215 + self.videoImgView.hidden = NO;
  216 + _timeLength.tz_left = self.videoImgView.tz_right;
  217 + _timeLength.textAlignment = NSTextAlignmentRight;
  218 + } else if (type == TZAssetCellTypePhotoGif && self.allowPickingGif) {
  219 + self.bottomView.hidden = NO;
  220 + self.timeLength.text = @"GIF";
  221 + self.videoImgView.hidden = YES;
  222 + _timeLength.tz_left = 5;
  223 + _timeLength.textAlignment = NSTextAlignmentLeft;
  224 + }
  225 +}
  226 +
  227 +- (void)setAllowPreview:(BOOL)allowPreview {
  228 + _allowPreview = allowPreview;
  229 + if (allowPreview) {
  230 + _imageView.userInteractionEnabled = NO;
  231 + _tapGesture.enabled = NO;
  232 + } else {
  233 + _imageView.userInteractionEnabled = YES;
  234 + _tapGesture.enabled = YES;
  235 + }
  236 +}
  237 +
  238 +- (void)selectPhotoButtonClick:(UIButton *)sender {
  239 + if (self.didSelectPhotoBlock) {
  240 + self.didSelectPhotoBlock(sender.isSelected);
  241 + }
  242 + self.selectImageView.image = sender.isSelected ? self.photoSelImage : self.photoDefImage;
  243 + if (sender.isSelected) {
  244 + if (![TZImagePickerConfig sharedInstance].showSelectedIndex && ![TZImagePickerConfig sharedInstance].showPhotoCannotSelectLayer) {
  245 + [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger];
  246 + }
  247 + // 用户选中了该图片,提前获取一下大图
  248 + [self requestBigImage];
  249 + } else { // 取消选中,取消大图的获取
  250 + [self cancelBigImageRequest];
  251 + }
  252 +}
  253 +
  254 +/// 只在单选状态且allowPreview为NO时会有该事件
  255 +- (void)didTapImageView {
  256 + if (self.didSelectPhotoBlock) {
  257 + self.didSelectPhotoBlock(NO);
  258 + }
  259 +}
  260 +
  261 +- (void)hideProgressView {
  262 + if (_progressView) {
  263 + self.progressView.hidden = YES;
  264 + self.imageView.alpha = 1.0;
  265 + }
  266 +}
  267 +
  268 +- (void)requestBigImage {
  269 + if (_bigImageRequestID) {
  270 + [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
  271 + }
  272 +
  273 + __weak typeof(self) weakSelf = self;
  274 + _bigImageRequestID = [[TZImageManager manager] requestImageDataForAsset:_model.asset completion:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  275 + [weakSelf hideProgressView];
  276 + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  277 + if (weakSelf.model.isSelected) {
  278 + progress = progress > 0.02 ? progress : 0.02;;
  279 + weakSelf.progressView.progress = progress;
  280 + weakSelf.progressView.hidden = NO;
  281 + weakSelf.imageView.alpha = 0.4;
  282 + if (progress >= 1) {
  283 + [weakSelf hideProgressView];
  284 + }
  285 + } else {
  286 + *stop = YES;
  287 + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
  288 + [weakSelf cancelBigImageRequest];
  289 + }
  290 + }];
  291 +}
  292 +
  293 +- (void)cancelBigImageRequest {
  294 + if (_bigImageRequestID) {
  295 + [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID];
  296 + }
  297 + [self hideProgressView];
  298 +}
  299 +
  300 +#pragma mark - Lazy load
  301 +
  302 +- (UIButton *)selectPhotoButton {
  303 + if (_selectPhotoButton == nil) {
  304 + UIButton *selectPhotoButton = [[UIButton alloc] init];
  305 + [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside];
  306 + [self.contentView addSubview:selectPhotoButton];
  307 + _selectPhotoButton = selectPhotoButton;
  308 + }
  309 + return _selectPhotoButton;
  310 +}
  311 +
  312 +- (UIImageView *)imageView {
  313 + if (_imageView == nil) {
  314 + UIImageView *imageView = [[UIImageView alloc] init];
  315 + imageView.contentMode = UIViewContentModeScaleAspectFill;
  316 + imageView.clipsToBounds = YES;
  317 + [self.contentView addSubview:imageView];
  318 + _imageView = imageView;
  319 +
  320 + _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapImageView)];
  321 + [_imageView addGestureRecognizer:_tapGesture];
  322 + }
  323 + return _imageView;
  324 +}
  325 +
  326 +- (UIImageView *)selectImageView {
  327 + if (_selectImageView == nil) {
  328 + UIImageView *selectImageView = [[UIImageView alloc] init];
  329 + selectImageView.contentMode = UIViewContentModeCenter;
  330 + selectImageView.clipsToBounds = YES;
  331 + [self.contentView addSubview:selectImageView];
  332 + _selectImageView = selectImageView;
  333 + }
  334 + return _selectImageView;
  335 +}
  336 +
  337 +- (UIView *)bottomView {
  338 + if (_bottomView == nil) {
  339 + UIView *bottomView = [[UIView alloc] init];
  340 + static NSInteger rgb = 0;
  341 + bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8];
  342 + [self.contentView addSubview:bottomView];
  343 + _bottomView = bottomView;
  344 + }
  345 + return _bottomView;
  346 +}
  347 +
  348 +- (UIButton *)cannotSelectLayerButton {
  349 + if (_cannotSelectLayerButton == nil) {
  350 + UIButton *cannotSelectLayerButton = [[UIButton alloc] init];
  351 + [self.contentView addSubview:cannotSelectLayerButton];
  352 + _cannotSelectLayerButton = cannotSelectLayerButton;
  353 + }
  354 + return _cannotSelectLayerButton;
  355 +}
  356 +
  357 +- (UIImageView *)videoImgView {
  358 + if (_videoImgView == nil) {
  359 + UIImageView *videoImgView = [[UIImageView alloc] init];
  360 + [videoImgView setImage:[UIImage imageNamedFromMyBundle:@"VideoSendIcon"]];
  361 + [self.bottomView addSubview:videoImgView];
  362 + _videoImgView = videoImgView;
  363 + }
  364 + return _videoImgView;
  365 +}
  366 +
  367 +- (UILabel *)timeLength {
  368 + if (_timeLength == nil) {
  369 + UILabel *timeLength = [[UILabel alloc] init];
  370 + timeLength.font = [UIFont boldSystemFontOfSize:11];
  371 + timeLength.textColor = [UIColor whiteColor];
  372 + timeLength.textAlignment = NSTextAlignmentRight;
  373 + [self.bottomView addSubview:timeLength];
  374 + _timeLength = timeLength;
  375 + }
  376 + return _timeLength;
  377 +}
  378 +
  379 +- (UILabel *)indexLabel {
  380 + if (_indexLabel == nil) {
  381 + UILabel *indexLabel = [[UILabel alloc] init];
  382 + indexLabel.font = [UIFont systemFontOfSize:14];
  383 + indexLabel.textColor = [UIColor whiteColor];
  384 + indexLabel.textAlignment = NSTextAlignmentCenter;
  385 + [self.contentView addSubview:indexLabel];
  386 + _indexLabel = indexLabel;
  387 + }
  388 + return _indexLabel;
  389 +}
  390 +
  391 +- (TZProgressView *)progressView {
  392 + if (_progressView == nil) {
  393 + _progressView = [[TZProgressView alloc] init];
  394 + _progressView.hidden = YES;
  395 + [self addSubview:_progressView];
  396 + }
  397 + return _progressView;
  398 +}
  399 +
  400 +- (void)layoutSubviews {
  401 + [super layoutSubviews];
  402 + _cannotSelectLayerButton.frame = self.bounds;
  403 + if (self.allowPreview) {
  404 + _selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44);
  405 + } else {
  406 + _selectPhotoButton.frame = self.bounds;
  407 + }
  408 + _selectImageView.frame = CGRectMake(self.tz_width - 27, 3, 24, 24);
  409 + if (_selectImageView.image.size.width <= 27) {
  410 + _selectImageView.contentMode = UIViewContentModeCenter;
  411 + } else {
  412 + _selectImageView.contentMode = UIViewContentModeScaleAspectFit;
  413 + }
  414 + _indexLabel.frame = _selectImageView.frame;
  415 + _imageView.frame = CGRectMake(0, 0, self.tz_width, self.tz_height);
  416 +
  417 + static CGFloat progressWH = 20;
  418 + CGFloat progressXY = (self.tz_width - progressWH) / 2;
  419 + _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH);
  420 +
  421 + _bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17);
  422 + _videoImgView.frame = CGRectMake(8, 0, 17, 17);
  423 + _timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17);
  424 +
  425 + self.type = (NSInteger)self.model.type;
  426 + self.showSelectBtn = self.showSelectBtn;
  427 +
  428 + [self.contentView bringSubviewToFront:_bottomView];
  429 + [self.contentView bringSubviewToFront:_cannotSelectLayerButton];
  430 + [self.contentView bringSubviewToFront:_selectPhotoButton];
  431 + [self.contentView bringSubviewToFront:_selectImageView];
  432 + [self.contentView bringSubviewToFront:_indexLabel];
  433 +
  434 + if (self.assetCellDidLayoutSubviewsBlock) {
  435 + self.assetCellDidLayoutSubviewsBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView);
  436 + }
  437 +}
  438 +
  439 +@end
  440 +
  441 +@interface TZAlbumCell ()
  442 +@property (weak, nonatomic) UIImageView *posterImageView;
  443 +@property (weak, nonatomic) UILabel *titleLabel;
  444 +@end
  445 +
  446 +@implementation TZAlbumCell
  447 +
  448 +- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
  449 + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
  450 + self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  451 + return self;
  452 +}
  453 +
  454 +- (void)setModel:(TZAlbumModel *)model {
  455 + _model = model;
  456 +
  457 + NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor blackColor]}];
  458 + NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}];
  459 + [nameString appendAttributedString:countString];
  460 + self.titleLabel.attributedText = nameString;
  461 + __weak typeof(self) weakSelf = self;
  462 + [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) {
  463 + weakSelf.posterImageView.image = postImage;
  464 + }];
  465 + if (model.selectedCount) {
  466 + self.selectedCountButton.hidden = NO;
  467 + [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal];
  468 + } else {
  469 + self.selectedCountButton.hidden = YES;
  470 + }
  471 +
  472 + if (!model.isExport) {
  473 + self.posterImageView.image = [UIImage imageNamed:@"placeImg.png"];
  474 + }
  475 +
  476 + if (self.albumCellDidSetModelBlock) {
  477 + self.albumCellDidSetModelBlock(self, _posterImageView, _titleLabel);
  478 + }
  479 +}
  480 +
  481 +/// For fitting iOS6
  482 +- (void)layoutSubviews {
  483 + if (iOS7Later) [super layoutSubviews];
  484 + _selectedCountButton.frame = CGRectMake(self.tz_width - 24 - 30, 23, 24, 24);
  485 + NSInteger titleHeight = ceil(self.titleLabel.font.lineHeight);
  486 + self.titleLabel.frame = CGRectMake(80, (self.tz_height - titleHeight) / 2, self.tz_width - 80 - 50, titleHeight);
  487 + self.posterImageView.frame = CGRectMake(0, 0, 70, 70);
  488 +
  489 + if (self.albumCellDidLayoutSubviewsBlock) {
  490 + self.albumCellDidLayoutSubviewsBlock(self, _posterImageView, _titleLabel);
  491 + }
  492 +}
  493 +
  494 +- (void)layoutSublayersOfLayer:(CALayer *)layer {
  495 + if (iOS7Later) [super layoutSublayersOfLayer:layer];
  496 +}
  497 +
  498 +#pragma mark - Lazy load
  499 +
  500 +- (UIImageView *)posterImageView {
  501 + if (_posterImageView == nil) {
  502 + UIImageView *posterImageView = [[UIImageView alloc] init];
  503 + posterImageView.contentMode = UIViewContentModeScaleAspectFill;
  504 + posterImageView.clipsToBounds = YES;
  505 + [self.contentView addSubview:posterImageView];
  506 + _posterImageView = posterImageView;
  507 + }
  508 + return _posterImageView;
  509 +}
  510 +
  511 +- (UILabel *)titleLabel {
  512 + if (_titleLabel == nil) {
  513 + UILabel *titleLabel = [[UILabel alloc] init];
  514 + titleLabel.font = [UIFont boldSystemFontOfSize:17];
  515 + titleLabel.textColor = [UIColor blackColor];
  516 + titleLabel.textAlignment = NSTextAlignmentLeft;
  517 + [self.contentView addSubview:titleLabel];
  518 + _titleLabel = titleLabel;
  519 + }
  520 + return _titleLabel;
  521 +}
  522 +
  523 +- (UIButton *)selectedCountButton {
  524 + if (_selectedCountButton == nil) {
  525 + UIButton *selectedCountButton = [[UIButton alloc] init];
  526 + selectedCountButton.layer.cornerRadius = 12;
  527 + selectedCountButton.clipsToBounds = YES;
  528 + selectedCountButton.backgroundColor = [UIColor redColor];
  529 + [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  530 + selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15];
  531 + [self.contentView addSubview:selectedCountButton];
  532 + _selectedCountButton = selectedCountButton;
  533 + }
  534 + return _selectedCountButton;
  535 +}
  536 +
  537 +@end
  538 +
  539 +
  540 +
  541 +@implementation TZAssetCameraCell
  542 +
  543 +- (instancetype)initWithFrame:(CGRect)frame {
  544 + self = [super initWithFrame:frame];
  545 + if (self) {
  546 + self.backgroundColor = [UIColor whiteColor];
  547 + _imageView = [[UIImageView alloc] init];
  548 + _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
  549 + _imageView.contentMode = UIViewContentModeScaleAspectFill;
  550 + [self.contentView addSubview:_imageView];
  551 + self.clipsToBounds = YES;
  552 + }
  553 + return self;
  554 +}
  555 +
  556 +- (void)layoutSubviews {
  557 + [super layoutSubviews];
  558 + _imageView.frame = self.bounds;
  559 +}
  560 +
  561 +@end
... ...
CNLiveImagePickerController/Classes/TZAssetModel.h 0 → 100755
  1 +//
  2 +// TZAssetModel.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +
  12 +typedef enum : NSUInteger {
  13 + TZAssetModelMediaTypePhoto = 0,
  14 + TZAssetModelMediaTypeLivePhoto,
  15 + TZAssetModelMediaTypePhotoGif,
  16 + TZAssetModelMediaTypeVideo,
  17 + TZAssetModelMediaTypeAudio
  18 +} TZAssetModelMediaType;
  19 +
  20 +@class PHAsset;
  21 +@interface TZAssetModel : NSObject
  22 +
  23 +@property (nonatomic, strong) id asset; ///< PHAsset or ALAsset
  24 +@property (nonatomic, assign) BOOL isSelected; ///< The select status of a photo, default is No
  25 +@property (nonatomic, assign) TZAssetModelMediaType type; // 类型
  26 +@property (assign, nonatomic) BOOL needOscillatoryAnimation;
  27 +@property (nonatomic, copy) NSString *timeLength;
  28 +@property (strong, nonatomic) UIImage *cachedImage;
  29 +@property (nonatomic, assign) BOOL isExport;//lxg:裂图是否导出
  30 +@property (nonatomic, strong) NSURL *exportURL;//lxg:导出视频URL
  31 +@property (nonatomic, assign) BOOL isICloudType;//lxg:是否是iCloud来源
  32 +@property (nonatomic, assign) BOOL isCheckICloudType;//lxg:是否检测过来源
  33 +
  34 +@property (nonatomic, assign) BOOL isVideoICloudDownLoad;//视频从iCloud拉取
  35 +
  36 +/// Init a photo dataModel With a asset
  37 +/// 用一个PHAsset/ALAsset实例,初始化一个照片模型
  38 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type;
  39 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength;
  40 +
  41 +@end
  42 +
  43 +
  44 +@class PHFetchResult;
  45 +@interface TZAlbumModel : NSObject
  46 +
  47 +@property (nonatomic, strong) NSString *name; ///< The album name
  48 +@property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain
  49 +@property (nonatomic, strong) id result; ///< PHFetchResult<PHAsset> or ALAssetsGroup<ALAsset>
  50 +
  51 +@property (nonatomic, strong) NSArray *models;
  52 +@property (nonatomic, strong) NSArray *selectedModels;
  53 +@property (nonatomic, assign) NSUInteger selectedCount;
  54 +
  55 +@property (nonatomic, assign) BOOL isCameraRoll;
  56 +
  57 +@property (nonatomic, assign) BOOL isExport;//lxg:裂图是否导出
  58 +
  59 +- (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets;
  60 +
  61 +@end
... ...
CNLiveImagePickerController/Classes/TZAssetModel.m 0 → 100755
  1 +//
  2 +// TZAssetModel.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZAssetModel.h"
  10 +#import "TZImageManager.h"
  11 +
  12 +@implementation TZAssetModel
  13 +
  14 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type{
  15 + TZAssetModel *model = [[TZAssetModel alloc] init];
  16 + model.asset = asset;
  17 + model.isSelected = NO;
  18 + model.type = type;
  19 + return model;
  20 +}
  21 +
  22 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength {
  23 + TZAssetModel *model = [self modelWithAsset:asset type:type];
  24 + model.timeLength = timeLength;
  25 + return model;
  26 +}
  27 +
  28 +@end
  29 +
  30 +
  31 +
  32 +@implementation TZAlbumModel
  33 +
  34 +- (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets {
  35 + _result = result;
  36 + if (needFetchAssets) {
  37 + __weak typeof(self) weakSelf = self;
  38 + [[TZImageManager manager] getAssetsFromFetchResult:result completion:^(NSArray<TZAssetModel *> *models) {
  39 + self->_models = models;
  40 + if (self->_selectedModels) {
  41 + [weakSelf checkSelectedModels];
  42 + }
  43 + }];
  44 + }
  45 +}
  46 +
  47 +- (void)setSelectedModels:(NSArray *)selectedModels {
  48 + _selectedModels = selectedModels;
  49 + if (_models) {
  50 + [self checkSelectedModels];
  51 + }
  52 +}
  53 +
  54 +- (void)checkSelectedModels {
  55 + self.selectedCount = 0;
  56 + NSMutableArray *selectedAssets = [NSMutableArray array];
  57 + for (TZAssetModel *model in _selectedModels) {
  58 + [selectedAssets addObject:model.asset];
  59 + }
  60 + for (TZAssetModel *model in _models) {
  61 + if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) {
  62 + self.selectedCount ++;
  63 + }
  64 + }
  65 +}
  66 +
  67 +- (NSString *)name {
  68 + if (_name) {
  69 + return _name;
  70 + }
  71 + return @"";
  72 +}
  73 +
  74 +@end
... ...
CNLiveImagePickerController/Classes/TZGifPhotoPreviewController.h 0 → 100755
  1 +//
  2 +// TZGifPhotoPreviewController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/13.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZGifPhotoPreviewController : UIViewController
  13 +
  14 +@property (nonatomic, strong) TZAssetModel *model;
  15 +
  16 +@end
... ...
CNLiveImagePickerController/Classes/TZGifPhotoPreviewController.m 0 → 100755
  1 +//
  2 +// TZGifPhotoPreviewController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/13.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZGifPhotoPreviewController.h"
  10 +#import "TZImagePickerController.h"
  11 +#import "TZAssetModel.h"
  12 +#import "UIView+TZLayout.h"
  13 +#import "TZPhotoPreviewCell.h"
  14 +#import "TZImageManager.h"
  15 +
  16 +#pragma clang diagnostic push
  17 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  18 +
  19 +@interface TZGifPhotoPreviewController () {
  20 + UIView *_toolBar;
  21 + UIButton *_doneButton;
  22 + UIProgressView *_progress;
  23 +
  24 + TZPhotoPreviewView *_previewView;
  25 +
  26 + UIStatusBarStyle _originStatusBarStyle;
  27 +}
  28 +@end
  29 +
  30 +@implementation TZGifPhotoPreviewController
  31 +
  32 +- (void)viewDidLoad {
  33 + [super viewDidLoad];
  34 + self.view.backgroundColor = [UIColor blackColor];
  35 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  36 + if (tzImagePickerVc) {
  37 + self.navigationItem.title = [NSString stringWithFormat:@"GIF %@",tzImagePickerVc.previewBtnTitleStr];
  38 + }
  39 + [self configPreviewView];
  40 + [self configBottomToolBar];
  41 +}
  42 +
  43 +- (void)viewWillAppear:(BOOL)animated {
  44 + [super viewWillAppear:animated];
  45 + _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
  46 + [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
  47 +}
  48 +
  49 +- (void)viewWillDisappear:(BOOL)animated {
  50 + [super viewWillDisappear:animated];
  51 + [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
  52 +}
  53 +
  54 +- (void)configPreviewView {
  55 + _previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
  56 + _previewView.model = self.model;
  57 + __weak typeof(self) weakSelf = self;
  58 + [_previewView setSingleTapGestureBlock:^{
  59 + __strong typeof(weakSelf) strongSelf = weakSelf;
  60 + [strongSelf signleTapAction];
  61 + }];
  62 + [self.view addSubview:_previewView];
  63 +}
  64 +
  65 +- (void)configBottomToolBar {
  66 + _toolBar = [[UIView alloc] initWithFrame:CGRectZero];
  67 + CGFloat rgb = 34 / 255.0;
  68 + _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
  69 +
  70 + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
  71 + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
  72 + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
  73 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  74 + if (tzImagePickerVc) {
  75 + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
  76 + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
  77 + } else {
  78 + [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
  79 + [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
  80 + }
  81 + [_toolBar addSubview:_doneButton];
  82 +
  83 + UILabel *byteLabel = [[UILabel alloc] init];
  84 + byteLabel.textColor = [UIColor whiteColor];
  85 + byteLabel.font = [UIFont systemFontOfSize:13];
  86 + byteLabel.frame = CGRectMake(10, 0, 100, 44);
  87 + [[TZImageManager manager] getPhotosBytesWithArray:@[_model] completion:^(NSString *totalBytes) {
  88 + byteLabel.text = totalBytes;
  89 + }];
  90 + [_toolBar addSubview:byteLabel];
  91 +
  92 + [self.view addSubview:_toolBar];
  93 +
  94 + if (tzImagePickerVc.gifPreviewPageUIConfigBlock) {
  95 + tzImagePickerVc.gifPreviewPageUIConfigBlock(_toolBar, _doneButton);
  96 + }
  97 +}
  98 +
  99 +#pragma mark - Layout
  100 +
  101 +- (void)viewDidLayoutSubviews {
  102 + [super viewDidLayoutSubviews];
  103 +
  104 + _previewView.frame = self.view.bounds;
  105 + _previewView.scrollView.frame = self.view.bounds;
  106 + CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
  107 + _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
  108 + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
  109 +
  110 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  111 + if (tzImagePickerVc.gifPreviewPageDidLayoutSubviewsBlock) {
  112 + tzImagePickerVc.gifPreviewPageDidLayoutSubviewsBlock(_toolBar, _doneButton);
  113 + }
  114 +}
  115 +
  116 +#pragma mark - Click Event
  117 +
  118 +- (void)signleTapAction {
  119 + _toolBar.hidden = !_toolBar.isHidden;
  120 + [self.navigationController setNavigationBarHidden:_toolBar.isHidden];
  121 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  122 + if (iOS7Later) {
  123 + if (_toolBar.isHidden) {
  124 + [UIApplication sharedApplication].statusBarHidden = YES;
  125 + } else if (tzImagePickerVc.needShowStatusBar) {
  126 + [UIApplication sharedApplication].statusBarHidden = NO;
  127 + }
  128 + }
  129 +}
  130 +
  131 +- (void)doneButtonClick {
  132 +#pragma mark - TODO: 导出
  133 +
  134 + if (self.navigationController) {
  135 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  136 + if (imagePickerVc.autoDismiss) {
  137 + [self.navigationController dismissViewControllerAnimated:YES completion:^{
  138 + [self callDelegateMethod];
  139 + }];
  140 + } else {
  141 + [self callDelegateMethod];
  142 + }
  143 + } else {
  144 + [self dismissViewControllerAnimated:YES completion:^{
  145 + [self callDelegateMethod];
  146 + }];
  147 + }
  148 +}
  149 +
  150 +- (void)callDelegateMethod {
  151 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  152 + UIImage *animatedImage = _previewView.imageView.image;
  153 + if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) {
  154 + [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset];
  155 + }
  156 + if (imagePickerVc.didFinishPickingGifImageHandle) {
  157 + imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset);
  158 + }
  159 +}
  160 +
  161 +#pragma clang diagnostic pop
  162 +
  163 +@end
... ...
CNLiveImagePickerController/Classes/TZImageCropManager.h 0 → 100755
  1 +//
  2 +// TZImageCropManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2016/12/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +// 图片裁剪管理类
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +
  12 +@interface TZImageCropManager : NSObject
  13 +
  14 +/// 裁剪框背景的处理
  15 ++ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop;
  16 +
  17 +/*
  18 + 1.7.2 为了解决多位同学对于图片裁剪的需求,我这两天有空便在研究图片裁剪
  19 + 幸好有tuyou的PhotoTweaks库做参考,裁剪的功能实现起来简单许多
  20 + 该方法和其内部引用的方法基本来自于tuyou的PhotoTweaks库,我做了稍许删减和修改
  21 + 感谢tuyou同学在github开源了优秀的裁剪库PhotoTweaks,表示感谢
  22 + PhotoTweaks库的github链接:https://github.com/itouch2/PhotoTweaks
  23 + */
  24 +/// 获得裁剪后的图片
  25 ++ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView;
  26 +
  27 +/// 获取圆形图片
  28 ++ (UIImage *)circularClipImage:(UIImage *)image;
  29 +
  30 +@end
  31 +
  32 +
  33 +/// 该分类的代码来自SDWebImage:https://github.com/rs/SDWebImage
  34 +/// 为了防止冲突,我将分类名字和方法名字做了修改
  35 +@interface UIImage (TZGif)
  36 +
  37 ++ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data;
  38 +
  39 +@end
... ...
CNLiveImagePickerController/Classes/TZImageCropManager.m 0 → 100755
  1 +//
  2 +// TZImageCropManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2016/12/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImageCropManager.h"
  10 +#import "UIView+TZLayout.h"
  11 +#import <ImageIO/ImageIO.h>
  12 +#import "TZImageManager.h"
  13 +#import "TZImagePickerController.h"
  14 +
  15 +@implementation TZImageCropManager
  16 +
  17 +/// 裁剪框背景的处理
  18 ++ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop {
  19 + UIBezierPath *path= [UIBezierPath bezierPathWithRect:[UIScreen mainScreen].bounds];
  20 + CAShapeLayer *layer = [CAShapeLayer layer];
  21 + if (needCircleCrop) { // 圆形裁剪框
  22 + [path appendPath:[UIBezierPath bezierPathWithArcCenter:containerView.center radius:cropRect.size.width / 2 startAngle:0 endAngle: 2 * M_PI clockwise:NO]];
  23 + } else { // 矩形裁剪框
  24 + [path appendPath:[UIBezierPath bezierPathWithRect:cropRect]];
  25 + }
  26 + layer.path = path.CGPath;
  27 + layer.fillRule = kCAFillRuleEvenOdd;
  28 + layer.fillColor = [[UIColor blackColor] CGColor];
  29 + layer.opacity = 0.5;
  30 + [view.layer addSublayer:layer];
  31 +}
  32 +
  33 +/// 获得裁剪后的图片
  34 ++ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView {
  35 + CGAffineTransform transform = CGAffineTransformIdentity;
  36 + // 平移的处理
  37 + CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView];
  38 + CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2, imageViewRect.origin.y + imageViewRect.size.height / 2);
  39 + CGFloat xMargin = containerView.tz_width - CGRectGetMaxX(rect) - rect.origin.x;
  40 + CGPoint zeroPoint = CGPointMake((CGRectGetWidth(containerView.frame) - xMargin) / 2, containerView.center.y);
  41 + CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y);
  42 + transform = CGAffineTransformTranslate(transform, translation.x, translation.y);
  43 + // 缩放的处理
  44 + transform = CGAffineTransformScale(transform, zoomScale, zoomScale);
  45 +
  46 + CGImageRef imageRef = [self newTransformedImage:transform
  47 + sourceImage:imageView.image.CGImage
  48 + sourceSize:imageView.image.size
  49 + outputWidth:rect.size.width * [UIScreen mainScreen].scale
  50 + cropSize:rect.size
  51 + imageViewSize:imageView.frame.size];
  52 + UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
  53 + cropedImage = [[TZImageManager manager] fixOrientation:cropedImage];
  54 + CGImageRelease(imageRef);
  55 + return cropedImage;
  56 +}
  57 +
  58 ++ (CGImageRef)newTransformedImage:(CGAffineTransform)transform sourceImage:(CGImageRef)sourceImage sourceSize:(CGSize)sourceSize outputWidth:(CGFloat)outputWidth cropSize:(CGSize)cropSize imageViewSize:(CGSize)imageViewSize {
  59 + CGImageRef source = [self newScaledImage:sourceImage toSize:sourceSize];
  60 +
  61 + CGFloat aspect = cropSize.height/cropSize.width;
  62 + CGSize outputSize = CGSizeMake(outputWidth, outputWidth*aspect);
  63 +
  64 + CGContextRef context = CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0, CGImageGetColorSpace(source), CGImageGetBitmapInfo(source));
  65 + CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
  66 + CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height));
  67 +
  68 + CGAffineTransform uiCoords = CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height);
  69 + uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width/2.0, cropSize.height / 2.0);
  70 + uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0);
  71 + CGContextConcatCTM(context, uiCoords);
  72 +
  73 + CGContextConcatCTM(context, transform);
  74 + CGContextScaleCTM(context, 1.0, -1.0);
  75 +
  76 + CGContextDrawImage(context, CGRectMake(-imageViewSize.width/2, -imageViewSize.height/2.0, imageViewSize.width, imageViewSize.height), source);
  77 + CGImageRef resultRef = CGBitmapContextCreateImage(context);
  78 + CGContextRelease(context);
  79 + CGImageRelease(source);
  80 + return resultRef;
  81 +}
  82 +
  83 ++ (CGImageRef)newScaledImage:(CGImageRef)source toSize:(CGSize)size {
  84 + CGSize srcSize = size;
  85 + CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
  86 + CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
  87 + CGColorSpaceRelease(rgbColorSpace);
  88 +
  89 + CGContextSetInterpolationQuality(context, kCGInterpolationNone);
  90 + CGContextTranslateCTM(context, size.width/2, size.height/2);
  91 +
  92 + CGContextDrawImage(context, CGRectMake(-srcSize.width/2, -srcSize.height/2, srcSize.width, srcSize.height), source);
  93 +
  94 + CGImageRef resultRef = CGBitmapContextCreateImage(context);
  95 + CGContextRelease(context);
  96 + return resultRef;
  97 +}
  98 +
  99 +/// 获取圆形图片
  100 ++ (UIImage *)circularClipImage:(UIImage *)image {
  101 + UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
  102 +
  103 + CGContextRef ctx = UIGraphicsGetCurrentContext();
  104 + CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
  105 + CGContextAddEllipseInRect(ctx, rect);
  106 + CGContextClip(ctx);
  107 +
  108 + [image drawInRect:rect];
  109 + UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext();
  110 +
  111 + UIGraphicsEndImageContext();
  112 + return circleImage;
  113 +}
  114 +
  115 +@end
  116 +
  117 +
  118 +@implementation UIImage (TZGif)
  119 +
  120 ++ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data {
  121 + if (!data) {
  122 + return nil;
  123 + }
  124 +
  125 + CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
  126 +
  127 + size_t count = CGImageSourceGetCount(source);
  128 +
  129 + UIImage *animatedImage;
  130 +
  131 + if (count <= 1) {
  132 + animatedImage = [[UIImage alloc] initWithData:data];
  133 + }
  134 + else {
  135 + // images数组过大时内存会飙升,在这里限制下最大count
  136 + NSInteger maxCount = [TZImagePickerConfig sharedInstance].gifPreviewMaxImagesCount ?: 200;
  137 + NSInteger interval = MAX((count + maxCount / 2) / maxCount, 1);
  138 +
  139 + NSMutableArray *images = [NSMutableArray array];
  140 +
  141 + NSTimeInterval duration = 0.0f;
  142 +
  143 + for (size_t i = 0; i < count; i+=interval) {
  144 + CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
  145 + if (!image) {
  146 + continue;
  147 + }
  148 +
  149 + duration += [self sd_frameDurationAtIndex:i source:source] * MIN(interval, 3);
  150 +
  151 + [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
  152 +
  153 + CGImageRelease(image);
  154 + }
  155 +
  156 + if (!duration) {
  157 + duration = (1.0f / 10.0f) * count;
  158 + }
  159 +
  160 + animatedImage = [UIImage animatedImageWithImages:images duration:duration];
  161 + }
  162 +
  163 + CFRelease(source);
  164 +
  165 + return animatedImage;
  166 +}
  167 +
  168 ++ (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
  169 + float frameDuration = 0.1f;
  170 + CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
  171 + NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
  172 + NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
  173 +
  174 + NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
  175 + if (delayTimeUnclampedProp) {
  176 + frameDuration = [delayTimeUnclampedProp floatValue];
  177 + }
  178 + else {
  179 +
  180 + NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
  181 + if (delayTimeProp) {
  182 + frameDuration = [delayTimeProp floatValue];
  183 + }
  184 + }
  185 +
  186 + // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
  187 + // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
  188 + // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
  189 + // for more information.
  190 +
  191 + if (frameDuration < 0.011f) {
  192 + frameDuration = 0.100f;
  193 + }
  194 +
  195 + CFRelease(cfFrameProperties);
  196 + return frameDuration;
  197 +}
  198 +
  199 +@end
... ...
CNLiveImagePickerController/Classes/TZImageManager.h 0 → 100755
  1 +//
  2 +// TZImageManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/4.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +// 图片资源获取管理类
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +#import <AVFoundation/AVFoundation.h>
  12 +#import <Photos/Photos.h>
  13 +#import "TZAssetModel.h"
  14 +
  15 +@class TZAlbumModel,TZAssetModel;
  16 +@protocol TZImagePickerControllerDelegate;
  17 +@interface TZImageManager : NSObject
  18 +
  19 +@property (nonatomic, strong) PHCachingImageManager *cachingImageManager;
  20 +
  21 ++ (instancetype)manager NS_SWIFT_NAME(default());
  22 ++ (void)deallocManager;
  23 +
  24 +@property (weak, nonatomic) id<TZImagePickerControllerDelegate> pickerDelegate;
  25 +
  26 +#pragma mark - 添加: 原有逻辑-会话id(LXG)
  27 +//zl__会话Id用于视频导出路径
  28 +@property (nonatomic, strong) NSString *conversationId;
  29 +
  30 +@property (nonatomic, assign) BOOL shouldFixOrientation;
  31 +
  32 +/// Default is 600px / 默认600像素宽
  33 +@property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
  34 +/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
  35 +@property (nonatomic, assign) CGFloat photoWidth;
  36 +
  37 +/// Default is 4, Use in photos collectionView in TZPhotoPickerController
  38 +/// 默认4列, TZPhotoPickerController中的照片collectionView
  39 +@property (nonatomic, assign) NSInteger columnNumber;
  40 +
  41 +/// Sort photos ascending by modificationDate,Default is YES
  42 +/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
  43 +@property (nonatomic, assign) BOOL sortAscendingByModificationDate;
  44 +
  45 +/// Minimum selectable photo width, Default is 0
  46 +/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
  47 +@property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
  48 +@property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
  49 +@property (nonatomic, assign) BOOL hideWhenCanNotSelect;
  50 +
  51 +/// Return YES if Authorized 返回YES如果得到了授权
  52 +- (BOOL)authorizationStatusAuthorized;
  53 ++ (NSInteger)authorizationStatus;
  54 +- (void)requestAuthorizationWithCompletion:(void (^)(void))completion;
  55 +
  56 +/// Get Album 获得相册/相册数组
  57 +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion;
  58 +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *models))completion;
  59 +
  60 +/// Get Assets 获得Asset数组
  61 +- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
  62 +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
  63 +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion;
  64 +
  65 +/// Get photo 获得照片
  66 +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion;
  67 +
  68 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  69 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  70 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
  71 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
  72 +- (int32_t)requestImageDataForAsset:(id)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler;
  73 +
  74 +/// Get full Image 获取原图
  75 +/// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。
  76 +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
  77 +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  78 +// 该方法中,completion只会走一次
  79 +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
  80 +- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
  81 +
  82 +/// Save photo 保存照片
  83 +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion;
  84 +- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
  85 +
  86 +/// Save video 保存视频
  87 +- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion;
  88 +- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
  89 +
  90 +/// Get video 获得视频
  91 +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
  92 +- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion;
  93 +
  94 +/// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480
  95 +- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
  96 +- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
  97 +/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
  98 +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion __attribute__((deprecated("Use -getVideoOutputPathWithAsset:failure:success:")));
  99 +
  100 +/// Get photo bytes 获得一组照片的大小
  101 +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
  102 +
  103 +/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
  104 +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset;
  105 +
  106 +- (NSString *)getAssetIdentifier:(id)asset;
  107 +- (BOOL)isCameraRollAlbum:(id)metadata;
  108 +
  109 +/// 检查照片大小是否满足最小要求
  110 +- (BOOL)isPhotoSelectableWithAsset:(id)asset;
  111 +- (CGSize)photoSizeWithAsset:(id)asset;
  112 +
  113 +/// 修正图片转向
  114 +- (UIImage *)fixOrientation:(UIImage *)aImage;
  115 +
  116 +/// 获取asset的资源类型
  117 +- (TZAssetModelMediaType)getAssetType:(id)asset;
  118 +/// 缩放图片至新尺寸
  119 +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size;
  120 +
  121 +/// 判断asset是否是视频
  122 +- (BOOL)isVideo:(id)asset;
  123 +
  124 +@end
  125 +
  126 +//@interface TZSortDescriptor : NSSortDescriptor
  127 +//
  128 +//@end
... ...
CNLiveImagePickerController/Classes/TZImageManager.m 0 → 100755
  1 +//
  2 +// TZImageManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/4.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImageManager.h"
  10 +#import <AssetsLibrary/AssetsLibrary.h>
  11 +#import "TZAssetModel.h"
  12 +#import "TZImagePickerController.h"
  13 +
  14 +@interface TZImageManager ()
  15 +#pragma clang diagnostic push
  16 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  17 +@property (nonatomic, strong) ALAssetsLibrary *assetLibrary;
  18 +@end
  19 +
  20 +@implementation TZImageManager
  21 +
  22 +CGSize AssetGridThumbnailSize;
  23 +CGFloat TZScreenWidth;
  24 +CGFloat TZScreenScale;
  25 +
  26 +static TZImageManager *manager;
  27 +static dispatch_once_t onceToken;
  28 +
  29 ++ (instancetype)manager {
  30 + dispatch_once(&onceToken, ^{
  31 + manager = [[self alloc] init];
  32 + if (iOS8Later) {
  33 + // manager.cachingImageManager = [[PHCachingImageManager alloc] init];
  34 + // manager.cachingImageManager.allowsCachingHighQualityImages = YES;
  35 + }
  36 +
  37 + [manager configTZScreenWidth];
  38 + });
  39 + return manager;
  40 +}
  41 +
  42 ++ (void)deallocManager {
  43 + onceToken = 0;
  44 + manager = nil;
  45 +}
  46 +
  47 +- (void)setPhotoWidth:(CGFloat)photoWidth {
  48 + _photoWidth = photoWidth;
  49 + TZScreenWidth = photoWidth / 2;
  50 +}
  51 +
  52 +- (void)setColumnNumber:(NSInteger)columnNumber {
  53 + [self configTZScreenWidth];
  54 +
  55 + _columnNumber = columnNumber;
  56 + CGFloat margin = 4;
  57 + CGFloat itemWH = (TZScreenWidth - 2 * margin - 4) / columnNumber - margin;
  58 + AssetGridThumbnailSize = CGSizeMake(itemWH * TZScreenScale, itemWH * TZScreenScale);
  59 +}
  60 +
  61 +- (void)configTZScreenWidth {
  62 + TZScreenWidth = [UIScreen mainScreen].bounds.size.width;
  63 + // 测试发现,如果scale在plus真机上取到3.0,内存会增大特别多。故这里写死成2.0
  64 + TZScreenScale = 2.0;
  65 + if (TZScreenWidth > 700) {
  66 + TZScreenScale = 1.5;
  67 + }
  68 +}
  69 +
  70 +- (ALAssetsLibrary *)assetLibrary {
  71 + if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init];
  72 + return _assetLibrary;
  73 +}
  74 +
  75 +/// Return YES if Authorized 返回YES如果得到了授权
  76 +- (BOOL)authorizationStatusAuthorized {
  77 + NSInteger status = [self.class authorizationStatus];
  78 + if (status == 0) {
  79 + /**
  80 + * 当某些情况下AuthorizationStatus == AuthorizationStatusNotDetermined时,无法弹出系统首次使用的授权alertView,系统应用设置里亦没有相册的设置,此时将无法使用,故作以下操作,弹出系统首次使用的授权alertView
  81 + */
  82 + [self requestAuthorizationWithCompletion:nil];
  83 + }
  84 +
  85 + return status == 3;
  86 +}
  87 +
  88 ++ (NSInteger)authorizationStatus {
  89 + if (iOS8Later) {
  90 + return [PHPhotoLibrary authorizationStatus];
  91 + } else {
  92 + return [ALAssetsLibrary authorizationStatus];
  93 + }
  94 + return NO;
  95 +}
  96 +
  97 +- (void)requestAuthorizationWithCompletion:(void (^)(void))completion {
  98 + void (^callCompletionBlock)(void) = ^(){
  99 + dispatch_async(dispatch_get_main_queue(), ^{
  100 + if (completion) {
  101 + completion();
  102 + }
  103 + });
  104 + };
  105 +
  106 + if (iOS8Later) {
  107 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  108 + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
  109 + callCompletionBlock();
  110 + }];
  111 + });
  112 + } else {
  113 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  114 + callCompletionBlock();
  115 + } failureBlock:^(NSError *error) {
  116 + callCompletionBlock();
  117 + }];
  118 + }
  119 +}
  120 +
  121 +#pragma mark - Get Album
  122 +
  123 +/// Get Album 获得相册/相册数组
  124 +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion {
  125 + __block TZAlbumModel *model;
  126 + if (iOS8Later) {
  127 + PHFetchOptions *option = [[PHFetchOptions alloc] init];
  128 + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
  129 + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
  130 + PHAssetMediaTypeVideo];
  131 + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
  132 + if (!self.sortAscendingByModificationDate) {
  133 + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
  134 + }
  135 + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  136 + for (PHAssetCollection *collection in smartAlbums) {
  137 + // 有可能是PHCollectionList类的的对象,过滤掉
  138 + if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  139 + // 过滤空相册
  140 + if (collection.estimatedAssetCount <= 0) continue;
  141 + if ([self isCameraRollAlbum:collection]) {
  142 + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
  143 + model = [self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets];
  144 + if (completion) completion(model);
  145 + break;
  146 + }
  147 + }
  148 + } else {
  149 + __weak typeof(self) weakSelf = self;
  150 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  151 + if ([group numberOfAssets] < 1) return;
  152 + if ([weakSelf isCameraRollAlbum:group]) {
  153 + NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
  154 + model = [weakSelf modelWithResult:group name:name isCameraRoll:YES needFetchAssets:needFetchAssets];
  155 + if (completion) completion(model);
  156 + *stop = YES;
  157 + }
  158 + } failureBlock:nil];
  159 + }
  160 +}
  161 +
  162 +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *))completion{
  163 + NSMutableArray *albumArr = [NSMutableArray array];
  164 + if (iOS8Later) {
  165 + PHFetchOptions *option = [[PHFetchOptions alloc] init];
  166 + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
  167 + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
  168 + PHAssetMediaTypeVideo];
  169 + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
  170 + if (!self.sortAscendingByModificationDate) {
  171 + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
  172 + }
  173 + // 我的照片流 1.6.10重新加入..
  174 + PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil];
  175 + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  176 + PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
  177 + PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil];
  178 + PHFetchResult *sharedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumCloudShared options:nil];
  179 + NSArray *allAlbums = @[myPhotoStreamAlbum,smartAlbums,topLevelUserCollections,syncedAlbums,sharedAlbums];
  180 + for (PHFetchResult *fetchResult in allAlbums) {
  181 + for (PHAssetCollection *collection in fetchResult) {
  182 + // 有可能是PHCollectionList类的的对象,过滤掉
  183 + if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  184 + // 过滤空相册
  185 + if (collection.estimatedAssetCount <= 0) continue;
  186 + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
  187 + if (fetchResult.count < 1) continue;
  188 +
  189 + if ([self.pickerDelegate respondsToSelector:@selector(isAlbumCanSelect:result:)]) {
  190 + if (![self.pickerDelegate isAlbumCanSelect:collection.localizedTitle result:fetchResult]) {
  191 + continue;
  192 + }
  193 + }
  194 +
  195 + if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumAllHidden) continue;
  196 + if (collection.assetCollectionSubtype == 1000000201) continue; //『最近删除』相册
  197 + if ([self isCameraRollAlbum:collection]) {
  198 + [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0];
  199 + } else {
  200 + [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:NO needFetchAssets:needFetchAssets]];
  201 + }
  202 + }
  203 + }
  204 + if (completion && albumArr.count > 0){
  205 + completion(albumArr);
  206 + }else {
  207 + completion(nil);
  208 + }
  209 + } else {
  210 + __weak typeof(self) weakSelf = self;
  211 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  212 + if (group == nil) {
  213 + if (completion && albumArr.count > 0) completion(albumArr);
  214 + }
  215 + if ([group numberOfAssets] < 1) return;
  216 + NSString *name = [group valueForProperty:ALAssetsGroupPropertyName];
  217 +
  218 + if ([self.pickerDelegate respondsToSelector:@selector(isAlbumCanSelect:result:)]) {
  219 + if (![weakSelf.pickerDelegate isAlbumCanSelect:name result:group]) {
  220 + return;
  221 + }
  222 + }
  223 +
  224 + if ([weakSelf isCameraRollAlbum:group]) {
  225 + [albumArr insertObject:[weakSelf modelWithResult:group name:name isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0];
  226 + } else if ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupPhotoStream) {
  227 + if (albumArr.count) {
  228 + [albumArr insertObject:[weakSelf modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets] atIndex:1];
  229 + } else {
  230 + [albumArr addObject:[weakSelf modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets]];
  231 + }
  232 + } else {
  233 + [albumArr addObject:[weakSelf modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets]];
  234 + }
  235 + } failureBlock:nil];
  236 + }
  237 +}
  238 +
  239 +#pragma mark - Get Assets
  240 +
  241 +/// Get Assets 获得照片数组
  242 +- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *))completion {
  243 + TZImagePickerConfig *config = [TZImagePickerConfig sharedInstance];
  244 + return [self getAssetsFromFetchResult:result allowPickingVideo:config.allowPickingVideo allowPickingImage:config.allowPickingImage completion:completion];
  245 +}
  246 +
  247 +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *))completion {
  248 + NSMutableArray *photoArr = [NSMutableArray array];
  249 + if ([result isKindOfClass:[PHFetchResult class]]) {
  250 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  251 + [fetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  252 + TZAssetModel *model = [self assetModelWithAsset:obj allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  253 + if (model) {
  254 + [photoArr addObject:model];
  255 + }
  256 + }];
  257 + if (completion) completion(photoArr);
  258 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  259 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  260 + if (allowPickingImage && allowPickingVideo) {
  261 + [group setAssetsFilter:[ALAssetsFilter allAssets]];
  262 + } else if (allowPickingVideo) {
  263 + [group setAssetsFilter:[ALAssetsFilter allVideos]];
  264 + } else if (allowPickingImage) {
  265 + [group setAssetsFilter:[ALAssetsFilter allPhotos]];
  266 + }
  267 + ALAssetsGroupEnumerationResultsBlock resultBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
  268 + if (result == nil) {
  269 + if (completion) completion(photoArr);
  270 + }
  271 + TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  272 + if (model) {
  273 + [photoArr addObject:model];
  274 + }
  275 + };
  276 + if (self.sortAscendingByModificationDate) {
  277 + [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  278 + if (resultBlock) { resultBlock(result,index,stop); }
  279 + }];
  280 + } else {
  281 + [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  282 + if (resultBlock) {resultBlock(result,index,stop); }
  283 + }];
  284 + }
  285 + }
  286 +}
  287 +
  288 +/// Get asset at index 获得下标为index的单个照片
  289 +/// if index beyond bounds, return nil in callback 如果索引越界, 在回调中返回 nil
  290 +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *))completion {
  291 + if ([result isKindOfClass:[PHFetchResult class]]) {
  292 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  293 + PHAsset *asset;
  294 + @try {
  295 + asset = fetchResult[index];
  296 + }
  297 + @catch (NSException* e) {
  298 + if (completion) completion(nil);
  299 + return;
  300 + }
  301 + TZAssetModel *model = [self assetModelWithAsset:asset allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  302 + if (completion) completion(model);
  303 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  304 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  305 + if (allowPickingImage && allowPickingVideo) {
  306 + [group setAssetsFilter:[ALAssetsFilter allAssets]];
  307 + } else if (allowPickingVideo) {
  308 + [group setAssetsFilter:[ALAssetsFilter allVideos]];
  309 + } else if (allowPickingImage) {
  310 + [group setAssetsFilter:[ALAssetsFilter allPhotos]];
  311 + }
  312 + NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:index];
  313 + @try {
  314 + [group enumerateAssetsAtIndexes:indexSet options:NSEnumerationConcurrent usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
  315 + if (!result) return;
  316 + TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage];
  317 + if (completion) completion(model);
  318 + }];
  319 + }
  320 + @catch (NSException* e) {
  321 + if (completion) completion(nil);
  322 + }
  323 + }
  324 +}
  325 +
  326 +- (TZAssetModel *)assetModelWithAsset:(id)asset allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage {
  327 + BOOL canSelect = YES;
  328 + if ([self.pickerDelegate respondsToSelector:@selector(isAssetCanSelect:)]) {
  329 + canSelect = [self.pickerDelegate isAssetCanSelect:asset];
  330 + }
  331 + if (!canSelect) return nil;
  332 +
  333 + TZAssetModel *model;
  334 + TZAssetModelMediaType type = [self getAssetType:asset];
  335 + if ([asset isKindOfClass:[PHAsset class]]) {
  336 + if (!allowPickingVideo && type == TZAssetModelMediaTypeVideo) return nil;
  337 + if (!allowPickingImage && type == TZAssetModelMediaTypePhoto) return nil;
  338 + if (!allowPickingImage && type == TZAssetModelMediaTypePhotoGif) return nil;
  339 +
  340 + PHAsset *phAsset = (PHAsset *)asset;
  341 + if (self.hideWhenCanNotSelect) {
  342 + // 过滤掉尺寸不满足要求的图片
  343 + if (![self isPhotoSelectableWithAsset:phAsset]) {
  344 + return nil;
  345 + }
  346 + }
  347 + NSString *timeLength = type == TZAssetModelMediaTypeVideo ? [NSString stringWithFormat:@"%0.0f",phAsset.duration] : @"";
  348 + timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
  349 + model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength];
  350 + } else {
  351 + if (!allowPickingVideo){
  352 + model = [TZAssetModel modelWithAsset:asset type:type];
  353 + return model;
  354 + }
  355 + /// Allow picking video
  356 + if (type == TZAssetModelMediaTypeVideo) {
  357 + NSTimeInterval duration = [[asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  358 + NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration];
  359 + timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue];
  360 + model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength];
  361 + } else {
  362 + if (self.hideWhenCanNotSelect) {
  363 + // 过滤掉尺寸不满足要求的图片
  364 + if (![self isPhotoSelectableWithAsset:asset]) {
  365 + return nil;
  366 + }
  367 + }
  368 + model = [TZAssetModel modelWithAsset:asset type:type];
  369 + }
  370 + }
  371 + return model;
  372 +}
  373 +
  374 +- (TZAssetModelMediaType)getAssetType:(id)asset {
  375 + TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
  376 + if ([asset isKindOfClass:[PHAsset class]]) {
  377 + PHAsset *phAsset = (PHAsset *)asset;
  378 + if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
  379 + else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
  380 + else if (phAsset.mediaType == PHAssetMediaTypeImage) {
  381 + if (@available(iOS 9.1, *)) {
  382 + // if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto;
  383 + }
  384 + // Gif
  385 + if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  386 + type = TZAssetModelMediaTypePhotoGif;
  387 + }
  388 + }
  389 + } else {
  390 + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
  391 + type = TZAssetModelMediaTypeVideo;
  392 + }
  393 + }
  394 + return type;
  395 +}
  396 +
  397 +- (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration {
  398 + NSString *newTime;
  399 + if (duration < 10) {
  400 + newTime = [NSString stringWithFormat:@"0:0%zd",duration];
  401 + } else if (duration < 60) {
  402 + newTime = [NSString stringWithFormat:@"0:%zd",duration];
  403 + } else {
  404 + NSInteger min = duration / 60;
  405 + NSInteger sec = duration - (min * 60);
  406 + if (sec < 10) {
  407 + newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec];
  408 + } else {
  409 + newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec];
  410 + }
  411 + }
  412 + return newTime;
  413 +}
  414 +
  415 +/// Get photo bytes 获得一组照片的大小
  416 +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion {
  417 + if (!photos || !photos.count) {
  418 + if (completion) completion(@"0B");
  419 + return;
  420 + }
  421 + __block NSInteger dataLength = 0;
  422 + __block NSInteger assetCount = 0;
  423 + for (NSInteger i = 0; i < photos.count; i++) {
  424 + TZAssetModel *model = photos[i];
  425 + if ([model.asset isKindOfClass:[PHAsset class]]) {
  426 + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  427 + options.resizeMode = PHImageRequestOptionsResizeModeFast;
  428 + options.networkAccessAllowed = YES;
  429 + if (model.type == TZAssetModelMediaTypePhotoGif) {
  430 + options.version = PHImageRequestOptionsVersionOriginal;
  431 + }
  432 + [[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  433 + if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length;
  434 + assetCount ++;
  435 + if (assetCount >= photos.count) {
  436 + NSString *bytes = [self getBytesFromDataLength:dataLength];
  437 + if (completion) completion(bytes);
  438 + }
  439 + }];
  440 + } else if ([model.asset isKindOfClass:[ALAsset class]]) {
  441 + ALAssetRepresentation *representation = [model.asset defaultRepresentation];
  442 + if (model.type != TZAssetModelMediaTypeVideo) dataLength += (NSInteger)representation.size;
  443 + if (i >= photos.count - 1) {
  444 + NSString *bytes = [self getBytesFromDataLength:dataLength];
  445 + if (completion) completion(bytes);
  446 + }
  447 + }
  448 + }
  449 +}
  450 +
  451 +- (NSString *)getBytesFromDataLength:(NSInteger)dataLength {
  452 + NSString *bytes;
  453 + if (dataLength >= 0.1 * (1024 * 1024)) {
  454 + bytes = [NSString stringWithFormat:@"%0.1fM",dataLength/1024/1024.0];
  455 + } else if (dataLength >= 1024) {
  456 + bytes = [NSString stringWithFormat:@"%0.0fK",dataLength/1024.0];
  457 + } else {
  458 + bytes = [NSString stringWithFormat:@"%zdB",dataLength];
  459 + }
  460 + return bytes;
  461 +}
  462 +
  463 +#pragma mark - Get Photo
  464 +
  465 +/// Get photo 获得照片本身
  466 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion {
  467 + CGFloat fullScreenWidth = TZScreenWidth;
  468 + if (fullScreenWidth > _photoPreviewMaxWidth) {
  469 + fullScreenWidth = _photoPreviewMaxWidth;
  470 + }
  471 + return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:nil networkAccessAllowed:YES];
  472 +}
  473 +
  474 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion {
  475 + return [self getPhotoWithAsset:asset photoWidth:photoWidth completion:completion progressHandler:nil networkAccessAllowed:YES];
  476 +}
  477 +
  478 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed {
  479 + CGFloat fullScreenWidth = TZScreenWidth;
  480 + if (fullScreenWidth > _photoPreviewMaxWidth) {
  481 + fullScreenWidth = _photoPreviewMaxWidth;
  482 + }
  483 + return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:progressHandler networkAccessAllowed:networkAccessAllowed];
  484 +}
  485 +
  486 +- (int32_t)requestImageDataForAsset:(id)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler {
  487 + if ([asset isKindOfClass:[PHAsset class]]) {
  488 + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  489 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  490 + dispatch_async(dispatch_get_main_queue(), ^{
  491 + if (progressHandler) {
  492 + progressHandler(progress, error, stop, info);
  493 + }
  494 + });
  495 + };
  496 + options.networkAccessAllowed = YES;
  497 + options.resizeMode = PHImageRequestOptionsResizeModeFast;
  498 + int32_t imageRequestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  499 + if (completion) completion(imageData,dataUTI,orientation,info);
  500 + }];
  501 + return imageRequestID;
  502 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  503 + ALAsset *alAsset = (ALAsset *)asset;
  504 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  505 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  506 + CGImageRef fullScrennImageRef = [assetRep fullScreenImage];
  507 + UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp];
  508 + dispatch_async(dispatch_get_main_queue(), ^{
  509 + if (completion) completion(UIImageJPEGRepresentation(fullScrennImage, 0.83), nil, UIImageOrientationUp, nil);
  510 + });
  511 + });
  512 + }
  513 + return 0;
  514 +}
  515 +
  516 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed {
  517 + if ([asset isKindOfClass:[PHAsset class]]) {
  518 + CGSize imageSize;
  519 + if (photoWidth < TZScreenWidth && photoWidth < _photoPreviewMaxWidth) {
  520 + imageSize = AssetGridThumbnailSize;
  521 + } else {
  522 + PHAsset *phAsset = (PHAsset *)asset;
  523 + CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
  524 + CGFloat pixelWidth = photoWidth * TZScreenScale * 1.5;
  525 + // 超宽图片
  526 + if (aspectRatio > 1.8) {
  527 + pixelWidth = pixelWidth * aspectRatio;
  528 + }
  529 + // 超高图片
  530 + if (aspectRatio < 0.2) {
  531 + pixelWidth = pixelWidth * 0.5;
  532 + }
  533 + CGFloat pixelHeight = pixelWidth / aspectRatio;
  534 + imageSize = CGSizeMake(pixelWidth, pixelHeight);
  535 + }
  536 +
  537 + __block UIImage *image;
  538 + // 修复获取图片时出现的瞬间内存过高问题
  539 + // 下面两行代码,来自hsjcom,他的github是:https://github.com/hsjcom 表示感谢
  540 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
  541 + option.resizeMode = PHImageRequestOptionsResizeModeFast;
  542 + int32_t imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) {
  543 + if (result) {
  544 + image = result;
  545 + }
  546 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  547 + if (downloadFinined && result) {
  548 + result = [self fixOrientation:result];
  549 + if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
  550 + }
  551 + // Download image from iCloud / 从iCloud下载图片
  552 + if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) {
  553 + NSLog(@"输出有iCloud图片存在");
  554 + PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
  555 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  556 + NSLog(@"输出从iClou取图片进度 = %f",progress);
  557 + dispatch_async(dispatch_get_main_queue(), ^{
  558 + if (progressHandler) {
  559 + progressHandler(progress, error, stop, info);
  560 + }
  561 + });
  562 + };
  563 + options.networkAccessAllowed = YES;
  564 + options.resizeMode = PHImageRequestOptionsResizeModeFast;
  565 + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  566 + UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1];
  567 + if (![TZImagePickerConfig sharedInstance].notScaleImage) {
  568 + resultImage = [self scaleImage:resultImage toSize:imageSize];
  569 + }
  570 + if (!resultImage) {
  571 + resultImage = image;
  572 + }
  573 + resultImage = [self fixOrientation:resultImage];
  574 + if (completion) completion(resultImage,info,NO);
  575 + }];
  576 + }
  577 + }];
  578 + return imageRequestID;
  579 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  580 + ALAsset *alAsset = (ALAsset *)asset;
  581 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  582 + CGImageRef thumbnailImageRef = alAsset.thumbnail;
  583 + UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp];
  584 + dispatch_async(dispatch_get_main_queue(), ^{
  585 + if (completion) completion(thumbnailImage,nil,YES);
  586 +
  587 + if (photoWidth == TZScreenWidth || photoWidth == self->_photoPreviewMaxWidth) {
  588 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  589 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  590 + CGImageRef fullScrennImageRef = [assetRep fullScreenImage];
  591 + UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp];
  592 +
  593 + dispatch_async(dispatch_get_main_queue(), ^{
  594 + if (completion) completion(fullScrennImage,nil,NO);
  595 + });
  596 + });
  597 + }
  598 + });
  599 + });
  600 + }
  601 + return 0;
  602 +}
  603 +
  604 +/// Get postImage / 获取封面图
  605 +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *))completion {
  606 + if (iOS8Later) {
  607 + id asset = [model.result lastObject];
  608 + if (!self.sortAscendingByModificationDate) {
  609 + asset = [model.result firstObject];
  610 + }
  611 + [[TZImageManager manager] getPhotoWithAsset:asset photoWidth:80 completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  612 + if (photo) {//lxg: 裂图
  613 + model.isExport = YES;
  614 + }else{
  615 + model.isExport = NO;
  616 + }
  617 + if (completion) completion(photo);
  618 + }];
  619 + } else {
  620 + ALAssetsGroup *group = model.result;
  621 + UIImage *postImage = [UIImage imageWithCGImage:group.posterImage];
  622 + if (completion) completion(postImage);
  623 + }
  624 +}
  625 +
  626 +/// Get Original Photo / 获取原图
  627 +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion {
  628 + [self getOriginalPhotoWithAsset:asset newCompletion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  629 + if (completion) {
  630 + completion(photo,info);
  631 + }
  632 + }];
  633 +}
  634 +
  635 +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion {
  636 + if ([asset isKindOfClass:[PHAsset class]]) {
  637 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init];
  638 + option.networkAccessAllowed = YES;
  639 + option.resizeMode = PHImageRequestOptionsResizeModeFast;
  640 + [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage *result, NSDictionary *info) {
  641 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  642 + if (downloadFinined && result) {
  643 + result = [self fixOrientation:result];
  644 + BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue];
  645 + if (completion) completion(result,info,isDegraded);
  646 + }
  647 + }];
  648 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  649 + ALAsset *alAsset = (ALAsset *)asset;
  650 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  651 +
  652 + dispatch_async(dispatch_get_global_queue(0,0), ^{
  653 + CGImageRef originalImageRef = [assetRep fullResolutionImage];
  654 + UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp];
  655 +
  656 + dispatch_async(dispatch_get_main_queue(), ^{
  657 + if (completion) completion(originalImage,nil,NO);
  658 + });
  659 + });
  660 + }
  661 +}
  662 +
  663 +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion {
  664 + [self getOriginalPhotoDataWithAsset:asset progressHandler:nil completion:completion];
  665 +}
  666 +
  667 +- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion {
  668 + if ([asset isKindOfClass:[PHAsset class]]) {
  669 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
  670 + option.networkAccessAllowed = YES;
  671 + if ([[asset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  672 + // if version isn't PHImageRequestOptionsVersionOriginal, the gif may cann't play
  673 + option.version = PHImageRequestOptionsVersionOriginal;
  674 + }
  675 + [option setProgressHandler:progressHandler];
  676 + option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  677 + [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  678 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  679 + if (downloadFinined && imageData) {
  680 + if (completion) completion(imageData,info,NO);
  681 + }
  682 + }];
  683 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  684 + ALAsset *alAsset = (ALAsset *)asset;
  685 + ALAssetRepresentation *assetRep = [alAsset defaultRepresentation];
  686 + Byte *imageBuffer = (Byte *)malloc(assetRep.size);
  687 + NSUInteger bufferSize = [assetRep getBytes:imageBuffer fromOffset:0.0 length:assetRep.size error:nil];
  688 + NSData *imageData = [NSData dataWithBytesNoCopy:imageBuffer length:bufferSize freeWhenDone:YES];
  689 + if (completion) completion(imageData,nil,NO);
  690 + }
  691 +}
  692 +
  693 +#pragma mark - Save photo
  694 +
  695 +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion {
  696 + [self savePhotoWithImage:image location:nil completion:completion];
  697 +}
  698 +
  699 +- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion {
  700 +
  701 + if (iOS8Later) {
  702 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  703 + if (@available(iOS 9, *)) {
  704 + NSData *data = UIImageJPEGRepresentation(image, 0.9);
  705 + PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
  706 + options.shouldMoveFile = YES;
  707 + PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
  708 + [request addResourceWithType:PHAssetResourceTypePhoto data:data options:options];
  709 + if (location) {
  710 + request.location = location;
  711 + }
  712 + request.creationDate = [NSDate date];
  713 + } else {
  714 + PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
  715 + if (location) {
  716 + request.location = location;
  717 + }
  718 + request.creationDate = [NSDate date];
  719 + }
  720 + } completionHandler:^(BOOL success, NSError *error) {
  721 + dispatch_async(dispatch_get_main_queue(), ^{
  722 + if (success && completion) {
  723 + completion(nil);
  724 + } else if (error) {
  725 + NSLog(@"保存照片出错:%@",error.localizedDescription);
  726 + if (completion) {
  727 + completion(error);
  728 + }
  729 + }
  730 + });
  731 + }];
  732 + } else {
  733 + [self.assetLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:[self orientationFromImage:image] completionBlock:^(NSURL *assetURL, NSError *error) {
  734 + if (error) {
  735 + NSLog(@"保存图片失败:%@",error.localizedDescription);
  736 + if (completion) {
  737 + completion(error);
  738 + }
  739 + } else {
  740 + // 多给系统0.5秒的时间,让系统去更新相册数据
  741 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  742 + if (completion) {
  743 + completion(nil);
  744 + }
  745 + });
  746 + }
  747 + }];
  748 + }
  749 +}
  750 +
  751 +#pragma mark - Save video
  752 +
  753 +- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion {
  754 + [self saveVideoWithUrl:url location:nil completion:completion];
  755 +}
  756 +
  757 +- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion {
  758 + if (iOS8Later) {
  759 + [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  760 + if (@available(iOS 9, *)) {
  761 + PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
  762 + options.shouldMoveFile = YES;
  763 + PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
  764 + [request addResourceWithType:PHAssetResourceTypeVideo fileURL:url options:options];
  765 + if (location) {
  766 + request.location = location;
  767 + }
  768 + request.creationDate = [NSDate date];
  769 + } else {
  770 + PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url];
  771 + if (location) {
  772 + request.location = location;
  773 + }
  774 + request.creationDate = [NSDate date];
  775 + }
  776 + } completionHandler:^(BOOL success, NSError *error) {
  777 + dispatch_async(dispatch_get_main_queue(), ^{
  778 + if (success && completion) {
  779 + completion(nil);
  780 + } else if (error) {
  781 + NSLog(@"保存视频出错:%@",error.localizedDescription);
  782 + if (completion) {
  783 + completion(error);
  784 + }
  785 + }
  786 + });
  787 + }];
  788 + } else {
  789 + [self.assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) {
  790 + if (error) {
  791 + NSLog(@"保存视频出错:%@",error.localizedDescription);
  792 + if (completion) {
  793 + completion(error);
  794 + }
  795 + } else {
  796 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  797 + if (completion) {
  798 + completion(nil);
  799 + }
  800 + });
  801 + }
  802 + }];
  803 + }
  804 +}
  805 +
  806 +#pragma mark - Get Video
  807 +
  808 +/// Get Video / 获取视频
  809 +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem *, NSDictionary *))completion {
  810 + [self getVideoWithAsset:asset progressHandler:nil completion:completion];
  811 +}
  812 +
  813 +- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion {
  814 + if ([asset isKindOfClass:[PHAsset class]]) {
  815 + PHVideoRequestOptions *option = [[PHVideoRequestOptions alloc] init];
  816 + option.networkAccessAllowed = YES;
  817 + option.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  818 + dispatch_async(dispatch_get_main_queue(), ^{
  819 + if (progressHandler) {
  820 + progressHandler(progress, error, stop, info);
  821 + }
  822 + });
  823 + };
  824 + [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:option resultHandler:^(AVPlayerItem *playerItem, NSDictionary *info) {
  825 + if (completion) completion(playerItem,info);
  826 + }];
  827 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  828 + ALAsset *alAsset = (ALAsset *)asset;
  829 + ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation];
  830 + NSString *uti = [defaultRepresentation UTI];
  831 + NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti];
  832 + AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL];
  833 + if (completion && playerItem) completion(playerItem,nil);
  834 + }
  835 +}
  836 +
  837 +#pragma mark - Export video
  838 +
  839 +/// Export Video / 导出视频
  840 +- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
  841 + [self getVideoOutputPathWithAsset:asset presetName:AVAssetExportPreset640x480 success:success failure:failure];
  842 +}
  843 +
  844 +- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
  845 + if ([asset isKindOfClass:[PHAsset class]]) {
  846 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  847 + options.version = PHVideoRequestOptionsVersionOriginal;
  848 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  849 + options.networkAccessAllowed = YES;
  850 + options.progressHandler = ^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) {
  851 + NSLog(@"输出进度 = %f",progress);
  852 +
  853 + };
  854 + [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
  855 + NSLog(@"Info:\n%@",info);
  856 + AVURLAsset *videoAsset = (AVURLAsset*)avasset;
  857 +// NSLog(@"AVAsset URL: %@",myAsset.URL);
  858 + [self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
  859 + }];
  860 + } else if ([asset isKindOfClass:[ALAsset class]]) {
  861 + NSURL *videoURL =[asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs
  862 + AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
  863 + [self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
  864 + }
  865 +}
  866 +
  867 +/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
  868 +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion {
  869 + [self getVideoOutputPathWithAsset:asset success:completion failure:nil];
  870 +}
  871 +
  872 +- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
  873 + // Find compatible presets by video asset.
  874 + NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset];
  875 +
  876 + // Begin to compress video
  877 + // Now we just compress to low resolution if it supports
  878 + // If you need to upload to the server, but server does't support to upload by streaming,
  879 + // You can compress the resolution to lower. Or you can support more higher resolution.
  880 + if ([presets containsObject:presetName]) {
  881 + AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:presetName];
  882 +
  883 + NSDateFormatter *formater = [[NSDateFormatter alloc] init];
  884 + [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss-SSS"];
  885 +#pragma mark - 添加: 原有逻辑-根据会话id取得path(LXG)
  886 + NSString *filaName = [NSString stringWithFormat:@"output-%@_%d_fileType=videoType.mp4",[formater stringFromDate:[NSDate date]],arc4random()];
  887 +// NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]];
  888 + NSString *outputPath = @"";
  889 + if (self.conversationId) {
  890 + outputPath = [[CNLiveBusinessTools newChatFilePathByUserId:self.conversationId] stringByAppendingPathComponent:filaName];//聊天
  891 +
  892 + }
  893 + else
  894 + {
  895 +
  896 + outputPath = [[CNLiveBusinessTools chatFilePathByUserId:[IMAPlatform sharedInstance].host.userId] stringByAppendingString:filaName];//朋友圈
  897 + }
  898 + NSLog(@"video outputPath = %@",outputPath);
  899 +
  900 + session.outputURL = [NSURL fileURLWithPath:outputPath];
  901 +
  902 + // Optimize for network use.
  903 + session.shouldOptimizeForNetworkUse = true;
  904 +
  905 + NSArray *supportedTypeArray = session.supportedFileTypes;
  906 + if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
  907 + session.outputFileType = AVFileTypeMPEG4;
  908 + } else if (supportedTypeArray.count == 0) {
  909 + if (failure) {
  910 + failure(@"该视频类型暂不支持导出", nil);
  911 + }
  912 + NSLog(@"No supported file types 视频类型暂不支持导出");
  913 + return;
  914 + } else {
  915 + session.outputFileType = [supportedTypeArray objectAtIndex:0];
  916 + }
  917 +
  918 + if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) {
  919 + [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil];
  920 + }
  921 +
  922 + if ([TZImagePickerConfig sharedInstance].needFixComposition) {
  923 + AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset];
  924 + if (videoComposition.renderSize.width) {
  925 + // 修正视频转向
  926 + session.videoComposition = videoComposition;
  927 + }
  928 + }
  929 +
  930 + // Begin to export video to the output path asynchronously.
  931 +#pragma mark - 添加: 原有逻辑-会话id置空(LXG)
  932 + self.conversationId = nil;
  933 + [session exportAsynchronouslyWithCompletionHandler:^(void) {
  934 + dispatch_async(dispatch_get_main_queue(), ^{
  935 +
  936 + switch (session.status) {
  937 + case AVAssetExportSessionStatusUnknown: {
  938 + NSLog(@"AVAssetExportSessionStatusUnknown");
  939 + } break;
  940 + case AVAssetExportSessionStatusWaiting: {
  941 + NSLog(@"AVAssetExportSessionStatusWaiting");
  942 + } break;
  943 + case AVAssetExportSessionStatusExporting: {
  944 + NSLog(@"AVAssetExportSessionStatusExporting");
  945 + } break;
  946 + case AVAssetExportSessionStatusCompleted: {
  947 + NSLog(@"AVAssetExportSessionStatusCompleted");
  948 + if (success) {
  949 + success(outputPath);
  950 + }
  951 + } break;
  952 + case AVAssetExportSessionStatusFailed: {
  953 + NSLog(@"AVAssetExportSessionStatusFailed");
  954 + if (failure) {
  955 + failure(@"视频导出失败", session.error);
  956 + }
  957 + } break;
  958 + case AVAssetExportSessionStatusCancelled: {
  959 + NSLog(@"AVAssetExportSessionStatusCancelled");
  960 + if (failure) {
  961 + failure(@"导出任务已被取消", nil);
  962 + }
  963 + } break;
  964 + default:
  965 + NSLog(@"未知错误");
  966 + break;
  967 + }
  968 + });
  969 + }];
  970 + } else {
  971 + if (failure) {
  972 + NSString *errorMessage = [NSString stringWithFormat:@"当前设备不支持该预设:%@", presetName];
  973 + failure(errorMessage, nil);
  974 + }
  975 + }
  976 +}
  977 +
  978 +/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
  979 +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset {
  980 + if (iOS8Later) {
  981 + return [assets containsObject:asset];
  982 + } else {
  983 + NSMutableArray *selectedAssetUrls = [NSMutableArray array];
  984 + for (ALAsset *asset_item in assets) {
  985 + [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]];
  986 + }
  987 + return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]];
  988 + }
  989 +}
  990 +
  991 +- (BOOL)isCameraRollAlbum:(id)metadata {
  992 + if ([metadata isKindOfClass:[PHAssetCollection class]]) {
  993 + NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
  994 + if (versionStr.length <= 1) {
  995 + versionStr = [versionStr stringByAppendingString:@"00"];
  996 + } else if (versionStr.length <= 2) {
  997 + versionStr = [versionStr stringByAppendingString:@"0"];
  998 + }
  999 + CGFloat version = versionStr.floatValue;
  1000 + // 目前已知8.0.0 ~ 8.0.2系统,拍照后的图片会保存在最近添加中
  1001 + if (version >= 800 && version <= 802) {
  1002 + return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded;
  1003 + } else {
  1004 + return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary;
  1005 + }
  1006 + }
  1007 + if ([metadata isKindOfClass:[ALAssetsGroup class]]) {
  1008 + ALAssetsGroup *group = metadata;
  1009 + return ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupSavedPhotos);
  1010 + }
  1011 +
  1012 + return NO;
  1013 +}
  1014 +
  1015 +- (NSString *)getAssetIdentifier:(id)asset {
  1016 + if (iOS8Later) {
  1017 + PHAsset *phAsset = (PHAsset *)asset;
  1018 + return phAsset.localIdentifier;
  1019 + } else {
  1020 + ALAsset *alAsset = (ALAsset *)asset;
  1021 + NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL];
  1022 + return assetUrl.absoluteString;
  1023 + }
  1024 +}
  1025 +
  1026 +/// 检查照片大小是否满足最小要求
  1027 +- (BOOL)isPhotoSelectableWithAsset:(id)asset {
  1028 + CGSize photoSize = [self photoSizeWithAsset:asset];
  1029 + if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) {
  1030 + return NO;
  1031 + }
  1032 + return YES;
  1033 +}
  1034 +
  1035 +- (CGSize)photoSizeWithAsset:(id)asset {
  1036 + if (iOS8Later) {
  1037 + PHAsset *phAsset = (PHAsset *)asset;
  1038 + return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight);
  1039 + } else {
  1040 + ALAsset *alAsset = (ALAsset *)asset;
  1041 + return alAsset.defaultRepresentation.dimensions;
  1042 + }
  1043 +}
  1044 +
  1045 +#pragma mark - Private Method
  1046 +
  1047 +- (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name isCameraRoll:(BOOL)isCameraRoll needFetchAssets:(BOOL)needFetchAssets {
  1048 + TZAlbumModel *model = [[TZAlbumModel alloc] init];
  1049 + [model setResult:result needFetchAssets:needFetchAssets];
  1050 + model.name = name;
  1051 + model.isCameraRoll = isCameraRoll;
  1052 + if ([result isKindOfClass:[PHFetchResult class]]) {
  1053 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  1054 + model.count = fetchResult.count;
  1055 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  1056 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  1057 + model.count = [group numberOfAssets];
  1058 + }
  1059 + return model;
  1060 +}
  1061 +
  1062 +/// 缩放图片至新尺寸
  1063 +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size {
  1064 + if (image.size.width > size.width) {
  1065 + UIGraphicsBeginImageContext(size);
  1066 + [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
  1067 + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  1068 + UIGraphicsEndImageContext();
  1069 + return newImage;
  1070 +
  1071 + /* 好像不怎么管用:https://mp.weixin.qq.com/s/CiqMlEIp1Ir2EJSDGgMooQ
  1072 + CGFloat maxPixelSize = MAX(size.width, size.height);
  1073 + CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)UIImageJPEGRepresentation(image, 0.9), nil);
  1074 + NSDictionary *options = @{(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways:(__bridge id)kCFBooleanTrue,
  1075 + (__bridge id)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithFloat:maxPixelSize]
  1076 + };
  1077 + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
  1078 + UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:2 orientation:image.imageOrientation];
  1079 + CGImageRelease(imageRef);
  1080 + CFRelease(sourceRef);
  1081 + return newImage;
  1082 + */
  1083 + } else {
  1084 + return image;
  1085 + }
  1086 +}
  1087 +
  1088 +/// 判断asset是否是视频
  1089 +- (BOOL)isVideo:(id)asset {
  1090 + if (iOS8Later) {
  1091 + PHAsset *phAsset = asset;
  1092 + return phAsset.mediaType == PHAssetMediaTypeVideo;
  1093 + } else {
  1094 + ALAsset *alAsset = asset;
  1095 + NSString *alAssetType = [[alAsset valueForProperty:ALAssetPropertyType] stringValue];
  1096 + return [alAssetType isEqualToString:ALAssetTypeVideo];
  1097 + }
  1098 +}
  1099 +
  1100 +- (ALAssetOrientation)orientationFromImage:(UIImage *)image {
  1101 + NSInteger orientation = image.imageOrientation;
  1102 + return orientation;
  1103 +}
  1104 +
  1105 +/// 获取优化后的视频转向信息
  1106 +- (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset {
  1107 + AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  1108 + // 视频转向
  1109 + int degrees = [self degressFromVideoFileWithAsset:videoAsset];
  1110 + if (degrees != 0) {
  1111 + CGAffineTransform translateToCenter;
  1112 + CGAffineTransform mixedTransform;
  1113 + videoComposition.frameDuration = CMTimeMake(1, 30);
  1114 +
  1115 + NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo];
  1116 + AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  1117 +
  1118 + AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  1119 + roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]);
  1120 + AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
  1121 +
  1122 + if (degrees == 90) {
  1123 + // 顺时针旋转90°
  1124 + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0);
  1125 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2);
  1126 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
  1127 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1128 + } else if(degrees == 180){
  1129 + // 顺时针旋转180°
  1130 + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height);
  1131 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI);
  1132 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height);
  1133 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1134 + } else if(degrees == 270){
  1135 + // 顺时针旋转270°
  1136 + translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width);
  1137 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0);
  1138 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
  1139 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1140 + }
  1141 +
  1142 + roateInstruction.layerInstructions = @[roateLayerInstruction];
  1143 + // 加入视频方向信息
  1144 + videoComposition.instructions = @[roateInstruction];
  1145 + }
  1146 + return videoComposition;
  1147 +}
  1148 +
  1149 +/// 获取视频角度
  1150 +- (int)degressFromVideoFileWithAsset:(AVAsset *)asset {
  1151 + int degress = 0;
  1152 + NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
  1153 + if([tracks count] > 0) {
  1154 + AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  1155 + CGAffineTransform t = videoTrack.preferredTransform;
  1156 + if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
  1157 + // Portrait
  1158 + degress = 90;
  1159 + } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
  1160 + // PortraitUpsideDown
  1161 + degress = 270;
  1162 + } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
  1163 + // LandscapeRight
  1164 + degress = 0;
  1165 + } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
  1166 + // LandscapeLeft
  1167 + degress = 180;
  1168 + }
  1169 + }
  1170 + return degress;
  1171 +}
  1172 +
  1173 +/// 修正图片转向
  1174 +- (UIImage *)fixOrientation:(UIImage *)aImage {
  1175 + if (!self.shouldFixOrientation) return aImage;
  1176 +
  1177 + // No-op if the orientation is already correct
  1178 + if (aImage.imageOrientation == UIImageOrientationUp)
  1179 + return aImage;
  1180 +
  1181 + // We need to calculate the proper transformation to make the image upright.
  1182 + // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
  1183 + CGAffineTransform transform = CGAffineTransformIdentity;
  1184 +
  1185 + switch (aImage.imageOrientation) {
  1186 + case UIImageOrientationDown:
  1187 + case UIImageOrientationDownMirrored:
  1188 + transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
  1189 + transform = CGAffineTransformRotate(transform, M_PI);
  1190 + break;
  1191 +
  1192 + case UIImageOrientationLeft:
  1193 + case UIImageOrientationLeftMirrored:
  1194 + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  1195 + transform = CGAffineTransformRotate(transform, M_PI_2);
  1196 + break;
  1197 +
  1198 + case UIImageOrientationRight:
  1199 + case UIImageOrientationRightMirrored:
  1200 + transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
  1201 + transform = CGAffineTransformRotate(transform, -M_PI_2);
  1202 + break;
  1203 + default:
  1204 + break;
  1205 + }
  1206 +
  1207 + switch (aImage.imageOrientation) {
  1208 + case UIImageOrientationUpMirrored:
  1209 + case UIImageOrientationDownMirrored:
  1210 + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  1211 + transform = CGAffineTransformScale(transform, -1, 1);
  1212 + break;
  1213 +
  1214 + case UIImageOrientationLeftMirrored:
  1215 + case UIImageOrientationRightMirrored:
  1216 + transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
  1217 + transform = CGAffineTransformScale(transform, -1, 1);
  1218 + break;
  1219 + default:
  1220 + break;
  1221 + }
  1222 +
  1223 + // Now we draw the underlying CGImage into a new context, applying the transform
  1224 + // calculated above.
  1225 + CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
  1226 + CGImageGetBitsPerComponent(aImage.CGImage), 0,
  1227 + CGImageGetColorSpace(aImage.CGImage),
  1228 + CGImageGetBitmapInfo(aImage.CGImage));
  1229 + CGContextConcatCTM(ctx, transform);
  1230 + switch (aImage.imageOrientation) {
  1231 + case UIImageOrientationLeft:
  1232 + case UIImageOrientationLeftMirrored:
  1233 + case UIImageOrientationRight:
  1234 + case UIImageOrientationRightMirrored:
  1235 + // Grr...
  1236 + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
  1237 + break;
  1238 +
  1239 + default:
  1240 + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
  1241 + break;
  1242 + }
  1243 +
  1244 + // And now we just create a new UIImage from the drawing context
  1245 + CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
  1246 + UIImage *img = [UIImage imageWithCGImage:cgimg];
  1247 + CGContextRelease(ctx);
  1248 + CGImageRelease(cgimg);
  1249 + return img;
  1250 +}
  1251 +
  1252 +#pragma clang diagnostic pop
  1253 +
  1254 +@end
  1255 +
  1256 +
  1257 +//@implementation TZSortDescriptor
  1258 +//
  1259 +//- (id)reversedSortDescriptor {
  1260 +// return [NSNumber numberWithBool:![TZImageManager manager].sortAscendingByModificationDate];
  1261 +//}
  1262 +//
  1263 +//@end
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png 0 → 100755

3.56 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png 0 → 100755

3.56 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/Root.plist 0 → 100755
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3 +<plist version="1.0">
  4 +<dict>
  5 + <key>StringsTable</key>
  6 + <string>Root</string>
  7 + <key>PreferenceSpecifiers</key>
  8 + <array>
  9 + <dict>
  10 + <key>Type</key>
  11 + <string>PSGroupSpecifier</string>
  12 + <key>Title</key>
  13 + <string>Group</string>
  14 + </dict>
  15 + <dict>
  16 + <key>Type</key>
  17 + <string>PSTextFieldSpecifier</string>
  18 + <key>Title</key>
  19 + <string>Name</string>
  20 + <key>Key</key>
  21 + <string>name_preference</string>
  22 + <key>DefaultValue</key>
  23 + <string></string>
  24 + <key>IsSecure</key>
  25 + <false/>
  26 + <key>KeyboardType</key>
  27 + <string>Alphabet</string>
  28 + <key>AutocapitalizationType</key>
  29 + <string>None</string>
  30 + <key>AutocorrectionType</key>
  31 + <string>No</string>
  32 + </dict>
  33 + <dict>
  34 + <key>Type</key>
  35 + <string>PSToggleSwitchSpecifier</string>
  36 + <key>Title</key>
  37 + <string>Enabled</string>
  38 + <key>Key</key>
  39 + <string>enabled_preference</string>
  40 + <key>DefaultValue</key>
  41 + <true/>
  42 + </dict>
  43 + <dict>
  44 + <key>Type</key>
  45 + <string>PSSliderSpecifier</string>
  46 + <key>Key</key>
  47 + <string>slider_preference</string>
  48 + <key>DefaultValue</key>
  49 + <real>0.5</real>
  50 + <key>MinimumValue</key>
  51 + <integer>0</integer>
  52 + <key>MaximumValue</key>
  53 + <integer>1</integer>
  54 + <key>MinimumValueImage</key>
  55 + <string></string>
  56 + <key>MaximumValueImage</key>
  57 + <string></string>
  58 + </dict>
  59 + </array>
  60 +</dict>
  61 +</plist>
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.bundle/VideoSendIcon@2x.png 0 → 100755

223 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/en.lproj/Localizable.strings 0 → 100755
1 1 Binary files /dev/null and b/CNLiveImagePickerController/Classes/TZImagePickerController.bundle/en.lproj/Localizable.strings differ
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.bundle/fb_quxiao@2x.png 0 → 100755

1.16 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/navi_back@2x.png 0 → 100755

116 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/ph_select@2x.png 0 → 100755

1.31 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/ph_unselect@2x.png 0 → 100755

902 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png 0 → 100755

1.13 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_def_previewVc@2x.png 0 → 100755

1.13 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_number_icon@2x.png 0 → 100755

501 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_original_def@2x.png 0 → 100755

1.56 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_original_sel@2x.png 0 → 100755

620 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png 0 → 100755

1006 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/photo_sel_previewVc@2x.png 0 → 100755

1.16 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/preview_number_icon@2x.png 0 → 100755

501 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/preview_original_def@2x.png 0 → 100755

392 Bytes

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/takePicture80@2x.png 0 → 100755

1.25 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/takePicture@2x.png 0 → 100755

2.98 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/upload_selection1@2x.png 0 → 100755

1.35 KB

CNLiveImagePickerController/Classes/TZImagePickerController.bundle/vi.lproj/Localizable.strings 0 → 100755
  1 +"OK" = "Xác nhận";
  2 +"Back" = "Quay lại";
  3 +"Done" = "Hoàn thành";
  4 +"Sorry" = "Xin lỗi";
  5 +"Cancel" = "Hủy";
  6 +"Setting" = "Cài đặt";
  7 +"Photos" = "Hình";
  8 +"Videos" = "Clip";
  9 +"Preview" = "Xem trước";
  10 +"Full image" = "Hình gốc";
  11 +"Processing..." = "Đang xử lý...";
  12 +"Can not use camera" = "Máy chụp hình không khả dụng";
  13 +"Synchronizing photos from iCloud" = "Đang đồng bộ hình ảnh từ ICloud";
  14 +"Can not choose both video and photo" = "Trong lúc chọn hình ảnh không cùng lúc chọn video";
  15 +"Can not choose both photo and GIF" = "Trong lúc chọn hình ảnh không cùng lúc chọn hình GIF";
  16 +"Select the video when in multi state, we will handle the video as a photo" = "Chọn hình ảnh cùng video, video sẽ bị mặc nhận thành hình ảnh và gửi đi.";
  17 +"Can not jump to the privacy settings page, please go to the settings page by self, thank you" = "Không thể chuyển tự động qua trang cài đặt riêng tư, bạn hãy thoát ra cà điều chỉnh lại, cám ơn bạn.";
  18 +
  19 +"Select a maximum of %zd photos" = "Bạn chỉ được chọn nhiều nhất %zd tấm hình";
  20 +"Select a minimum of %zd photos" = "Chọn ít nhất %zd tấm hình";
  21 +"Allow %@ to access your album in \"Settings -> Privacy -> Photos\"" = "Vui lòng tại mục iPhone \" Cài đặt – quyền riêng tư - Ảnh\" mở quyền cho phép %@ truy cập ảnh.";
  22 +"Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\"" = "Vui lòng tại mục iPhone \" Cài đặt – quyền riêng tư - Ảnh\" mở quyền cho phép %@ truy cập máy ảnh";
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings 0 → 100755
1 1 Binary files /dev/null and b/CNLiveImagePickerController/Classes/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings differ
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings 0 → 100755
1 1 Binary files /dev/null and b/CNLiveImagePickerController/Classes/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings differ
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.h 0 → 100755
  1 +//
  2 +// TZImagePickerController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +// version 2.2.6 - 2018.08.21
  8 +// 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
  9 +
  10 +/*
  11 + 经过测试,比起xib的方式,把TZAssetCell改用纯代码的方式来写,滑动帧数明显提高了(约提高10帧左右)
  12 +
  13 + 最初发现这个问题并修复的是@小鱼周凌宇同学,她的博客地址: http://zhoulingyu.com/
  14 + 表示感谢~
  15 +
  16 + 原来xib确实会导致性能问题啊...大家也要注意了...
  17 + */
  18 +
  19 +#import <UIKit/UIKit.h>
  20 +#import "TZAssetModel.h"
  21 +#import "NSBundle+TZImagePicker.h"
  22 +#import "TZImageManager.h"
  23 +#import "TZVideoPlayerController.h"
  24 +#import "TZGifPhotoPreviewController.h"
  25 +#import "TZLocationManager.h"
  26 +#import "TZPhotoPreviewController.h"
  27 +
  28 +#define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f)
  29 +#define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f)
  30 +///
  31 +#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
  32 +#define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
  33 +
  34 +@class TZAlbumCell, TZAssetCell;
  35 +@protocol TZImagePickerControllerDelegate;
  36 +@interface TZImagePickerController : UINavigationController
  37 +
  38 +#pragma mark -
  39 +/// Use this init method / 用这个初始化方法
  40 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate;
  41 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate;
  42 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc;
  43 +/// This init method just for previewing photos / 用这个初始化方法以预览图片
  44 +- (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index;
  45 +/// This init method for crop photo / 用这个初始化方法以裁剪图片
  46 +- (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion;
  47 +
  48 +#pragma mark - 添加:conversationId
  49 +/** 会话ID */
  50 +@property (nonatomic, copy) NSString *conversationId;
  51 +
  52 +/** 是否导出视频URL */
  53 +@property (nonatomic, assign) BOOL isExportVideo;
  54 +
  55 +#pragma mark - 添加:视频编辑(LXG)
  56 +///**
  57 +// 是否允许编辑视频,选择一张时候才允许编辑,默认NO
  58 +// */
  59 +//@property (nonatomic, assign) BOOL allowEditVideo;
  60 +
  61 +/**
  62 + 编辑视频时最大裁剪时间,单位:秒,默认10s 且最低10s
  63 +
  64 + @discussion 当该参数为10s时,所选视频时长必须大于等于10s才允许进行编辑
  65 + */
  66 +@property (nonatomic, assign) NSInteger maxEditVideoTime;
  67 +
  68 +/**
  69 + 允许选择视频的最大时长,单位:秒, 默认 120s
  70 + */
  71 +@property (nonatomic, assign) NSInteger maxVideoDuration;
  72 +
  73 +/// Default is 9 / 默认最大可选9张图片
  74 +@property (nonatomic, assign) NSInteger maxImagesCount;
  75 +
  76 +/// The minimum count photos user must pick, Default is 0
  77 +/// 最小照片必选张数,默认是0
  78 +@property (nonatomic, assign) NSInteger minImagesCount;
  79 +
  80 +/// Always enale the done button, not require minimum 1 photo be picked
  81 +/// 让完成按钮一直可以点击,无须最少选择一张图片
  82 +@property (nonatomic, assign) BOOL alwaysEnableDoneBtn;
  83 +
  84 +/// Sort photos ascending by modificationDate,Default is YES
  85 +/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
  86 +@property (nonatomic, assign) BOOL sortAscendingByModificationDate;
  87 +
  88 +/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
  89 +@property (nonatomic, assign) CGFloat photoWidth;
  90 +
  91 +/// Default is 600px / 默认600像素宽
  92 +@property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
  93 +
  94 +/// Default is 15, While fetching photo, HUD will dismiss automatic if timeout;
  95 +/// 超时时间,默认为15秒,当取图片时间超过15秒还没有取成功时,会自动dismiss HUD;
  96 +@property (nonatomic, assign) NSInteger timeout;
  97 +
  98 +/// Default is YES, if set NO, the original photo button will hide. user can't picking original photo.
  99 +/// 默认为YES,如果设置为NO,原图按钮将隐藏,用户不能选择发送原图
  100 +@property (nonatomic, assign) BOOL allowPickingOriginalPhoto;
  101 +
  102 +/// Default is YES, if set NO, user can't picking video.
  103 +/// 默认为YES,如果设置为NO,用户将不能选择视频
  104 +@property (nonatomic, assign) BOOL allowPickingVideo;
  105 +/// Default is NO / 默认为NO,为YES时可以多选视频/gif/图片,和照片共享最大可选张数maxImagesCount的限制
  106 +@property (nonatomic, assign) BOOL allowPickingMultipleVideo;
  107 +
  108 +/// Default is NO, if set YES, user can picking gif image.
  109 +/// 默认为NO,如果设置为YES,用户可以选择gif图片
  110 +@property (nonatomic, assign) BOOL allowPickingGif;
  111 +
  112 +/// Default is YES, if set NO, user can't picking image.
  113 +/// 默认为YES,如果设置为NO,用户将不能选择发送图片
  114 +@property (nonatomic, assign) BOOL allowPickingImage;
  115 +
  116 +/// Default is YES, if set NO, user can't take picture.
  117 +/// 默认为YES,如果设置为NO, 用户将不能拍摄照片
  118 +@property (nonatomic, assign) BOOL allowTakePicture;
  119 +@property (nonatomic, assign) BOOL allowCameraLocation;
  120 +
  121 +/// Default is YES, if set NO, user can't take video.
  122 +/// 默认为YES,如果设置为NO, 用户将不能拍摄视频
  123 +@property(nonatomic, assign) BOOL allowTakeVideo;
  124 +/// Default value is 10 minutes / 视频最大拍摄时间,默认是10分钟,单位是秒
  125 +@property (assign, nonatomic) NSTimeInterval videoMaximumDuration;
  126 +/// Customizing UIImagePickerController's other properties, such as videoQuality / 定制UIImagePickerController的其它属性,比如视频拍摄质量videoQuality
  127 +@property (nonatomic, copy) void(^uiImagePickerControllerSettingBlock)(UIImagePickerController *imagePickerController);
  128 +
  129 +/// 首选语言,如果设置了就用该语言,不设则取当前系统语言。
  130 +/// 由于目前只支持中文、繁体中文、英文、越南语。故该属性只支持zh-Hans、zh-Hant、en、vi四种值,其余值无效。
  131 +@property (copy, nonatomic) NSString *preferredLanguage;
  132 +
  133 +/// 语言bundle,preferredLanguage变化时languageBundle会变化
  134 +/// 可通过手动设置bundle,让选择器支持新的的语言(需要在设置preferredLanguage后设置languageBundle)。欢迎提交PR把语言文件提交上来~
  135 +@property (strong, nonatomic) NSBundle *languageBundle;
  136 +
  137 +/// Default is YES, if set NO, user can't preview photo.
  138 +/// 默认为YES,如果设置为NO,预览按钮将隐藏,用户将不能去预览照片
  139 +@property (nonatomic, assign) BOOL allowPreview;
  140 +
  141 +/// Default is YES, if set NO, the picker don't dismiss itself.
  142 +/// 默认为YES,如果设置为NO, 选择器将不会自己dismiss
  143 +@property(nonatomic, assign) BOOL autoDismiss;
  144 +
  145 +/// Default is NO, if set YES, in the delegate method the photos and infos will be nil, only assets hava value.
  146 +/// 默认为NO,如果设置为YES,代理方法里photos和infos会是nil,只返回assets
  147 +@property (assign, nonatomic) BOOL onlyReturnAsset;
  148 +
  149 +/// Default is NO, if set YES, will show the image's selected index.
  150 +/// 默认为NO,如果设置为YES,会显示照片的选中序号
  151 +@property (assign, nonatomic) BOOL showSelectedIndex;
  152 +
  153 +/// Default is NO, if set YES, when selected photos's count up to maxImagesCount, other photo will show float layer what's color is cannotSelectLayerColor.
  154 +/// 默认是NO,如果设置为YES,当照片选择张数达到maxImagesCount时,其它照片会显示颜色为cannotSelectLayerColor的浮层
  155 +@property (assign, nonatomic) BOOL showPhotoCannotSelectLayer;
  156 +/// Default is white color with 0.8 alpha;
  157 +@property (strong, nonatomic) UIColor *cannotSelectLayerColor;
  158 +
  159 +/// Default is No, if set YES, the result photo will not be scaled to photoWidth pixel width. The photoWidth default is 828px
  160 +/// 默认是NO,如果设置为YES,内部不会缩放图片到photoWidth像素宽
  161 +@property (assign, nonatomic) BOOL notScaleImage;
  162 +
  163 +/// 默认是NO,如果设置为YES,导出视频时会修正转向(慎重设为YES,可能导致部分安卓下拍的视频导出失败)
  164 +@property (assign, nonatomic) BOOL needFixComposition;
  165 +
  166 +/// The photos user have selected
  167 +/// 用户选中过的图片数组
  168 +@property (nonatomic, strong) NSMutableArray *selectedAssets;
  169 +@property (nonatomic, strong) NSMutableArray<TZAssetModel *> *selectedModels;
  170 +@property (nonatomic, strong) NSMutableArray *selectedAssetIds;
  171 +- (void)addSelectedModel:(TZAssetModel *)model;
  172 +- (void)removeSelectedModel:(TZAssetModel *)model;
  173 +
  174 +/// Minimum selectable photo width, Default is 0
  175 +/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
  176 +@property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
  177 +@property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
  178 +/// Hide the photo what can not be selected, Default is NO
  179 +/// 隐藏不可以选中的图片,默认是NO,不推荐将其设置为YES
  180 +@property (nonatomic, assign) BOOL hideWhenCanNotSelect;
  181 +/// Deprecated, Use statusBarStyle (顶部statusBar 是否为系统默认的黑色,默认为NO)
  182 +@property (nonatomic, assign) BOOL isStatusBarDefault __attribute__((deprecated("Use -statusBarStyle.")));
  183 +/// statusBar的样式,默认为UIStatusBarStyleLightContent
  184 +@property (assign, nonatomic) UIStatusBarStyle statusBarStyle;
  185 +
  186 +#pragma mark -
  187 +/// Single selection mode, valid when maxImagesCount = 1
  188 +/// 单选模式,maxImagesCount为1时才生效
  189 +@property (nonatomic, assign) BOOL showSelectBtn; ///< 在单选模式下,照片列表页中,显示选择按钮,默认为NO
  190 +@property (nonatomic, assign) BOOL allowCrop; ///< 允许裁剪,默认为YES,showSelectBtn为NO才生效
  191 +@property (nonatomic, assign) CGRect cropRect; ///< 裁剪框的尺寸
  192 +@property (nonatomic, assign) CGRect cropRectPortrait; ///< 裁剪框的尺寸(竖屏)
  193 +@property (nonatomic, assign) CGRect cropRectLandscape; ///< 裁剪框的尺寸(横屏)
  194 +@property (nonatomic, assign) BOOL needCircleCrop; ///< 需要圆形裁剪框
  195 +@property (nonatomic, assign) NSInteger circleCropRadius; ///< 圆形裁剪框半径大小
  196 +@property (nonatomic, copy) void (^cropViewSettingBlock)(UIView *cropView); ///< 自定义裁剪框的其他属性
  197 +@property (nonatomic, copy) void (^navLeftBarButtonSettingBlock)(UIButton *leftButton); ///< 自定义返回按钮样式及其属性
  198 +
  199 +/// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等
  200 +@property (nonatomic, copy) void (^photoPickerPageUIConfigBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine);
  201 +@property (nonatomic, copy) void (^photoPreviewPageUIConfigBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel);
  202 +@property (nonatomic, copy) void (^videoPreviewPageUIConfigBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton);
  203 +@property (nonatomic, copy) void (^gifPreviewPageUIConfigBlock)(UIView *toolBar, UIButton *doneButton);
  204 +@property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  205 +@property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  206 +/// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等
  207 +@property (nonatomic, copy) void (^photoPickerPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine);
  208 +@property (nonatomic, copy) void (^photoPreviewPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel);
  209 +@property (nonatomic, copy) void (^videoPreviewPageDidLayoutSubviewsBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton);
  210 +@property (nonatomic, copy) void (^gifPreviewPageDidLayoutSubviewsBlock)(UIView *toolBar, UIButton *doneButton);
  211 +@property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  212 +@property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  213 +
  214 +#pragma mark -
  215 +- (id)showAlertWithTitle:(NSString *)title;
  216 +- (void)hideAlertView:(id)alertView;
  217 +- (void)showProgressHUD;
  218 +- (void)hideProgressHUD;
  219 +@property (nonatomic, assign) BOOL isSelectOriginalPhoto;
  220 +@property (assign, nonatomic) BOOL needShowStatusBar;
  221 +
  222 +#pragma mark -
  223 +@property (nonatomic, copy) NSString *takePictureImageName __attribute__((deprecated("Use -takePictureImage.")));
  224 +@property (nonatomic, copy) NSString *photoSelImageName __attribute__((deprecated("Use -photoSelImage.")));
  225 +@property (nonatomic, copy) NSString *photoDefImageName __attribute__((deprecated("Use -photoDefImage.")));
  226 +@property (nonatomic, copy) NSString *photoOriginSelImageName __attribute__((deprecated("Use -photoOriginSelImage.")));
  227 +@property (nonatomic, copy) NSString *photoOriginDefImageName __attribute__((deprecated("Use -photoOriginDefImage.")));
  228 +@property (nonatomic, copy) NSString *photoPreviewOriginDefImageName __attribute__((deprecated("Use -photoPreviewOriginDefImage.")));
  229 +@property (nonatomic, copy) NSString *photoNumberIconImageName __attribute__((deprecated("Use -photoNumberIconImage.")));
  230 +@property (nonatomic, strong) UIImage *takePictureImage;
  231 +@property (nonatomic, strong) UIImage *photoSelImage;
  232 +@property (nonatomic, strong) UIImage *photoDefImage;
  233 +@property (nonatomic, strong) UIImage *photoOriginSelImage;
  234 +@property (nonatomic, strong) UIImage *photoOriginDefImage;
  235 +@property (nonatomic, strong) UIImage *photoPreviewOriginDefImage;
  236 +@property (nonatomic, strong) UIImage *photoNumberIconImage;
  237 +
  238 +#pragma mark -
  239 +/// Appearance / 外观颜色 + 按钮文字
  240 +@property (nonatomic, strong) UIColor *oKButtonTitleColorNormal;
  241 +@property (nonatomic, strong) UIColor *oKButtonTitleColorDisabled;
  242 +@property (nonatomic, strong) UIColor *naviBgColor;
  243 +@property (nonatomic, strong) UIColor *naviTitleColor;
  244 +@property (nonatomic, strong) UIFont *naviTitleFont;
  245 +@property (nonatomic, strong) UIColor *barItemTextColor;
  246 +@property (nonatomic, strong) UIFont *barItemTextFont;
  247 +@property (nonatomic, strong) UIColor *editBtnTitleColor;///LXG编辑按钮title颜色
  248 +
  249 +@property (nonatomic, copy) NSString *doneBtnTitleStr;
  250 +@property (nonatomic, copy) NSString *cancelBtnTitleStr;
  251 +@property (nonatomic, copy) NSString *previewBtnTitleStr;
  252 +@property (nonatomic, copy) NSString *fullImageBtnTitleStr;
  253 +@property (nonatomic, copy) NSString *settingBtnTitleStr;
  254 +@property (nonatomic, copy) NSString *processHintStr;
  255 +@property (nonatomic, copy) NSString *editBtnTitleStr;///LXG编辑按钮
  256 +
  257 +
  258 +
  259 +/// Icon theme color, default is green color like wechat, the value is r:31 g:185 b:34. Currently only support image selection icon when showSelectedIndex is YES. If you need it, please set it as soon as possible
  260 +/// icon主题色,默认是微信的绿色,值是r:31 g:185 b:34。目前仅支持showSelectedIndex为YES时的图片选中icon。如需要,请尽早设置它。
  261 +@property (strong, nonatomic) UIColor *iconThemeColor;
  262 +
  263 +#pragma mark -
  264 +- (void)cancelButtonClick;
  265 +
  266 +// The picker should dismiss itself; when it dismissed these handle will be called.
  267 +// You can also set autoDismiss to NO, then the picker don't dismiss itself.
  268 +// If isOriginalPhoto is YES, user picked the original photo.
  269 +// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:].
  270 +// The UIImage Object in photos default width is 828px, you can set it by photoWidth property.
  271 +// 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的handle
  272 +// 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了
  273 +// 如果isSelectOriginalPhoto为YES,表明用户选择了原图
  274 +// 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:]
  275 +// photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它
  276 +@property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
  277 +@property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray<NSDictionary *> *infos);
  278 +@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(void);
  279 +
  280 +#pragma mark - LXG: 视频导出URL
  281 +@property (nonatomic, copy) void (^didNewFinishPickingPhotosHandle) (NSArray<UIImage *> *photos,NSArray<TZAssetModel *> *models,NSArray *assets,BOOL isSelectOriginalPhoto);
  282 +
  283 +
  284 +// If user picking a video, this handle will be called.
  285 +// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
  286 +// 如果用户选择了一个视频,下面的handle会被执行
  287 +// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
  288 +@property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,id asset);
  289 +
  290 +// If user picking a gif image, this callback will be called.
  291 +// 如果用户选择了一个gif图片,下面的handle会被执行
  292 +@property (nonatomic, copy) void (^didFinishPickingGifImageHandle)(UIImage *animatedImage,id sourceAssets);
  293 +
  294 +@property (nonatomic, weak) id<TZImagePickerControllerDelegate> pickerDelegate;
  295 +
  296 +@end
  297 +
  298 +
  299 +@protocol TZImagePickerControllerDelegate <NSObject>
  300 +@optional
  301 +// The picker should dismiss itself; when it dismissed these handle will be called.
  302 +// You can also set autoDismiss to NO, then the picker don't dismiss itself.
  303 +// If isOriginalPhoto is YES, user picked the original photo.
  304 +// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:].
  305 +// The UIImage Object in photos default width is 828px, you can set it by photoWidth property.
  306 +// 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的handle
  307 +// 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了
  308 +// 如果isSelectOriginalPhoto为YES,表明用户选择了原图
  309 +// 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:]
  310 +// photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它
  311 +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto;
  312 +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray<NSDictionary *> *)infos;
  313 +//- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker __attribute__((deprecated("Use -tz_imagePickerControllerDidCancel:.")));
  314 +- (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker;
  315 +
  316 +// If user picking a video, this callback will be called.
  317 +// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
  318 +// 如果用户选择了一个视频,下面的handle会被执行
  319 +// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象
  320 +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset;
  321 +
  322 +// If user picking a gif image, this callback will be called.
  323 +// 如果用户选择了一个gif图片,下面的handle会被执行
  324 +- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(id)asset;
  325 +
  326 +// Decide album show or not't
  327 +// 决定相册显示与否 albumName:相册名字 result:相册原始数据
  328 +- (BOOL)isAlbumCanSelect:(NSString *)albumName result:(id)result;
  329 +
  330 +// Decide asset show or not't
  331 +// 决定照片显示与否
  332 +- (BOOL)isAssetCanSelect:(id)asset;
  333 +@end
  334 +
  335 +
  336 +@interface TZAlbumPickerController : UIViewController
  337 +@property (nonatomic, assign) NSInteger columnNumber;
  338 +@property (assign, nonatomic) BOOL isFirstAppear;
  339 +- (void)configTableView;
  340 +@end
  341 +
  342 +
  343 +@interface UIImage (MyBundle)
  344 ++ (UIImage *)imageNamedFromMyBundle:(NSString *)name;
  345 +@end
  346 +
  347 +
  348 +@interface NSString (TzExtension)
  349 +- (BOOL)tz_containsString:(NSString *)string;
  350 +- (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize;
  351 +@end
  352 +
  353 +
  354 +@interface TZCommonTools : NSObject
  355 ++ (BOOL)tz_isIPhoneX;
  356 ++ (CGFloat)tz_statusBarHeight;
  357 +// 获得Info.plist数据字典
  358 ++ (NSDictionary *)tz_getInfoDictionary;
  359 +@end
  360 +
  361 +
  362 +@interface TZImagePickerConfig : NSObject
  363 ++ (instancetype)sharedInstance;
  364 +@property (copy, nonatomic) NSString *preferredLanguage;
  365 +@property(nonatomic, assign) BOOL allowPickingImage;
  366 +@property (nonatomic, assign) BOOL allowPickingVideo;
  367 +@property (strong, nonatomic) NSBundle *languageBundle;
  368 +/// 默认是200,如果一个GIF过大,里面图片个数可能超过1000,会导致内存飙升而崩溃
  369 +@property (assign, nonatomic) NSInteger gifPreviewMaxImagesCount;
  370 +@property (assign, nonatomic) BOOL showSelectedIndex;
  371 +@property (assign, nonatomic) BOOL showPhotoCannotSelectLayer;
  372 +@property (assign, nonatomic) BOOL notScaleImage;
  373 +@property (assign, nonatomic) BOOL needFixComposition;
  374 +@end
... ...
CNLiveImagePickerController/Classes/TZImagePickerController.m 0 → 100755
  1 +//
  2 +// TZImagePickerController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +// version 2.2.6 - 2018.08.21
  8 +// 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
  9 +
  10 +#import "TZImagePickerController.h"
  11 +#import "TZPhotoPickerController.h"
  12 +#import "TZPhotoPreviewController.h"
  13 +#import "TZAssetModel.h"
  14 +#import "TZAssetCell.h"
  15 +#import "UIView+TZLayout.h"
  16 +#import "TZImageManager.h"
  17 +#import <sys/utsname.h>
  18 +
  19 +@interface TZImagePickerController () {
  20 + NSTimer *_timer;
  21 + UILabel *_tipLabel;
  22 + UIButton *_settingBtn;
  23 + BOOL _pushPhotoPickerVc;
  24 + BOOL _didPushPhotoPickerVc;
  25 +
  26 + UIButton *_progressHUD;
  27 + UIView *_HUDContainer;
  28 + UIActivityIndicatorView *_HUDIndicatorView;
  29 + UILabel *_HUDLabel;
  30 +
  31 + UIStatusBarStyle _originStatusBarStyle;
  32 +}
  33 +/// Default is 4, Use in photos collectionView in TZPhotoPickerController
  34 +/// 默认4列, TZPhotoPickerController中的照片collectionView
  35 +@property (nonatomic, assign) NSInteger columnNumber;
  36 +@end
  37 +
  38 +@implementation TZImagePickerController
  39 +
  40 +- (instancetype)init {
  41 + self = [super init];
  42 + if (self) {
  43 + self = [self initWithMaxImagesCount:9 delegate:nil];
  44 + }
  45 + return self;
  46 +}
  47 +
  48 +#pragma clang diagnostic push
  49 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  50 +- (void)viewDidLoad {
  51 + [super viewDidLoad];
  52 + self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden;
  53 + self.view.backgroundColor = [UIColor whiteColor];
  54 + self.navigationBar.barStyle = UIBarStyleBlack;
  55 + self.navigationBar.translucent = YES;
  56 + [TZImageManager manager].shouldFixOrientation = NO;
  57 +
  58 + // Default appearance, you can reset these after this method
  59 + // 默认的外观,你可以在这个方法后重置
  60 + self.oKButtonTitleColorNormal = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0];
  61 + self.oKButtonTitleColorDisabled = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:0.5];
  62 + self.editBtnTitleColor = [UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0];///LXG 默认编辑按钮颜色
  63 +
  64 + if (iOS7Later) {
  65 + self.navigationBar.barTintColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:1.0];
  66 + self.navigationBar.tintColor = [UIColor whiteColor];
  67 + self.automaticallyAdjustsScrollViewInsets = NO;
  68 + if (self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
  69 + }
  70 +}
  71 +
  72 +- (void)setNaviBgColor:(UIColor *)naviBgColor {
  73 + _naviBgColor = naviBgColor;
  74 + if (iOS7Later) {
  75 + self.navigationBar.barTintColor = naviBgColor;
  76 + }
  77 +}
  78 +
  79 +- (void)setNaviTitleColor:(UIColor *)naviTitleColor {
  80 + _naviTitleColor = naviTitleColor;
  81 + [self configNaviTitleAppearance];
  82 +}
  83 +
  84 +- (void)setNaviTitleFont:(UIFont *)naviTitleFont {
  85 + _naviTitleFont = naviTitleFont;
  86 + [self configNaviTitleAppearance];
  87 +}
  88 +
  89 +- (void)configNaviTitleAppearance {
  90 + NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
  91 + if (self.naviTitleColor) {
  92 + textAttrs[NSForegroundColorAttributeName] = self.naviTitleColor;
  93 + }
  94 + if (self.naviTitleFont) {
  95 + textAttrs[NSFontAttributeName] = self.naviTitleFont;
  96 + }
  97 + self.navigationBar.titleTextAttributes = textAttrs;
  98 +}
  99 +
  100 +- (void)setBarItemTextFont:(UIFont *)barItemTextFont {
  101 + _barItemTextFont = barItemTextFont;
  102 + [self configBarButtonItemAppearance];
  103 +}
  104 +
  105 +- (void)setBarItemTextColor:(UIColor *)barItemTextColor {
  106 + _barItemTextColor = barItemTextColor;
  107 + [self configBarButtonItemAppearance];
  108 +}
  109 +
  110 +- (void)setIsStatusBarDefault:(BOOL)isStatusBarDefault {
  111 + _isStatusBarDefault = isStatusBarDefault;
  112 +
  113 + if (isStatusBarDefault) {
  114 + self.statusBarStyle = iOS7Later ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque;
  115 + } else {
  116 + self.statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
  117 + }
  118 +}
  119 +
  120 +- (void)configBarButtonItemAppearance {
  121 + UIBarButtonItem *barItem;
  122 + if (@available(iOS 9, *)) {
  123 + barItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
  124 + } else {
  125 + barItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil];
  126 + }
  127 + NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
  128 + textAttrs[NSForegroundColorAttributeName] = self.barItemTextColor;
  129 + textAttrs[NSFontAttributeName] = self.barItemTextFont;
  130 + [barItem setTitleTextAttributes:textAttrs forState:UIControlStateNormal];
  131 +}
  132 +
  133 +- (void)viewWillAppear:(BOOL)animated {
  134 + [super viewWillAppear:animated];
  135 + _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
  136 + [UIApplication sharedApplication].statusBarStyle = self.statusBarStyle;
  137 +}
  138 +
  139 +- (void)viewWillDisappear:(BOOL)animated {
  140 + [super viewWillDisappear:animated];
  141 + [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
  142 + [self hideProgressHUD];
  143 +}
  144 +
  145 +- (UIStatusBarStyle)preferredStatusBarStyle {
  146 + return self.statusBarStyle;
  147 +}
  148 +
  149 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate {
  150 + return [self initWithMaxImagesCount:maxImagesCount columnNumber:4 delegate:delegate pushPhotoPickerVc:YES];
  151 +}
  152 +
  153 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate {
  154 + return [self initWithMaxImagesCount:maxImagesCount columnNumber:columnNumber delegate:delegate pushPhotoPickerVc:YES];
  155 +}
  156 +
  157 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc {
  158 + _pushPhotoPickerVc = pushPhotoPickerVc;
  159 + TZAlbumPickerController *albumPickerVc = [[TZAlbumPickerController alloc] init];
  160 + albumPickerVc.isFirstAppear = YES;
  161 + albumPickerVc.columnNumber = columnNumber;
  162 + self = [super initWithRootViewController:albumPickerVc];
  163 + if (self) {
  164 + self.maxImagesCount = maxImagesCount > 0 ? maxImagesCount : 9; // Default is 9 / 默认最大可选9张图片
  165 + self.pickerDelegate = delegate;
  166 + self.selectedAssets = [NSMutableArray array];
  167 +
  168 + // 添加是否导出
  169 + self.isExportVideo = NO;
  170 + self.conversationId = @"";
  171 +#pragma mark - 添加:视频编辑(LXG)
  172 + self.maxEditVideoTime = 10;
  173 + self.maxVideoDuration = 120;
  174 + // Allow user picking original photo and video, you also can set No after this method
  175 + // 默认准许用户选择原图和视频, 你也可以在这个方法后置为NO
  176 + self.allowPickingOriginalPhoto = YES;
  177 + self.allowPickingVideo = YES;
  178 + self.allowPickingImage = YES;
  179 + self.allowTakePicture = YES;
  180 + self.allowTakeVideo = YES;
  181 + self.videoMaximumDuration = 10 * 60;
  182 + self.sortAscendingByModificationDate = YES;
  183 + self.autoDismiss = YES;
  184 + self.columnNumber = columnNumber;
  185 + [self configDefaultSetting];
  186 +
  187 + if (![[TZImageManager manager] authorizationStatusAuthorized]) {
  188 + _tipLabel = [[UILabel alloc] init];
  189 + _tipLabel.frame = CGRectMake(8, 120, self.view.tz_width - 16, 60);
  190 + _tipLabel.textAlignment = NSTextAlignmentCenter;
  191 + _tipLabel.numberOfLines = 0;
  192 + _tipLabel.font = [UIFont systemFontOfSize:16];
  193 + _tipLabel.textColor = [UIColor blackColor];
  194 +
  195 + NSDictionary *infoDict = [TZCommonTools tz_getInfoDictionary];
  196 + NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"];
  197 + if (!appName) appName = [infoDict valueForKey:@"CFBundleName"];
  198 + NSString *tipText = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Allow %@ to access your album in \"Settings -> Privacy -> Photos\""],appName];
  199 + _tipLabel.text = tipText;
  200 + [self.view addSubview:_tipLabel];
  201 +
  202 + if (iOS8Later) {
  203 + _settingBtn = [UIButton buttonWithType:UIButtonTypeSystem];
  204 + [_settingBtn setTitle:self.settingBtnTitleStr forState:UIControlStateNormal];
  205 + _settingBtn.frame = CGRectMake(0, 180, self.view.tz_width, 44);
  206 + _settingBtn.titleLabel.font = [UIFont systemFontOfSize:18];
  207 + [_settingBtn addTarget:self action:@selector(settingBtnClick) forControlEvents:UIControlEventTouchUpInside];
  208 + [self.view addSubview:_settingBtn];
  209 + }
  210 +
  211 + if ([TZImageManager authorizationStatus] == 0) {
  212 + _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO];
  213 + }
  214 + } else {
  215 + [self pushPhotoPickerVc];
  216 + }
  217 + }
  218 + return self;
  219 +}
  220 +
  221 +/// This init method just for previewing photos / 用这个初始化方法以预览图片
  222 +- (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index{
  223 + TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init];
  224 + self = [super initWithRootViewController:previewVc];
  225 + if (self) {
  226 + self.selectedAssets = [NSMutableArray arrayWithArray:selectedAssets];
  227 + self.allowPickingOriginalPhoto = self.allowPickingOriginalPhoto;
  228 + [self configDefaultSetting];
  229 +
  230 + previewVc.photos = [NSMutableArray arrayWithArray:selectedPhotos];
  231 + previewVc.currentIndex = index;
  232 + __weak typeof(self) weakSelf = self;
  233 + [previewVc setDoneButtonClickBlockWithPreviewType:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  234 + __strong typeof(weakSelf) strongSelf = weakSelf;
  235 + [strongSelf dismissViewControllerAnimated:YES completion:^{
  236 + if (!strongSelf) return;
  237 + if (strongSelf.didFinishPickingPhotosHandle) {
  238 + strongSelf.didFinishPickingPhotosHandle(photos,assets,isSelectOriginalPhoto);
  239 + }
  240 + }];
  241 + }];
  242 + }
  243 + return self;
  244 +}
  245 +
  246 +/// This init method for crop photo / 用这个初始化方法以裁剪图片
  247 +- (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion {
  248 + TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init];
  249 + self = [super initWithRootViewController:previewVc];
  250 + if (self) {
  251 + self.maxImagesCount = 1;
  252 + self.allowCrop = YES;
  253 + self.selectedAssets = [NSMutableArray arrayWithArray:@[asset]];
  254 + [self configDefaultSetting];
  255 +
  256 + previewVc.photos = [NSMutableArray arrayWithArray:@[photo]];
  257 + previewVc.isCropImage = YES;
  258 + previewVc.currentIndex = 0;
  259 + __weak typeof(self) weakSelf = self;
  260 + [previewVc setDoneButtonClickBlockCropMode:^(UIImage *cropImage, id asset) {
  261 + __strong typeof(weakSelf) strongSelf = weakSelf;
  262 + [strongSelf dismissViewControllerAnimated:YES completion:^{
  263 + if (completion) {
  264 + completion(cropImage,asset);
  265 + }
  266 + }];
  267 + }];
  268 + }
  269 + return self;
  270 +}
  271 +
  272 +- (void)configDefaultSetting {
  273 + self.timeout = 15;
  274 + self.photoWidth = 828.0;
  275 + self.photoPreviewMaxWidth = 600;
  276 + self.naviTitleColor = [UIColor whiteColor];
  277 + self.naviTitleFont = [UIFont systemFontOfSize:17];
  278 + self.barItemTextFont = [UIFont systemFontOfSize:15];
  279 + self.barItemTextColor = [UIColor whiteColor];
  280 + self.allowPreview = YES;
  281 + // 2.2.26版本,不主动缩放图片,降低内存占用
  282 + self.notScaleImage = YES;
  283 + self.needFixComposition = NO;
  284 + self.statusBarStyle = UIStatusBarStyleLightContent;
  285 + self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
  286 + self.allowCameraLocation = YES;
  287 +
  288 + self.iconThemeColor = [UIColor colorWithRed:31 / 255.0 green:185 / 255.0 blue:34 / 255.0 alpha:1.0];
  289 + [self configDefaultBtnTitle];
  290 +
  291 + CGFloat cropViewWH = MIN(self.view.tz_width, self.view.tz_height) / 3 * 2;
  292 + self.cropRect = CGRectMake((self.view.tz_width - cropViewWH) / 2, (self.view.tz_height - cropViewWH) / 2, cropViewWH, cropViewWH);
  293 +}
  294 +
  295 +- (void)configDefaultImageName {
  296 + self.takePictureImageName = @"takePicture80";
  297 + self.photoSelImageName = @"photo_sel_photoPickerVc";
  298 + self.photoDefImageName = @"photo_def_photoPickerVc";
  299 + self.photoNumberIconImage = [self createImageWithColor:nil size:CGSizeMake(24, 24) radius:12]; // @"photo_number_icon";
  300 + self.photoPreviewOriginDefImageName = @"preview_original_def";
  301 + self.photoOriginDefImageName = @"photo_original_def";
  302 + self.photoOriginSelImageName = @"photo_original_sel";
  303 +}
  304 +
  305 +- (void)setTakePictureImageName:(NSString *)takePictureImageName {
  306 + _takePictureImageName = takePictureImageName;
  307 + _takePictureImage = [UIImage imageNamedFromMyBundle:takePictureImageName];
  308 +}
  309 +
  310 +- (void)setPhotoSelImageName:(NSString *)photoSelImageName {
  311 + _photoSelImageName = photoSelImageName;
  312 + _photoSelImage = [UIImage imageNamedFromMyBundle:photoSelImageName];
  313 +}
  314 +
  315 +- (void)setPhotoDefImageName:(NSString *)photoDefImageName {
  316 + _photoDefImageName = photoDefImageName;
  317 + _photoDefImage = [UIImage imageNamedFromMyBundle:photoDefImageName];
  318 +}
  319 +
  320 +- (void)setPhotoNumberIconImageName:(NSString *)photoNumberIconImageName {
  321 + _photoNumberIconImageName = photoNumberIconImageName;
  322 + _photoNumberIconImage = [UIImage imageNamedFromMyBundle:photoNumberIconImageName];
  323 +}
  324 +
  325 +- (void)setPhotoPreviewOriginDefImageName:(NSString *)photoPreviewOriginDefImageName {
  326 + _photoPreviewOriginDefImageName = photoPreviewOriginDefImageName;
  327 + _photoPreviewOriginDefImage = [UIImage imageNamedFromMyBundle:photoPreviewOriginDefImageName];
  328 +}
  329 +
  330 +- (void)setPhotoOriginDefImageName:(NSString *)photoOriginDefImageName {
  331 + _photoOriginDefImageName = photoOriginDefImageName;
  332 + _photoOriginDefImage = [UIImage imageNamedFromMyBundle:photoOriginDefImageName];
  333 +}
  334 +
  335 +- (void)setPhotoOriginSelImageName:(NSString *)photoOriginSelImageName {
  336 + _photoOriginSelImageName = photoOriginSelImageName;
  337 + _photoOriginSelImage = [UIImage imageNamedFromMyBundle:photoOriginSelImageName];
  338 +}
  339 +
  340 +- (void)setIconThemeColor:(UIColor *)iconThemeColor {
  341 + _iconThemeColor = iconThemeColor;
  342 + [self configDefaultImageName];
  343 +}
  344 +
  345 +- (void)configDefaultBtnTitle {
  346 + self.doneBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Done"];
  347 + self.cancelBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Cancel"];
  348 + self.previewBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Preview"];
  349 + self.fullImageBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Full image"];
  350 + self.settingBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Setting"];
  351 + self.processHintStr = [NSBundle tz_localizedStringForKey:@"Processing..."];
  352 + self.editBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Edit"];
  353 +}
  354 +
  355 +- (void)setShowSelectedIndex:(BOOL)showSelectedIndex {
  356 + _showSelectedIndex = showSelectedIndex;
  357 + if (showSelectedIndex) {
  358 + self.photoSelImage = [self createImageWithColor:nil size:CGSizeMake(24, 24) radius:12];
  359 + }
  360 + [TZImagePickerConfig sharedInstance].showSelectedIndex = showSelectedIndex;
  361 +}
  362 +
  363 +- (void)setShowPhotoCannotSelectLayer:(BOOL)showPhotoCannotSelectLayer {
  364 + _showPhotoCannotSelectLayer = showPhotoCannotSelectLayer;
  365 + [TZImagePickerConfig sharedInstance].showPhotoCannotSelectLayer = showPhotoCannotSelectLayer;
  366 +}
  367 +
  368 +- (void)setNotScaleImage:(BOOL)notScaleImage {
  369 + _notScaleImage = notScaleImage;
  370 + [TZImagePickerConfig sharedInstance].notScaleImage = notScaleImage;
  371 +}
  372 +
  373 +- (void)setNeedFixComposition:(BOOL)needFixComposition {
  374 + _needFixComposition = needFixComposition;
  375 + [TZImagePickerConfig sharedInstance].needFixComposition = needFixComposition;
  376 +}
  377 +
  378 +- (void)observeAuthrizationStatusChange {
  379 + [_timer invalidate];
  380 + _timer = nil;
  381 + if ([TZImageManager authorizationStatus] == 0) {
  382 + _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO];
  383 + }
  384 +
  385 + if ([[TZImageManager manager] authorizationStatusAuthorized]) {
  386 + [_tipLabel removeFromSuperview];
  387 + [_settingBtn removeFromSuperview];
  388 +
  389 + [self pushPhotoPickerVc];
  390 +
  391 + TZAlbumPickerController *albumPickerVc = (TZAlbumPickerController *)self.visibleViewController;
  392 + if ([albumPickerVc isKindOfClass:[TZAlbumPickerController class]]) {
  393 + [albumPickerVc configTableView];
  394 + }
  395 + }
  396 +}
  397 +
  398 +- (void)pushPhotoPickerVc {
  399 + _didPushPhotoPickerVc = NO;
  400 + // 1.6.8 判断是否需要push到照片选择页,如果_pushPhotoPickerVc为NO,则不push
  401 + if (!_didPushPhotoPickerVc && _pushPhotoPickerVc) {
  402 + TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init];
  403 + photoPickerVc.isFirstAppear = YES;
  404 + photoPickerVc.columnNumber = self.columnNumber;
  405 + __weak typeof(self) weakSelf = self;
  406 + [[TZImageManager manager] getCameraRollAlbum:self.allowPickingVideo allowPickingImage:self.allowPickingImage needFetchAssets:NO completion:^(TZAlbumModel *model) {
  407 + photoPickerVc.model = model;
  408 + [weakSelf pushViewController:photoPickerVc animated:YES];
  409 + self->_didPushPhotoPickerVc = YES;
  410 + }];
  411 + }
  412 +}
  413 +
  414 +- (id)showAlertWithTitle:(NSString *)title {
  415 + if (iOS8Later) {
  416 + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert];
  417 + [alertController addAction:[UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"OK"] style:UIAlertActionStyleDefault handler:nil]];
  418 + [self presentViewController:alertController animated:YES completion:nil];
  419 + return alertController;
  420 + } else {
  421 + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:nil delegate:nil cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles:nil, nil];
  422 + [alertView show];
  423 + return alertView;
  424 + }
  425 +}
  426 +
  427 +- (void)hideAlertView:(id)alertView {
  428 + if ([alertView isKindOfClass:[UIAlertController class]]) {
  429 + UIAlertController *alertC = alertView;
  430 + [alertC dismissViewControllerAnimated:YES completion:nil];
  431 + } else if ([alertView isKindOfClass:[UIAlertView class]]) {
  432 + UIAlertView *alertV = alertView;
  433 + [alertV dismissWithClickedButtonIndex:0 animated:YES];
  434 + }
  435 + alertView = nil;
  436 +}
  437 +
  438 +- (void)showProgressHUD {
  439 + if (!_progressHUD) {
  440 + _progressHUD = [UIButton buttonWithType:UIButtonTypeCustom];
  441 + [_progressHUD setBackgroundColor:[UIColor clearColor]];
  442 + _progressHUD.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);///解决多次点击内存溢出问题(lxg)
  443 +
  444 + _HUDContainer = [[UIView alloc] init];
  445 + _HUDContainer.layer.cornerRadius = 8;
  446 + _HUDContainer.clipsToBounds = YES;
  447 + _HUDContainer.backgroundColor = [UIColor darkGrayColor];
  448 + _HUDContainer.alpha = 0.7;
  449 +
  450 + _HUDIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
  451 +
  452 + _HUDLabel = [[UILabel alloc] init];
  453 + _HUDLabel.textAlignment = NSTextAlignmentCenter;
  454 + _HUDLabel.text = self.processHintStr;
  455 + _HUDLabel.font = [UIFont systemFontOfSize:15];
  456 + _HUDLabel.textColor = [UIColor whiteColor];
  457 +
  458 + [_HUDContainer addSubview:_HUDLabel];
  459 + [_HUDContainer addSubview:_HUDIndicatorView];
  460 + [_progressHUD addSubview:_HUDContainer];
  461 + }
  462 + [_HUDIndicatorView startAnimating];
  463 + [[UIApplication sharedApplication].keyWindow addSubview:_progressHUD];
  464 +
  465 + // if over time, dismiss HUD automatic
  466 + __weak typeof(self) weakSelf = self;
  467 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  468 + __strong typeof(weakSelf) strongSelf = weakSelf;
  469 + [strongSelf hideProgressHUD];
  470 + });
  471 +}
  472 +
  473 +- (void)hideProgressHUD {
  474 + if (_progressHUD) {
  475 + [_HUDIndicatorView stopAnimating];
  476 + [_progressHUD removeFromSuperview];
  477 + }
  478 +}
  479 +
  480 +- (void)setMaxImagesCount:(NSInteger)maxImagesCount {
  481 + _maxImagesCount = maxImagesCount;
  482 + if (maxImagesCount > 1) {
  483 + _showSelectBtn = YES;
  484 + _allowCrop = NO;
  485 + }
  486 +}
  487 +
  488 +- (void)setShowSelectBtn:(BOOL)showSelectBtn {
  489 + _showSelectBtn = showSelectBtn;
  490 + // 多选模式下,不允许让showSelectBtn为NO
  491 + if (!showSelectBtn && _maxImagesCount > 1) {
  492 + _showSelectBtn = YES;
  493 + }
  494 +}
  495 +
  496 +- (void)setAllowCrop:(BOOL)allowCrop {
  497 + _allowCrop = _maxImagesCount > 1 ? NO : allowCrop;
  498 + if (allowCrop) { // 允许裁剪的时候,不能选原图和GIF
  499 + self.allowPickingOriginalPhoto = NO;
  500 + self.allowPickingGif = NO;
  501 + }
  502 +}
  503 +
  504 +- (void)setCircleCropRadius:(NSInteger)circleCropRadius {
  505 + _circleCropRadius = circleCropRadius;
  506 + self.cropRect = CGRectMake(self.view.tz_width / 2 - circleCropRadius, self.view.tz_height / 2 - _circleCropRadius, _circleCropRadius * 2, _circleCropRadius * 2);
  507 +}
  508 +
  509 +- (void)setCropRect:(CGRect)cropRect {
  510 + _cropRect = cropRect;
  511 + _cropRectPortrait = cropRect;
  512 + CGFloat widthHeight = cropRect.size.width;
  513 + _cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, cropRect.origin.x, widthHeight, widthHeight);
  514 +}
  515 +
  516 +- (void)setTimeout:(NSInteger)timeout {
  517 + _timeout = timeout;
  518 + if (timeout < 5) {
  519 + _timeout = 5;
  520 + } else if (_timeout > 600) {
  521 + _timeout = 600;
  522 + }
  523 +}
  524 +
  525 +- (void)setPickerDelegate:(id<TZImagePickerControllerDelegate>)pickerDelegate {
  526 + _pickerDelegate = pickerDelegate;
  527 + [TZImageManager manager].pickerDelegate = pickerDelegate;
  528 +}
  529 +
  530 +- (void)setColumnNumber:(NSInteger)columnNumber {
  531 + _columnNumber = columnNumber;
  532 + if (columnNumber <= 2) {
  533 + _columnNumber = 2;
  534 + } else if (columnNumber >= 6) {
  535 + _columnNumber = 6;
  536 + }
  537 +
  538 + TZAlbumPickerController *albumPickerVc = [self.childViewControllers firstObject];
  539 + albumPickerVc.columnNumber = _columnNumber;
  540 + [TZImageManager manager].columnNumber = _columnNumber;
  541 +}
  542 +
  543 +- (void)setMinPhotoWidthSelectable:(NSInteger)minPhotoWidthSelectable {
  544 + _minPhotoWidthSelectable = minPhotoWidthSelectable;
  545 + [TZImageManager manager].minPhotoWidthSelectable = minPhotoWidthSelectable;
  546 +}
  547 +
  548 +- (void)setMinPhotoHeightSelectable:(NSInteger)minPhotoHeightSelectable {
  549 + _minPhotoHeightSelectable = minPhotoHeightSelectable;
  550 + [TZImageManager manager].minPhotoHeightSelectable = minPhotoHeightSelectable;
  551 +}
  552 +
  553 +- (void)setHideWhenCanNotSelect:(BOOL)hideWhenCanNotSelect {
  554 + _hideWhenCanNotSelect = hideWhenCanNotSelect;
  555 + [TZImageManager manager].hideWhenCanNotSelect = hideWhenCanNotSelect;
  556 +}
  557 +
  558 +- (void)setPhotoPreviewMaxWidth:(CGFloat)photoPreviewMaxWidth {
  559 + _photoPreviewMaxWidth = photoPreviewMaxWidth;
  560 + if (photoPreviewMaxWidth > 800) {
  561 + _photoPreviewMaxWidth = 800;
  562 + } else if (photoPreviewMaxWidth < 500) {
  563 + _photoPreviewMaxWidth = 500;
  564 + }
  565 + [TZImageManager manager].photoPreviewMaxWidth = _photoPreviewMaxWidth;
  566 +}
  567 +
  568 +- (void)setPhotoWidth:(CGFloat)photoWidth {
  569 + _photoWidth = photoWidth;
  570 + [TZImageManager manager].photoWidth = photoWidth;
  571 +}
  572 +
  573 +- (void)setSelectedAssets:(NSMutableArray *)selectedAssets {
  574 + _selectedAssets = selectedAssets;
  575 + _selectedModels = [NSMutableArray array];
  576 + _selectedAssetIds = [NSMutableArray array];
  577 + for (id asset in selectedAssets) {
  578 + TZAssetModel *model = [TZAssetModel modelWithAsset:asset type:[[TZImageManager manager] getAssetType:asset]];
  579 + model.isSelected = YES;
  580 + [self addSelectedModel:model];
  581 + }
  582 +}
  583 +
  584 +- (void)setAllowPickingImage:(BOOL)allowPickingImage {
  585 + _allowPickingImage = allowPickingImage;
  586 + [TZImagePickerConfig sharedInstance].allowPickingImage = allowPickingImage;
  587 + if (!allowPickingImage) {
  588 + _allowTakePicture = NO;
  589 + }
  590 +}
  591 +
  592 +- (void)setAllowPickingVideo:(BOOL)allowPickingVideo {
  593 + _allowPickingVideo = allowPickingVideo;
  594 + [TZImagePickerConfig sharedInstance].allowPickingVideo = allowPickingVideo;
  595 + if (!allowPickingVideo) {
  596 + _allowTakeVideo = NO;
  597 + }
  598 +}
  599 +
  600 +- (void)setPreferredLanguage:(NSString *)preferredLanguage {
  601 + _preferredLanguage = preferredLanguage;
  602 + [TZImagePickerConfig sharedInstance].preferredLanguage = preferredLanguage;
  603 + [self configDefaultBtnTitle];
  604 +}
  605 +
  606 +- (void)setLanguageBundle:(NSBundle *)languageBundle {
  607 + _languageBundle = languageBundle;
  608 + [TZImagePickerConfig sharedInstance].languageBundle = languageBundle;
  609 + [self configDefaultBtnTitle];
  610 +}
  611 +
  612 +- (void)setSortAscendingByModificationDate:(BOOL)sortAscendingByModificationDate {
  613 + _sortAscendingByModificationDate = sortAscendingByModificationDate;
  614 + [TZImageManager manager].sortAscendingByModificationDate = sortAscendingByModificationDate;
  615 +}
  616 +
  617 +- (void)settingBtnClick {
  618 + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  619 +}
  620 +
  621 +- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
  622 + if (iOS7Later) {
  623 + viewController.automaticallyAdjustsScrollViewInsets = NO;
  624 + }
  625 + [super pushViewController:viewController animated:animated];
  626 +}
  627 +
  628 +- (void)dealloc {
  629 + // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
  630 + NSLog(@"相册_导航_TZImagePickerController_释放");
  631 +}
  632 +
  633 +- (void)addSelectedModel:(TZAssetModel *)model {
  634 + [_selectedModels addObject:model];
  635 + NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset];
  636 + [_selectedAssetIds addObject:assetId];
  637 +}
  638 +
  639 +- (void)removeSelectedModel:(TZAssetModel *)model {
  640 + [_selectedModels removeObject:model];
  641 + NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset];
  642 + [_selectedAssetIds removeObject:assetId];
  643 +}
  644 +
  645 +- (UIImage *)createImageWithColor:(UIColor *)color size:(CGSize)size radius:(CGFloat)radius {
  646 + if (!color) {
  647 + color = self.iconThemeColor;
  648 + }
  649 + CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
  650 + UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
  651 + CGContextRef context = UIGraphicsGetCurrentContext();
  652 + CGContextSetFillColorWithColor(context, [color CGColor]);
  653 + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius];
  654 + CGContextAddPath(context, path.CGPath);
  655 + CGContextFillPath(context);
  656 + UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
  657 + UIGraphicsEndImageContext();
  658 + return image;
  659 +}
  660 +
  661 +#pragma mark - UIContentContainer
  662 +
  663 +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
  664 + [self willInterfaceOrientionChange];
  665 + if (size.width > size.height) {
  666 + _cropRect = _cropRectLandscape;
  667 + } else {
  668 + _cropRect = _cropRectPortrait;
  669 + }
  670 +}
  671 +
  672 +- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
  673 + [self willInterfaceOrientionChange];
  674 + if (toInterfaceOrientation >= 3) {
  675 + _cropRect = _cropRectLandscape;
  676 + } else {
  677 + _cropRect = _cropRectPortrait;
  678 + }
  679 +}
  680 +
  681 +- (void)willInterfaceOrientionChange {
  682 + __weak typeof(self) weakSelf = self;
  683 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  684 + if (![UIApplication sharedApplication].statusBarHidden) {
  685 + if (iOS7Later && weakSelf.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
  686 + }
  687 + });
  688 +}
  689 +
  690 +#pragma mark - Layout
  691 +
  692 +- (void)viewDidLayoutSubviews {
  693 + [super viewDidLayoutSubviews];
  694 +
  695 + _HUDContainer.frame = CGRectMake((self.view.tz_width - 120) / 2, (self.view.tz_height - 90) / 2, 120, 90);
  696 + _HUDIndicatorView.frame = CGRectMake(45, 15, 30, 30);
  697 + _HUDLabel.frame = CGRectMake(0,40, 120, 50);
  698 +}
  699 +
  700 +#pragma mark - Public
  701 +
  702 +- (void)cancelButtonClick {
  703 + if (self.autoDismiss) {
  704 +
  705 + if (_timer) {
  706 + [_timer invalidate];
  707 + _timer = nil;
  708 + }
  709 + [self hideProgressHUD];
  710 +
  711 + __weak typeof(self) weakSelf = self;
  712 + [self dismissViewControllerAnimated:YES completion:^{
  713 + [weakSelf callDelegateMethod];
  714 +
  715 + }];
  716 + } else {
  717 + [self callDelegateMethod];
  718 + }
  719 +}
  720 +
  721 +- (void)callDelegateMethod {
  722 + if ([self.pickerDelegate respondsToSelector:@selector(tz_imagePickerControllerDidCancel:)]) {
  723 + [self.pickerDelegate tz_imagePickerControllerDidCancel:self];
  724 + }
  725 + if (self.imagePickerControllerDidCancelHandle) {
  726 + self.imagePickerControllerDidCancelHandle();
  727 + }
  728 +}
  729 +
  730 +@end
  731 +
  732 +
  733 +@interface TZAlbumPickerController ()<UITableViewDataSource,UITableViewDelegate> {
  734 + UITableView *_tableView;
  735 +}
  736 +@property (nonatomic, strong) NSMutableArray *albumArr;
  737 +@end
  738 +
  739 +@implementation TZAlbumPickerController
  740 +
  741 +- (void)viewDidLoad {
  742 + [super viewDidLoad];
  743 + self.isFirstAppear = YES;
  744 + self.view.backgroundColor = [UIColor whiteColor];
  745 +
  746 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  747 + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:imagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:imagePickerVc action:@selector(cancelButtonClick)];
  748 +}
  749 +
  750 +- (void)viewWillAppear:(BOOL)animated {
  751 + [super viewWillAppear:animated];
  752 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  753 + [imagePickerVc hideProgressHUD];
  754 + if (imagePickerVc.allowPickingImage) {
  755 + self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Photos"];
  756 + } else if (imagePickerVc.allowPickingVideo) {
  757 + self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Videos"];
  758 + }
  759 +
  760 + if (self.isFirstAppear && !imagePickerVc.navLeftBarButtonSettingBlock) {
  761 + self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Back"] style:UIBarButtonItemStylePlain target:nil action:nil];
  762 + }
  763 +
  764 + [self configTableView];
  765 +}
  766 +
  767 +- (void)configTableView {
  768 + if (![[TZImageManager manager] authorizationStatusAuthorized]) {
  769 + return;
  770 + }
  771 +
  772 + if (self.isFirstAppear) {
  773 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  774 + [imagePickerVc showProgressHUD];
  775 + }
  776 + __weak typeof(self) weakSelf = self;
  777 + dispatch_async(dispatch_get_global_queue(0, 0), ^{
  778 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)weakSelf.navigationController;
  779 + [[TZImageManager manager] getAllAlbums:imagePickerVc.allowPickingVideo allowPickingImage:imagePickerVc.allowPickingImage needFetchAssets:!weakSelf.isFirstAppear completion:^(NSArray<TZAlbumModel *> *models) {
  780 + dispatch_async(dispatch_get_main_queue(), ^{
  781 + if (models == nil) {
  782 + [imagePickerVc hideProgressHUD];
  783 + return;
  784 + }
  785 + self->_albumArr = [NSMutableArray arrayWithArray:models];
  786 + for (TZAlbumModel *albumModel in self->_albumArr) {
  787 + albumModel.selectedModels = imagePickerVc.selectedModels;
  788 + }
  789 + [imagePickerVc hideProgressHUD];
  790 +
  791 + if (weakSelf.isFirstAppear) {
  792 + weakSelf.isFirstAppear = NO;
  793 + [weakSelf configTableView];
  794 + }
  795 +
  796 + if (!self->_tableView) {
  797 + self->_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
  798 + self->_tableView.rowHeight = 70;
  799 + self->_tableView.tableFooterView = [[UIView alloc] init];
  800 + self->_tableView.dataSource = self;
  801 + self->_tableView.delegate = self;
  802 + [self->_tableView registerClass:[TZAlbumCell class] forCellReuseIdentifier:@"TZAlbumCell"];
  803 + [weakSelf.view addSubview:self->_tableView];
  804 + } else {
  805 + [self->_tableView reloadData];
  806 + }
  807 + });
  808 + }];
  809 + });
  810 +}
  811 +
  812 +- (void)dealloc {
  813 + // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
  814 +
  815 + NSLog(@"相册_相簿_TZAlbumPickerController_dealloc");
  816 +
  817 +}
  818 +
  819 +#pragma mark - Layout
  820 +
  821 +- (void)viewDidLayoutSubviews {
  822 + [super viewDidLayoutSubviews];
  823 +
  824 + CGFloat top = 0;
  825 + CGFloat tableViewHeight = 0;
  826 + CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height;
  827 + BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
  828 + if (self.navigationController.navigationBar.isTranslucent) {
  829 + top = naviBarHeight;
  830 + if (iOS7Later && !isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight];
  831 + tableViewHeight = self.view.tz_height - top;
  832 + } else {
  833 + tableViewHeight = self.view.tz_height;
  834 + }
  835 + _tableView.frame = CGRectMake(0, top, self.view.tz_width, tableViewHeight);
  836 +}
  837 +
  838 +#pragma mark - UITableViewDataSource && Delegate
  839 +
  840 +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  841 + return _albumArr.count;
  842 +}
  843 +
  844 +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  845 + TZAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TZAlbumCell"];
  846 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  847 + cell.albumCellDidLayoutSubviewsBlock = imagePickerVc.albumCellDidLayoutSubviewsBlock;
  848 + cell.albumCellDidSetModelBlock = imagePickerVc.albumCellDidSetModelBlock;
  849 + cell.selectedCountButton.backgroundColor = imagePickerVc.iconThemeColor;
  850 + cell.model = _albumArr[indexPath.row];
  851 + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
  852 + return cell;
  853 +}
  854 +
  855 +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  856 + TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init];
  857 + photoPickerVc.columnNumber = self.columnNumber;
  858 + TZAlbumModel *model = _albumArr[indexPath.row];
  859 + photoPickerVc.model = model;
  860 + [self.navigationController pushViewController:photoPickerVc animated:YES];
  861 + [tableView deselectRowAtIndexPath:indexPath animated:NO];
  862 +}
  863 +
  864 +#pragma clang diagnostic pop
  865 +
  866 +@end
  867 +
  868 +
  869 +@implementation UIImage (MyBundle)
  870 +
  871 ++ (UIImage *)imageNamedFromMyBundle:(NSString *)name {
  872 + NSBundle *imageBundle = [NSBundle tz_imagePickerBundle];
  873 + name = [name stringByAppendingString:@"@2x"];
  874 + NSString *imagePath = [imageBundle pathForResource:name ofType:@"png"];
  875 + UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
  876 + if (!image) {
  877 + // 兼容业务方自己设置图片的方式
  878 + name = [name stringByReplacingOccurrencesOfString:@"@2x" withString:@""];
  879 + image = [UIImage imageNamed:name];
  880 + }
  881 + return image;
  882 +}
  883 +
  884 +@end
  885 +
  886 +
  887 +@implementation NSString (TzExtension)
  888 +
  889 +- (BOOL)tz_containsString:(NSString *)string {
  890 + if (iOS8Later) {
  891 + return [self containsString:string];
  892 + } else {
  893 + NSRange range = [self rangeOfString:string];
  894 + return range.location != NSNotFound;
  895 + }
  896 +}
  897 +
  898 +#pragma clang diagnostic push
  899 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  900 +- (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize {
  901 + CGSize size;
  902 + if (iOS7Later) {
  903 + size = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
  904 + } else {
  905 + size = [self sizeWithFont:attributes[NSFontAttributeName] constrainedToSize:maxSize];
  906 + }
  907 + return size;
  908 +}
  909 +#pragma clang diagnostic pop
  910 +
  911 +@end
  912 +
  913 +
  914 +@implementation TZCommonTools
  915 +
  916 ++ (BOOL)tz_isIPhoneX {
  917 +
  918 + return (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||
  919 + CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)) ||
  920 + CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(414, 896)) ||
  921 + CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(896, 414)));
  922 +
  923 +}
  924 +
  925 ++ (CGFloat)tz_statusBarHeight {
  926 + return [self tz_isIPhoneX] ? 44 : 20;
  927 +}
  928 +
  929 +// 获得Info.plist数据字典
  930 ++ (NSDictionary *)tz_getInfoDictionary {
  931 + NSDictionary *infoDict = [NSBundle mainBundle].localizedInfoDictionary;
  932 + if (!infoDict || !infoDict.count) {
  933 + infoDict = [NSBundle mainBundle].infoDictionary;
  934 + }
  935 + if (!infoDict || !infoDict.count) {
  936 + NSString *path = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"];
  937 + infoDict = [NSDictionary dictionaryWithContentsOfFile:path];
  938 + }
  939 + return infoDict ? infoDict : @{};
  940 +}
  941 +@end
  942 +
  943 +
  944 +@implementation TZImagePickerConfig
  945 +
  946 ++ (instancetype)sharedInstance {
  947 + static dispatch_once_t onceToken;
  948 + static TZImagePickerConfig *config = nil;
  949 + dispatch_once(&onceToken, ^{
  950 + if (config == nil) {
  951 + config = [[TZImagePickerConfig alloc] init];
  952 + config.preferredLanguage = nil;
  953 + config.gifPreviewMaxImagesCount = 200;
  954 + }
  955 + });
  956 + return config;
  957 +}
  958 +
  959 +- (void)setPreferredLanguage:(NSString *)preferredLanguage {
  960 + _preferredLanguage = preferredLanguage;
  961 +
  962 + if (!preferredLanguage || !preferredLanguage.length) {
  963 + preferredLanguage = [NSLocale preferredLanguages].firstObject;
  964 + }
  965 + if ([preferredLanguage rangeOfString:@"zh-Hans"].location != NSNotFound) {
  966 + preferredLanguage = @"zh-Hans";
  967 + } else if ([preferredLanguage rangeOfString:@"zh-Hant"].location != NSNotFound) {
  968 + preferredLanguage = @"zh-Hant";
  969 + } else if ([preferredLanguage rangeOfString:@"vi"].location != NSNotFound) {
  970 + preferredLanguage = @"vi";
  971 + } else {
  972 + preferredLanguage = @"en";
  973 + }
  974 + _languageBundle = [NSBundle bundleWithPath:[[NSBundle tz_imagePickerBundle] pathForResource:preferredLanguage ofType:@"lproj"]];
  975 +}
  976 +
  977 +@end
... ...
CNLiveImagePickerController/Classes/TZLocationManager.h 0 → 100755
  1 +//
  2 +// TZLocationManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2017/06/03.
  6 +// Copyright © 2017年 谭真. All rights reserved.
  7 +// 定位管理类
  8 +
  9 +
  10 +#import <Foundation/Foundation.h>
  11 +#import <CoreLocation/CoreLocation.h>
  12 +
  13 +@interface TZLocationManager : NSObject
  14 +
  15 ++ (instancetype)manager;
  16 +
  17 +/// 开始定位
  18 +- (void)startLocation;
  19 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock;
  20 +- (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
  21 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
  22 +
  23 +@end
  24 +
... ...
CNLiveImagePickerController/Classes/TZLocationManager.m 0 → 100755
  1 +//
  2 +// TZLocationManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2017/06/03.
  6 +// Copyright © 2017年 谭真. All rights reserved.
  7 +// 定位管理类
  8 +
  9 +#import "TZLocationManager.h"
  10 +#import "TZImagePickerController.h"
  11 +
  12 +@interface TZLocationManager ()<CLLocationManagerDelegate>
  13 +@property (nonatomic, strong) CLLocationManager *locationManager;
  14 +/// 定位成功的回调block
  15 +@property (nonatomic, copy) void (^successBlock)(NSArray<CLLocation *> *);
  16 +/// 编码成功的回调block
  17 +@property (nonatomic, copy) void (^geocodeBlock)(NSArray *geocodeArray);
  18 +/// 定位失败的回调block
  19 +@property (nonatomic, copy) void (^failureBlock)(NSError *error);
  20 +@end
  21 +
  22 +@implementation TZLocationManager
  23 +
  24 ++ (instancetype)manager {
  25 + static TZLocationManager *manager;
  26 + static dispatch_once_t onceToken;
  27 + dispatch_once(&onceToken, ^{
  28 + manager = [[self alloc] init];
  29 + manager.locationManager = [[CLLocationManager alloc] init];
  30 + manager.locationManager.delegate = manager;
  31 + if (iOS8Later) {
  32 + [manager.locationManager requestWhenInUseAuthorization];
  33 + }
  34 + });
  35 + return manager;
  36 +}
  37 +
  38 +- (void)startLocation {
  39 + [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:nil];
  40 +}
  41 +
  42 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock {
  43 + [self startLocationWithSuccessBlock:successBlock failureBlock:failureBlock geocoderBlock:nil];
  44 +}
  45 +
  46 +- (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
  47 + [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:geocoderBlock];
  48 +}
  49 +
  50 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
  51 + [self.locationManager startUpdatingLocation];
  52 + _successBlock = successBlock;
  53 + _geocodeBlock = geocoderBlock;
  54 + _failureBlock = failureBlock;
  55 +}
  56 +
  57 +#pragma mark - CLLocationManagerDelegate
  58 +
  59 +/// 地理位置发生改变时触发
  60 +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
  61 + [manager stopUpdatingLocation];
  62 +
  63 + if (_successBlock) {
  64 + _successBlock(locations);
  65 + }
  66 +
  67 + if (_geocodeBlock && locations.count) {
  68 + CLGeocoder *geocoder = [[CLGeocoder alloc] init];
  69 + [geocoder reverseGeocodeLocation:[locations firstObject] completionHandler:^(NSArray *array, NSError *error) {
  70 + self->_geocodeBlock(array);
  71 + }];
  72 + }
  73 +}
  74 +
  75 +/// 定位失败回调方法
  76 +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
  77 + NSLog(@"定位失败, 错误: %@",error);
  78 + switch([error code]) {
  79 + case kCLErrorDenied: { // 用户禁止了定位权限
  80 +
  81 + } break;
  82 + default: break;
  83 + }
  84 + if (_failureBlock) {
  85 + _failureBlock(error);
  86 + }
  87 +}
  88 +
  89 +@end
... ...
CNLiveImagePickerController/Classes/TZPhotoPickerController.h 0 → 100755
  1 +//
  2 +// TZPhotoPickerController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAlbumModel;
  12 +@interface TZPhotoPickerController : UIViewController
  13 +
  14 +@property (nonatomic, assign) BOOL isFirstAppear;
  15 +@property (nonatomic, assign) NSInteger columnNumber;
  16 +@property (nonatomic, strong) TZAlbumModel *model;
  17 +@end
  18 +
  19 +
  20 +@interface TZCollectionView : UICollectionView
  21 +
  22 +@end
... ...
CNLiveImagePickerController/Classes/TZPhotoPickerController.m 0 → 100755
  1 +//
  2 +// TZPhotoPickerController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZPhotoPickerController.h"
  10 +#import "TZImagePickerController.h"
  11 +#import "TZPhotoPreviewController.h"
  12 +#import "TZAssetCell.h"
  13 +#import "TZAssetModel.h"
  14 +#import "UIView+TZLayout.h"
  15 +#import "TZImageManager.h"
  16 +#import "TZVideoPlayerController.h"
  17 +#import "TZGifPhotoPreviewController.h"
  18 +#import "TZLocationManager.h"
  19 +#import <MobileCoreServices/MobileCoreServices.h>
  20 +#import <AssetsLibrary/AssetsLibrary.h>///lxg
  21 +#import "CNLiveUploadManager.h"
  22 +
  23 +@implementation PHAsset (Qiniu)
  24 +
  25 +- (NSURL *)movieURL {
  26 + __block NSURL *url = nil;
  27 +
  28 + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  29 +
  30 + if (self.mediaType == PHAssetMediaTypeVideo) {
  31 + PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
  32 + options.version = PHVideoRequestOptionsVersionOriginal;
  33 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  34 + options.networkAccessAllowed = YES;
  35 +
  36 + PHImageManager *manager = [PHImageManager defaultManager];
  37 + [manager requestAVAssetForVideo:self options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
  38 + AVURLAsset *urlAsset = (AVURLAsset *)asset;
  39 + url = urlAsset.URL;
  40 +
  41 + dispatch_semaphore_signal(semaphore);
  42 + }];
  43 + }else {
  44 + dispatch_semaphore_signal(semaphore);
  45 + }
  46 +
  47 + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  48 +
  49 + return url;
  50 +}
  51 +
  52 +- (UIImage *)getPhoto {
  53 +
  54 + __block UIImage *getPhoto = nil;
  55 +
  56 + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  57 + if (self.mediaType == PHAssetMediaTypeImage) {
  58 + /*** 根据asset取图片 ***/
  59 + PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init];
  60 + option.synchronous = YES;//主要是这个设为YES这样才会只走一次
  61 + option.networkAccessAllowed = YES;
  62 + option.resizeMode = PHImageRequestOptionsResizeModeFast;
  63 + [[PHImageManager defaultManager] requestImageForAsset:self targetSize:CGSizeMake(100, 100) contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
  64 +
  65 + if (result) {
  66 + getPhoto = result;
  67 + }else {
  68 + getPhoto = nil;
  69 + }
  70 + dispatch_semaphore_signal(semaphore);
  71 +
  72 + }];
  73 +
  74 + }else {
  75 + dispatch_semaphore_signal(semaphore);
  76 + }
  77 +
  78 + dispatch_time_t duration = dispatch_time(DISPATCH_TIME_NOW, (int64_t)10* NSEC_PER_SEC); //超时10秒
  79 + dispatch_semaphore_wait(semaphore, duration);
  80 +
  81 + return getPhoto;
  82 +}
  83 +
  84 +
  85 +@end
  86 +
  87 +@interface TZPhotoPickerController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIAlertViewDelegate> {
  88 + NSMutableArray *_models;
  89 +
  90 + UIView *_bottomToolBar;
  91 + UIButton *_previewButton;
  92 + UIButton *_doneButton;
  93 + UIImageView *_numberImageView;
  94 + UILabel *_numberLabel;
  95 + UIButton *_originalPhotoButton;
  96 + UILabel *_originalPhotoLabel;
  97 + UIView *_divideLine;
  98 +
  99 + BOOL _shouldScrollToBottom;
  100 + BOOL _showTakePhotoBtn;
  101 +
  102 + CGFloat _offsetItemCount;
  103 +
  104 + BOOL _isClickDone;///防止多次点击(LXG)
  105 +}
  106 +@property CGRect previousPreheatRect;
  107 +@property (nonatomic, assign) BOOL isSelectOriginalPhoto;
  108 +@property (nonatomic, strong) TZCollectionView *collectionView;
  109 +@property (strong, nonatomic) UICollectionViewFlowLayout *layout;
  110 +@property (nonatomic, strong) UIImagePickerController *imagePickerVc;
  111 +@property (strong, nonatomic) CLLocation *location;
  112 +@property (assign, nonatomic) BOOL useCachedImage;
  113 +@end
  114 +
  115 +static CGSize AssetGridThumbnailSize;
  116 +static CGFloat itemMargin = 5;
  117 +
  118 +@implementation TZPhotoPickerController
  119 +
  120 +#pragma clang diagnostic push
  121 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  122 +- (UIImagePickerController *)imagePickerVc {
  123 + if (_imagePickerVc == nil) {
  124 + _imagePickerVc = [[UIImagePickerController alloc] init];
  125 + _imagePickerVc.delegate = self;
  126 + // set appearance / 改变相册选择页的导航栏外观
  127 + if (iOS7Later) {
  128 + _imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor;
  129 + }
  130 + _imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
  131 + UIBarButtonItem *tzBarItem, *BarItem;
  132 + if (@available(iOS 9, *)) {
  133 + tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
  134 + BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]];
  135 + } else {
  136 + tzBarItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil];
  137 + BarItem = [UIBarButtonItem appearanceWhenContainedIn:[UIImagePickerController class], nil];
  138 + }
  139 + NSDictionary *titleTextAttributes = [tzBarItem titleTextAttributesForState:UIControlStateNormal];
  140 + [BarItem setTitleTextAttributes:titleTextAttributes forState:UIControlStateNormal];
  141 + }
  142 + return _imagePickerVc;
  143 +}
  144 +
  145 +- (void)viewDidLoad {
  146 + [super viewDidLoad];
  147 + _isClickDone = NO;
  148 + self.isFirstAppear = YES;
  149 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  150 + _isSelectOriginalPhoto = tzImagePickerVc.isSelectOriginalPhoto;
  151 + _shouldScrollToBottom = YES;
  152 + self.view.backgroundColor = [UIColor whiteColor];
  153 + self.navigationItem.title = _model.name;
  154 + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:tzImagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:tzImagePickerVc action:@selector(cancelButtonClick)];
  155 + if (tzImagePickerVc.navLeftBarButtonSettingBlock) {
  156 + UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeCustom];
  157 + leftButton.frame = CGRectMake(0, 0, 44, 44);
  158 + [leftButton addTarget:self action:@selector(navLeftBarButtonClick) forControlEvents:UIControlEventTouchUpInside];
  159 + tzImagePickerVc.navLeftBarButtonSettingBlock(leftButton);
  160 + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:leftButton];
  161 + } else if (tzImagePickerVc.childViewControllers.count) {
  162 + [tzImagePickerVc.childViewControllers firstObject].navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Back"] style:UIBarButtonItemStylePlain target:nil action:nil];
  163 + }
  164 + _showTakePhotoBtn = _model.isCameraRoll && ((tzImagePickerVc.allowTakePicture && tzImagePickerVc.allowPickingImage) || (tzImagePickerVc.allowTakeVideo && tzImagePickerVc.allowPickingVideo));
  165 + // [self resetCachedAssets];
  166 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
  167 +}
  168 +
  169 +- (void)fetchAssetModels {
  170 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  171 + if (_isFirstAppear && !_model.models.count) {
  172 + [tzImagePickerVc showProgressHUD];
  173 + }
  174 + __weak typeof(self) weakSelf = self;
  175 + dispatch_async(dispatch_get_global_queue(0, 0), ^{
  176 + if (!tzImagePickerVc.sortAscendingByModificationDate && self->_isFirstAppear && iOS8Later && self->_model.isCameraRoll) {
  177 + [[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage needFetchAssets:YES completion:^(TZAlbumModel *model) {
  178 + self->_model = model;
  179 + self->_models = [NSMutableArray arrayWithArray:self->_model.models];
  180 + [weakSelf initSubviews];
  181 + }];
  182 + } else {
  183 + if (self->_showTakePhotoBtn || !iOS8Later || self->_isFirstAppear) {
  184 + __weak typeof(self) weakSelf = self;
  185 + [[TZImageManager manager] getAssetsFromFetchResult:self->_model.result completion:^(NSArray<TZAssetModel *> *models) {
  186 + self->_models = [NSMutableArray arrayWithArray:models];
  187 + [weakSelf initSubviews];
  188 + }];
  189 + } else {
  190 + self->_models = [NSMutableArray arrayWithArray:self->_model.models];
  191 + [weakSelf initSubviews];
  192 + }
  193 + }
  194 + });
  195 +}
  196 +
  197 +- (void)initSubviews {
  198 + __weak typeof(self) weakSelf = self;
  199 + dispatch_async(dispatch_get_main_queue(), ^{
  200 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)weakSelf.navigationController;
  201 + [tzImagePickerVc hideProgressHUD];
  202 +
  203 + [weakSelf checkSelectedModels];
  204 + [weakSelf configCollectionView];
  205 + self->_collectionView.hidden = YES;
  206 + [weakSelf configBottomToolBar];
  207 +
  208 + [weakSelf scrollCollectionViewToBottom];
  209 + });
  210 +}
  211 +
  212 +- (void)viewWillDisappear:(BOOL)animated {
  213 + [super viewWillDisappear:animated];
  214 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  215 + tzImagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto;
  216 +}
  217 +
  218 +- (BOOL)prefersStatusBarHidden {
  219 + return NO;
  220 +}
  221 +
  222 +- (void)configCollectionView {
  223 + _layout = [[UICollectionViewFlowLayout alloc] init];
  224 + _collectionView = [[TZCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout];
  225 + _collectionView.backgroundColor = [UIColor whiteColor];
  226 + _collectionView.dataSource = self;
  227 + _collectionView.delegate = self;
  228 + _collectionView.alwaysBounceHorizontal = NO;
  229 + _collectionView.contentInset = UIEdgeInsetsMake(itemMargin, itemMargin, itemMargin, itemMargin);
  230 +
  231 + if (_showTakePhotoBtn) {
  232 + _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber) / self.columnNumber) * self.view.tz_width);
  233 + } else {
  234 + _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber - 1) / self.columnNumber) * self.view.tz_width);
  235 + }
  236 + [self.view addSubview:_collectionView];
  237 + [_collectionView registerClass:[TZAssetCell class] forCellWithReuseIdentifier:@"TZAssetCell"];
  238 + [_collectionView registerClass:[TZAssetCameraCell class] forCellWithReuseIdentifier:@"TZAssetCameraCell"];
  239 +}
  240 +
  241 +- (void)viewWillAppear:(BOOL)animated {
  242 + [super viewWillAppear:animated];
  243 + // Determine the size of the thumbnails to request from the PHCachingImageManager
  244 + CGFloat scale = 2.0;
  245 + if ([UIScreen mainScreen].bounds.size.width > 600) {
  246 + scale = 1.0;
  247 + }
  248 + CGSize cellSize = ((UICollectionViewFlowLayout *)_collectionView.collectionViewLayout).itemSize;
  249 + AssetGridThumbnailSize = CGSizeMake(cellSize.width * scale, cellSize.height * scale);
  250 +
  251 + if (!_models) {
  252 + [self fetchAssetModels];
  253 + }
  254 +}
  255 +
  256 +- (void)viewDidAppear:(BOOL)animated {
  257 + [super viewDidAppear:animated];
  258 + if (iOS8Later) {
  259 + // [self updateCachedAssets];
  260 + }
  261 +}
  262 +
  263 +- (void)configBottomToolBar {
  264 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  265 + if (!tzImagePickerVc.showSelectBtn) return;
  266 +
  267 + _bottomToolBar = [[UIView alloc] initWithFrame:CGRectZero];
  268 + CGFloat rgb = 253 / 255.0;
  269 + _bottomToolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
  270 +
  271 + _previewButton = [UIButton buttonWithType:UIButtonTypeCustom];
  272 + [_previewButton addTarget:self action:@selector(previewButtonClick) forControlEvents:UIControlEventTouchUpInside];
  273 + _previewButton.titleLabel.font = [UIFont systemFontOfSize:16];
  274 + [_previewButton setTitle:tzImagePickerVc.previewBtnTitleStr forState:UIControlStateNormal];
  275 + [_previewButton setTitle:tzImagePickerVc.previewBtnTitleStr forState:UIControlStateDisabled];
  276 + [_previewButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
  277 + [_previewButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
  278 + _previewButton.enabled = tzImagePickerVc.selectedModels.count;
  279 +
  280 + if (tzImagePickerVc.allowPickingOriginalPhoto) {
  281 + _originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
  282 + _originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
  283 + [_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside];
  284 + _originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  285 + [_originalPhotoButton setTitle:tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateNormal];
  286 + [_originalPhotoButton setTitle:tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateSelected];
  287 + [_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
  288 + [_originalPhotoButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected];
  289 + [_originalPhotoButton setImage:tzImagePickerVc.photoOriginDefImage forState:UIControlStateNormal];
  290 + [_originalPhotoButton setImage:tzImagePickerVc.photoOriginSelImage forState:UIControlStateSelected];
  291 + _originalPhotoButton.imageView.clipsToBounds = YES;
  292 + _originalPhotoButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
  293 + _originalPhotoButton.selected = _isSelectOriginalPhoto;
  294 + _originalPhotoButton.enabled = tzImagePickerVc.selectedModels.count > 0;
  295 +
  296 + _originalPhotoLabel = [[UILabel alloc] init];
  297 + _originalPhotoLabel.textAlignment = NSTextAlignmentLeft;
  298 + _originalPhotoLabel.font = [UIFont systemFontOfSize:16];
  299 + _originalPhotoLabel.textColor = [UIColor blackColor];
  300 + if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes];
  301 + }
  302 +
  303 + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
  304 + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
  305 + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
  306 + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
  307 + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateDisabled];
  308 + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
  309 + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled];
  310 + _doneButton.enabled = tzImagePickerVc.selectedModels.count || tzImagePickerVc.alwaysEnableDoneBtn;
  311 +
  312 + _numberImageView = [[UIImageView alloc] initWithImage:tzImagePickerVc.photoNumberIconImage];
  313 + _numberImageView.hidden = tzImagePickerVc.selectedModels.count <= 0;
  314 + _numberImageView.clipsToBounds = YES;
  315 + _numberImageView.contentMode = UIViewContentModeScaleAspectFit;
  316 + _numberImageView.backgroundColor = [UIColor clearColor];
  317 +
  318 + _numberLabel = [[UILabel alloc] init];
  319 + _numberLabel.font = [UIFont systemFontOfSize:15];
  320 + _numberLabel.textColor = [UIColor whiteColor];
  321 + _numberLabel.textAlignment = NSTextAlignmentCenter;
  322 + _numberLabel.text = [NSString stringWithFormat:@"%zd",tzImagePickerVc.selectedModels.count];
  323 + _numberLabel.hidden = tzImagePickerVc.selectedModels.count <= 0;
  324 + _numberLabel.backgroundColor = [UIColor clearColor];
  325 +#pragma mark - 添加: 选择图片个数显示(LXG)
  326 + _numberImageView.hidden = YES;
  327 + _numberLabel.hidden = YES;
  328 + [_doneButton setTitle:[NSString stringWithFormat:@"完成(%zd)",tzImagePickerVc.selectedModels.count] forState:UIControlStateNormal];
  329 +
  330 + _divideLine = [[UIView alloc] init];
  331 + CGFloat rgb2 = 222 / 255.0;
  332 + _divideLine.backgroundColor = [UIColor colorWithRed:rgb2 green:rgb2 blue:rgb2 alpha:1.0];
  333 +
  334 + [_bottomToolBar addSubview:_divideLine];
  335 + [_bottomToolBar addSubview:_previewButton];
  336 + [_bottomToolBar addSubview:_doneButton];
  337 + [_bottomToolBar addSubview:_numberImageView];
  338 + [_bottomToolBar addSubview:_numberLabel];
  339 + [_bottomToolBar addSubview:_originalPhotoButton];
  340 + [self.view addSubview:_bottomToolBar];
  341 + [_originalPhotoButton addSubview:_originalPhotoLabel];
  342 +
  343 + if (tzImagePickerVc.photoPickerPageUIConfigBlock) {
  344 + tzImagePickerVc.photoPickerPageUIConfigBlock(_collectionView, _bottomToolBar, _previewButton, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel, _divideLine);
  345 + }
  346 +}
  347 +
  348 +#pragma mark - Layout
  349 +
  350 +- (void)viewDidLayoutSubviews {
  351 + [super viewDidLayoutSubviews];
  352 +
  353 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  354 +
  355 + CGFloat top = 0;
  356 + CGFloat collectionViewHeight = 0;
  357 + CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height;
  358 + BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
  359 + CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 50 + (83 - 49) : 50;
  360 + if (self.navigationController.navigationBar.isTranslucent) {
  361 + top = naviBarHeight;
  362 + if (iOS7Later && !isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight];
  363 + collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - toolBarHeight - top : self.view.tz_height - top;;
  364 + } else {
  365 + collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - toolBarHeight : self.view.tz_height;
  366 + }
  367 + _collectionView.frame = CGRectMake(0, top, self.view.tz_width, collectionViewHeight);
  368 + CGFloat itemWH = (self.view.tz_width - (self.columnNumber + 1) * itemMargin) / self.columnNumber;
  369 + _layout.itemSize = CGSizeMake(itemWH, itemWH);
  370 + _layout.minimumInteritemSpacing = itemMargin;
  371 + _layout.minimumLineSpacing = itemMargin;
  372 + [_collectionView setCollectionViewLayout:_layout];
  373 + if (_offsetItemCount > 0) {
  374 + CGFloat offsetY = _offsetItemCount * (_layout.itemSize.height + _layout.minimumLineSpacing);
  375 + [_collectionView setContentOffset:CGPointMake(0, offsetY)];
  376 + }
  377 +
  378 + CGFloat toolBarTop = 0;
  379 + if (!self.navigationController.navigationBar.isHidden) {
  380 + toolBarTop = self.view.tz_height - toolBarHeight;
  381 + } else {
  382 + CGFloat navigationHeight = naviBarHeight;
  383 + if (iOS7Later) navigationHeight += [TZCommonTools tz_statusBarHeight];
  384 + toolBarTop = self.view.tz_height - toolBarHeight - navigationHeight;
  385 + }
  386 + _bottomToolBar.frame = CGRectMake(0, toolBarTop, self.view.tz_width, toolBarHeight);
  387 + CGFloat previewWidth = [tzImagePickerVc.previewBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width + 2;
  388 + if (!tzImagePickerVc.allowPreview) {
  389 + previewWidth = 0.0;
  390 + }
  391 + _previewButton.frame = CGRectMake(10, 3, previewWidth, 44);
  392 + _previewButton.tz_width = !tzImagePickerVc.showSelectBtn ? 0 : previewWidth;
  393 + if (tzImagePickerVc.allowPickingOriginalPhoto) {
  394 + CGFloat fullImageWidth = [tzImagePickerVc.fullImageBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width;
  395 + _originalPhotoButton.frame = CGRectMake(CGRectGetMaxX(_previewButton.frame), 0, fullImageWidth + 56, 50);
  396 + _originalPhotoLabel.frame = CGRectMake(fullImageWidth + 46, 0, 80, 50);
  397 + }
  398 + [_doneButton sizeToFit];
  399 + _doneButton.frame = CGRectMake(self.view.tz_width - _doneButton.tz_width - 12, 0, _doneButton.tz_width, 50);
  400 + _numberImageView.frame = CGRectMake(_doneButton.tz_left - 24 - 5, 13, 24, 24);
  401 + _numberLabel.frame = _numberImageView.frame;
  402 + _divideLine.frame = CGRectMake(0, 0, self.view.tz_width, 1);
  403 +
  404 + [TZImageManager manager].columnNumber = [TZImageManager manager].columnNumber;
  405 + [self.collectionView reloadData];
  406 +
  407 + if (tzImagePickerVc.photoPickerPageDidLayoutSubviewsBlock) {
  408 + tzImagePickerVc.photoPickerPageDidLayoutSubviewsBlock(_collectionView, _bottomToolBar, _previewButton, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel, _divideLine);
  409 + }
  410 +}
  411 +
  412 +#pragma mark - Notification
  413 +
  414 +- (void)didChangeStatusBarOrientationNotification:(NSNotification *)noti {
  415 + _offsetItemCount = _collectionView.contentOffset.y / (_layout.itemSize.height + _layout.minimumLineSpacing);
  416 +}
  417 +
  418 +#pragma mark - Click Event
  419 +- (void)navLeftBarButtonClick{
  420 + [self.navigationController popViewControllerAnimated:YES];
  421 +}
  422 +
  423 +- (void)previewButtonClick {
  424 + //根据进入方式不同判断
  425 + TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
  426 + photoPreviewVc.enterType = PhotoPreviewEnterTypeSelected;
  427 + [self pushPhotoPrevireViewController:photoPreviewVc needCheckSelectedModels:YES];
  428 +}
  429 +
  430 +- (void)originalPhotoButtonClick {
  431 + _originalPhotoButton.selected = !_originalPhotoButton.isSelected;
  432 + _isSelectOriginalPhoto = _originalPhotoButton.isSelected;
  433 + _originalPhotoLabel.hidden = YES; ///lxg添加
  434 +// _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected;///lxg注释
  435 + if (_isSelectOriginalPhoto) {
  436 + [self getSelectedPhotoBytes];
  437 + }
  438 +}
  439 +
  440 +#pragma mark - TODO: done 完成
  441 +- (void)doneButtonClick {
  442 + NSLog(@"-----相册完成选择----");
  443 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  444 +#pragma mark - 筛选
  445 + /*** 筛选 ***/
  446 + __block BOOL isBad = NO;
  447 + __weak typeof(self) weakSelf = self;
  448 + [tzImagePickerVc.selectedModels enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TZAssetModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  449 +
  450 + /*** 筛选损坏视频 ***/
  451 + if (obj.type == TZAssetModelMediaTypeVideo) {
  452 + NSURL *url = [obj.asset movieURL];
  453 + if (!url) {
  454 + isBad = YES;
  455 +
  456 + }
  457 + }
  458 +
  459 + /*** 筛选损坏图片 ***/
  460 + if (obj.type == TZAssetModelMediaTypePhotoGif
  461 + || obj.type == TZAssetModelMediaTypePhoto) {
  462 +
  463 + UIImage *photo = [obj.asset getPhoto];
  464 + if (!photo) {
  465 + isBad = YES;
  466 + }
  467 +
  468 + }
  469 +
  470 + }];
  471 +
  472 + if (isBad) {
  473 + NSString *imgShowStr = [NSString stringWithFormat:@"选择中内容已损坏,已从选中删除"];
  474 + [tzImagePickerVc showAlertWithTitle:imgShowStr];
  475 + [weakSelf checkSelectedModels];
  476 + [weakSelf refreshBottomToolBarStatus];
  477 + [weakSelf.collectionView reloadData];
  478 +
  479 + [[NSNotificationCenter defaultCenter] postNotificationName:@"refreshPhotoPreview" object:nil];
  480 +
  481 + return;
  482 + }
  483 +
  484 +#pragma mark - 上传
  485 +
  486 + if (!_isClickDone) {
  487 + _isClickDone = YES;
  488 + }else{
  489 + return;
  490 + }
  491 +
  492 + // 1.6.8 判断是否满足最小必选张数的限制
  493 + if (tzImagePickerVc.minImagesCount && tzImagePickerVc.selectedModels.count < tzImagePickerVc.minImagesCount) {
  494 + NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a minimum of %zd photos"], tzImagePickerVc.minImagesCount];
  495 + [tzImagePickerVc showAlertWithTitle:title];
  496 + return;
  497 + }
  498 +
  499 +
  500 + dispatch_async(dispatch_get_main_queue(), ^{
  501 + [tzImagePickerVc showProgressHUD];
  502 + });
  503 +
  504 + dispatch_async(dispatch_get_global_queue(0, 0), ^{
  505 + NSMutableArray *selectedModels = [NSMutableArray array];
  506 + NSMutableArray *assets = [NSMutableArray array];
  507 + NSMutableArray *photos = [NSMutableArray array];
  508 + NSMutableArray *infoArr = [NSMutableArray array];
  509 +
  510 + dispatch_queue_t queue = dispatch_queue_create("export", DISPATCH_QUEUE_SERIAL);//串行
  511 + if (tzImagePickerVc.onlyReturnAsset) {
  512 + for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) {
  513 + TZAssetModel *model = tzImagePickerVc.selectedModels[i];
  514 + [assets addObject:model.asset];
  515 + }
  516 +
  517 + }else {
  518 + /*** 默认添加数字站位 ***/
  519 + for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) {
  520 +
  521 + [selectedModels addObject:@1];
  522 + [photos addObject:@1];
  523 + [assets addObject:@1];
  524 + [infoArr addObject:@1];
  525 +
  526 + }
  527 +
  528 + __block BOOL havenotShowAlert = YES;
  529 + __block id alertView;
  530 + [TZImageManager manager].shouldFixOrientation = YES;
  531 + for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) {
  532 + TZAssetModel *model = tzImagePickerVc.selectedModels[i];
  533 + ///导出
  534 + dispatch_sync(queue, ^{
  535 + // 判断是否导出视频url
  536 + if (tzImagePickerVc.isExportVideo) {
  537 + if (model.type == TZAssetModelMediaTypeVideo)
  538 + {
  539 + model.exportURL = [weakSelf getURLWithModel:model];
  540 + }
  541 + [selectedModels replaceObjectAtIndex:i withObject:model];
  542 + }
  543 +
  544 + });
  545 +
  546 + ///导出
  547 + dispatch_sync(queue, ^{
  548 +
  549 + /*** 根据asset取图片 ***/
  550 + [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  551 + if (isDegraded) return;
  552 + if (photo) {
  553 + if (![TZImagePickerConfig sharedInstance].notScaleImage) {
  554 + photo = [[TZImageManager manager] scaleImage:photo toSize:CGSizeMake(tzImagePickerVc.photoWidth, (int)(tzImagePickerVc.photoWidth * photo.size.height / photo.size.width))];
  555 + }
  556 + [photos replaceObjectAtIndex:i withObject:photo];
  557 + }
  558 +
  559 + if (info) {
  560 + [infoArr replaceObjectAtIndex:i withObject:info];
  561 + }
  562 +
  563 + [assets replaceObjectAtIndex:i withObject:model.asset];
  564 +
  565 + /*** 有数字就不让过 ***/
  566 + for (id item in photos) {
  567 + if ([item isKindOfClass:[NSNumber class]]){
  568 + return;
  569 + }
  570 + }
  571 +
  572 + if (havenotShowAlert) {
  573 + dispatch_async(dispatch_get_main_queue(), ^{
  574 + [tzImagePickerVc hideProgressHUD];
  575 + [tzImagePickerVc hideAlertView:alertView];
  576 + });
  577 + [weakSelf didGetAllPhotos:photos assets:assets selectedModels:selectedModels infoArr:infoArr];
  578 + }
  579 + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  580 + // 如果图片正在从iCloud同步中,提醒用户
  581 + if (progress < 1 && havenotShowAlert && !alertView) {
  582 + dispatch_async(dispatch_get_main_queue(), ^{
  583 + [tzImagePickerVc hideProgressHUD];
  584 + });
  585 + alertView = [tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]];
  586 + havenotShowAlert = NO;
  587 +
  588 + if (self->_isClickDone) {
  589 + self->_isClickDone = NO;
  590 + }
  591 +
  592 + return;
  593 + }
  594 + if (progress >= 1) {
  595 + havenotShowAlert = YES;
  596 + }
  597 + } networkAccessAllowed:YES];
  598 +
  599 + });
  600 +
  601 + }
  602 +
  603 + }
  604 +
  605 + dispatch_async(dispatch_get_main_queue(), ^{
  606 + [tzImagePickerVc hideProgressHUD];
  607 + });
  608 +
  609 + /*** 当只有返回Asset 和 没选择时走 ***/
  610 + if (tzImagePickerVc.selectedModels.count <= 0 || tzImagePickerVc.onlyReturnAsset) {
  611 + [weakSelf didGetAllPhotos:photos assets:assets selectedModels:selectedModels infoArr:infoArr];
  612 + }
  613 +
  614 + });
  615 +
  616 +
  617 +
  618 + /////////////////////////////////////////////////////////////////////
  619 +
  620 +// NSMutableArray *selectedModels = [NSMutableArray array];
  621 +// NSMutableArray *assets = [NSMutableArray array];
  622 +// NSMutableArray *photos;
  623 +// NSMutableArray *infoArr;
  624 +// if (tzImagePickerVc.onlyReturnAsset) { // not fetch image
  625 +// for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) {
  626 +// TZAssetModel *model = tzImagePickerVc.selectedModels[i];
  627 +// [assets addObject:model.asset];
  628 +// }
  629 +// } else { // fetch image
  630 +// photos = [NSMutableArray array];
  631 +// infoArr = [NSMutableArray array];
  632 +// for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) {
  633 +//
  634 +// [selectedModels addObject:@1];
  635 +// [photos addObject:@1];
  636 +// [assets addObject:@1];
  637 +// [infoArr addObject:@1];
  638 +//
  639 +// }
  640 +//
  641 +// __block BOOL havenotShowAlert = YES;
  642 +// [TZImageManager manager].shouldFixOrientation = YES;
  643 +// __block id alertView;
  644 +// for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) {
  645 +// TZAssetModel *model = tzImagePickerVc.selectedModels[i];
  646 +//
  647 +// /// 判断是否导出
  648 +// if (tzImagePickerVc.isExport) {
  649 +// if (model.type == TZAssetModelMediaTypeVideo) {
  650 +// model.exportURL = [self getURLWithModel:model];
  651 +// }
  652 +// [selectedModels replaceObjectAtIndex:i withObject:model];
  653 +// }else {
  654 +// [selectedModels replaceObjectAtIndex:i withObject:model];
  655 +// }
  656 +//
  657 +// [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  658 +// if (isDegraded) return;
  659 +// if (photo) {
  660 +// if (![TZImagePickerConfig sharedInstance].notScaleImage) {
  661 +// photo = [[TZImageManager manager] scaleImage:photo toSize:CGSizeMake(tzImagePickerVc.photoWidth, (int)(tzImagePickerVc.photoWidth * photo.size.height / photo.size.width))];
  662 +// }
  663 +// [photos replaceObjectAtIndex:i withObject:photo];
  664 +// }
  665 +// if (info) {
  666 +// [infoArr replaceObjectAtIndex:i withObject:info];
  667 +// }
  668 +// [assets replaceObjectAtIndex:i withObject:model.asset];
  669 +//// [self getPhotoMetadataWithAsset:model.asset];
  670 +// for (id item in photos) { if ([item isKindOfClass:[NSNumber class]]) return; }
  671 +//
  672 +// if (havenotShowAlert) {
  673 +// [tzImagePickerVc hideAlertView:alertView];
  674 +// [self didGetAllPhotos:photos assets:assets selectedModels:selectedModels infoArr:infoArr];
  675 +// }
  676 +// } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  677 +// // 如果图片正在从iCloud同步中,提醒用户
  678 +// if (progress < 1 && havenotShowAlert && !alertView) {
  679 +// [tzImagePickerVc hideProgressHUD];
  680 +// alertView = [tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]];
  681 +// havenotShowAlert = NO;
  682 +// return;
  683 +// }
  684 +// if (progress >= 1) {
  685 +// havenotShowAlert = YES;
  686 +// }
  687 +// } networkAccessAllowed:YES];
  688 +// }
  689 +// }
  690 +// if (tzImagePickerVc.selectedModels.count <= 0 || tzImagePickerVc.onlyReturnAsset) {
  691 +// [self didGetAllPhotos:photos assets:assets selectedModels:selectedModels infoArr:infoArr];
  692 +// }
  693 +}
  694 +
  695 +/// 导出视频URL
  696 +- (NSURL *)getURLWithModel:(TZAssetModel *)model{
  697 +
  698 + __block NSURL *returnURL = nil;
  699 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  700 +
  701 + [CNLiveUploadManager zipNewVideoWithAsset:model.asset conversationId:tzImagePickerVc.conversationId limitType:AppPhototLimitTypeChat progressCount:^(float progress) {
  702 +
  703 + } success:^(NSURL *url) {
  704 + returnURL = url;
  705 + } failure:^{
  706 +
  707 + }];
  708 +
  709 + return returnURL;
  710 +
  711 +}
  712 +
  713 +//- (void)getPhotoMetadataWithAsset:(PHAsset *)asset
  714 +//{
  715 +// PHImageRequestOptions *request = [PHImageRequestOptions new];
  716 +// request.version = PHImageRequestOptionsVersionCurrent;
  717 +// request.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
  718 +// request.resizeMode = PHImageRequestOptionsResizeModeNone;
  719 +// request.synchronous = YES;
  720 +// NSData *data1 = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"file:///var/mobile/Media/DCIM/100APPLE/IMG_0178.JPG"]];
  721 +// UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"file:///var/mobile/Media/DCIM/100APPLE/1.JPG"]]];
  722 +// [[PHImageManager defaultManager] requestImageDataForAsset:asset options: request resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
  723 +// NSURL *url = [info valueForKey:@"PHImageFileURLKey"];
  724 +// NSString *str = [url absoluteString]; //url>string
  725 +// NSArray *arr = [str componentsSeparatedByString:@"/"];
  726 +// NSString *imgName = [arr lastObject];
  727 +// NSLog(@"imgName:%@",imgName);
  728 +//
  729 +// CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
  730 +// if (NULL != source) {
  731 +// NSDictionary * metadataDic = (NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source, 0, NULL));
  732 +// NSLog(@"metada:%@",metadataDic);
  733 +// CFRelease(source);
  734 +// }
  735 +// }];
  736 +//}
  737 +
  738 +- (void)didGetAllPhotos:(NSArray *)photos assets:(NSArray *)assets selectedModels:(NSArray *)selectedModels infoArr:(NSArray *)infoArr {
  739 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  740 + [tzImagePickerVc hideProgressHUD];
  741 +
  742 + if (tzImagePickerVc.autoDismiss) {
  743 + [self.navigationController dismissViewControllerAnimated:YES completion:^{
  744 + [self callDelegateMethodWithPhotos:photos assets:assets selectedModels:selectedModels infoArr:infoArr];
  745 + }];
  746 + } else {
  747 + [self callDelegateMethodWithPhotos:photos assets:assets selectedModels:selectedModels infoArr:infoArr];
  748 + }
  749 +}
  750 +
  751 +///lxg:更改
  752 +- (void)callDelegateMethodWithPhotos:(NSArray *)photos assets:(NSArray *)assets selectedModels:(NSArray *)selectedModels infoArr:(NSArray *)infoArr {
  753 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  754 + if (tzImagePickerVc.allowPickingVideo && tzImagePickerVc.maxImagesCount == 1) {
  755 + if ([[TZImageManager manager] isVideo:[assets firstObject]]) {
  756 + if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) {
  757 + [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingVideo:[photos firstObject] sourceAssets:[assets firstObject]];
  758 + }
  759 + if (tzImagePickerVc.didFinishPickingVideoHandle) {
  760 + tzImagePickerVc.didFinishPickingVideoHandle([photos firstObject], [assets firstObject]);
  761 + }
  762 + return;
  763 + }
  764 + }
  765 +
  766 + if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:)]) {
  767 + [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:_isSelectOriginalPhoto];
  768 + }
  769 + if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:infos:)]) {
  770 + [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:_isSelectOriginalPhoto infos:infoArr];
  771 + }
  772 + if (tzImagePickerVc.didFinishPickingPhotosHandle) {
  773 + tzImagePickerVc.didFinishPickingPhotosHandle(photos,assets,_isSelectOriginalPhoto);
  774 + }
  775 + if (tzImagePickerVc.didFinishPickingPhotosWithInfosHandle) {
  776 + tzImagePickerVc.didFinishPickingPhotosWithInfosHandle(photos,assets,_isSelectOriginalPhoto,infoArr);
  777 + }
  778 +#pragma mark - TODO: 导出
  779 + if (tzImagePickerVc.didNewFinishPickingPhotosHandle) {
  780 + tzImagePickerVc.didNewFinishPickingPhotosHandle(photos, selectedModels, assets, _isSelectOriginalPhoto);
  781 + }
  782 +
  783 +}
  784 +
  785 +#pragma mark - UICollectionViewDataSource && Delegate
  786 +
  787 +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  788 + if (_showTakePhotoBtn) {
  789 + return _models.count + 1;
  790 + }
  791 + return _models.count;
  792 +}
  793 +
  794 +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  795 + // the cell lead to take a picture / 去拍照的cell
  796 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  797 + if (((tzImagePickerVc.sortAscendingByModificationDate && indexPath.item >= _models.count) || (!tzImagePickerVc.sortAscendingByModificationDate && indexPath.item == 0)) && _showTakePhotoBtn) {
  798 + TZAssetCameraCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCameraCell" forIndexPath:indexPath];
  799 + cell.imageView.image = tzImagePickerVc.takePictureImage;
  800 + if ([tzImagePickerVc.takePictureImageName isEqualToString:@"takePicture80"]) {
  801 + cell.imageView.contentMode = UIViewContentModeCenter;
  802 + CGFloat rgb = 223 / 255.0;
  803 + cell.imageView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0];
  804 + } else {
  805 + cell.imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
  806 + }
  807 + return cell;
  808 + }
  809 + // the cell dipaly photo or video / 展示照片或视频的cell
  810 + TZAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCell" forIndexPath:indexPath];
  811 + cell.allowPickingMultipleVideo = tzImagePickerVc.allowPickingMultipleVideo;
  812 + cell.photoDefImage = tzImagePickerVc.photoDefImage;
  813 + cell.photoSelImage = tzImagePickerVc.photoSelImage;
  814 + cell.useCachedImage = self.useCachedImage;
  815 + cell.assetCellDidSetModelBlock = tzImagePickerVc.assetCellDidSetModelBlock;
  816 + cell.assetCellDidLayoutSubviewsBlock = tzImagePickerVc.assetCellDidLayoutSubviewsBlock;
  817 + TZAssetModel *model;
  818 + if (tzImagePickerVc.sortAscendingByModificationDate || !_showTakePhotoBtn) {
  819 + model = _models[indexPath.item];
  820 + } else {
  821 + model = _models[indexPath.item - 1];
  822 + }
  823 + cell.allowPickingGif = tzImagePickerVc.allowPickingGif;
  824 + cell.model = model;
  825 + if (model.isSelected && tzImagePickerVc.showSelectedIndex) {
  826 + NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset];
  827 + cell.index = [tzImagePickerVc.selectedAssetIds indexOfObject:assetId] + 1;
  828 + }
  829 + cell.showSelectBtn = tzImagePickerVc.showSelectBtn;
  830 + cell.allowPreview = tzImagePickerVc.allowPreview;
  831 +
  832 + if (tzImagePickerVc.selectedModels.count >= tzImagePickerVc.maxImagesCount && tzImagePickerVc.showPhotoCannotSelectLayer && !model.isSelected) {
  833 + cell.cannotSelectLayerButton.backgroundColor = tzImagePickerVc.cannotSelectLayerColor;
  834 + cell.cannotSelectLayerButton.hidden = NO;
  835 + } else {
  836 + cell.cannotSelectLayerButton.hidden = YES;
  837 + }
  838 +
  839 + __weak typeof(cell) weakCell = cell;
  840 + __weak typeof(self) weakSelf = self;
  841 + __weak typeof(_numberImageView.layer) weakLayer = _numberImageView.layer;
  842 + cell.didSelectPhotoBlock = ^(BOOL isSelected) { //选择相册图片
  843 + __strong typeof(weakCell) strongCell = weakCell;
  844 + __strong typeof(weakSelf) strongSelf = weakSelf;
  845 + __strong typeof(weakLayer) strongLayer = weakLayer;
  846 +
  847 + if (!strongCell.model.isExport) {///lxg:裂图
  848 + [tzImagePickerVc showAlertWithTitle:@"图有损坏不可选"];
  849 +
  850 + return;
  851 + }
  852 +
  853 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)strongSelf.navigationController;
  854 + // 1. cancel select / 取消选择
  855 + if (isSelected) {
  856 + strongCell.selectPhotoButton.selected = NO;
  857 + model.isSelected = NO;
  858 + NSArray *selectedModels = [NSArray arrayWithArray:tzImagePickerVc.selectedModels];
  859 + for (TZAssetModel *model_item in selectedModels) {
  860 + if ([[[TZImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[TZImageManager manager] getAssetIdentifier:model_item.asset]]) {
  861 + [tzImagePickerVc removeSelectedModel:model_item];
  862 + break;
  863 + }
  864 + }
  865 + [strongSelf refreshBottomToolBarStatus];
  866 + if (tzImagePickerVc.showSelectedIndex || tzImagePickerVc.showPhotoCannotSelectLayer) {
  867 + [strongSelf setUseCachedImageAndReloadData];
  868 + }
  869 + [UIView showOscillatoryAnimationWithLayer:strongLayer type:TZOscillatoryAnimationToSmaller];
  870 + } else {
  871 +#pragma mark - 处理iCloud视频
  872 + if (weakCell.model.type == TZAssetModelMediaTypeVideo) {
  873 +
  874 + if (weakCell.model.isCheckICloudType) {//检查完成
  875 + if (weakCell.model.isICloudType) {//源是iCloud
  876 + if (!weakCell.model.isVideoICloudDownLoad ) {//未下载完成
  877 +
  878 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  879 + options.version = PHVideoRequestOptionsVersionOriginal;
  880 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  881 + options.networkAccessAllowed = YES;
  882 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  883 +
  884 + if (progress >= 1) {
  885 +
  886 +
  887 + } else {
  888 +
  889 +
  890 + }
  891 + NSLog(@"输出进度 = %f",progress);
  892 + };
  893 + /** requestPlayerItemForVideo */
  894 + [[PHImageManager defaultManager] requestAVAssetForVideo:model.asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
  895 + NSLog(@"Info:%@",info);
  896 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  897 + if (downloadFinined && avasset) {//成功
  898 + weakCell.model.isVideoICloudDownLoad = YES;
  899 +
  900 +
  901 + }else {
  902 + weakCell.model.isVideoICloudDownLoad = NO;
  903 +
  904 + }
  905 +
  906 +
  907 + }];
  908 +
  909 + [tzImagePickerVc showAlertWithTitle:@"请进入视频详情加载iCloud视频"];
  910 + return;
  911 +
  912 + }else {//已下载
  913 +
  914 + }
  915 + }else {//源不是iCloud
  916 +
  917 + }
  918 +
  919 +
  920 + }else {
  921 + [tzImagePickerVc showAlertWithTitle:@"请进入视频详情查看iCloud视频"];
  922 + return;
  923 + }
  924 +
  925 + }
  926 +
  927 + // 2. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制
  928 + if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) {
  929 + ///lxg禁止选中限制时长视频
  930 + NSTimeInterval duration = 0.0;
  931 + if ([model.asset isKindOfClass:[PHAsset class]]) {
  932 + PHAsset *asset = model.asset;
  933 + duration = asset.duration;
  934 + }else if ([model.asset isKindOfClass:[ALAsset class]]){
  935 + duration = [[model.asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  936 + }
  937 + if (model.type == TZAssetModelMediaTypeVideo
  938 + && tzImagePickerVc.allowPickingMultipleVideo
  939 + && duration > tzImagePickerVc.maxVideoDuration) {//视频,支持混选,时长超过最大时长限制
  940 + NSInteger minutes = tzImagePickerVc.maxVideoDuration / 60;
  941 + NSInteger seconds = tzImagePickerVc.maxVideoDuration % 60;
  942 + NSString *timeStr = [NSString string];
  943 + if (minutes == 0) {
  944 + timeStr = [NSString stringWithFormat:@"不能选择超过%li秒视频",(long)seconds];
  945 + }else if (seconds == 0){
  946 + timeStr = [NSString stringWithFormat:@"不能选择超过%li分视频",(long)minutes];
  947 + }else{
  948 + timeStr = [NSString stringWithFormat:@"不能选择超过%li分%li秒视频",(long)minutes,(long)seconds];
  949 + }
  950 + [tzImagePickerVc showAlertWithTitle:timeStr];
  951 +
  952 + return;
  953 + }
  954 +
  955 +
  956 + if (tzImagePickerVc.maxImagesCount == 1 && !tzImagePickerVc.allowPreview) {
  957 + model.isSelected = YES;
  958 + [tzImagePickerVc addSelectedModel:model];
  959 + [strongSelf doneButtonClick];
  960 + return;
  961 + }
  962 + strongCell.selectPhotoButton.selected = YES;
  963 + model.isSelected = YES;
  964 + if (tzImagePickerVc.showSelectedIndex || tzImagePickerVc.showPhotoCannotSelectLayer) {
  965 + model.needOscillatoryAnimation = YES;
  966 + [strongSelf setUseCachedImageAndReloadData];
  967 + }
  968 + [tzImagePickerVc addSelectedModel:model];
  969 + [strongSelf refreshBottomToolBarStatus];
  970 + [UIView showOscillatoryAnimationWithLayer:strongLayer type:TZOscillatoryAnimationToSmaller];
  971 + } else {
  972 + NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], tzImagePickerVc.maxImagesCount];
  973 + [tzImagePickerVc showAlertWithTitle:title];
  974 + }
  975 + }
  976 + };
  977 + return cell;
  978 +}
  979 +
  980 +- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  981 +
  982 + // take a photo / 去拍照
  983 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  984 +
  985 + if (((tzImagePickerVc.sortAscendingByModificationDate && indexPath.item >= _models.count) || (!tzImagePickerVc.sortAscendingByModificationDate && indexPath.item == 0)) && _showTakePhotoBtn) {
  986 + [self takePhoto]; return;
  987 + }
  988 +
  989 + //lxg:损坏
  990 + TZAssetModel *assetModel = _models[indexPath.row];
  991 + if (assetModel) {
  992 + if (!assetModel.isExport) {///lxg:裂图
  993 + [tzImagePickerVc showAlertWithTitle:@"图有损坏不可选"];
  994 +
  995 + return;
  996 + }
  997 + }
  998 +
  999 + // preview phote or video / 预览照片或视频
  1000 + NSInteger index = indexPath.item;
  1001 + if (!tzImagePickerVc.sortAscendingByModificationDate && _showTakePhotoBtn) {
  1002 + index = indexPath.item - 1;
  1003 + }
  1004 +// TZAssetModel *model = _models[index];
  1005 +
  1006 +#pragma mark - 聊天里面进入和朋友圈中进入LXG
  1007 +
  1008 + TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
  1009 + photoPreviewVc.enterType = PhotoPreviewEnterTypeNormal;
  1010 + photoPreviewVc.currentIndex = index;
  1011 + photoPreviewVc.models = _models;
  1012 + photoPreviewVc.isSelectOriginalPhoto = tzImagePickerVc.isSelectOriginalPhoto;
  1013 + [self pushPhotoPrevireViewController:photoPreviewVc];
  1014 +
  1015 +
  1016 +// ///LXG进行 注释
  1017 +// if (model.type == TZAssetModelMediaTypeVideo && !tzImagePickerVc.allowPickingMultipleVideo) {///支持混选+点击视频
  1018 +// if (tzImagePickerVc.selectedModels.count > 0) {
  1019 +// TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  1020 +// [imagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Can not choose both video and photo"]];
  1021 +// } else {
  1022 +// TZVideoPlayerController *videoPlayerVc = [[TZVideoPlayerController alloc] init];
  1023 +// videoPlayerVc.model = model;
  1024 +// videoPlayerVc.isOther = NO;//相册内部进入(LXG)
  1025 +// [self.navigationController pushViewController:videoPlayerVc animated:YES];
  1026 +// }
  1027 +// } else if (model.type == TZAssetModelMediaTypePhotoGif && tzImagePickerVc.allowPickingGif && !tzImagePickerVc.allowPickingMultipleVideo) {//支持混选+GIF
  1028 +// if (tzImagePickerVc.selectedModels.count > 0) {
  1029 +// TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  1030 +// [imagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Can not choose both photo and GIF"]];
  1031 +// } else {
  1032 +// TZGifPhotoPreviewController *gifPreviewVc = [[TZGifPhotoPreviewController alloc] init];
  1033 +// gifPreviewVc.model = model;
  1034 +// [self.navigationController pushViewController:gifPreviewVc animated:YES];
  1035 +// }
  1036 +// } else {
  1037 +//#pragma mark - 当可以混选
  1038 +// TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
  1039 +// photoPreviewVc.currentIndex = index;
  1040 +// photoPreviewVc.models = _models;
  1041 +// [self pushPhotoPrevireViewController:photoPreviewVc];
  1042 +// }
  1043 +}
  1044 +
  1045 +#pragma mark - UIScrollViewDelegate
  1046 +
  1047 +- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  1048 + if (iOS8Later) {
  1049 + // [self updateCachedAssets];
  1050 + }
  1051 +}
  1052 +
  1053 +#pragma mark - Private Method
  1054 +
  1055 +- (void)setUseCachedImageAndReloadData {
  1056 + self.useCachedImage = YES;
  1057 + [self.collectionView reloadData];
  1058 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1059 + self.useCachedImage = NO;
  1060 + });
  1061 +}
  1062 +
  1063 +/// 拍照按钮点击事件
  1064 +- (void)takePhoto {
  1065 + AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  1066 + if ((authStatus == AVAuthorizationStatusRestricted || authStatus ==AVAuthorizationStatusDenied) && iOS7Later) {
  1067 +
  1068 + NSDictionary *infoDict = [TZCommonTools tz_getInfoDictionary];
  1069 + // 无权限 做一个友好的提示
  1070 + NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"];
  1071 + if (!appName) appName = [infoDict valueForKey:@"CFBundleName"];
  1072 +
  1073 + NSString *message = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\""],appName];
  1074 + if (iOS8Later) {
  1075 + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Can not use camera"] message:message delegate:self cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"Cancel"] otherButtonTitles:[NSBundle tz_localizedStringForKey:@"Setting"], nil];
  1076 + [alert show];
  1077 + } else {
  1078 + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Can not use camera"] message:message delegate:self cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles:nil];
  1079 + [alert show];
  1080 + }
  1081 + } else if (authStatus == AVAuthorizationStatusNotDetermined) {
  1082 + // fix issue 466, 防止用户首次拍照拒绝授权时相机页黑屏
  1083 + if (iOS7Later) {
  1084 + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
  1085 + if (granted) {
  1086 + dispatch_async(dispatch_get_main_queue(), ^{
  1087 + [self pushImagePickerController];
  1088 + });
  1089 + }
  1090 + }];
  1091 + } else {
  1092 + [self pushImagePickerController];
  1093 + }
  1094 + } else {
  1095 + [self pushImagePickerController];
  1096 + }
  1097 +}
  1098 +
  1099 +// 调用相机
  1100 +- (void)pushImagePickerController {
  1101 + // 提前定位
  1102 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  1103 + if (tzImagePickerVc.allowCameraLocation) {
  1104 + __weak typeof(self) weakSelf = self;
  1105 + [[TZLocationManager manager] startLocationWithSuccessBlock:^(NSArray<CLLocation *> *locations) {
  1106 + __strong typeof(weakSelf) strongSelf = weakSelf;
  1107 + strongSelf.location = [locations firstObject];
  1108 + } failureBlock:^(NSError *error) {
  1109 + __strong typeof(weakSelf) strongSelf = weakSelf;
  1110 + strongSelf.location = nil;
  1111 + }];
  1112 + }
  1113 +
  1114 + UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
  1115 + if ([UIImagePickerController isSourceTypeAvailable: sourceType]) {
  1116 + self.imagePickerVc.sourceType = sourceType;
  1117 + NSMutableArray *mediaTypes = [NSMutableArray array];
  1118 + if (tzImagePickerVc.allowTakePicture) {
  1119 + [mediaTypes addObject:(NSString *)kUTTypeImage];
  1120 + }
  1121 + if (tzImagePickerVc.allowTakeVideo) {
  1122 + [mediaTypes addObject:(NSString *)kUTTypeMovie];
  1123 + self.imagePickerVc.videoMaximumDuration = tzImagePickerVc.videoMaximumDuration;
  1124 + }
  1125 + self.imagePickerVc.mediaTypes= mediaTypes;
  1126 + if (iOS8Later) {
  1127 + _imagePickerVc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
  1128 + }
  1129 + if (tzImagePickerVc.uiImagePickerControllerSettingBlock) {
  1130 + tzImagePickerVc.uiImagePickerControllerSettingBlock(_imagePickerVc);
  1131 + }
  1132 + [self presentViewController:_imagePickerVc animated:YES completion:nil];
  1133 + } else {
  1134 + NSLog(@"模拟器中无法打开照相机,请在真机中使用");
  1135 + }
  1136 +}
  1137 +
  1138 +- (void)refreshBottomToolBarStatus {
  1139 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  1140 +
  1141 + _previewButton.enabled = tzImagePickerVc.selectedModels.count > 0;
  1142 + _doneButton.enabled = tzImagePickerVc.selectedModels.count > 0 || tzImagePickerVc.alwaysEnableDoneBtn;
  1143 +
  1144 + _numberImageView.hidden = tzImagePickerVc.selectedModels.count <= 0;
  1145 + _numberLabel.hidden = tzImagePickerVc.selectedModels.count <= 0;
  1146 + _numberLabel.text = [NSString stringWithFormat:@"%zd",tzImagePickerVc.selectedModels.count];
  1147 +#pragma mark - 添加: 选择图片个数显示(LXG)
  1148 + _numberImageView.hidden = YES;
  1149 + _numberLabel.hidden = YES;
  1150 + [_doneButton setTitle:[NSString stringWithFormat:@"完成(%zd)",tzImagePickerVc.selectedModels.count] forState:UIControlStateNormal];
  1151 +
  1152 + _originalPhotoButton.enabled = tzImagePickerVc.selectedModels.count > 0;
  1153 + _originalPhotoButton.selected = (_isSelectOriginalPhoto && _originalPhotoButton.enabled);
  1154 + _originalPhotoLabel.hidden = YES;///lxg添加
  1155 +// _originalPhotoLabel.hidden = (!_originalPhotoButton.isSelected);///lxg注释
  1156 + if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes];
  1157 +}
  1158 +
  1159 +- (void)pushPhotoPrevireViewController:(TZPhotoPreviewController *)photoPreviewVc {
  1160 + [self pushPhotoPrevireViewController:photoPreviewVc needCheckSelectedModels:NO];
  1161 +}
  1162 +
  1163 +- (void)pushPhotoPrevireViewController:(TZPhotoPreviewController *)photoPreviewVc needCheckSelectedModels:(BOOL)needCheckSelectedModels {
  1164 + __weak typeof(self) weakSelf = self;
  1165 + photoPreviewVc.isSelectOriginalPhoto = _isSelectOriginalPhoto;
  1166 + [photoPreviewVc setBackButtonClickBlock:^(BOOL isSelectOriginalPhoto) {
  1167 + __strong typeof(weakSelf) strongSelf = weakSelf;
  1168 + strongSelf.isSelectOriginalPhoto = isSelectOriginalPhoto;
  1169 + if (needCheckSelectedModels) {
  1170 + [strongSelf checkSelectedModels];
  1171 + }
  1172 + [strongSelf.collectionView reloadData];
  1173 + [strongSelf refreshBottomToolBarStatus];
  1174 + }];
  1175 + [photoPreviewVc setDoneButtonClickBlock:^(BOOL isSelectOriginalPhoto) {
  1176 + __strong typeof(weakSelf) strongSelf = weakSelf;
  1177 + strongSelf.isSelectOriginalPhoto = isSelectOriginalPhoto;
  1178 + [strongSelf doneButtonClick];
  1179 +
  1180 + }];
  1181 + [photoPreviewVc setDoneButtonClickBlockCropMode:^(UIImage *cropedImage, id asset) {
  1182 + __strong typeof(weakSelf) strongSelf = weakSelf;
  1183 +
  1184 + [strongSelf didGetAllPhotos:@[cropedImage] assets:@[asset] selectedModels:@[] infoArr:nil];
  1185 + }];
  1186 + [self.navigationController pushViewController:photoPreviewVc animated:YES];
  1187 +}
  1188 +
  1189 +- (void)getSelectedPhotoBytes {
  1190 + // 越南语 && 5屏幕时会显示不下,暂时这样处理
  1191 + if ([[TZImagePickerConfig sharedInstance].preferredLanguage isEqualToString:@"vi"] && self.view.tz_width <= 320) {
  1192 + return;
  1193 + }
  1194 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  1195 + [[TZImageManager manager] getPhotosBytesWithArray:imagePickerVc.selectedModels completion:^(NSString *totalBytes) {
  1196 + self->_originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes];
  1197 + self->_originalPhotoLabel.hidden = YES;///lxg添加
  1198 + }];
  1199 +}
  1200 +
  1201 +- (void)scrollCollectionViewToBottom {
  1202 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  1203 + if (_shouldScrollToBottom && _models.count > 0) {
  1204 + NSInteger item = 0;
  1205 + if (tzImagePickerVc.sortAscendingByModificationDate) {
  1206 + item = _models.count - 1;
  1207 + if (_showTakePhotoBtn) {
  1208 + item += 1;
  1209 + }
  1210 + }
  1211 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  1212 + [self->_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO];
  1213 + self->_shouldScrollToBottom = NO;
  1214 + self->_collectionView.hidden = NO;
  1215 + });
  1216 + } else {
  1217 + _collectionView.hidden = NO;
  1218 + }
  1219 +}
  1220 +
  1221 +#pragma mark - TODO: 选中中删除
  1222 +- (void)checkSelectedModels {
  1223 + NSMutableArray *selectedAssets = [NSMutableArray array];
  1224 +
  1225 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  1226 +
  1227 + [tzImagePickerVc.selectedModels enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(TZAssetModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  1228 +
  1229 + /*** 筛选损坏视频 ***/
  1230 + if (obj.type == TZAssetModelMediaTypeVideo) {
  1231 + NSURL *url = [obj.asset movieURL];
  1232 + if (!url) {
  1233 + [tzImagePickerVc removeSelectedModel:obj];
  1234 + NSString *imgShowStr = [NSString stringWithFormat:@"选择中第%ld已损坏,已删除",(idx + 1)];
  1235 + [tzImagePickerVc showAlertWithTitle:imgShowStr];
  1236 +
  1237 + }
  1238 + }
  1239 + /*** 筛选损坏图片 ***/
  1240 + if (obj.type == TZAssetModelMediaTypePhotoGif
  1241 + || obj.type == TZAssetModelMediaTypePhoto) {
  1242 +
  1243 + UIImage *photo = [obj.asset getPhoto];
  1244 + if (!photo) {
  1245 + [tzImagePickerVc removeSelectedModel:obj];
  1246 + NSString *imgShowStr = [NSString stringWithFormat:@"选择中第%ld已损坏,已删除",(idx + 1)];
  1247 + [tzImagePickerVc showAlertWithTitle:imgShowStr];
  1248 + }
  1249 +
  1250 + }
  1251 +
  1252 + }];
  1253 +
  1254 + for (TZAssetModel *model in tzImagePickerVc.selectedModels) {
  1255 + [selectedAssets addObject:model.asset];
  1256 + }
  1257 + for (TZAssetModel *model in _models) {
  1258 + model.isSelected = NO;
  1259 + if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) {
  1260 + model.isSelected = YES;
  1261 + }
  1262 + }
  1263 +
  1264 +}
  1265 +
  1266 +#pragma mark - UIAlertViewDelegate
  1267 +
  1268 +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
  1269 + if (buttonIndex == 1) { // 去设置界面,开启相机访问权限
  1270 + if (iOS8Later) {
  1271 + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
  1272 + }
  1273 + }
  1274 +}
  1275 +
  1276 +#pragma mark - UIImagePickerControllerDelegate
  1277 +
  1278 +- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
  1279 + [picker dismissViewControllerAnimated:YES completion:nil];
  1280 + NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
  1281 + if ([type isEqualToString:@"public.image"]) {
  1282 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  1283 + [imagePickerVc showProgressHUD];
  1284 + UIImage *photo = [info objectForKey:UIImagePickerControllerOriginalImage];
  1285 + if (photo) {
  1286 + [[TZImageManager manager] savePhotoWithImage:photo location:self.location completion:^(NSError *error){
  1287 + if (!error) {
  1288 + [self reloadPhotoArrayWithMediaType:type];
  1289 + }
  1290 + }];
  1291 + self.location = nil;
  1292 + }
  1293 + } else if ([type isEqualToString:@"public.movie"]) {
  1294 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  1295 + [imagePickerVc showProgressHUD];
  1296 + NSURL *videoUrl = [info objectForKey:UIImagePickerControllerMediaURL];
  1297 + if (videoUrl) {
  1298 + [[TZImageManager manager] saveVideoWithUrl:videoUrl location:self.location completion:^(NSError *error) {
  1299 + if (!error) {
  1300 + [self reloadPhotoArrayWithMediaType:type];
  1301 + }
  1302 + }];
  1303 + self.location = nil;
  1304 + }
  1305 + }
  1306 +}
  1307 +
  1308 +- (void)reloadPhotoArrayWithMediaType:(NSString *)mediaType {
  1309 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  1310 + [[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage needFetchAssets:NO completion:^(TZAlbumModel *model) {
  1311 + self->_model = model;
  1312 + [[TZImageManager manager] getAssetsFromFetchResult:self->_model.result completion:^(NSArray<TZAssetModel *> *models) {
  1313 + [tzImagePickerVc hideProgressHUD];
  1314 +
  1315 + TZAssetModel *assetModel;
  1316 + if (tzImagePickerVc.sortAscendingByModificationDate) {
  1317 + assetModel = [models lastObject];
  1318 + [self->_models addObject:assetModel];
  1319 + } else {
  1320 + assetModel = [models firstObject];
  1321 + [self->_models insertObject:assetModel atIndex:0];
  1322 + }
  1323 +
  1324 + if (tzImagePickerVc.maxImagesCount <= 1) {
  1325 + if (tzImagePickerVc.allowCrop) {
  1326 + TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init];
  1327 + if (tzImagePickerVc.sortAscendingByModificationDate) {
  1328 + photoPreviewVc.currentIndex = self->_models.count - 1;
  1329 + } else {
  1330 + photoPreviewVc.currentIndex = 0;
  1331 + }
  1332 + photoPreviewVc.models = self->_models;
  1333 + [self pushPhotoPrevireViewController:photoPreviewVc];
  1334 + } else {
  1335 + [tzImagePickerVc addSelectedModel:assetModel];
  1336 + [self doneButtonClick];
  1337 + }
  1338 + return;
  1339 + }
  1340 +
  1341 + if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) {
  1342 + if ([mediaType isEqualToString:@"public.movie"] && !tzImagePickerVc.allowPickingMultipleVideo) {
  1343 + // 不能多选视频的情况下,不选中拍摄的视频
  1344 + } else {
  1345 + assetModel.isSelected = YES;
  1346 + [tzImagePickerVc addSelectedModel:assetModel];
  1347 + [self refreshBottomToolBarStatus];
  1348 + }
  1349 + }
  1350 + self->_collectionView.hidden = YES;
  1351 + [self->_collectionView reloadData];
  1352 +
  1353 + self->_shouldScrollToBottom = YES;
  1354 + [self scrollCollectionViewToBottom];
  1355 + }];
  1356 + }];
  1357 +}
  1358 +
  1359 +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
  1360 + [picker dismissViewControllerAnimated:YES completion:nil];
  1361 +}
  1362 +
  1363 +- (void)dealloc {
  1364 + // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
  1365 + NSLog(@"相册_相册_TZPhotoPickerController_dealloc");
  1366 +}
  1367 +
  1368 +#pragma mark - Asset Caching
  1369 +
  1370 +- (void)resetCachedAssets {
  1371 + [[TZImageManager manager].cachingImageManager stopCachingImagesForAllAssets];
  1372 + self.previousPreheatRect = CGRectZero;
  1373 +}
  1374 +
  1375 +- (void)updateCachedAssets {
  1376 + BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil;
  1377 + if (!isViewVisible) { return; }
  1378 +
  1379 + // The preheat window is twice the height of the visible rect.
  1380 + CGRect preheatRect = _collectionView.bounds;
  1381 + preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect));
  1382 +
  1383 + /*
  1384 + Check if the collection view is showing an area that is significantly
  1385 + different to the last preheated area.
  1386 + */
  1387 + CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect));
  1388 + if (delta > CGRectGetHeight(_collectionView.bounds) / 3.0f) {
  1389 +
  1390 + // Compute the assets to start caching and to stop caching.
  1391 + NSMutableArray *addedIndexPaths = [NSMutableArray array];
  1392 + NSMutableArray *removedIndexPaths = [NSMutableArray array];
  1393 +
  1394 + [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) {
  1395 + NSArray *indexPaths = [self aapl_indexPathsForElementsInRect:removedRect];
  1396 + [removedIndexPaths addObjectsFromArray:indexPaths];
  1397 + } addedHandler:^(CGRect addedRect) {
  1398 + NSArray *indexPaths = [self aapl_indexPathsForElementsInRect:addedRect];
  1399 + [addedIndexPaths addObjectsFromArray:indexPaths];
  1400 + }];
  1401 +
  1402 + NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths];
  1403 + NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths];
  1404 +
  1405 + // Update the assets the PHCachingImageManager is caching.
  1406 + [[TZImageManager manager].cachingImageManager startCachingImagesForAssets:assetsToStartCaching
  1407 + targetSize:AssetGridThumbnailSize
  1408 + contentMode:PHImageContentModeAspectFill
  1409 + options:nil];
  1410 + [[TZImageManager manager].cachingImageManager stopCachingImagesForAssets:assetsToStopCaching
  1411 + targetSize:AssetGridThumbnailSize
  1412 + contentMode:PHImageContentModeAspectFill
  1413 + options:nil];
  1414 +
  1415 + // Store the preheat rect to compare against in the future.
  1416 + self.previousPreheatRect = preheatRect;
  1417 + }
  1418 +}
  1419 +
  1420 +- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler {
  1421 + if (CGRectIntersectsRect(newRect, oldRect)) {
  1422 + CGFloat oldMaxY = CGRectGetMaxY(oldRect);
  1423 + CGFloat oldMinY = CGRectGetMinY(oldRect);
  1424 + CGFloat newMaxY = CGRectGetMaxY(newRect);
  1425 + CGFloat newMinY = CGRectGetMinY(newRect);
  1426 +
  1427 + if (newMaxY > oldMaxY) {
  1428 + CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY));
  1429 + addedHandler(rectToAdd);
  1430 + }
  1431 +
  1432 + if (oldMinY > newMinY) {
  1433 + CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY));
  1434 + addedHandler(rectToAdd);
  1435 + }
  1436 +
  1437 + if (newMaxY < oldMaxY) {
  1438 + CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY));
  1439 + removedHandler(rectToRemove);
  1440 + }
  1441 +
  1442 + if (oldMinY < newMinY) {
  1443 + CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY));
  1444 + removedHandler(rectToRemove);
  1445 + }
  1446 + } else {
  1447 + addedHandler(newRect);
  1448 + removedHandler(oldRect);
  1449 + }
  1450 +}
  1451 +
  1452 +- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths {
  1453 + if (indexPaths.count == 0) { return nil; }
  1454 +
  1455 + NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count];
  1456 + for (NSIndexPath *indexPath in indexPaths) {
  1457 + if (indexPath.item < _models.count) {
  1458 + TZAssetModel *model = _models[indexPath.item];
  1459 + [assets addObject:model.asset];
  1460 + }
  1461 + }
  1462 +
  1463 + return assets;
  1464 +}
  1465 +
  1466 +- (NSArray *)aapl_indexPathsForElementsInRect:(CGRect)rect {
  1467 + NSArray *allLayoutAttributes = [_collectionView.collectionViewLayout layoutAttributesForElementsInRect:rect];
  1468 + if (allLayoutAttributes.count == 0) { return nil; }
  1469 + NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count];
  1470 + for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) {
  1471 + NSIndexPath *indexPath = layoutAttributes.indexPath;
  1472 + [indexPaths addObject:indexPath];
  1473 + }
  1474 + return indexPaths;
  1475 +}
  1476 +#pragma clang diagnostic pop
  1477 +
  1478 +@end
  1479 +
  1480 +
  1481 +
  1482 +@implementation TZCollectionView
  1483 +
  1484 +- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
  1485 + if ([view isKindOfClass:[UIControl class]]) {
  1486 + return YES;
  1487 + }
  1488 + return [super touchesShouldCancelInContentView:view];
  1489 +}
  1490 +
  1491 +@end
... ...
CNLiveImagePickerController/Classes/TZPhotoPreviewCell.h 0 → 100755
  1 +//
  2 +// TZPhotoPreviewCell.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZAssetPreviewCell : UICollectionViewCell
  13 +@property (nonatomic, strong) TZAssetModel *model;
  14 +@property (nonatomic, copy) void (^singleTapGestureBlock)(void);
  15 +- (void)configSubviews;
  16 +- (void)photoPreviewCollectionViewDidScroll;
  17 +@end
  18 +
  19 +
  20 +@class TZAssetModel,TZProgressView,TZPhotoPreviewView;
  21 +@interface TZPhotoPreviewCell : TZAssetPreviewCell
  22 +
  23 +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
  24 +
  25 +@property (nonatomic, strong) TZPhotoPreviewView *previewView;
  26 +
  27 +@property (nonatomic, assign) BOOL allowCrop;
  28 +@property (nonatomic, assign) CGRect cropRect;
  29 +
  30 +- (void)recoverSubviews;
  31 +
  32 +@end
  33 +
  34 +
  35 +@interface TZPhotoPreviewView : UIView
  36 +@property (nonatomic, strong) UIImageView *imageView;
  37 +@property (nonatomic, strong) UIScrollView *scrollView;
  38 +@property (nonatomic, strong) UIView *imageContainerView;
  39 +@property (nonatomic, strong) TZProgressView *progressView;
  40 +
  41 +@property (nonatomic, assign) BOOL allowCrop;
  42 +@property (nonatomic, assign) CGRect cropRect;
  43 +
  44 +@property (nonatomic, strong) TZAssetModel *model;
  45 +@property (nonatomic, strong) id asset;
  46 +@property (nonatomic, copy) void (^singleTapGestureBlock)(void);
  47 +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
  48 +
  49 +@property (nonatomic, assign) int32_t imageRequestID;
  50 +
  51 +- (void)recoverSubviews;
  52 +@end
  53 +
  54 +
  55 +@class AVPlayer, AVPlayerLayer;
  56 +@interface TZVideoPreviewCell : TZAssetPreviewCell
  57 +@property (strong, nonatomic) AVPlayer *player;
  58 +@property (strong, nonatomic) AVPlayerLayer *playerLayer;
  59 +@property (strong, nonatomic) UIButton *playButton;
  60 +@property (strong, nonatomic) UIImage *cover;
  61 +
  62 +@property (nonatomic, strong) TZProgressView *progressView;
  63 +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(TZVideoPreviewCell *cell);
  64 +
  65 +- (void)pausePlayerAndShowNaviBar;
  66 +@end
  67 +
  68 +
  69 +@interface TZGifPreviewCell : TZAssetPreviewCell
  70 +@property (strong, nonatomic) TZPhotoPreviewView *previewView;
  71 +@end
... ...
CNLiveImagePickerController/Classes/TZPhotoPreviewCell.m 0 → 100755
  1 +//
  2 +// TZPhotoPreviewCell.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZPhotoPreviewCell.h"
  10 +#import "TZAssetModel.h"
  11 +#import "UIView+TZLayout.h"
  12 +#import "TZImageManager.h"
  13 +#import "TZProgressView.h"
  14 +#import "TZImageCropManager.h"
  15 +#import <MediaPlayer/MediaPlayer.h>
  16 +#import "TZImagePickerController.h"
  17 +#import "CNAudioOrVideoMananger.h"
  18 +
  19 +@implementation TZAssetPreviewCell
  20 +
  21 +- (instancetype)initWithFrame:(CGRect)frame {
  22 + self = [super initWithFrame:frame];
  23 + if (self) {
  24 + self.backgroundColor = [UIColor blackColor];
  25 + [self configSubviews];
  26 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(photoPreviewCollectionViewDidScroll) name:@"photoPreviewCollectionViewDidScroll" object:nil];
  27 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didViewLoadVC) name:@"didViewLoadController" object:nil];
  28 + }
  29 + return self;
  30 +}
  31 +
  32 +- (void)configSubviews {
  33 +
  34 +}
  35 +
  36 +#pragma mark - Notification
  37 +
  38 +- (void)photoPreviewCollectionViewDidScroll {
  39 +
  40 +}
  41 +
  42 +- (void)didViewLoadVC {
  43 +
  44 +}
  45 +
  46 +
  47 +- (void)dealloc {
  48 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  49 +}
  50 +
  51 +@end
  52 +
  53 +
  54 +@implementation TZPhotoPreviewCell
  55 +
  56 +- (void)configSubviews {
  57 + self.previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
  58 + __weak typeof(self) weakSelf = self;
  59 + [self.previewView setSingleTapGestureBlock:^{
  60 + __strong typeof(weakSelf) strongSelf = weakSelf;
  61 + if (strongSelf.singleTapGestureBlock) {
  62 + strongSelf.singleTapGestureBlock();
  63 + }
  64 + }];
  65 + [self.previewView setImageProgressUpdateBlock:^(double progress) {
  66 + __strong typeof(weakSelf) strongSelf = weakSelf;
  67 + if (strongSelf.imageProgressUpdateBlock) {
  68 + strongSelf.imageProgressUpdateBlock(progress);
  69 + }
  70 + }];
  71 + [self addSubview:self.previewView];
  72 +}
  73 +
  74 +- (void)setModel:(TZAssetModel *)model {
  75 + [super setModel:model];
  76 + _previewView.asset = model.asset;
  77 +}
  78 +
  79 +- (void)recoverSubviews {
  80 + [_previewView recoverSubviews];
  81 +}
  82 +
  83 +- (void)setAllowCrop:(BOOL)allowCrop {
  84 + _allowCrop = allowCrop;
  85 + _previewView.allowCrop = allowCrop;
  86 +}
  87 +
  88 +- (void)setCropRect:(CGRect)cropRect {
  89 + _cropRect = cropRect;
  90 + _previewView.cropRect = cropRect;
  91 +}
  92 +
  93 +- (void)layoutSubviews {
  94 + [super layoutSubviews];
  95 + self.previewView.frame = self.bounds;
  96 +}
  97 +
  98 +@end
  99 +
  100 +
  101 +@interface TZPhotoPreviewView ()<UIScrollViewDelegate>
  102 +@property (assign, nonatomic) BOOL isRequestingGIF;
  103 +@end
  104 +
  105 +@implementation TZPhotoPreviewView
  106 +
  107 +- (instancetype)initWithFrame:(CGRect)frame {
  108 + self = [super initWithFrame:frame];
  109 + if (self) {
  110 + _scrollView = [[UIScrollView alloc] init];
  111 + _scrollView.bouncesZoom = YES;
  112 + _scrollView.maximumZoomScale = 2.5;
  113 + _scrollView.minimumZoomScale = 1.0;
  114 + _scrollView.multipleTouchEnabled = YES;
  115 + _scrollView.delegate = self;
  116 + _scrollView.scrollsToTop = NO;
  117 + _scrollView.showsHorizontalScrollIndicator = NO;
  118 + _scrollView.showsVerticalScrollIndicator = YES;
  119 + _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
  120 + _scrollView.delaysContentTouches = NO;
  121 + _scrollView.canCancelContentTouches = YES;
  122 + _scrollView.alwaysBounceVertical = NO;
  123 + if (@available(iOS 11, *)) {
  124 + _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
  125 + }
  126 + [self addSubview:_scrollView];
  127 +
  128 + _imageContainerView = [[UIView alloc] init];
  129 + _imageContainerView.clipsToBounds = YES;
  130 + _imageContainerView.contentMode = UIViewContentModeScaleAspectFill;
  131 + [_scrollView addSubview:_imageContainerView];
  132 +
  133 + _imageView = [[UIImageView alloc] init];
  134 + _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500];
  135 + _imageView.contentMode = UIViewContentModeScaleAspectFill;
  136 + _imageView.clipsToBounds = YES;
  137 + [_imageContainerView addSubview:_imageView];
  138 +
  139 + UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
  140 + [self addGestureRecognizer:tap1];
  141 + UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
  142 + tap2.numberOfTapsRequired = 2;
  143 + [tap1 requireGestureRecognizerToFail:tap2];
  144 + [self addGestureRecognizer:tap2];
  145 +
  146 + [self configProgressView];
  147 + }
  148 + return self;
  149 +}
  150 +
  151 +- (void)configProgressView {
  152 + _progressView = [[TZProgressView alloc] init];
  153 + _progressView.hidden = YES;
  154 + [self addSubview:_progressView];
  155 +}
  156 +
  157 +- (void)setModel:(TZAssetModel *)model {
  158 + _model = model;
  159 + self.isRequestingGIF = NO;
  160 + [_scrollView setZoomScale:1.0 animated:NO];
  161 + if (model.type == TZAssetModelMediaTypePhotoGif) {
  162 + // 先显示缩略图
  163 + [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  164 + self.imageView.image = photo;
  165 + [self resizeSubviews];
  166 + if (self.isRequestingGIF) {
  167 + return;
  168 + }
  169 + // 再显示gif动图
  170 + self.isRequestingGIF = YES;
  171 + [[TZImageManager manager] getOriginalPhotoDataWithAsset:model.asset progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  172 + progress = progress > 0.02 ? progress : 0.02;
  173 + dispatch_async(dispatch_get_main_queue(), ^{
  174 + self.progressView.progress = progress;
  175 + if (progress >= 1) {
  176 + self.progressView.hidden = YES;
  177 + } else {
  178 + self.progressView.hidden = NO;
  179 + }
  180 + });
  181 +#ifdef DEBUG
  182 + NSLog(@"[TZImagePickerController] getOriginalPhotoDataWithAsset:%f error:%@", progress, error);
  183 +#endif
  184 + } completion:^(NSData *data, NSDictionary *info, BOOL isDegraded) {
  185 + if (!isDegraded) {
  186 + self.isRequestingGIF = NO;
  187 + self.progressView.hidden = YES;
  188 + self.imageView.image = [UIImage sd_tz_animatedGIFWithData:data];
  189 + [self resizeSubviews];
  190 + }
  191 + }];
  192 + } progressHandler:nil networkAccessAllowed:NO];
  193 + } else {
  194 + self.asset = model.asset;
  195 + }
  196 +}
  197 +
  198 +- (void)setAsset:(id)asset {
  199 + if (_asset && self.imageRequestID) {
  200 + [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID];
  201 + }
  202 +
  203 + _asset = asset;
  204 + self.imageRequestID = [[TZImageManager manager] getPhotoWithAsset:asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  205 + if (![asset isEqual:self->_asset]) return;
  206 + self.imageView.image = photo;
  207 + [self resizeSubviews];
  208 + self->_progressView.hidden = YES;
  209 + if (self.imageProgressUpdateBlock) {
  210 + self.imageProgressUpdateBlock(1);
  211 + }
  212 + if (!isDegraded) {
  213 + self.imageRequestID = 0;
  214 + }
  215 + } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  216 + if (![asset isEqual:self->_asset]) return;
  217 + self->_progressView.hidden = NO;
  218 + [self bringSubviewToFront:self->_progressView];
  219 + progress = progress > 0.02 ? progress : 0.02;
  220 + self->_progressView.progress = progress;
  221 + if (self.imageProgressUpdateBlock && progress < 1) {
  222 + self.imageProgressUpdateBlock(progress);
  223 + }
  224 +
  225 + if (progress >= 1) {
  226 + self->_progressView.hidden = YES;
  227 + self.imageRequestID = 0;
  228 + }
  229 + } networkAccessAllowed:YES];
  230 +}
  231 +
  232 +- (void)recoverSubviews {
  233 + [_scrollView setZoomScale:1.0 animated:NO];
  234 + [self resizeSubviews];
  235 +}
  236 +
  237 +- (void)resizeSubviews {
  238 + _imageContainerView.tz_origin = CGPointZero;
  239 + _imageContainerView.tz_width = self.scrollView.tz_width;
  240 +
  241 + UIImage *image = _imageView.image;
  242 + if (image.size.height / image.size.width > self.tz_height / self.scrollView.tz_width) {
  243 + _imageContainerView.tz_height = floor(image.size.height / (image.size.width / self.scrollView.tz_width));
  244 + } else {
  245 + CGFloat height = image.size.height / image.size.width * self.scrollView.tz_width;
  246 + if (height < 1 || isnan(height)) height = self.tz_height;
  247 + height = floor(height);
  248 + _imageContainerView.tz_height = height;
  249 + _imageContainerView.tz_centerY = self.tz_height / 2;
  250 + }
  251 + if (_imageContainerView.tz_height > self.tz_height && _imageContainerView.tz_height - self.tz_height <= 1) {
  252 + _imageContainerView.tz_height = self.tz_height;
  253 + }
  254 + CGFloat contentSizeH = MAX(_imageContainerView.tz_height, self.tz_height);
  255 + _scrollView.contentSize = CGSizeMake(self.scrollView.tz_width, contentSizeH);
  256 + [_scrollView scrollRectToVisible:self.bounds animated:NO];
  257 + _scrollView.alwaysBounceVertical = _imageContainerView.tz_height <= self.tz_height ? NO : YES;
  258 + _imageView.frame = _imageContainerView.bounds;
  259 +
  260 + [self refreshScrollViewContentSize];
  261 +}
  262 +
  263 +- (void)setAllowCrop:(BOOL)allowCrop {
  264 + _allowCrop = allowCrop;
  265 + _scrollView.maximumZoomScale = allowCrop ? 4.0 : 2.5;
  266 +
  267 + if ([self.asset isKindOfClass:[PHAsset class]]) {
  268 + PHAsset *phAsset = (PHAsset *)self.asset;
  269 + CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
  270 + // 优化超宽图片的显示
  271 + if (aspectRatio > 1.5) {
  272 + self.scrollView.maximumZoomScale *= aspectRatio / 1.5;
  273 + }
  274 + }
  275 +}
  276 +
  277 +- (void)refreshScrollViewContentSize {
  278 + if (_allowCrop) {
  279 + // 1.7.2 如果允许裁剪,需要让图片的任意部分都能在裁剪框内,于是对_scrollView做了如下处理:
  280 + // 1.让contentSize增大(裁剪框右下角的图片部分)
  281 + CGFloat contentWidthAdd = self.scrollView.tz_width - CGRectGetMaxX(_cropRect);
  282 + CGFloat contentHeightAdd = (MIN(_imageContainerView.tz_height, self.tz_height) - self.cropRect.size.height) / 2;
  283 + CGFloat newSizeW = self.scrollView.contentSize.width + contentWidthAdd;
  284 + CGFloat newSizeH = MAX(self.scrollView.contentSize.height, self.tz_height) + contentHeightAdd;
  285 + _scrollView.contentSize = CGSizeMake(newSizeW, newSizeH);
  286 + _scrollView.alwaysBounceVertical = YES;
  287 + // 2.让scrollView新增滑动区域(裁剪框左上角的图片部分)
  288 + if (contentHeightAdd > 0 || contentWidthAdd > 0) {
  289 + _scrollView.contentInset = UIEdgeInsetsMake(contentHeightAdd, _cropRect.origin.x, 0, 0);
  290 + } else {
  291 + _scrollView.contentInset = UIEdgeInsetsZero;
  292 + }
  293 + }
  294 +}
  295 +
  296 +- (void)layoutSubviews {
  297 + [super layoutSubviews];
  298 + _scrollView.frame = CGRectMake(10, 0, self.tz_width - 20, self.tz_height);
  299 + static CGFloat progressWH = 40;
  300 + CGFloat progressX = (self.tz_width - progressWH) / 2;
  301 + CGFloat progressY = (self.tz_height - progressWH) / 2;
  302 + _progressView.frame = CGRectMake(progressX, progressY, progressWH, progressWH);
  303 +
  304 + [self recoverSubviews];
  305 +}
  306 +
  307 +#pragma mark - UITapGestureRecognizer Event
  308 +
  309 +- (void)doubleTap:(UITapGestureRecognizer *)tap {
  310 + if (_scrollView.zoomScale > 1.0) {
  311 + _scrollView.contentInset = UIEdgeInsetsZero;
  312 + [_scrollView setZoomScale:1.0 animated:YES];
  313 + } else {
  314 + CGPoint touchPoint = [tap locationInView:self.imageView];
  315 + CGFloat newZoomScale = _scrollView.maximumZoomScale;
  316 + CGFloat xsize = self.frame.size.width / newZoomScale;
  317 + CGFloat ysize = self.frame.size.height / newZoomScale;
  318 + [_scrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES];
  319 + }
  320 +}
  321 +
  322 +- (void)singleTap:(UITapGestureRecognizer *)tap {
  323 + if (self.singleTapGestureBlock) {
  324 + self.singleTapGestureBlock();
  325 + }
  326 +}
  327 +
  328 +#pragma mark - UIScrollViewDelegate
  329 +
  330 +- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
  331 + return _imageContainerView;
  332 +}
  333 +
  334 +- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
  335 + scrollView.contentInset = UIEdgeInsetsZero;
  336 +}
  337 +
  338 +- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
  339 + [self refreshImageContainerViewCenter];
  340 +}
  341 +
  342 +- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
  343 + [self refreshScrollViewContentSize];
  344 +}
  345 +
  346 +#pragma mark - Private
  347 +
  348 +- (void)refreshImageContainerViewCenter {
  349 + CGFloat offsetX = (_scrollView.tz_width > _scrollView.contentSize.width) ? ((_scrollView.tz_width - _scrollView.contentSize.width) * 0.5) : 0.0;
  350 + CGFloat offsetY = (_scrollView.tz_height > _scrollView.contentSize.height) ? ((_scrollView.tz_height - _scrollView.contentSize.height) * 0.5) : 0.0;
  351 + self.imageContainerView.center = CGPointMake(_scrollView.contentSize.width * 0.5 + offsetX, _scrollView.contentSize.height * 0.5 + offsetY);
  352 +}
  353 +
  354 +@end
  355 +
  356 +
  357 +@implementation TZVideoPreviewCell
  358 +
  359 +- (void)dealloc
  360 +{
  361 + if (_player) {
  362 + [_playerLayer removeFromSuperlayer];
  363 + _playerLayer = nil;
  364 + [_player pause];
  365 + _player = nil;
  366 +
  367 + }
  368 +}
  369 +
  370 +- (void)configSubviews {
  371 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil];
  372 +
  373 + [[NSNotificationCenter defaultCenter] addObserver:self
  374 + selector:@selector(pauseVideoView:) name:CNVideoOrAudioEnterNotification
  375 + object:nil];
  376 +
  377 + [[NSNotificationCenter defaultCenter] addObserver:self
  378 + selector:@selector(playVideoView:) name:CNVideoOrAudioOutNotification
  379 + object:nil];
  380 +
  381 +}
  382 +
  383 +- (void)configPlayButton {
  384 + if (_playButton) {
  385 + [_playButton removeFromSuperview];
  386 + }
  387 + _playButton = [UIButton buttonWithType:UIButtonTypeCustom];
  388 + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
  389 + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
  390 + [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
  391 + [self addSubview:_playButton];
  392 +}
  393 +
  394 +- (void)configProgressView {
  395 + if (_progressView) {
  396 + [_progressView removeFromSuperview];
  397 + }
  398 +
  399 + _progressView = [[TZProgressView alloc]init];
  400 + _progressView.hidden = YES;
  401 + [self addSubview:_progressView];
  402 +
  403 +}
  404 +
  405 +
  406 +- (void)setModel:(TZAssetModel *)model {
  407 + [super setModel:model];
  408 + [self configMoviePlayer];
  409 +}
  410 +
  411 +- (void)configMoviePlayer {
  412 +
  413 + if (_player) {
  414 + [_playerLayer removeFromSuperlayer];
  415 + _playerLayer = nil;
  416 + [_player pause];
  417 + _player = nil;
  418 + }
  419 +
  420 + if (_progressView) {
  421 + [_progressView removeFromSuperview];
  422 + _progressView = nil;
  423 + }
  424 +
  425 + __weak typeof(self) weakSelf = self;
  426 + [[TZImageManager manager] getPhotoWithAsset:self.model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  427 + NSLog(@"输出图片info = %@",info);
  428 + /** 获取图片 */
  429 + weakSelf.cover = photo;
  430 +
  431 +
  432 + }];
  433 +
  434 +#pragma mark - iCloud 视频
  435 +
  436 + if (self.model.isCheckICloudType) {//已检查
  437 +
  438 + if (self.model.isVideoICloudDownLoad || !self.model.isICloudType) {//已下载 或 不是iCloud
  439 +
  440 + [[TZImageManager manager] getVideoWithAsset:self.model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
  441 +
  442 + dispatch_async(dispatch_get_main_queue(), ^{
  443 +
  444 + weakSelf.progressView.hidden = YES;
  445 + weakSelf.playButton.hidden = NO;
  446 +
  447 + self->_player = [AVPlayer playerWithPlayerItem:playerItem];
  448 + self->_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self->_player];
  449 + self->_playerLayer.backgroundColor = [UIColor blackColor].CGColor;
  450 + self->_playerLayer.frame = self.bounds;
  451 + [self.layer addSublayer:self->_playerLayer];
  452 + [self configPlayButton];
  453 +
  454 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem];
  455 +
  456 + if (weakSelf.imageProgressUpdateBlock) {
  457 + weakSelf.imageProgressUpdateBlock(self);
  458 + }
  459 + });
  460 +
  461 + }];
  462 +
  463 + }else {//未下载 且 是iCloud
  464 +
  465 + [self configProgressView];//添加HUD
  466 +
  467 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  468 + options.version = PHVideoRequestOptionsVersionOriginal;
  469 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  470 + options.networkAccessAllowed = YES;
  471 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  472 + dispatch_async(dispatch_get_main_queue(), ^{
  473 +
  474 + weakSelf.progressView.progress = progress;
  475 + if (progress >= 1) {
  476 + weakSelf.progressView.hidden = YES;
  477 + weakSelf.playButton.hidden = NO;
  478 +
  479 + } else {
  480 + weakSelf.progressView.hidden = NO;
  481 + weakSelf.playButton.hidden = YES;
  482 + }
  483 +
  484 + NSLog(@"输出进度 = %f",progress);
  485 +
  486 + });
  487 + };
  488 + /** requestPlayerItemForVideo */
  489 + [[PHImageManager defaultManager] requestAVAssetForVideo:self.model.asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
  490 + NSLog(@"Info:%@",info);
  491 +
  492 + if ([[info objectForKey: PHImageResultIsInCloudKey] boolValue])
  493 + {
  494 + weakSelf.model.isICloudType = YES;
  495 + }else {
  496 + weakSelf.model.isICloudType = NO;
  497 + }
  498 +
  499 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  500 + if (downloadFinined && avasset) {
  501 +
  502 + dispatch_async(dispatch_get_main_queue(), ^{
  503 + weakSelf.model.isVideoICloudDownLoad = YES;
  504 +
  505 + weakSelf.progressView.hidden = YES;
  506 + weakSelf.playButton.hidden = NO;
  507 + AVURLAsset *videoAsset = (AVURLAsset*)avasset;
  508 + AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:videoAsset];
  509 + weakSelf.player = [AVPlayer playerWithPlayerItem:playerItem];
  510 + weakSelf.playerLayer = [AVPlayerLayer playerLayerWithPlayer:weakSelf.player];
  511 + weakSelf.playerLayer.backgroundColor = [UIColor blackColor].CGColor;
  512 + weakSelf.playerLayer.frame = weakSelf.bounds;
  513 + [weakSelf.layer addSublayer:weakSelf.playerLayer];
  514 + [weakSelf configPlayButton];
  515 +
  516 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:weakSelf.player.currentItem];
  517 +
  518 + if (weakSelf.imageProgressUpdateBlock) {
  519 + weakSelf.imageProgressUpdateBlock(self);
  520 + }
  521 + });
  522 + }else {
  523 + weakSelf.model.isVideoICloudDownLoad = NO;
  524 +
  525 + if (weakSelf.imageProgressUpdateBlock) {
  526 + weakSelf.imageProgressUpdateBlock(self);
  527 + }
  528 + }
  529 +
  530 + }];
  531 +
  532 + }
  533 +
  534 +
  535 + }else {//未检查
  536 +
  537 + [self configProgressView];//添加HUD
  538 +
  539 + [[TZImageManager manager] getVideoWithAsset:self.model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
  540 +
  541 + NSLog(@"输出视频info = %@",info);
  542 +
  543 + weakSelf.model.isCheckICloudType = YES;
  544 + if ([[info objectForKey: PHImageResultIsInCloudKey] boolValue])
  545 + {
  546 + weakSelf.model.isICloudType = YES;
  547 +
  548 + }else {
  549 + weakSelf.model.isICloudType = NO;
  550 + }
  551 +
  552 + if (weakSelf.imageProgressUpdateBlock) {
  553 + weakSelf.imageProgressUpdateBlock(self);
  554 + }
  555 +
  556 + if (weakSelf.model.isICloudType) {//是iCloud加载
  557 +
  558 + PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
  559 + options.version = PHVideoRequestOptionsVersionOriginal;
  560 + options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;
  561 + options.networkAccessAllowed = YES;
  562 + options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) {
  563 + dispatch_async(dispatch_get_main_queue(), ^{
  564 +
  565 + weakSelf.progressView.progress = progress;
  566 + if (progress >= 1) {
  567 + weakSelf.progressView.hidden = YES;
  568 + weakSelf.playButton.hidden = NO;
  569 +
  570 + } else {
  571 + weakSelf.progressView.hidden = NO;
  572 + weakSelf.playButton.hidden = YES;
  573 + }
  574 +
  575 + NSLog(@"输出进度 = %f",progress);
  576 +
  577 + });
  578 + };
  579 + /** requestPlayerItemForVideo */
  580 + [[PHImageManager defaultManager] requestAVAssetForVideo:self.model.asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
  581 + NSLog(@"Info:%@",info);
  582 + BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
  583 + if (downloadFinined && avasset) {
  584 + dispatch_async(dispatch_get_main_queue(), ^{
  585 + weakSelf.model.isVideoICloudDownLoad = YES;
  586 +
  587 + weakSelf.progressView.hidden = YES;
  588 + weakSelf.playButton.hidden = NO;
  589 +
  590 + AVURLAsset *videoAsset = (AVURLAsset*)avasset;
  591 + AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:videoAsset];
  592 + weakSelf.player = [AVPlayer playerWithPlayerItem:playerItem];
  593 + weakSelf.playerLayer = [AVPlayerLayer playerLayerWithPlayer:weakSelf.player];
  594 + weakSelf.playerLayer.backgroundColor = [UIColor blackColor].CGColor;
  595 + weakSelf.playerLayer.frame = weakSelf.bounds;
  596 + [weakSelf.layer addSublayer:weakSelf.playerLayer];
  597 + [weakSelf configPlayButton];
  598 +
  599 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:weakSelf.player.currentItem];
  600 +
  601 + if (weakSelf.imageProgressUpdateBlock) {
  602 + weakSelf.imageProgressUpdateBlock(self);
  603 + }
  604 + });
  605 + }else {
  606 + weakSelf.model.isVideoICloudDownLoad = NO;
  607 +
  608 + if (weakSelf.imageProgressUpdateBlock) {
  609 + weakSelf.imageProgressUpdateBlock(self);
  610 + }
  611 + }
  612 +
  613 + }];
  614 +
  615 + }else {//不是iCloud加载
  616 +
  617 + dispatch_async(dispatch_get_main_queue(), ^{
  618 +
  619 + weakSelf.progressView.hidden = YES;
  620 + weakSelf.playButton.hidden = NO;
  621 + self->_player = [AVPlayer playerWithPlayerItem:playerItem];
  622 + self->_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self->_player];
  623 + self->_playerLayer.backgroundColor = [UIColor blackColor].CGColor;
  624 + self->_playerLayer.frame = self.bounds;
  625 + [self.layer addSublayer:self->_playerLayer];
  626 + [self configPlayButton];
  627 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem];
  628 + if (weakSelf.imageProgressUpdateBlock) {
  629 + weakSelf.imageProgressUpdateBlock(self);
  630 + }
  631 + });
  632 +
  633 + }
  634 + }];
  635 +
  636 + }
  637 +}
  638 +
  639 +- (void)didViewLoadVC {
  640 + if (_player) {
  641 + [_playerLayer removeFromSuperlayer];
  642 + _playerLayer = nil;
  643 + [_player pause];
  644 + _player = nil;
  645 +
  646 + }
  647 +}
  648 +
  649 +
  650 +- (void)layoutSubviews {
  651 + [super layoutSubviews];
  652 + _playerLayer.frame = self.bounds;
  653 + _playButton.frame = CGRectMake(0, 64, self.tz_width, self.tz_height - 64 - 44);
  654 + _progressView.frame = CGRectMake((self.tz_width - 50)/2, (self.tz_height - 50)/2 , 50, 50);
  655 +}
  656 +
  657 +- (void)photoPreviewCollectionViewDidScroll {
  658 + [self pausePlayerAndShowNaviBar];
  659 +}
  660 +
  661 +#pragma mark - Click Event
  662 +
  663 +- (void)playButtonClick {
  664 +
  665 + if ([CNAudioOrVideoMananger IsEnter]) {//在房间
  666 + [QMUITips showWithText:@"音视频通话中..." inView:AppKeyWindow hideAfterDelay:1.5];
  667 + return;
  668 + }else {
  669 + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
  670 + }
  671 +
  672 + CMTime currentTime = _player.currentItem.currentTime;
  673 + CMTime durationTime = _player.currentItem.duration;
  674 + if (_player.rate == 0.0f) {
  675 + if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
  676 + [_player play];
  677 + [_playButton setImage:nil forState:UIControlStateNormal];
  678 + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
  679 + if (self.singleTapGestureBlock) {
  680 + self.singleTapGestureBlock();
  681 + }
  682 + } else {
  683 + [self pausePlayerAndShowNaviBar];
  684 + }
  685 +}
  686 +
  687 +- (void)pausePlayerAndShowNaviBar {
  688 + if (_player.rate != 0.0) {
  689 + [_player pause];
  690 + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
  691 + if (self.singleTapGestureBlock) {
  692 + self.singleTapGestureBlock();
  693 + }
  694 + }
  695 +}
  696 +
  697 +
  698 +- (void)pauseVideoView:(NSNotification *)note
  699 +{
  700 + [self playButtonClick];
  701 +}
  702 +
  703 +- (void)playVideoView:(NSNotification *)note
  704 +{
  705 +
  706 +
  707 +}
  708 +
  709 +
  710 +
  711 +@end
  712 +
  713 +
  714 +@implementation TZGifPreviewCell
  715 +
  716 +- (void)configSubviews {
  717 + [self configPreviewView];
  718 +}
  719 +
  720 +- (void)configPreviewView {
  721 + _previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
  722 + __weak typeof(self) weakSelf = self;
  723 + [_previewView setSingleTapGestureBlock:^{
  724 + __strong typeof(weakSelf) strongSelf = weakSelf;
  725 + [strongSelf signleTapAction];
  726 + }];
  727 + [self addSubview:_previewView];
  728 +}
  729 +
  730 +- (void)setModel:(TZAssetModel *)model {
  731 + [super setModel:model];
  732 + _previewView.model = self.model;
  733 +}
  734 +
  735 +- (void)layoutSubviews {
  736 + [super layoutSubviews];
  737 + _previewView.frame = self.bounds;
  738 +}
  739 +
  740 +#pragma mark - Click Event
  741 +
  742 +- (void)signleTapAction {
  743 + if (self.singleTapGestureBlock) {
  744 + self.singleTapGestureBlock();
  745 + }
  746 +}
  747 +
  748 +@end
... ...
CNLiveImagePickerController/Classes/TZPhotoPreviewController.h 0 → 100755
  1 +//
  2 +// TZPhotoPreviewController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +typedef enum : NSUInteger {
  12 + PhotoPreviewEnterTypeNormal,
  13 + PhotoPreviewEnterTypeSelected,
  14 +} PhotoPreviewEnterType;
  15 +
  16 +@interface TZPhotoPreviewController : UIViewController
  17 +
  18 +@property (nonatomic, assign) PhotoPreviewEnterType enterType;
  19 +
  20 +@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组
  21 +@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组
  22 +@property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / 用户点击的图片的索引
  23 +@property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / 是否返回原图
  24 +@property (nonatomic, assign) BOOL isCropImage;
  25 +
  26 +/// Return the new selected photos / 返回最新的选中图片数组
  27 +@property (nonatomic, copy) void (^backButtonClickBlock)(BOOL isSelectOriginalPhoto);
  28 +@property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto);
  29 +@property (nonatomic, copy) void (^doneButtonClickBlockCropMode)(UIImage *cropedImage,id asset);
  30 +@property (nonatomic, copy) void (^doneButtonClickBlockWithPreviewType)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
  31 +
  32 +
  33 +
  34 +@end
... ...
CNLiveImagePickerController/Classes/TZPhotoPreviewController.m 0 → 100755
  1 +//
  2 +// TZPhotoPreviewController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZPhotoPreviewController.h"
  10 +#import "TZPhotoPreviewCell.h"
  11 +#import "TZAssetModel.h"
  12 +#import "UIView+TZLayout.h"
  13 +#import "TZImagePickerController.h"
  14 +#import "TZImageManager.h"
  15 +#import "TZImageCropManager.h"
  16 +#import <AssetsLibrary/AssetsLibrary.h>///lxg
  17 +#import "CNEditVideoController.h"
  18 +#import "CNAudioOrVideoMananger.h"
  19 +
  20 +@interface TZPhotoPreviewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIScrollViewDelegate> {
  21 + UICollectionView *_collectionView;
  22 + UICollectionViewFlowLayout *_layout;
  23 + NSArray *_photosTemp;
  24 + NSArray *_assetsTemp;
  25 +
  26 + UIView *_naviBar;
  27 + UIButton *_backButton;
  28 + UIButton *_selectButton;
  29 + UILabel *_indexLabel;
  30 + UIView *_navBarLine;///LXG线
  31 +
  32 + UIView *_tipBar;///LXG添加提示视图
  33 + UILabel *_tipContentLabel;///LXG添加提示内容
  34 +
  35 +
  36 + UIView *_toolBar;
  37 + UIButton *_doneButton;
  38 + UIImageView *_numberImageView;
  39 + UILabel *_numberLabel;
  40 + UIButton *_originalPhotoButton;
  41 + UILabel *_originalPhotoLabel;
  42 + UILabel *_editTipLable;//LXG底部提示
  43 + UIButton *_editTipButton;//LXG编辑按钮
  44 +
  45 +
  46 + CGFloat _offsetItemCount;
  47 +
  48 + BOOL _didSetIsSelectOriginalPhoto;
  49 +}
  50 +@property (nonatomic, assign) BOOL isHideNaviBar;
  51 +@property (nonatomic, strong) UIView *cropBgView;
  52 +@property (nonatomic, strong) UIView *cropView;
  53 +
  54 +@property (nonatomic, assign) double progress;
  55 +@property (strong, nonatomic) id alertView;
  56 +@end
  57 +
  58 +@implementation TZPhotoPreviewController
  59 +
  60 +- (void)viewDidLoad {
  61 + [super viewDidLoad];
  62 + [TZImageManager manager].shouldFixOrientation = YES;
  63 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  64 + if (!_didSetIsSelectOriginalPhoto) {
  65 + _isSelectOriginalPhoto = _tzImagePickerVc.isSelectOriginalPhoto;
  66 + }
  67 + if (!self.models.count) {
  68 + self.models = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedModels];
  69 + _assetsTemp = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedAssets];
  70 + }
  71 + [self configCollectionView];
  72 + [self configCustomNaviBar];
  73 + [self configCustomTipBar];///lxg 添加提示
  74 + [self configBottomToolBar];
  75 + self.view.clipsToBounds = YES;
  76 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
  77 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshPhotoPreview) name:@"refreshPhotoPreview" object:nil];
  78 +}
  79 +
  80 +- (void)setIsSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto {
  81 + _isSelectOriginalPhoto = isSelectOriginalPhoto;
  82 + _didSetIsSelectOriginalPhoto = YES;
  83 +}
  84 +
  85 +- (void)setPhotos:(NSMutableArray *)photos {
  86 + _photos = photos;
  87 + _photosTemp = [NSArray arrayWithArray:photos];
  88 +}
  89 +
  90 +- (void)viewWillAppear:(BOOL)animated {
  91 + [super viewWillAppear:animated];
  92 + [self.navigationController setNavigationBarHidden:YES animated:YES];
  93 + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
  94 + if (_currentIndex) [_collectionView setContentOffset:CGPointMake((self.view.tz_width + 20) * _currentIndex, 0) animated:NO];
  95 + [self refreshNaviBarAndBottomBarState];
  96 +}
  97 +
  98 +- (void)viewWillDisappear:(BOOL)animated {
  99 + [super viewWillDisappear:animated];
  100 + [self.navigationController setNavigationBarHidden:NO animated:YES];
  101 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  102 + if (tzImagePickerVc.needShowStatusBar && iOS7Later) {
  103 + [UIApplication sharedApplication].statusBarHidden = NO;
  104 + }
  105 + [TZImageManager manager].shouldFixOrientation = NO;
  106 +
  107 + [[NSNotificationCenter defaultCenter] postNotificationName:@"didViewLoadController" object:nil];
  108 +}
  109 +
  110 +- (BOOL)prefersStatusBarHidden {
  111 + return YES;
  112 +}
  113 +
  114 +- (void)configCustomNaviBar {
  115 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  116 +
  117 + _naviBar = [[UIView alloc] initWithFrame:CGRectZero];
  118 + _naviBar.backgroundColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:0.7];
  119 +
  120 + _backButton = [[UIButton alloc] initWithFrame:CGRectZero];
  121 + [_backButton setImage:[UIImage imageNamedFromMyBundle:@"navi_back"] forState:UIControlStateNormal];
  122 + [_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  123 + [_backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside];
  124 +
  125 + _selectButton = [[UIButton alloc] initWithFrame:CGRectZero];
  126 + [_selectButton setImage:tzImagePickerVc.photoDefImage forState:UIControlStateNormal];
  127 + [_selectButton setImage:tzImagePickerVc.photoSelImage forState:UIControlStateSelected];
  128 + _selectButton.imageView.clipsToBounds = YES;
  129 + _selectButton.imageEdgeInsets = UIEdgeInsetsMake(10, 0, 10, 0);
  130 + _selectButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
  131 + [_selectButton addTarget:self action:@selector(select:) forControlEvents:UIControlEventTouchUpInside];
  132 + _selectButton.hidden = !tzImagePickerVc.showSelectBtn;
  133 +
  134 + _indexLabel = [[UILabel alloc] init];
  135 + _indexLabel.font = [UIFont systemFontOfSize:14];
  136 + _indexLabel.textColor = [UIColor whiteColor];
  137 + _indexLabel.textAlignment = NSTextAlignmentCenter;
  138 + ///lxg 导航栏线
  139 + _navBarLine = [[UIView alloc]init];
  140 + _navBarLine.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1];
  141 + _navBarLine.hidden = YES;
  142 +
  143 + [_naviBar addSubview:_selectButton];
  144 + [_naviBar addSubview:_indexLabel];
  145 + [_naviBar addSubview:_backButton];
  146 + [_naviBar addSubview:_navBarLine];///lxg 添加线
  147 + [self.view addSubview:_naviBar];
  148 +}
  149 +
  150 +/// 添加提示条(LXG)
  151 +- (void)configCustomTipBar {
  152 + _tipBar = [[UIView alloc] initWithFrame:CGRectZero];
  153 + static CGFloat rgb = 34 / 255.0;
  154 + _tipBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
  155 + _tipBar.hidden = YES;
  156 +
  157 + _tipContentLabel = [[UILabel alloc] init];
  158 + _tipContentLabel.font = [UIFont systemFontOfSize:15];
  159 + _tipContentLabel.textColor = [UIColor whiteColor];
  160 + _tipContentLabel.textAlignment = NSTextAlignmentLeft;
  161 + _tipContentLabel.backgroundColor = [UIColor clearColor];
  162 +
  163 + [_tipBar addSubview:_tipContentLabel];
  164 + [self.view addSubview:_tipBar];
  165 +
  166 +
  167 +}
  168 +
  169 +- (void)configBottomToolBar {
  170 + _toolBar = [[UIView alloc] initWithFrame:CGRectZero];
  171 + static CGFloat rgb = 34 / 255.0;
  172 + _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
  173 +
  174 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  175 + if (_tzImagePickerVc.allowPickingOriginalPhoto) {
  176 + _originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
  177 + _originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
  178 + _originalPhotoButton.backgroundColor = [UIColor clearColor];
  179 + [_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside];
  180 + _originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:13];
  181 + [_originalPhotoButton setTitle:_tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateNormal];
  182 + [_originalPhotoButton setTitle:_tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateSelected];
  183 + [_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal];
  184 + [_originalPhotoButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
  185 + [_originalPhotoButton setImage:_tzImagePickerVc.photoPreviewOriginDefImage forState:UIControlStateNormal];
  186 + [_originalPhotoButton setImage:_tzImagePickerVc.photoOriginSelImage forState:UIControlStateSelected];
  187 +
  188 + _originalPhotoLabel = [[UILabel alloc] init];
  189 + _originalPhotoLabel.textAlignment = NSTextAlignmentLeft;
  190 + _originalPhotoLabel.font = [UIFont systemFontOfSize:13];
  191 + _originalPhotoLabel.textColor = [UIColor whiteColor];
  192 + _originalPhotoLabel.backgroundColor = [UIColor clearColor];
  193 + if (_isSelectOriginalPhoto) [self showPhotoBytes];
  194 + }
  195 +
  196 + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
  197 + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
  198 + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
  199 + [_doneButton setTitle:_tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
  200 + [_doneButton setTitleColor:_tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
  201 +
  202 + _numberImageView = [[UIImageView alloc] initWithImage:_tzImagePickerVc.photoNumberIconImage];
  203 + _numberImageView.backgroundColor = [UIColor clearColor];
  204 + _numberImageView.clipsToBounds = YES;
  205 + _numberImageView.contentMode = UIViewContentModeScaleAspectFit;
  206 + _numberImageView.hidden = _tzImagePickerVc.selectedModels.count <= 0;
  207 +
  208 + _numberLabel = [[UILabel alloc] init];
  209 + _numberLabel.font = [UIFont systemFontOfSize:15];
  210 + _numberLabel.textColor = [UIColor whiteColor];
  211 + _numberLabel.textAlignment = NSTextAlignmentCenter;
  212 + _numberLabel.text = [NSString stringWithFormat:@"%zd",_tzImagePickerVc.selectedModels.count];
  213 + _numberLabel.hidden = _tzImagePickerVc.selectedModels.count <= 0;
  214 + _numberLabel.backgroundColor = [UIColor clearColor];
  215 +#pragma mark - 添加: 选择图片个数显示(LXG)
  216 + _numberImageView.hidden = YES;
  217 + _numberLabel.hidden = YES;
  218 + NSString *titleStr = _tzImagePickerVc.selectedModels.count > 0 ? [NSString stringWithFormat:@"完成(%zd)",_tzImagePickerVc.selectedModels.count] : @"完成";
  219 + [_doneButton setTitle:titleStr forState:UIControlStateNormal];
  220 +
  221 + ///LXG 添加视频编辑
  222 + _editTipLable = [[UILabel alloc] init];
  223 + _editTipLable.font = [UIFont systemFontOfSize:15];
  224 + _editTipLable.textAlignment = NSTextAlignmentLeft;
  225 + _editTipLable.hidden = YES;
  226 + _editTipLable.textColor = [UIColor whiteColor];
  227 + _editTipLable.backgroundColor = [UIColor clearColor];
  228 + _editTipButton = [UIButton buttonWithType:UIButtonTypeCustom];
  229 + _editTipButton.titleLabel.font = [UIFont systemFontOfSize:16];
  230 + [_editTipButton addTarget:self action:@selector(editVideoButtonClick) forControlEvents:UIControlEventTouchUpInside];
  231 + _editTipButton.hidden = YES;
  232 + [_editTipButton setTitle:_tzImagePickerVc.editBtnTitleStr forState:UIControlStateNormal];
  233 + [_editTipButton setTitleColor:_tzImagePickerVc.editBtnTitleColor forState:UIControlStateNormal];
  234 +
  235 + [_originalPhotoButton addSubview:_originalPhotoLabel];
  236 + [_toolBar addSubview:_doneButton];
  237 + [_toolBar addSubview:_originalPhotoButton];
  238 + [_toolBar addSubview:_numberImageView];
  239 + [_toolBar addSubview:_numberLabel];
  240 + [_toolBar addSubview:_editTipLable];///LXG
  241 + [_toolBar addSubview:_editTipButton];///LXG
  242 + [self.view addSubview:_toolBar];
  243 +
  244 + if (_tzImagePickerVc.photoPreviewPageUIConfigBlock) {
  245 + _tzImagePickerVc.photoPreviewPageUIConfigBlock(_collectionView, _naviBar, _backButton, _selectButton, _indexLabel, _toolBar, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel);
  246 + }
  247 +}
  248 +
  249 +- (void)configCollectionView {
  250 + _layout = [[UICollectionViewFlowLayout alloc] init];
  251 + _layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
  252 + _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout];
  253 + _collectionView.backgroundColor = [UIColor blackColor];
  254 + _collectionView.dataSource = self;
  255 + _collectionView.delegate = self;
  256 + _collectionView.pagingEnabled = YES;
  257 + _collectionView.scrollsToTop = NO;
  258 + _collectionView.showsHorizontalScrollIndicator = NO;
  259 + _collectionView.contentOffset = CGPointMake(0, 0);
  260 + _collectionView.contentSize = CGSizeMake(self.models.count * (self.view.tz_width + 20), 0);
  261 + [self.view addSubview:_collectionView];
  262 + [_collectionView registerClass:[TZPhotoPreviewCell class] forCellWithReuseIdentifier:@"TZPhotoPreviewCell"];
  263 + [_collectionView registerClass:[TZVideoPreviewCell class] forCellWithReuseIdentifier:@"TZVideoPreviewCell"];
  264 + [_collectionView registerClass:[TZGifPreviewCell class] forCellWithReuseIdentifier:@"TZGifPreviewCell"];
  265 +}
  266 +
  267 +- (void)configCropView {
  268 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  269 + if (_tzImagePickerVc.maxImagesCount <= 1 && _tzImagePickerVc.allowCrop) {
  270 + [_cropView removeFromSuperview];
  271 + [_cropBgView removeFromSuperview];
  272 +
  273 + _cropBgView = [UIView new];
  274 + _cropBgView.userInteractionEnabled = NO;
  275 + _cropBgView.frame = self.view.bounds;
  276 + _cropBgView.backgroundColor = [UIColor clearColor];
  277 + [self.view addSubview:_cropBgView];
  278 + [TZImageCropManager overlayClippingWithView:_cropBgView cropRect:_tzImagePickerVc.cropRect containerView:self.view needCircleCrop:_tzImagePickerVc.needCircleCrop];
  279 +
  280 + _cropView = [UIView new];
  281 + _cropView.userInteractionEnabled = NO;
  282 + _cropView.frame = _tzImagePickerVc.cropRect;
  283 + _cropView.backgroundColor = [UIColor clearColor];
  284 + _cropView.layer.borderColor = [UIColor whiteColor].CGColor;
  285 + _cropView.layer.borderWidth = 1.0;
  286 + if (_tzImagePickerVc.needCircleCrop) {
  287 + _cropView.layer.cornerRadius = _tzImagePickerVc.cropRect.size.width / 2;
  288 + _cropView.clipsToBounds = YES;
  289 + }
  290 + [self.view addSubview:_cropView];
  291 + if (_tzImagePickerVc.cropViewSettingBlock) {
  292 + _tzImagePickerVc.cropViewSettingBlock(_cropView);
  293 + }
  294 +
  295 + [self.view bringSubviewToFront:_naviBar];
  296 + [self.view bringSubviewToFront:_tipBar];
  297 + [self.view bringSubviewToFront:_toolBar];
  298 + }
  299 +}
  300 +
  301 +#pragma mark - Layout
  302 +
  303 +- (void)viewDidLayoutSubviews {
  304 + [super viewDidLayoutSubviews];
  305 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  306 +
  307 + CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight];
  308 + CGFloat statusBarHeightInterval = statusBarHeight - 20;
  309 + CGFloat naviBarHeight = statusBarHeight + _tzImagePickerVc.navigationBar.tz_height;
  310 + _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight);
  311 + _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44);
  312 + _selectButton.frame = CGRectMake(self.view.tz_width - 56, 10 + statusBarHeightInterval, 44, 44);
  313 + _indexLabel.frame = _selectButton.frame;
  314 + _navBarLine.frame = CGRectMake(0, _naviBar.tz_height - 0.5, _naviBar.tz_width, 0.5);
  315 +
  316 + ///Lxg 提示视图约束
  317 + CGFloat tipBarHeight = _tzImagePickerVc.navigationBar.tz_height;
  318 + _tipBar.frame = CGRectMake(0, _naviBar.tz_bottom, _naviBar.tz_width, tipBarHeight);
  319 + _tipContentLabel.frame = CGRectMake(12, 0, _tipBar.tz_width - 24, tipBarHeight);
  320 +
  321 + _layout.itemSize = CGSizeMake(self.view.tz_width + 20, self.view.tz_height);
  322 + _layout.minimumInteritemSpacing = 0;
  323 + _layout.minimumLineSpacing = 0;
  324 + _collectionView.frame = CGRectMake(-10, 0, self.view.tz_width + 20, self.view.tz_height);
  325 + [_collectionView setCollectionViewLayout:_layout];
  326 + if (_offsetItemCount > 0) {
  327 + CGFloat offsetX = _offsetItemCount * _layout.itemSize.width;
  328 + [_collectionView setContentOffset:CGPointMake(offsetX, 0)];
  329 + }
  330 + if (_tzImagePickerVc.allowCrop) {
  331 + [_collectionView reloadData];
  332 + }
  333 +
  334 + CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
  335 + CGFloat toolBarTop = self.view.tz_height - toolBarHeight;
  336 + _toolBar.frame = CGRectMake(0, toolBarTop, self.view.tz_width, toolBarHeight);
  337 + if (_tzImagePickerVc.allowPickingOriginalPhoto) {
  338 + CGFloat fullImageWidth = [_tzImagePickerVc.fullImageBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width;
  339 + _originalPhotoButton.frame = CGRectMake(0, 0, fullImageWidth + 56, 44);
  340 + _originalPhotoLabel.frame = CGRectMake(fullImageWidth + 42, 0, 80, 44);
  341 + }
  342 + [_doneButton sizeToFit];
  343 + _doneButton.frame = CGRectMake(self.view.tz_width - _doneButton.tz_width - 12, 0, _doneButton.tz_width, 44);
  344 + _numberImageView.frame = CGRectMake(_doneButton.tz_left - 24 - 5, 10, 24, 24);
  345 + _numberLabel.frame = _numberImageView.frame;
  346 + ///LXG
  347 + [_editTipButton sizeToFit];
  348 + _editTipButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
  349 + _editTipLable.frame = CGRectMake(12, 10, self.view.tz_width - 24 - _editTipButton.tz_width, 24);
  350 +
  351 + [self configCropView];
  352 +
  353 + if (_tzImagePickerVc.photoPreviewPageDidLayoutSubviewsBlock) {
  354 + _tzImagePickerVc.photoPreviewPageDidLayoutSubviewsBlock(_collectionView, _naviBar, _backButton, _selectButton, _indexLabel, _toolBar, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel);
  355 + }
  356 +}
  357 +
  358 +#pragma mark - Notification
  359 +
  360 +- (void)didChangeStatusBarOrientationNotification:(NSNotification *)noti {
  361 + _offsetItemCount = _collectionView.contentOffset.x / _layout.itemSize.width;
  362 +}
  363 +
  364 +- (void)refreshPhotoPreview {
  365 + [self refreshNaviBarAndBottomBarState];
  366 +}
  367 +
  368 +#pragma mark - Click Event
  369 +
  370 +- (void)select:(UIButton *)selectButton {
  371 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  372 + TZAssetModel *model = _models[_currentIndex];
  373 + ///LXG:加入当点击选择时 滑动到另一个页面 选中为当前页面判断是否可选
  374 + if (!selectButton.enabled) {
  375 + return;
  376 + }
  377 +
  378 + if (!selectButton.isSelected) {
  379 + // 1. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制
  380 + if (_tzImagePickerVc.selectedModels.count >= _tzImagePickerVc.maxImagesCount) {
  381 + NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], _tzImagePickerVc.maxImagesCount];
  382 + [_tzImagePickerVc showAlertWithTitle:title];
  383 + return;
  384 + // 2. if not over the maxImagesCount / 如果没有超过最大个数限制
  385 + } else {
  386 + [_tzImagePickerVc addSelectedModel:model];
  387 + if (self.photos) {
  388 + [_tzImagePickerVc.selectedAssets addObject:_assetsTemp[_currentIndex]];
  389 + [self.photos addObject:_photosTemp[_currentIndex]];
  390 + }
  391 + if (model.type == TZAssetModelMediaTypeVideo && !_tzImagePickerVc.allowPickingMultipleVideo) {
  392 + [_tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Select the video when in multi state, we will handle the video as a photo"]];
  393 + }
  394 + }
  395 + } else {
  396 + NSArray *selectedModels = [NSArray arrayWithArray:_tzImagePickerVc.selectedModels];
  397 + for (TZAssetModel *model_item in selectedModels) {
  398 + if ([[[TZImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[TZImageManager manager] getAssetIdentifier:model_item.asset]]) {
  399 + // 1.6.7版本更新:防止有多个一样的model,一次性被移除了
  400 + NSArray *selectedModelsTmp = [NSArray arrayWithArray:_tzImagePickerVc.selectedModels];
  401 + for (NSInteger i = 0; i < selectedModelsTmp.count; i++) {
  402 + TZAssetModel *model = selectedModelsTmp[i];
  403 + if ([model isEqual:model_item]) {
  404 + [_tzImagePickerVc removeSelectedModel:model];
  405 + // [_tzImagePickerVc.selectedModels removeObjectAtIndex:i];
  406 + break;
  407 + }
  408 + }
  409 + if (self.photos) {
  410 + // 1.6.7版本更新:防止有多个一样的asset,一次性被移除了
  411 + NSArray *selectedAssetsTmp = [NSArray arrayWithArray:_tzImagePickerVc.selectedAssets];
  412 + for (NSInteger i = 0; i < selectedAssetsTmp.count; i++) {
  413 + id asset = selectedAssetsTmp[i];
  414 + if ([asset isEqual:_assetsTemp[_currentIndex]]) {
  415 + [_tzImagePickerVc.selectedAssets removeObjectAtIndex:i];
  416 + break;
  417 + }
  418 + }
  419 + // [_tzImagePickerVc.selectedAssets removeObject:_assetsTemp[_currentIndex]];
  420 + [self.photos removeObject:_photosTemp[_currentIndex]];
  421 + }
  422 + break;
  423 + }
  424 + }
  425 + }
  426 +
  427 + model.isSelected = !selectButton.isSelected;
  428 + [self refreshNaviBarAndBottomBarState];
  429 + if (model.isSelected) {
  430 + [UIView showOscillatoryAnimationWithLayer:selectButton.imageView.layer type:TZOscillatoryAnimationToBigger];
  431 + }
  432 + [UIView showOscillatoryAnimationWithLayer:_numberImageView.layer type:TZOscillatoryAnimationToSmaller];
  433 +
  434 +}
  435 +
  436 +- (void)backButtonClick {
  437 + if (self.navigationController.childViewControllers.count < 2) {
  438 + [self.navigationController dismissViewControllerAnimated:YES completion:nil];
  439 + if ([self.navigationController isKindOfClass: [TZImagePickerController class]]) {
  440 + TZImagePickerController *nav = (TZImagePickerController *)self.navigationController;
  441 + if (nav.imagePickerControllerDidCancelHandle) {
  442 + nav.imagePickerControllerDidCancelHandle();
  443 + }
  444 + }
  445 + return;
  446 + }
  447 + [self.navigationController popViewControllerAnimated:YES];
  448 + if (self.backButtonClickBlock) {
  449 + self.backButtonClickBlock(_isSelectOriginalPhoto);
  450 + }
  451 +}
  452 +
  453 +#pragma mark - TODO: 导出done
  454 +- (void)doneButtonClick {
  455 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  456 + // 如果图片正在从iCloud同步中,提醒用户
  457 + if (_progress > 0 && _progress < 1 && (_selectButton.isSelected || !_tzImagePickerVc.selectedModels.count )) {
  458 + _alertView = [_tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]];
  459 + return;
  460 + }
  461 +
  462 + // 如果没有选中过照片 点击确定时选中当前预览的照片
  463 + if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) {
  464 + TZAssetModel *model = _models[_currentIndex];
  465 + [_tzImagePickerVc addSelectedModel:model];
  466 + }
  467 + if (_tzImagePickerVc.allowCrop) { // 裁剪状态
  468 + NSIndexPath *indexPath = [NSIndexPath indexPathForItem:_currentIndex inSection:0];
  469 + TZPhotoPreviewCell *cell = (TZPhotoPreviewCell *)[_collectionView cellForItemAtIndexPath:indexPath];
  470 + UIImage *cropedImage = [TZImageCropManager cropImageView:cell.previewView.imageView toRect:_tzImagePickerVc.cropRect zoomScale:cell.previewView.scrollView.zoomScale containerView:self.view];
  471 + if (_tzImagePickerVc.needCircleCrop) {
  472 + cropedImage = [TZImageCropManager circularClipImage:cropedImage];
  473 + }
  474 + if (self.doneButtonClickBlockCropMode) {
  475 + TZAssetModel *model = _models[_currentIndex];
  476 + self.doneButtonClickBlockCropMode(cropedImage,model.asset);
  477 +
  478 + }
  479 + } else if (self.doneButtonClickBlock) { // 非裁剪状态
  480 + self.doneButtonClickBlock(_isSelectOriginalPhoto);
  481 + }
  482 + if (self.doneButtonClickBlockWithPreviewType) {
  483 + self.doneButtonClickBlockWithPreviewType(self.photos,_tzImagePickerVc.selectedAssets,self.isSelectOriginalPhoto);
  484 + }
  485 +}
  486 +
  487 +///lxg 编辑按钮实现
  488 +- (void)editVideoButtonClick{
  489 +
  490 + if ([CNAudioOrVideoMananger IsEnter]) {//在房间
  491 + [QMUITips showWithText:@"音视频通话中..." inView:AppKeyWindow hideAfterDelay:1.5];
  492 + return;
  493 + }
  494 +
  495 + NSLog(@"开始编辑视频了");
  496 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  497 + CNEditVideoController *editVideoVC = [[CNEditVideoController alloc]init];
  498 + TZAssetModel *model = _models[_currentIndex];
  499 + editVideoVC.model = model;
  500 + editVideoVC.models = _models;
  501 + editVideoVC.currentIndex = _currentIndex;
  502 + editVideoVC.isCropImage = _isCropImage;
  503 + __weak typeof(self) weakSelf = self;
  504 +
  505 + editVideoVC.doneButtonEditClickBlock = ^(BOOL isSelectOriginalPhoto) {
  506 + __strong typeof(weakSelf) strongSelf = weakSelf;
  507 + strongSelf.doneButtonClickBlock(isSelectOriginalPhoto);
  508 +
  509 + };
  510 +
  511 + [_tzImagePickerVc pushViewController:editVideoVC animated:NO];
  512 +}
  513 +
  514 +- (void)originalPhotoButtonClick {
  515 + _originalPhotoButton.selected = !_originalPhotoButton.isSelected;
  516 + _isSelectOriginalPhoto = _originalPhotoButton.isSelected;
  517 + _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected;
  518 + if (_isSelectOriginalPhoto) {
  519 + [self showPhotoBytes];
  520 + if (!_selectButton.isSelected) {
  521 + // 如果当前已选择照片张数 < 最大可选张数 && 最大可选张数大于1,就选中该张图
  522 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  523 + if (_tzImagePickerVc.selectedModels.count < _tzImagePickerVc.maxImagesCount && _tzImagePickerVc.showSelectBtn) {
  524 + [self select:_selectButton];
  525 + }
  526 + }
  527 + }
  528 +}
  529 +
  530 +- (void)didTapPreviewCell {
  531 + self.isHideNaviBar = !self.isHideNaviBar;
  532 + _naviBar.hidden = self.isHideNaviBar;
  533 + _toolBar.hidden = self.isHideNaviBar;
  534 +
  535 + if (_naviBar.hidden && _toolBar.hidden) {
  536 + _tipBar.hidden = YES;
  537 + }else{
  538 + [self refreshNaviBarAndBottomBarState];
  539 + }
  540 +
  541 +}
  542 +
  543 +#pragma mark - UIScrollViewDelegate
  544 +
  545 +- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
  546 + CGFloat offSetWidth = scrollView.contentOffset.x;
  547 + offSetWidth = offSetWidth + ((self.view.tz_width + 20) * 0.5);
  548 +
  549 + NSInteger currentIndex = offSetWidth / (self.view.tz_width + 20);
  550 +
  551 + if (currentIndex < _models.count && _currentIndex != currentIndex) {
  552 + _currentIndex = currentIndex;
  553 + [self refreshNaviBarAndBottomBarState];
  554 + }
  555 +
  556 + [[NSNotificationCenter defaultCenter] postNotificationName:@"photoPreviewCollectionViewDidScroll" object:nil];
  557 +}
  558 +
  559 +#pragma mark - UICollectionViewDataSource && Delegate
  560 +
  561 +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  562 + return _models.count;
  563 +}
  564 +
  565 +- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  566 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  567 + TZAssetModel *model = _models[indexPath.item];
  568 +
  569 + TZAssetPreviewCell *cell;
  570 + __weak typeof(self) weakSelf = self;
  571 +#pragma mark - 更改视频,GIF,显示
  572 + if (model.type == TZAssetModelMediaTypeVideo) {
  573 + cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZVideoPreviewCell" forIndexPath:indexPath];
  574 + TZVideoPreviewCell *videoCell = (TZVideoPreviewCell *)cell;
  575 +
  576 + videoCell.imageProgressUpdateBlock = ^(TZVideoPreviewCell *cell) {
  577 + NSLog(@"输出是否icloud的状态");
  578 + dispatch_async(dispatch_get_main_queue(), ^{
  579 + [weakSelf refreshNaviBarAndBottomBarState];
  580 + });
  581 + };
  582 + } else if (model.type == TZAssetModelMediaTypePhotoGif && _tzImagePickerVc.allowPickingGif) {
  583 + cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZGifPreviewCell" forIndexPath:indexPath];
  584 + } else {
  585 + cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZPhotoPreviewCell" forIndexPath:indexPath];
  586 + TZPhotoPreviewCell *photoPreviewCell = (TZPhotoPreviewCell *)cell;
  587 + photoPreviewCell.cropRect = _tzImagePickerVc.cropRect;
  588 + photoPreviewCell.allowCrop = _tzImagePickerVc.allowCrop;
  589 + __weak typeof(_tzImagePickerVc) weakTzImagePickerVc = _tzImagePickerVc;
  590 + __weak typeof(_collectionView) weakCollectionView = _collectionView;
  591 + __weak typeof(photoPreviewCell) weakCell = photoPreviewCell;
  592 + [photoPreviewCell setImageProgressUpdateBlock:^(double progress) {
  593 + __strong typeof(weakSelf) strongSelf = weakSelf;
  594 + __strong typeof(weakTzImagePickerVc) strongTzImagePickerVc = weakTzImagePickerVc;
  595 + __strong typeof(weakCollectionView) strongCollectionView = weakCollectionView;
  596 + __strong typeof(weakCell) strongCell = weakCell;
  597 + strongSelf.progress = progress;
  598 + if (progress >= 1) {
  599 + if (strongSelf.isSelectOriginalPhoto) [strongSelf showPhotoBytes];
  600 + if (strongSelf.alertView && [strongCollectionView.visibleCells containsObject:strongCell]) {
  601 + [strongTzImagePickerVc hideAlertView:strongSelf.alertView];
  602 + strongSelf.alertView = nil;
  603 + [strongSelf doneButtonClick];
  604 + }
  605 + }
  606 + }];
  607 + }
  608 +
  609 + cell.model = model;
  610 + [cell setSingleTapGestureBlock:^{
  611 + __strong typeof(weakSelf) strongSelf = weakSelf;
  612 + [strongSelf didTapPreviewCell];
  613 + }];
  614 + return cell;
  615 +}
  616 +
  617 +- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
  618 + if ([cell isKindOfClass:[TZPhotoPreviewCell class]]) {
  619 + [(TZPhotoPreviewCell *)cell recoverSubviews];
  620 + }
  621 +}
  622 +
  623 +- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
  624 + if ([cell isKindOfClass:[TZPhotoPreviewCell class]]) {
  625 + [(TZPhotoPreviewCell *)cell recoverSubviews];
  626 + } else if ([cell isKindOfClass:[TZVideoPreviewCell class]]) {
  627 + [(TZVideoPreviewCell *)cell pausePlayerAndShowNaviBar];
  628 + }
  629 +}
  630 +
  631 +#pragma mark - Private Method
  632 +
  633 +- (void)dealloc {
  634 + // NSLog(@"%@ dealloc",NSStringFromClass(self.class));
  635 + NSLog(@"相册_详情_TZPhotoPreviewController_dealloc");
  636 +
  637 +
  638 +}
  639 +
  640 +- (void)refreshNaviBarAndBottomBarState {
  641 +
  642 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  643 +
  644 + TZAssetModel *model = _models[_currentIndex];
  645 + _selectButton.selected = model.isSelected;
  646 + [self refreshSelectButtonImageViewContentMode];
  647 + if (_selectButton.isSelected && _tzImagePickerVc.showSelectedIndex && _tzImagePickerVc.showSelectBtn) {
  648 + NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset];
  649 + NSString *index = [NSString stringWithFormat:@"%zd", [_tzImagePickerVc.selectedAssetIds indexOfObject:assetId] + 1];
  650 + _indexLabel.text = index;
  651 + _indexLabel.hidden = NO;
  652 + } else {
  653 + _indexLabel.hidden = YES;
  654 + }
  655 + _numberLabel.text = [NSString stringWithFormat:@"%zd",_tzImagePickerVc.selectedModels.count];
  656 + _numberImageView.hidden = (_tzImagePickerVc.selectedModels.count <= 0 || _isHideNaviBar || _isCropImage);
  657 + _numberLabel.hidden = (_tzImagePickerVc.selectedModels.count <= 0 || _isHideNaviBar || _isCropImage);
  658 +
  659 +#pragma mark - 添加: 选择图片个数显示(LXG)
  660 + //隐藏图标
  661 + _numberLabel.hidden = YES;
  662 + _numberImageView.hidden = YES;
  663 + NSString *titleStr = _tzImagePickerVc.selectedModels.count > 0 ? [NSString stringWithFormat:@"完成(%zd)",_tzImagePickerVc.selectedModels.count] : @"完成";
  664 + [_doneButton setTitle:titleStr forState:UIControlStateNormal];
  665 + _originalPhotoButton.selected = _isSelectOriginalPhoto;
  666 + _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected;
  667 + if (_isSelectOriginalPhoto) [self showPhotoBytes];
  668 +
  669 + // If is previewing video, hide original photo button
  670 + // 如果正在预览的是视频,隐藏原图按钮
  671 + if (!_isHideNaviBar) {
  672 + if (model.type == TZAssetModelMediaTypeVideo) {
  673 + _originalPhotoButton.hidden = YES;
  674 + _originalPhotoLabel.hidden = YES;
  675 + } else {
  676 + _originalPhotoButton.hidden = NO;
  677 + if (_isSelectOriginalPhoto) _originalPhotoLabel.hidden = NO;
  678 + }
  679 + }
  680 +
  681 + _doneButton.hidden = NO;
  682 + _selectButton.hidden = !_tzImagePickerVc.showSelectBtn;
  683 + // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中
  684 + if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) {
  685 + _numberLabel.hidden = YES;
  686 + _numberImageView.hidden = YES;
  687 + _selectButton.hidden = YES;
  688 + _originalPhotoButton.hidden = YES;
  689 + _originalPhotoLabel.hidden = YES;
  690 + _doneButton.hidden = YES;
  691 + }
  692 +
  693 +#pragma mark - 添加: 视频显示操作(LXG)
  694 + //多选状态下**不允许**图片和视频混选
  695 + if (!_tzImagePickerVc.allowPickingMultipleVideo) {
  696 +
  697 + if (model.type == TZAssetModelMediaTypeVideo) {//多选状态下**不允许**图片和视频混选 -> 视频
  698 +
  699 + TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  700 + if (_tzImagePickerVc.selectedModels.count > 0) {//当选择图片大于0时
  701 + TZAssetModel *model = _tzImagePickerVc.selectedModels[0];
  702 + if (model.type == TZAssetModelMediaTypePhoto
  703 + || model.type == TZAssetModelMediaTypePhotoGif
  704 + ||model.type == TZAssetModelMediaTypeLivePhoto) {//选择为图片时
  705 +
  706 + _selectButton.hidden = YES;
  707 + _selectButton.enabled = NO;
  708 + _navBarLine.hidden = NO;
  709 + _tipBar.hidden = NO;
  710 + _tipContentLabel.text = @"选择照片时不能选择视频";
  711 + _doneButton.hidden = NO;
  712 + _doneButton.enabled = YES;
  713 + _editTipButton.hidden = YES;
  714 + _editTipLable.hidden = YES;
  715 +
  716 + }else{//未来可能是语音
  717 +
  718 + _selectButton.hidden = YES;
  719 + _selectButton.enabled = NO;
  720 + _navBarLine.hidden = NO;
  721 + _tipBar.hidden = NO;
  722 + _tipContentLabel.text = @"选择照片时不能选择音频";
  723 + _doneButton.hidden = NO;
  724 + _doneButton.enabled = YES;
  725 + _editTipButton.hidden = YES;
  726 + _editTipLable.hidden = YES;
  727 +
  728 + }
  729 + }else{//当选择图片==0时
  730 +
  731 + NSTimeInterval duration = 0.0;
  732 + if ([model.asset isKindOfClass:[PHAsset class]]) {
  733 + PHAsset *asset = model.asset;
  734 + duration = asset.duration;
  735 + }else if ([model.asset isKindOfClass:[ALAsset class]]){
  736 + duration = [[model.asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  737 + }
  738 +
  739 + if (duration > _tzImagePickerVc.maxVideoDuration) {//视频长度>最大限制长度
  740 +
  741 + NSInteger minutes = _tzImagePickerVc.maxVideoDuration / 60;
  742 + NSInteger seconds = _tzImagePickerVc.maxVideoDuration % 60;
  743 + NSString *timeStr = [NSString string];
  744 + if (minutes == 0) {
  745 + timeStr = [NSString stringWithFormat:@"不能分享超过%li秒视频",(long)seconds];
  746 + }else if (seconds == 0){
  747 + timeStr = [NSString stringWithFormat:@"不能分享超过%li分视频",(long)minutes];
  748 + }else{
  749 + timeStr = [NSString stringWithFormat:@"不能分享超过%li分%li秒视频",(long)minutes,(long)seconds];
  750 + }
  751 + _tipContentLabel.text = timeStr;
  752 +
  753 + //当选择图片==0时,视频长度>最大限制长度
  754 + _selectButton.hidden = YES;
  755 + _selectButton.enabled = NO;
  756 + _navBarLine.hidden = NO;
  757 + _tipBar.hidden = NO;
  758 + _tipContentLabel.text = timeStr;
  759 + _doneButton.hidden = NO;
  760 + if (_tzImagePickerVc.selectedModels.count > 0) {
  761 + _doneButton.enabled = YES;
  762 + }else{
  763 + _doneButton.enabled = NO;
  764 + }
  765 + _editTipButton.hidden = YES;
  766 + _editTipLable.hidden = YES;
  767 +
  768 + }else if(duration <= _tzImagePickerVc.maxVideoDuration && duration > _tzImagePickerVc.maxEditVideoTime){//视频长度<=最大限制长度,视频长度>=最小限制长度
  769 +
  770 + NSInteger minutes = _tzImagePickerVc.maxEditVideoTime / 60;
  771 + NSInteger seconds = _tzImagePickerVc.maxEditVideoTime % 60;
  772 + NSString *timeStr = [NSString string];
  773 + if (minutes == 0) {
  774 + timeStr = [NSString stringWithFormat:@"朋友圈只能分享%li秒限制的视频,需进行编辑",(long)seconds];
  775 + }else if (seconds == 0){
  776 + timeStr = [NSString stringWithFormat:@"朋友圈只能分享%li分限制的视频,需进行编辑",(long)minutes];
  777 + }else{
  778 + timeStr = [NSString stringWithFormat:@"朋友圈只能分享%li分%li秒限制的视频,需进行编辑",(long)minutes,(long)seconds];
  779 + }
  780 + _editTipLable.text = timeStr;
  781 + //当选择图片==0时,视频长度<=最大限制长度,视频长度>最大分享长度
  782 + _selectButton.hidden = YES;
  783 + _selectButton.enabled = NO;
  784 + _navBarLine.hidden = YES;
  785 + _tipBar.hidden = YES;
  786 + _tipContentLabel.text = timeStr;
  787 + _doneButton.hidden = YES;
  788 + _doneButton.enabled = YES;
  789 + _editTipButton.hidden = NO;
  790 + _editTipLable.hidden = NO;
  791 +
  792 + }else{//视频长度<=最大分享长度
  793 + //当选择图片==0时,视频长度<=最大分享长度
  794 + _selectButton.hidden = YES;
  795 + _selectButton.enabled = NO;
  796 + _navBarLine.hidden = YES;
  797 + _tipBar.hidden = YES;
  798 + _doneButton.hidden = NO;
  799 + _doneButton.enabled = YES;
  800 + _editTipButton.hidden = YES;
  801 + _editTipLable.hidden = YES;
  802 + }
  803 + }
  804 +
  805 + } else {//滑动到不是视频时
  806 + //滑动到不是视频时
  807 + _selectButton.hidden = NO;
  808 + _selectButton.enabled = YES;
  809 + _navBarLine.hidden = YES;
  810 + _tipBar.hidden = YES;
  811 + _doneButton.hidden = NO;
  812 + _doneButton.enabled = YES;
  813 + _editTipButton.hidden = YES;
  814 + _editTipLable.hidden = YES;
  815 +
  816 + }
  817 + }else{///多选状态下**允许**图片和视频混选(lxg)
  818 + NSTimeInterval duration = 0.0;
  819 + if ([model.asset isKindOfClass:[PHAsset class]]) {
  820 + PHAsset *asset = model.asset;
  821 + duration = asset.duration;
  822 + }else if([model.asset isKindOfClass:[ALAsset class]]) {
  823 + duration = [[model.asset valueForProperty:ALAssetPropertyDuration] doubleValue];
  824 + }
  825 + if (model.type == TZAssetModelMediaTypeVideo
  826 + && duration > _tzImagePickerVc.maxVideoDuration) {//视频,支持混选,时长超过最大时长限制
  827 + NSInteger minutes = _tzImagePickerVc.maxVideoDuration / 60;
  828 + NSInteger seconds = _tzImagePickerVc.maxVideoDuration % 60;
  829 + NSString *timeStr = [NSString string];
  830 + if (minutes == 0) {
  831 + timeStr = [NSString stringWithFormat:@"不能选择超过%li秒视频",(long)seconds];
  832 + }else if (seconds == 0){
  833 + timeStr = [NSString stringWithFormat:@"不能选择超过%li分视频",(long)minutes];
  834 + }else{
  835 + timeStr = [NSString stringWithFormat:@"不能选择超过%li分%li秒视频",(long)minutes,(long)seconds];
  836 + }
  837 +
  838 + _selectButton.hidden = YES;
  839 + _selectButton.enabled = NO;
  840 + _selectButton.enabled = NO;
  841 + _navBarLine.hidden = NO;
  842 + _tipBar.hidden = NO;
  843 + _tipContentLabel.text = timeStr;
  844 + _doneButton.hidden = NO;
  845 + if (_tzImagePickerVc.selectedModels.count > 0) {
  846 + _doneButton.enabled = YES;
  847 + }else{
  848 + _doneButton.enabled = NO;
  849 + }
  850 + _editTipButton.hidden = YES;
  851 + _editTipLable.hidden = YES;
  852 +
  853 +
  854 + }else{///多选状态下**允许**图片和视频混选(lxg) - 不是视频 || 视频<= _tzImagePickerVc.maxVideoDuration 最大时长限制
  855 +
  856 + _selectButton.hidden = NO;
  857 + _selectButton.enabled = YES;
  858 + _navBarLine.hidden = YES;
  859 + _tipBar.hidden = YES;
  860 + _doneButton.hidden = NO;
  861 + _doneButton.enabled = YES;
  862 + _editTipButton.hidden = YES;
  863 + _editTipLable.hidden = YES;
  864 +
  865 + }
  866 +
  867 + }
  868 +
  869 + ///LXG:添加预览按钮进来判断
  870 + if (self.enterType == PhotoPreviewEnterTypeSelected) {
  871 + if (_tzImagePickerVc.selectedModels.count <= 0) {
  872 + _doneButton.enabled = NO;
  873 + }else{
  874 + _doneButton.enabled = YES;
  875 + }
  876 + }else{
  877 +
  878 + }
  879 +
  880 +#pragma mark - ///iCloud加载视频
  881 + if (model.type == TZAssetModelMediaTypeVideo) {
  882 + ///iCloud加载视频
  883 + if (model.isCheckICloudType && model.isICloudType && !model.isVideoICloudDownLoad) {
  884 + _selectButton.hidden = YES;
  885 + _selectButton.enabled = NO;
  886 + _doneButton.hidden = NO;
  887 + _doneButton.enabled = NO;
  888 + _navBarLine.hidden = NO;
  889 + _tipBar.hidden = NO;
  890 + _tipContentLabel.text = @"正在同步iCloud中...";
  891 + _editTipButton.hidden = YES;
  892 + _editTipLable.hidden = YES;
  893 + }
  894 +
  895 + ///识别中
  896 + if (!model.isCheckICloudType) {
  897 + _selectButton.hidden = YES;
  898 + _selectButton.enabled = NO;
  899 + _doneButton.hidden = NO;
  900 + _doneButton.enabled = NO;
  901 + _navBarLine.hidden = NO;
  902 + _tipBar.hidden = NO;
  903 + _tipContentLabel.text = @"正在识别中...";
  904 + _editTipButton.hidden = YES;
  905 + _editTipLable.hidden = YES;
  906 + }
  907 +
  908 + }
  909 +
  910 +}
  911 +
  912 +- (void)refreshSelectButtonImageViewContentMode {
  913 + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  914 + if (self->_selectButton.imageView.image.size.width <= 27) {
  915 + self->_selectButton.imageView.contentMode = UIViewContentModeCenter;
  916 + } else {
  917 + self->_selectButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
  918 + }
  919 + });
  920 +}
  921 +
  922 +- (void)showPhotoBytes {
  923 + [[TZImageManager manager] getPhotosBytesWithArray:@[_models[_currentIndex]] completion:^(NSString *totalBytes) {
  924 + self->_originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes];
  925 + }];
  926 +}
  927 +
  928 +@end
... ...
CNLiveImagePickerController/Classes/TZProgressView.h 0 → 100755
  1 +//
  2 +// TZProgressView.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/6.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface TZProgressView : UIView
  12 +
  13 +@property (nonatomic, assign) double progress;
  14 +
  15 +@end
... ...
CNLiveImagePickerController/Classes/TZProgressView.m 0 → 100755
  1 +//
  2 +// TZProgressView.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/6.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZProgressView.h"
  10 +
  11 +@interface TZProgressView ()
  12 +@property (nonatomic, strong) CAShapeLayer *progressLayer;
  13 +@end
  14 +
  15 +@implementation TZProgressView
  16 +
  17 +- (instancetype)init {
  18 + self = [super init];
  19 + if (self) {
  20 + self.backgroundColor = [UIColor clearColor];
  21 +
  22 + _progressLayer = [CAShapeLayer layer];
  23 + _progressLayer.fillColor = [[UIColor clearColor] CGColor];
  24 + _progressLayer.strokeColor = [[UIColor whiteColor] CGColor];
  25 + _progressLayer.opacity = 1;
  26 + _progressLayer.lineCap = kCALineCapRound;
  27 + _progressLayer.lineWidth = 5;
  28 +
  29 + [_progressLayer setShadowColor:[UIColor blackColor].CGColor];
  30 + [_progressLayer setShadowOffset:CGSizeMake(1, 1)];
  31 + [_progressLayer setShadowOpacity:0.5];
  32 + [_progressLayer setShadowRadius:2];
  33 + }
  34 + return self;
  35 +}
  36 +
  37 +- (void)drawRect:(CGRect)rect {
  38 + CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);
  39 + CGFloat radius = rect.size.width / 2;
  40 + CGFloat startA = - M_PI_2;
  41 + CGFloat endA = - M_PI_2 + M_PI * 2 * _progress;
  42 + _progressLayer.frame = self.bounds;
  43 + UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
  44 + _progressLayer.path =[path CGPath];
  45 +
  46 + [_progressLayer removeFromSuperlayer];
  47 + [self.layer addSublayer:_progressLayer];
  48 +}
  49 +
  50 +- (void)setProgress:(double)progress {
  51 + _progress = progress;
  52 + [self setNeedsDisplay];
  53 +}
  54 +
  55 +@end
... ...
CNLiveImagePickerController/Classes/TZVideoPlayerController.h 0 → 100755
  1 +//
  2 +// TZVideoPlayerController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZVideoPlayerController : UIViewController
  13 +
  14 +@property (nonatomic, copy) void(^videoFinishedAction)(TZAssetModel *model,BOOL isOther);
  15 +
  16 +@property (nonatomic, strong) TZAssetModel *model;
  17 +///其他进入和相册进入(lxg)
  18 +@property (nonatomic, assign) BOOL isOther;
  19 +
  20 +@end
... ...
CNLiveImagePickerController/Classes/TZVideoPlayerController.m 0 → 100755
  1 +//
  2 +// TZVideoPlayerController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZVideoPlayerController.h"
  10 +#import <MediaPlayer/MediaPlayer.h>
  11 +#import "UIView+TZLayout.h"
  12 +#import "TZImageManager.h"
  13 +#import "TZAssetModel.h"
  14 +#import "TZImagePickerController.h"
  15 +#import "TZPhotoPreviewController.h"
  16 +#import "CNAudioOrVideoMananger.h"
  17 +
  18 +@interface TZVideoPlayerController () {
  19 + AVPlayer *_player;
  20 + AVPlayerLayer *_playerLayer;
  21 + UIButton *_playButton;
  22 + UIImage *_cover;
  23 + ///LXG nav属性
  24 + UIView *_naviBar;
  25 + UIButton *_backButton;
  26 +
  27 + UIView *_toolBar;
  28 + UIButton *_doneButton;
  29 + UIProgressView *_progress;
  30 +
  31 + UIStatusBarStyle _originStatusBarStyle;
  32 +}
  33 +@property (assign, nonatomic) BOOL needShowStatusBar;
  34 +@end
  35 +
  36 +#pragma clang diagnostic push
  37 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  38 +
  39 +@implementation TZVideoPlayerController
  40 +
  41 +- (void)viewDidLoad {
  42 + [super viewDidLoad];
  43 + ///LXG 注释
  44 +// self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden;
  45 + self.view.backgroundColor = [UIColor blackColor];
  46 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  47 + if (tzImagePickerVc) {
  48 + self.navigationItem.title = tzImagePickerVc.previewBtnTitleStr;
  49 + }
  50 + [self configMoviePlayer];
  51 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil];
  52 + [[NSNotificationCenter defaultCenter] addObserver:self
  53 + selector:@selector(pauseVideoView:) name:CNVideoOrAudioEnterNotification
  54 + object:nil];
  55 +
  56 + [[NSNotificationCenter defaultCenter] addObserver:self
  57 + selector:@selector(playVideoView:) name:CNVideoOrAudioOutNotification
  58 + object:nil];
  59 +}
  60 +#pragma mark - 添加: 导航栏(LXG)
  61 +- (void)viewWillAppear:(BOOL)animated {
  62 + [super viewWillAppear:animated];
  63 + _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle;
  64 + ///LXG 导航栏隐藏
  65 + [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
  66 + [self.navigationController setNavigationBarHidden:YES animated:YES];
  67 + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
  68 +}
  69 +
  70 +- (void)viewWillDisappear:(BOOL)animated {
  71 + [super viewWillDisappear:animated];
  72 + ///LXG 导航栏显示
  73 + [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle;
  74 + [self.navigationController setNavigationBarHidden:NO animated:YES];
  75 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  76 + if (tzImagePickerVc.needShowStatusBar && iOS7Later) {
  77 + [UIApplication sharedApplication].statusBarHidden = NO;
  78 + }
  79 + [TZImageManager manager].shouldFixOrientation = NO;
  80 +}
  81 +///LXG iOS7之后使用
  82 +- (BOOL)prefersStatusBarHidden {
  83 + return YES;
  84 +}
  85 +
  86 +- (void)configMoviePlayer {
  87 + [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
  88 + if (!isDegraded && photo) {
  89 + self->_cover = photo;
  90 + self->_doneButton.enabled = YES;
  91 + }
  92 + }];
  93 + [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
  94 + dispatch_async(dispatch_get_main_queue(), ^{
  95 + self->_player = [AVPlayer playerWithPlayerItem:playerItem];
  96 + self->_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self->_player];
  97 + self->_playerLayer.frame = self.view.bounds;
  98 + [self.view.layer addSublayer:self->_playerLayer];
  99 + [self addProgressObserver];
  100 + [self configCustomNaviBar];
  101 + [self configPlayButton];
  102 + [self configBottomToolBar];
  103 + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem];
  104 + });
  105 + }];
  106 +}
  107 +
  108 +/// Show progress,do it next time / 给播放器添加进度更新,下次加上
  109 +- (void)addProgressObserver{
  110 + AVPlayerItem *playerItem = _player.currentItem;
  111 + UIProgressView *progress = _progress;
  112 + [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
  113 + float current = CMTimeGetSeconds(time);
  114 + float total = CMTimeGetSeconds([playerItem duration]);
  115 + if (current) {
  116 + [progress setProgress:(current/total) animated:YES];
  117 + }
  118 + }];
  119 +}
  120 +
  121 +- (void)configPlayButton {
  122 + _playButton = [UIButton buttonWithType:UIButtonTypeCustom];
  123 + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
  124 + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
  125 + [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
  126 + [self.view addSubview:_playButton];
  127 +}
  128 +///XLG 自定义NAV
  129 +- (void)configCustomNaviBar {
  130 +
  131 + _naviBar = [[UIView alloc] initWithFrame:CGRectZero];
  132 + _naviBar.backgroundColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:0.7];
  133 +
  134 + _backButton = [[UIButton alloc] initWithFrame:CGRectZero];
  135 + [_backButton setImage:[UIImage imageNamedFromMyBundle:@"navi_back"] forState:UIControlStateNormal];
  136 + [_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
  137 + [_backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside];
  138 +
  139 + [_naviBar addSubview:_backButton];
  140 + [self.view addSubview:_naviBar];
  141 +}
  142 +
  143 +
  144 +
  145 +- (void)configBottomToolBar {
  146 + _toolBar = [[UIView alloc] initWithFrame:CGRectZero];
  147 + CGFloat rgb = 34 / 255.0;
  148 + _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
  149 +
  150 + _doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
  151 + _doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
  152 + if (!_cover) {
  153 + _doneButton.enabled = NO;
  154 + }
  155 + [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
  156 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  157 + if (tzImagePickerVc) {
  158 + [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
  159 + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
  160 + } else {
  161 + [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
  162 + [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
  163 + }
  164 + [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled];
  165 + [_toolBar addSubview:_doneButton];
  166 + [self.view addSubview:_toolBar];
  167 +
  168 + if (tzImagePickerVc.videoPreviewPageUIConfigBlock) {
  169 + tzImagePickerVc.videoPreviewPageUIConfigBlock(_playButton, _toolBar, _doneButton);
  170 + }
  171 +}
  172 +
  173 +#pragma mark - Layout
  174 +
  175 +- (void)viewDidLayoutSubviews {
  176 + [super viewDidLayoutSubviews];
  177 +
  178 + CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight];
  179 + CGFloat statusBarAndNaviBarHeight = statusBarHeight + self.navigationController.navigationBar.tz_height;
  180 + _playerLayer.frame = self.view.bounds;
  181 + CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
  182 + _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
  183 + _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
  184 + _playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight);
  185 +
  186 + TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
  187 + ///LXG NAV布局
  188 + if (_isOther) {
  189 + CGFloat statusBarHeightInterval = statusBarHeight - 20;
  190 + CGFloat naviBarHeight = statusBarHeight + 44;
  191 + _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight);
  192 + _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44);
  193 + //完成按钮
  194 + _doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  195 + [_doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  196 + [_doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  197 + [_doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  198 +
  199 + //颜色绘制成图片
  200 + UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  201 + [_doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  202 + UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  203 + [_doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  204 + _doneButton.layer.masksToBounds = YES;
  205 + _doneButton.layer.cornerRadius = 5;
  206 + CGRect frame = _toolBar.frame;
  207 + _doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  208 +
  209 + }else{
  210 + CGFloat statusBarHeightInterval = statusBarHeight - 20;
  211 + CGFloat naviBarHeight = statusBarHeight + tzImagePickerVc.navigationBar.tz_height;
  212 + _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight);
  213 + _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44);
  214 + }
  215 + [self.view bringSubviewToFront:_naviBar];
  216 + if (tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock) {
  217 + tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock(_playButton, _toolBar, _doneButton);
  218 + }
  219 +}
  220 +
  221 +#pragma mark - Click Event
  222 +
  223 +- (void)playButtonClick {
  224 +
  225 + if ([CNAudioOrVideoMananger IsEnter]) {//在房间
  226 + [QMUITips showWithText:@"音视频通话中..." inView:AppKeyWindow hideAfterDelay:1.5];
  227 + return;
  228 + }
  229 +
  230 + CMTime currentTime = _player.currentItem.currentTime;
  231 + CMTime durationTime = _player.currentItem.duration;
  232 + if (_player.rate == 0.0f) {
  233 + if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
  234 + [_player play];
  235 + [self.navigationController setNavigationBarHidden:YES];
  236 + _toolBar.hidden = YES;
  237 + ///LXG 隐藏NAV
  238 + _naviBar.hidden = YES;
  239 + [_playButton setImage:nil forState:UIControlStateNormal];
  240 + if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
  241 + } else {
  242 + [self pausePlayerAndShowNaviBar];
  243 + }
  244 +}
  245 +
  246 +#pragma mark - TODO: 导出done
  247 +- (void)doneButtonClick {
  248 +
  249 + if (self.videoFinishedAction) {
  250 + self.videoFinishedAction(self.model, self.isOther);
  251 + }
  252 +
  253 + if (self.navigationController) {
  254 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  255 + if (imagePickerVc.autoDismiss) {
  256 + [self.navigationController dismissViewControllerAnimated:YES completion:^{
  257 + [self callDelegateMethod];
  258 + }];
  259 + } else {
  260 + [self callDelegateMethod];
  261 + }
  262 + } else {
  263 + [self dismissViewControllerAnimated:YES completion:^{
  264 + [self callDelegateMethod];
  265 + }];
  266 + }
  267 +}
  268 +
  269 +- (void)callDelegateMethod {
  270 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  271 + if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) {
  272 + [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset];
  273 + }
  274 + if (imagePickerVc.didFinishPickingVideoHandle) {
  275 + imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset);
  276 + }
  277 +}
  278 +
  279 +///LXG 返回实现
  280 +- (void)backButtonClick {
  281 +
  282 + if (self.videoFinishedAction) {
  283 + self.videoFinishedAction(self.model, self.isOther);
  284 + }
  285 + if (self.navigationController) {
  286 + TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
  287 + [imagePickerVc popViewControllerAnimated:YES];
  288 + } else {
  289 + [self dismissViewControllerAnimated:YES completion:^{
  290 +
  291 + }];
  292 + }
  293 +}
  294 +
  295 +
  296 +#pragma mark - Notification Method
  297 +
  298 +- (void)pausePlayerAndShowNaviBar {
  299 + [_player pause];
  300 + _toolBar.hidden = NO;
  301 + _naviBar.hidden = NO;
  302 +// [self.navigationController setNavigationBarHidden:NO];
  303 + [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
  304 + ///LXG 注释
  305 +// if (self.needShowStatusBar && iOS7Later) {
  306 +// [UIApplication sharedApplication].statusBarHidden = NO;
  307 +// }
  308 +}
  309 +
  310 +- (void)pauseVideoView:(NSNotification *)note
  311 +{
  312 + [self playButtonClick];
  313 +}
  314 +
  315 +- (void)playVideoView:(NSNotification *)note
  316 +{
  317 +
  318 +
  319 +}
  320 +
  321 +
  322 +- (void)dealloc {
  323 + [[NSNotificationCenter defaultCenter] removeObserver:self];
  324 +}
  325 +
  326 +#pragma clang diagnostic pop
  327 +
  328 +@end
... ...
CNLiveImagePickerController/Classes/UIView+TZLayout.h 0 → 100755
  1 +//
  2 +// UIView+TZLayout.h
  3 +//
  4 +// Created by 谭真 on 15/2/24.
  5 +// Copyright © 2015年 谭真. All rights reserved.
  6 +//
  7 +
  8 +#import <UIKit/UIKit.h>
  9 +
  10 +typedef enum : NSUInteger {
  11 + TZOscillatoryAnimationToBigger,
  12 + TZOscillatoryAnimationToSmaller,
  13 +} TZOscillatoryAnimationType;
  14 +
  15 +@interface UIView (TZLayout)
  16 +
  17 +@property (nonatomic) CGFloat tz_left; ///< Shortcut for frame.origin.x.
  18 +@property (nonatomic) CGFloat tz_top; ///< Shortcut for frame.origin.y
  19 +@property (nonatomic) CGFloat tz_right; ///< Shortcut for frame.origin.x + frame.size.width
  20 +@property (nonatomic) CGFloat tz_bottom; ///< Shortcut for frame.origin.y + frame.size.height
  21 +@property (nonatomic) CGFloat tz_width; ///< Shortcut for frame.size.width.
  22 +@property (nonatomic) CGFloat tz_height; ///< Shortcut for frame.size.height.
  23 +@property (nonatomic) CGFloat tz_centerX; ///< Shortcut for center.x
  24 +@property (nonatomic) CGFloat tz_centerY; ///< Shortcut for center.y
  25 +@property (nonatomic) CGPoint tz_origin; ///< Shortcut for frame.origin.
  26 +@property (nonatomic) CGSize tz_size; ///< Shortcut for frame.size.
  27 +
  28 ++ (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type;
  29 +
  30 +@end
... ...
CNLiveImagePickerController/Classes/UIView+TZLayout.m 0 → 100755
  1 +//
  2 +// UIView+TZLayout.m
  3 +//
  4 +// Created by 谭真 on 15/2/24.
  5 +// Copyright © 2015年 谭真. All rights reserved.
  6 +//
  7 +
  8 +#import "UIView+TZLayout.h"
  9 +
  10 +@implementation UIView (TZLayout)
  11 +
  12 +- (CGFloat)tz_left {
  13 + return self.frame.origin.x;
  14 +}
  15 +
  16 +- (void)setTz_left:(CGFloat)x {
  17 + CGRect frame = self.frame;
  18 + frame.origin.x = x;
  19 + self.frame = frame;
  20 +}
  21 +
  22 +- (CGFloat)tz_top {
  23 + return self.frame.origin.y;
  24 +}
  25 +
  26 +- (void)setTz_top:(CGFloat)y {
  27 + CGRect frame = self.frame;
  28 + frame.origin.y = y;
  29 + self.frame = frame;
  30 +}
  31 +
  32 +- (CGFloat)tz_right {
  33 + return self.frame.origin.x + self.frame.size.width;
  34 +}
  35 +
  36 +- (void)setTz_right:(CGFloat)right {
  37 + CGRect frame = self.frame;
  38 + frame.origin.x = right - frame.size.width;
  39 + self.frame = frame;
  40 +}
  41 +
  42 +- (CGFloat)tz_bottom {
  43 + return self.frame.origin.y + self.frame.size.height;
  44 +}
  45 +
  46 +- (void)setTz_bottom:(CGFloat)bottom {
  47 + CGRect frame = self.frame;
  48 + frame.origin.y = bottom - frame.size.height;
  49 + self.frame = frame;
  50 +}
  51 +
  52 +- (CGFloat)tz_width {
  53 + return self.frame.size.width;
  54 +}
  55 +
  56 +- (void)setTz_width:(CGFloat)width {
  57 + CGRect frame = self.frame;
  58 + frame.size.width = width;
  59 + self.frame = frame;
  60 +}
  61 +
  62 +- (CGFloat)tz_height {
  63 + return self.frame.size.height;
  64 +}
  65 +
  66 +- (void)setTz_height:(CGFloat)height {
  67 + CGRect frame = self.frame;
  68 + frame.size.height = height;
  69 + self.frame = frame;
  70 +}
  71 +
  72 +- (CGFloat)tz_centerX {
  73 + return self.center.x;
  74 +}
  75 +
  76 +- (void)setTz_centerX:(CGFloat)centerX {
  77 + self.center = CGPointMake(centerX, self.center.y);
  78 +}
  79 +
  80 +- (CGFloat)tz_centerY {
  81 + return self.center.y;
  82 +}
  83 +
  84 +- (void)setTz_centerY:(CGFloat)centerY {
  85 + self.center = CGPointMake(self.center.x, centerY);
  86 +}
  87 +
  88 +- (CGPoint)tz_origin {
  89 + return self.frame.origin;
  90 +}
  91 +
  92 +- (void)setTz_origin:(CGPoint)origin {
  93 + CGRect frame = self.frame;
  94 + frame.origin = origin;
  95 + self.frame = frame;
  96 +}
  97 +
  98 +- (CGSize)tz_size {
  99 + return self.frame.size;
  100 +}
  101 +
  102 +- (void)setTz_size:(CGSize)size {
  103 + CGRect frame = self.frame;
  104 + frame.size = size;
  105 + self.frame = frame;
  106 +}
  107 +
  108 ++ (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(TZOscillatoryAnimationType)type{
  109 + NSNumber *animationScale1 = type == TZOscillatoryAnimationToBigger ? @(1.15) : @(0.5);
  110 + NSNumber *animationScale2 = type == TZOscillatoryAnimationToBigger ? @(0.92) : @(1.15);
  111 +
  112 + [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
  113 + [layer setValue:animationScale1 forKeyPath:@"transform.scale"];
  114 + } completion:^(BOOL finished) {
  115 + [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
  116 + [layer setValue:animationScale2 forKeyPath:@"transform.scale"];
  117 + } completion:^(BOOL finished) {
  118 + [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{
  119 + [layer setValue:@(1.0) forKeyPath:@"transform.scale"];
  120 + } completion:nil];
  121 + }];
  122 + }];
  123 +}
  124 +
  125 +@end
... ...
CNLiveImagePickerController/Classes/placeImg.png 0 → 100644

7.02 KB