Commit e69396e3194e1955a4342113964d82795bbf1ec9
1 parent
506347e9
提交创建
Showing
109 changed files
with
1239 additions
and
8995 deletions
.gitignore
0 → 100644
| 1 | +# OS X | |
| 2 | +.DS_Store | |
| 3 | + | |
| 4 | +# Xcode | |
| 5 | +build/ | |
| 6 | +Products/ | |
| 7 | +*.pbxuser | |
| 8 | +!default.pbxuser | |
| 9 | +*.mode1v3 | |
| 10 | +!default.mode1v3 | |
| 11 | +*.mode2v3 | |
| 12 | +!default.mode2v3 | |
| 13 | +*.perspectivev3 | |
| 14 | +!default.perspectivev3 | |
| 15 | +xcuserdata/ | |
| 16 | +*.xccheckout | |
| 17 | +profile | |
| 18 | +*.moved-aside | |
| 19 | +DerivedData | |
| 20 | +*.hmap | |
| 21 | +*.ipa | |
| 22 | + | |
| 23 | +# Bundler | |
| 24 | +.bundle | |
| 25 | + | |
| 26 | +# Add this line if you want to avoid checking in source code from Carthage dependencies. | |
| 27 | +# Carthage/Checkouts | |
| 28 | + | |
| 29 | +Carthage/Build | |
| 30 | + | |
| 31 | +# We recommend against adding the Pods directory to your .gitignore. However | |
| 32 | +# you should judge for yourself, the pros and cons are mentioned at: | |
| 33 | +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control | |
| 34 | +# | |
| 35 | +# Note: if you ignore the Pods directory, make sure to uncomment | |
| 36 | +# `pod install` in .travis.yml | |
| 37 | +# | |
| 38 | +# Pods/ | ... | ... |
CNLiveImagePickerController.podspec
| 1 | 1 | # |
| 2 | -# Be sure to run `pod spec lint CNLiveImagePickerController.podspec' to ensure this is a | |
| 3 | -# valid spec and to remove all comments including this before submitting the spec. | |
| 2 | +# Be sure to run `pod lib lint CNLiveImagePickerController.podspec' to ensure this is a | |
| 3 | +# valid spec before submitting. | |
| 4 | 4 | # |
| 5 | -# To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html | |
| 6 | -# To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ | |
| 5 | +# Any lines starting with a # are optional, but their use is encouraged | |
| 6 | +# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html | |
| 7 | 7 | # |
| 8 | 8 | |
| 9 | 9 | Pod::Spec.new do |s| |
| 10 | - | |
| 11 | -# | |
| 12 | - # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 13 | - # | |
| 14 | - # These will help people to find your library, and whilst it | |
| 15 | - # can feel like a chore to fill in it's definitely to your advantage. The | |
| 16 | - # summary should be tweet-length, and the description more in depth. | |
| 17 | - # | |
| 18 | - | |
| 19 | - s.name = "CNLiveImagePickerController" # 项目名称 | |
| 20 | - s.version = "0.0.2" # 版本号 与 你仓库的 标签号 对应 | |
| 21 | - s.summary = "相册选择基于TZImagePickerController" # 项目简介 | |
| 22 | - | |
| 23 | - # This description is used to generate tags and improve search results. | |
| 24 | - # * Think: What does it do? Why did you write it? What is the focus? | |
| 25 | - # * Try to keep it short, snappy and to the point. | |
| 26 | - # * Write the description between the DESC delimiters below. | |
| 27 | - # * Finally, don't worry about the indent, CocoaPods strips it! | |
| 28 | - s.description = <<-DESC | |
| 29 | - 1.相册选择图片,视频 | |
| 30 | - 2.更改了相册适配问题 | |
| 31 | - DESC | |
| 32 | - | |
| 33 | - s.homepage = "http://bj.gitlab.cnlive.com/ios-team/CNLiveImagePickerController" | |
| 34 | - | |
| 35 | - # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif" | |
| 36 | - | |
| 37 | - | |
| 38 | - # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 39 | - # | |
| 40 | - # Licensing your code is important. See http://choosealicense.com for more info. | |
| 41 | - # CocoaPods will detect a license file if there is a named LICENSE* | |
| 42 | - # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'. | |
| 43 | - # | |
| 44 | - | |
| 45 | - s.license = "MIT" # 开源证书 | |
| 46 | - # s.license = { :type => "MIT", :file => "FILE_LICENSE" } | |
| 47 | - | |
| 48 | - | |
| 49 | - # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 50 | - # | |
| 51 | - # Specify the authors of the library, with email addresses. Email addresses | |
| 52 | - # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also | |
| 53 | - # accepts just a name if you'd rather not provide an email address. | |
| 54 | - # | |
| 55 | - # Specify a social_media_url where others can refer to, for example a twitter | |
| 56 | - # profile URL. | |
| 57 | - # | |
| 58 | - | |
| 59 | - s.author = { "梁星国" => "liangxingguo@cnlive.com" } | |
| 60 | - # Or just: s.author = "梁星国" | |
| 61 | - # s.authors = { "梁星国" => "jyyjkt@qq.com" } | |
| 62 | - # s.social_media_url = "http://twitter.com/梁星国" | |
| 63 | - | |
| 64 | - # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 65 | - # | |
| 66 | - # If this Pod runs only on iOS or OS X, then specify the platform and | |
| 67 | - # the deployment target. You can optionally include the target after the platform. | |
| 68 | - # | |
| 69 | - | |
| 70 | - # s.platform = :ios | |
| 71 | - s.platform = :ios, "9.0" | |
| 72 | - | |
| 73 | - # When using multiple platforms | |
| 74 | - # s.ios.deployment_target = "5.0" | |
| 75 | - # s.osx.deployment_target = "10.7" | |
| 76 | - # s.watchos.deployment_target = "2.0" | |
| 77 | - # s.tvos.deployment_target = "9.0" | |
| 78 | - | |
| 79 | - | |
| 80 | - # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 81 | - # | |
| 82 | - # Specify the location from where the source should be retrieved. | |
| 83 | - # Supports git, hg, bzr, svn and HTTP. | |
| 84 | - # | |
| 85 | - | |
| 86 | - s.source = { :git => "http://bj.gitlab.cnlive.com/ios-team/CNLiveImagePickerController.git", :tag => "#{s.version}" } #你的仓库地址 | |
| 87 | - | |
| 88 | - | |
| 89 | - # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 90 | - # | |
| 91 | - # CocoaPods is smart about how it includes source code. For source files | |
| 92 | - # giving a folder will include any swift, h, m, mm, c & cpp files. | |
| 93 | - # For header files it will include any header in the folder. | |
| 94 | - # Not including the public_header_files will make all headers public. | |
| 95 | - # | |
| 96 | - | |
| 97 | - s.source_files = "CNLiveImagePickerController/*" | |
| 98 | - s.exclude_files = "Classes/Exclude" | |
| 99 | - | |
| 100 | - # s.public_header_files = "Classes/**/*.h" | |
| 101 | - | |
| 102 | - | |
| 103 | - # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 104 | - # | |
| 105 | - # A list of resources included with the Pod. These are copied into the | |
| 106 | - # target bundle with a build phase script. Anything else will be cleaned. | |
| 107 | - # You can preserve files from being cleaned, please don't preserve | |
| 108 | - # non-essential files like tests, examples and documentation. | |
| 109 | - # | |
| 110 | - | |
| 111 | - # s.resource = "icon.png" | |
| 112 | - # s.resources = "Resources/*.png" | |
| 113 | - | |
| 114 | - # s.preserve_paths = "FilesToSave", "MoreFilesToSave" | |
| 115 | - | |
| 116 | - | |
| 117 | - # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 118 | - # | |
| 119 | - # Link your library with frameworks, or libraries. Libraries do not include | |
| 120 | - # the lib prefix of their name. | |
| 121 | - # | |
| 122 | - | |
| 123 | - # s.framework = "SomeFramework" | |
| 124 | - s.frameworks = "UIKit", "Foundation" #支持的框架 | |
| 125 | - | |
| 126 | - # s.library = "iconv" | |
| 127 | - # s.libraries = "iconv", "xml2" | |
| 128 | - | |
| 129 | - | |
| 130 | - # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # | |
| 131 | - # | |
| 132 | - # If your library depends on compiler flags you can set them in the xcconfig hash | |
| 133 | - # where they will only apply to your library. If you depend on other Podspecs | |
| 134 | - # you can include multiple dependencies to ensure it works. | |
| 135 | - | |
| 136 | - s.requires_arc = true | |
| 137 | - | |
| 138 | - # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } | |
| 139 | - # s.dependency "JSONKit", "~> 1.4" | |
| 140 | - | |
| 10 | + s.name = 'CNLiveImagePickerController' | |
| 11 | + s.version = '0.1.0' | |
| 12 | + s.summary = 'A short description of CNLiveImagePickerController.' | |
| 13 | + | |
| 14 | +# This description is used to generate tags and improve search results. | |
| 15 | +# * Think: What does it do? Why did you write it? What is the focus? | |
| 16 | +# * Try to keep it short, snappy and to the point. | |
| 17 | +# * Write the description between the DESC delimiters below. | |
| 18 | +# * Finally, don't worry about the indent, CocoaPods strips it! | |
| 19 | + | |
| 20 | + s.description = <<-DESC | |
| 21 | +TODO: Add long description of the pod here. | |
| 22 | + DESC | |
| 23 | + | |
| 24 | + s.homepage = 'https://github.com/jyyjkt/CNLiveImagePickerController' | |
| 25 | + # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' | |
| 26 | + s.license = { :type => 'MIT', :file => 'LICENSE' } | |
| 27 | + s.author = { 'jyyjkt' => 'jyyjkt@qq.com' } | |
| 28 | + s.source = { :git => 'https://github.com/jyyjkt/CNLiveImagePickerController.git', :tag => s.version.to_s } | |
| 29 | + # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>' | |
| 30 | + | |
| 31 | + s.ios.deployment_target = '8.0' | |
| 32 | + | |
| 33 | + s.source_files = 'CNLiveImagePickerController/Classes/**/*' | |
| 34 | + | |
| 35 | + # s.resource_bundles = { | |
| 36 | + # 'CNLiveImagePickerController' => ['CNLiveImagePickerController/Assets/*.png'] | |
| 37 | + # } | |
| 38 | + | |
| 39 | + # s.public_header_files = 'Pod/Classes/**/*.h' | |
| 40 | + # s.frameworks = 'UIKit', 'MapKit' | |
| 41 | + # s.dependency 'AFNetworking', '~> 2.3' | |
| 141 | 42 | end | ... | ... |
CNLiveImagePickerController/Assets/.gitkeep
0 → 100644
CNLiveImagePickerController/CNEditVideoController.h deleted
100755 → 0
| 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/CNEditVideoController.m deleted
100755 → 0
| 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.frame.size.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, [UIScreen mainScreen].bounds.size.width-30, [UIScreen mainScreen].bounds.size.height-160-inset.bottom); | |
| 308 | - | |
| 309 | - self.editView.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width-kItemWidth*10)/2, [UIScreen mainScreen].bounds.size.height-100-inset.bottom, kItemWidth*10, kItemHeight); | |
| 310 | - self.editView.validRect = self.editView.bounds; | |
| 311 | - self.collectionView.frame = CGRectMake(inset.left, [UIScreen mainScreen].bounds.size.height-100-inset.bottom, [UIScreen mainScreen].bounds.size.width-inset.left-inset.right, kItemHeight); | |
| 312 | - | |
| 313 | - CGFloat leftOffset = (([UIScreen mainScreen].bounds.size.width-kItemWidth*10)/2-inset.left); | |
| 314 | - CGFloat rightOffset = (([UIScreen mainScreen].bounds.size.width-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, [UIScreen mainScreen].bounds.size.height-bottomViewH-inset.bottom, [UIScreen mainScreen].bounds.size.width, kItemHeight); | |
| 321 | - _cancelBtn.frame = CGRectMake(10+inset.left, 7, 60, bottomBtnH); | |
| 322 | - _doneBtn.frame = CGRectMake([UIScreen mainScreen].bounds.size.width-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 (self.backButtonEditClickBlock) { | |
| 476 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 477 | - self.backButtonEditClickBlock(_tzImagePickerVc.isSelectOriginalPhoto); | |
| 478 | - } | |
| 479 | - UIViewController *vc = [self.navigationController popViewControllerAnimated:NO]; | |
| 480 | - if (!vc) { | |
| 481 | - [self dismissViewControllerAnimated:YES completion:nil]; | |
| 482 | - } | |
| 483 | -} | |
| 484 | - | |
| 485 | -- (void)btnDone_click | |
| 486 | -{ | |
| 487 | - [self stopTimer]; | |
| 488 | - | |
| 489 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 490 | - [_tzImagePickerVc showProgressHUD]; | |
| 491 | - | |
| 492 | - [self exportEditVideoForAsset:_avAsset range:[self getTimeRange] complete:^(BOOL isSuc, id asset) { | |
| 493 | - [_tzImagePickerVc hideProgressHUD]; | |
| 494 | - if (isSuc) { | |
| 495 | - TZAssetModel *editModel = [TZAssetModel modelWithAsset:asset type:TZAssetModelMediaTypeVideo]; | |
| 496 | - | |
| 497 | - // 如果没有选中过照片 点击确定时选中当前预览的照片 | |
| 498 | - if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) { | |
| 499 | - [_tzImagePickerVc addSelectedModel:editModel]; | |
| 500 | - } | |
| 501 | - | |
| 502 | - if (self.doneButtonEditClickBlock) { | |
| 503 | - self.doneButtonEditClickBlock(_tzImagePickerVc.isSelectOriginalPhoto); | |
| 504 | - } | |
| 505 | - [_tzImagePickerVc hideProgressHUD]; | |
| 506 | - }else{ | |
| 507 | - [_tzImagePickerVc showAlertWithTitle:@"编辑失败"]; | |
| 508 | - } | |
| 509 | - | |
| 510 | - }]; | |
| 511 | -} | |
| 512 | -#pragma mark - 截取视频 | |
| 513 | - | |
| 514 | -- (void)exportEditVideoForAsset:(AVAsset *)asset range:(CMTimeRange)range complete:(void (^)(BOOL, id))complete | |
| 515 | -{ | |
| 516 | - [self export:asset range:range presetName:AVAssetExportPresetPassthrough renderSize:CGSizeZero imageSize:CGSizeZero effectImage:nil birthRate:0 velocity:0 complete:^(NSString *exportFilePath, NSError *error) { | |
| 517 | - if (!error) { | |
| 518 | - [self saveVideoToAblum:[NSURL fileURLWithPath:exportFilePath] completion:^(BOOL isSuc, id asset) { | |
| 519 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 520 | - if (complete) complete(isSuc, asset); | |
| 521 | - }); | |
| 522 | - }]; | |
| 523 | - } else { | |
| 524 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 525 | - if (complete) complete(NO, nil); | |
| 526 | - }); | |
| 527 | - } | |
| 528 | - }]; | |
| 529 | -} | |
| 530 | - | |
| 531 | -///保存视频到相册 | |
| 532 | -- (void)saveVideoToAblum:(NSURL *)url completion:(void (^)(BOOL, id))completion | |
| 533 | -{ | |
| 534 | - if (iOS8Later) { | |
| 535 | - PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; | |
| 536 | - if (status == PHAuthorizationStatusDenied) { | |
| 537 | - if (completion) completion(NO, nil); | |
| 538 | - } else if (status == PHAuthorizationStatusRestricted) { | |
| 539 | - if (completion) completion(NO, nil); | |
| 540 | - } else { | |
| 541 | - __block PHObjectPlaceholder *placeholderAsset=nil; | |
| 542 | - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ | |
| 543 | - PHAssetChangeRequest *newAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url]; | |
| 544 | - placeholderAsset = newAssetRequest.placeholderForCreatedAsset; | |
| 545 | - } completionHandler:^(BOOL success, NSError * _Nullable error) { | |
| 546 | - if (!success) { | |
| 547 | - if (completion) completion(NO, nil); | |
| 548 | - return; | |
| 549 | - } | |
| 550 | - PHAsset *asset = [self getAssetFromlocalIdentifier:placeholderAsset.localIdentifier]; | |
| 551 | - PHAssetCollection *desCollection = [self getDestinationCollection]; | |
| 552 | - if (!desCollection) completion(NO, nil); | |
| 553 | - | |
| 554 | - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ | |
| 555 | - [[PHAssetCollectionChangeRequest changeRequestForAssetCollection:desCollection] addAssets:@[asset]]; | |
| 556 | - } completionHandler:^(BOOL success, NSError * _Nullable error) { | |
| 557 | - if (completion) completion(success, asset); | |
| 558 | - }]; | |
| 559 | - }]; | |
| 560 | - } | |
| 561 | - }else{ | |
| 562 | - | |
| 563 | - ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init]; | |
| 564 | - [assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) { | |
| 565 | - if (error) { | |
| 566 | - NSLog(@"保存视频出错:%@",error.localizedDescription); | |
| 567 | - if (completion) { | |
| 568 | - completion(NO,nil); | |
| 569 | - } | |
| 570 | - } else { | |
| 571 | - [assetLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) { | |
| 572 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 573 | - if (completion) { | |
| 574 | - completion(YES,asset); | |
| 575 | - } | |
| 576 | - }); | |
| 577 | - } failureBlock:^(NSError *error) { | |
| 578 | - | |
| 579 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 580 | - if (completion) { | |
| 581 | - completion(NO,nil); | |
| 582 | - } | |
| 583 | - }); | |
| 584 | - | |
| 585 | - }]; | |
| 586 | - } | |
| 587 | - }]; | |
| 588 | - | |
| 589 | - } | |
| 590 | - | |
| 591 | -} | |
| 592 | - | |
| 593 | -- (PHAsset *)getAssetFromlocalIdentifier:(NSString *)localIdentifier{ | |
| 594 | - if(localIdentifier == nil){ | |
| 595 | - NSLog(@"Cannot get asset from localID because it is nil"); | |
| 596 | - return nil; | |
| 597 | - } | |
| 598 | - PHFetchResult *result = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil]; | |
| 599 | - if(result.count){ | |
| 600 | - return result[0]; | |
| 601 | - } | |
| 602 | - return nil; | |
| 603 | -} | |
| 604 | - | |
| 605 | -//获取自定义相册 | |
| 606 | -- (PHAssetCollection *)getDestinationCollection | |
| 607 | -{ | |
| 608 | - //找是否已经创建自定义相册 | |
| 609 | - PHFetchResult<PHAssetCollection *> *collectionResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; | |
| 610 | - for (PHAssetCollection *collection in collectionResult) { | |
| 611 | - if ([collection.localizedTitle isEqualToString:kAPPName]) { | |
| 612 | - return collection; | |
| 613 | - } | |
| 614 | - } | |
| 615 | - //新建自定义相册 | |
| 616 | - __block NSString *collectionId = nil; | |
| 617 | - NSError *error = nil; | |
| 618 | - [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{ | |
| 619 | - collectionId = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:kAPPName].placeholderForCreatedAssetCollection.localIdentifier; | |
| 620 | - } error:&error]; | |
| 621 | - if (error) { | |
| 622 | - return nil; | |
| 623 | - } | |
| 624 | - return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[collectionId] options:nil].lastObject; | |
| 625 | -} | |
| 626 | - | |
| 627 | -- (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 | |
| 628 | -{ | |
| 629 | - NSString *exportFilePath = [self getVideoExportFilePath]; | |
| 630 | - | |
| 631 | - AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:asset presetName:presetName]; | |
| 632 | - | |
| 633 | - NSURL *exportFileUrl = [NSURL fileURLWithPath:exportFilePath]; | |
| 634 | - | |
| 635 | - exportSession.outputURL = exportFileUrl; | |
| 636 | - exportSession.outputFileType = AVFileTypeMPEG4; | |
| 637 | - exportSession.timeRange = range; | |
| 638 | - // exportSession.shouldOptimizeForNetworkUse = YES; | |
| 639 | - if (!CGSizeEqualToSize(renderSize, CGSizeZero)) { | |
| 640 | - AVMutableVideoComposition *com = [self getVideoComposition:asset renderSize:renderSize imageSize:imageSize effectImage:effectImage birthRate:birthRate velocity:velocity]; | |
| 641 | - if (!com) { | |
| 642 | - if (complete) { | |
| 643 | - complete(nil, [NSError errorWithDomain:@"视频裁剪导出失败" code:-1 userInfo:@{@"message": @"视频对象格式可能有错误,没有检测到视频通道"}]); | |
| 644 | - } | |
| 645 | - return; | |
| 646 | - } | |
| 647 | - exportSession.videoComposition = com; | |
| 648 | - } | |
| 649 | - | |
| 650 | - [exportSession exportAsynchronouslyWithCompletionHandler:^{ | |
| 651 | - BOOL suc = NO; | |
| 652 | - switch ([exportSession status]) { | |
| 653 | - case AVAssetExportSessionStatusFailed: | |
| 654 | - NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]); | |
| 655 | - break; | |
| 656 | - case AVAssetExportSessionStatusCancelled: | |
| 657 | - NSLog(@"Export canceled"); | |
| 658 | - break; | |
| 659 | - | |
| 660 | - case AVAssetExportSessionStatusCompleted:{ | |
| 661 | - NSLog(@"Export completed"); | |
| 662 | - suc = YES; | |
| 663 | - } | |
| 664 | - break; | |
| 665 | - | |
| 666 | - default: | |
| 667 | - NSLog(@"Export other"); | |
| 668 | - break; | |
| 669 | - } | |
| 670 | - | |
| 671 | - if (complete) { | |
| 672 | - complete(suc?exportFilePath:nil, suc?nil:exportSession.error); | |
| 673 | - if (!suc) { | |
| 674 | - [exportSession cancelExport]; | |
| 675 | - } | |
| 676 | - } | |
| 677 | - }]; | |
| 678 | -} | |
| 679 | - | |
| 680 | -- (NSString *)getVideoExportFilePath | |
| 681 | -{ | |
| 682 | - NSString *format = @"mp4"; | |
| 683 | - | |
| 684 | - NSString *exportFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", [self getUniqueStrByUUID], format]]; | |
| 685 | - | |
| 686 | - return exportFilePath; | |
| 687 | -} | |
| 688 | - | |
| 689 | -- (NSString *)getUniqueStrByUUID | |
| 690 | -{ | |
| 691 | - CFUUIDRef uuidObj = CFUUIDCreate(nil);//create a new UUID | |
| 692 | - | |
| 693 | - //get the string representation of the UUID | |
| 694 | - CFStringRef uuidString = CFUUIDCreateString(nil, uuidObj); | |
| 695 | - | |
| 696 | - NSString *str = [NSString stringWithString:(__bridge NSString *)uuidString]; | |
| 697 | - | |
| 698 | - CFRelease(uuidObj); | |
| 699 | - CFRelease(uuidString); | |
| 700 | - | |
| 701 | - return [str lowercaseString]; | |
| 702 | -} | |
| 703 | - | |
| 704 | - | |
| 705 | -- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset renderSize:(CGSize)renderSize imageSize:(CGSize)imageSize effectImage:(UIImage *)effectImage birthRate:(NSInteger)birthRate velocity:(CGFloat)velocity | |
| 706 | -{ | |
| 707 | - AVMutableComposition *composition = [AVMutableComposition composition]; | |
| 708 | - //视频通道 | |
| 709 | - AVMutableCompositionTrack *assetVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; | |
| 710 | - //音频通道 | |
| 711 | - AVMutableCompositionTrack *assetAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; | |
| 712 | - | |
| 713 | - NSError *error = nil; | |
| 714 | - //裁剪时长 | |
| 715 | - CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); | |
| 716 | - | |
| 717 | - AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;//视频 | |
| 718 | - AVAssetTrack *audioTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;//音频 | |
| 719 | - | |
| 720 | - if (!videoTrack) { | |
| 721 | - return nil; | |
| 722 | - } | |
| 723 | - [assetVideoTrack insertTimeRange:timeRange ofTrack:videoTrack atTime:kCMTimeZero error:&error]; | |
| 724 | - NSLog(@"%@", error); | |
| 725 | - if (audioTrack) { | |
| 726 | - [assetAudioTrack insertTimeRange:timeRange ofTrack:audioTrack atTime:kCMTimeZero error:&error]; | |
| 727 | - NSLog(@"%@", error); | |
| 728 | - } | |
| 729 | - | |
| 730 | - if (error) { | |
| 731 | - return nil; | |
| 732 | - } | |
| 733 | - | |
| 734 | - AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; | |
| 735 | - instruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration); | |
| 736 | - | |
| 737 | - //处理视频旋转 | |
| 738 | - AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:assetVideoTrack]; | |
| 739 | - [layerInstruction setOpacity:0.0 atTime:assetVideoTrack.timeRange.duration]; | |
| 740 | - //视频旋转,获取视频旋转角度,然后旋转对应角度,保持视频方向正确 | |
| 741 | - CGFloat degree = [self getVideoDegree:videoTrack]; | |
| 742 | - CGSize naturalSize = assetVideoTrack.naturalSize; | |
| 743 | - | |
| 744 | - CGAffineTransform mixedTransform = CGAffineTransformIdentity; | |
| 745 | - //处理renderSize,不能大于视频宽高 | |
| 746 | - CGFloat videoWidth = (degree==0 || degree==M_PI) ? naturalSize.width : naturalSize.height; | |
| 747 | - CGFloat videoHeight = (degree==0 || degree==M_PI) ? naturalSize.height : naturalSize.width; | |
| 748 | - CGSize cropSize = CGSizeMake(MIN(videoWidth, renderSize.width), MIN(videoHeight, renderSize.height)); | |
| 749 | - CGFloat x, y; | |
| 750 | - if (degree == M_PI_2) { | |
| 751 | - //顺时针 90° | |
| 752 | - CGAffineTransform t = CGAffineTransformMakeTranslation(naturalSize.height,.0); | |
| 753 | - CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI_2); | |
| 754 | - //x为正向下 y为正向左 | |
| 755 | - x = -(videoHeight-cropSize.height)/2; | |
| 756 | - y = (videoWidth-cropSize.width)/2; | |
| 757 | - mixedTransform = CGAffineTransformTranslate(t1, x, y); | |
| 758 | - } else if (degree == M_PI) { | |
| 759 | - //顺时针 180° | |
| 760 | - CGAffineTransform t = CGAffineTransformMakeTranslation(naturalSize.width, naturalSize.height); | |
| 761 | - CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI); | |
| 762 | - //x为正向左 y为正向上 | |
| 763 | - x = (videoWidth-cropSize.width)/2; | |
| 764 | - y = (videoHeight-cropSize.height)/2; | |
| 765 | - mixedTransform = CGAffineTransformTranslate(t1, x, y); | |
| 766 | - } else if (degree == (M_PI_2 * 3)) { | |
| 767 | - //顺时针 270° | |
| 768 | - CGAffineTransform t = CGAffineTransformMakeTranslation(.0, naturalSize.width); | |
| 769 | - CGAffineTransform t1 = CGAffineTransformRotate(t, M_PI_2*3); | |
| 770 | - //x为正向上 y为正向右 | |
| 771 | - x = (videoHeight-cropSize.height)/2; | |
| 772 | - y = -(videoWidth-cropSize.width)/2; | |
| 773 | - mixedTransform = CGAffineTransformTranslate(t1, x, y); | |
| 774 | - } else { | |
| 775 | - //x为正向右 y为正向下 | |
| 776 | - x = -(videoWidth-cropSize.width)/2; | |
| 777 | - y = -(videoHeight-cropSize.height)/2; | |
| 778 | - mixedTransform = CGAffineTransformMakeTranslation(x, y); | |
| 779 | - } | |
| 780 | - | |
| 781 | - [layerInstruction setTransform:mixedTransform atTime:kCMTimeZero]; | |
| 782 | - | |
| 783 | - //管理所有需要处理的视频 | |
| 784 | - AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; | |
| 785 | - videoComposition.frameDuration = CMTimeMake(1, 30); | |
| 786 | - videoComposition.renderScale = 1; | |
| 787 | - videoComposition.renderSize = cropSize; | |
| 788 | - | |
| 789 | - instruction.layerInstructions = @[layerInstruction]; | |
| 790 | - videoComposition.instructions = @[instruction]; | |
| 791 | - | |
| 792 | - return videoComposition; | |
| 793 | -} | |
| 794 | - | |
| 795 | -- (CGFloat)getVideoDegree:(AVAssetTrack *)videoTrack | |
| 796 | -{ | |
| 797 | - CGAffineTransform tf = videoTrack.preferredTransform; | |
| 798 | - | |
| 799 | - CGFloat degree = 0; | |
| 800 | - if (tf.b == 1.0 && tf.c == -1.0) { | |
| 801 | - degree = M_PI_2; | |
| 802 | - } else if (tf.a == -1.0 && tf.d == -1.0) { | |
| 803 | - degree = M_PI; | |
| 804 | - } else if (tf.b == -1.0 && tf.c == 1.0) { | |
| 805 | - degree = M_PI_2 * 3; | |
| 806 | - } | |
| 807 | - return degree; | |
| 808 | -} | |
| 809 | - | |
| 810 | - | |
| 811 | - | |
| 812 | -#pragma mark - timer | |
| 813 | -- (void)startTimer | |
| 814 | -{ | |
| 815 | - [self stopTimer]; | |
| 816 | - | |
| 817 | - CGFloat duration = _interval * self.editView.validRect.size.width / (kItemWidth); | |
| 818 | - _timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(playPartVideo:) userInfo:nil repeats:YES]; | |
| 819 | - [_timer fire]; | |
| 820 | - [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; | |
| 821 | - | |
| 822 | - _indicatorLine.frame = CGRectMake(self.editView.validRect.origin.x, 0, 4, kItemHeight); | |
| 823 | - [self.editView addSubview:_indicatorLine]; | |
| 824 | - [UIView animateWithDuration:duration delay:.0 options:UIViewAnimationOptionRepeat|UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear animations:^{ | |
| 825 | - _indicatorLine.frame = CGRectMake(CGRectGetMaxX(self.editView.validRect)-2, 0, 2, kItemHeight); | |
| 826 | - } completion:nil]; | |
| 827 | -} | |
| 828 | - | |
| 829 | -- (void)stopTimer | |
| 830 | -{ | |
| 831 | - [_timer invalidate]; | |
| 832 | - _timer = nil; | |
| 833 | - [_indicatorLine removeFromSuperview]; | |
| 834 | - [self.playerLayer.player pause]; | |
| 835 | -} | |
| 836 | - | |
| 837 | -- (CMTime)getStartTime | |
| 838 | -{ | |
| 839 | - CGRect rect = [self.collectionView convertRect:self.editView.validRect fromView:self.editView]; | |
| 840 | - CGFloat s = MAX(0, _interval * rect.origin.x / (kItemWidth)); | |
| 841 | - return CMTimeMakeWithSeconds(s, self.playerLayer.player.currentTime.timescale); | |
| 842 | -} | |
| 843 | - | |
| 844 | -- (CMTimeRange)getTimeRange | |
| 845 | -{ | |
| 846 | - CMTime start = [self getStartTime]; | |
| 847 | - CGFloat d = _interval * self.editView.validRect.size.width / (kItemWidth); | |
| 848 | - CMTime duration = CMTimeMakeWithSeconds(d, self.playerLayer.player.currentTime.timescale); | |
| 849 | - return CMTimeRangeMake(start, duration); | |
| 850 | -} | |
| 851 | - | |
| 852 | -- (void)playPartVideo:(NSTimer *)timer | |
| 853 | -{ | |
| 854 | - [self.playerLayer.player play]; | |
| 855 | - [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; | |
| 856 | -} | |
| 857 | - | |
| 858 | -#pragma mark - edit view delegate | |
| 859 | -- (void)editViewValidRectChanged | |
| 860 | -{ | |
| 861 | - [self stopTimer]; | |
| 862 | - [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; | |
| 863 | -} | |
| 864 | - | |
| 865 | -- (void)editViewValidRectEndChanged | |
| 866 | -{ | |
| 867 | - [self startTimer]; | |
| 868 | -} | |
| 869 | - | |
| 870 | -#pragma mark - scroll view delegate | |
| 871 | -- (void)scrollViewDidScroll:(UIScrollView *)scrollView | |
| 872 | -{ | |
| 873 | - if (!self.playerLayer.player || _orientationChanged) { | |
| 874 | - _orientationChanged = NO; | |
| 875 | - return; | |
| 876 | - } | |
| 877 | - [self stopTimer]; | |
| 878 | - [self.playerLayer.player seekToTime:[self getStartTime] toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero]; | |
| 879 | -} | |
| 880 | - | |
| 881 | -- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate | |
| 882 | -{ | |
| 883 | - if (!decelerate) { | |
| 884 | - [self startTimer]; | |
| 885 | - } | |
| 886 | -} | |
| 887 | - | |
| 888 | -- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView | |
| 889 | -{ | |
| 890 | - [self startTimer]; | |
| 891 | -} | |
| 892 | - | |
| 893 | -#pragma mark - collection view data sources | |
| 894 | -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section | |
| 895 | -{ | |
| 896 | - return _measureCount; | |
| 897 | -} | |
| 898 | - | |
| 899 | -- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath | |
| 900 | -{ | |
| 901 | - CNEditVideoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CNEditVideoCell" forIndexPath:indexPath]; | |
| 902 | - | |
| 903 | - UIImage *image = _imageCache[@(indexPath.row).stringValue]; | |
| 904 | - if (image) { | |
| 905 | - cell.imageView.image = image; | |
| 906 | - } | |
| 907 | - | |
| 908 | - return cell; | |
| 909 | -} | |
| 910 | - | |
| 911 | -static const char _CNOperationCellKey; | |
| 912 | -- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath | |
| 913 | -{ | |
| 914 | - if (!_avAsset) return; | |
| 915 | - | |
| 916 | - if (_imageCache[@(indexPath.row).stringValue] || _opCache[@(indexPath.row).stringValue]) { | |
| 917 | - return; | |
| 918 | - } | |
| 919 | - | |
| 920 | - NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ | |
| 921 | - NSInteger row = indexPath.row; | |
| 922 | - NSInteger i = row * _interval; | |
| 923 | - | |
| 924 | - CMTime time = CMTimeMake((i+0.35) * _avAsset.duration.timescale, _avAsset.duration.timescale); | |
| 925 | - | |
| 926 | - NSError *error = nil; | |
| 927 | - CGImageRef cgImg = [self.generator copyCGImageAtTime:time actualTime:NULL error:&error]; | |
| 928 | - if (!error && cgImg) { | |
| 929 | - UIImage *image = [UIImage imageWithCGImage:cgImg]; | |
| 930 | - CGImageRelease(cgImg); | |
| 931 | - | |
| 932 | - [_imageCache setValue:image forKey:@(row).stringValue]; | |
| 933 | - | |
| 934 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 935 | - | |
| 936 | - NSIndexPath *nowIndexPath = [collectionView indexPathForCell:cell]; | |
| 937 | - if (row == nowIndexPath.row) { | |
| 938 | - [(CNEditVideoCell *)cell imageView].image = image; | |
| 939 | - } else { | |
| 940 | - UIImage *cacheImage = _imageCache[@(nowIndexPath.row).stringValue]; | |
| 941 | - if (cacheImage) { | |
| 942 | - [(CNEditVideoCell *)cell imageView].image = cacheImage; | |
| 943 | - } | |
| 944 | - } | |
| 945 | - }); | |
| 946 | - [_opCache removeObjectForKey:@(row).stringValue]; | |
| 947 | - } | |
| 948 | - objc_removeAssociatedObjects(cell); | |
| 949 | - }]; | |
| 950 | - [_queue addOperation:op]; | |
| 951 | - [_opCache setValue:op forKey:@(indexPath.row).stringValue]; | |
| 952 | - | |
| 953 | - objc_setAssociatedObject(cell, &_CNOperationCellKey, op, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| 954 | -} | |
| 955 | - | |
| 956 | -- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath | |
| 957 | -{ | |
| 958 | - NSBlockOperation *op = objc_getAssociatedObject(cell, &_CNOperationCellKey); | |
| 959 | - if (op) { | |
| 960 | - [op cancel]; | |
| 961 | - objc_removeAssociatedObjects(cell); | |
| 962 | - [_opCache removeObjectForKey:@(indexPath.row).stringValue]; | |
| 963 | - } | |
| 964 | -} | |
| 965 | - | |
| 966 | -- (void)didReceiveMemoryWarning { | |
| 967 | - [super didReceiveMemoryWarning]; | |
| 968 | - // Dispose of any resources that can be recreated. | |
| 969 | -} | |
| 970 | - | |
| 971 | -/* | |
| 972 | -#pragma mark - Navigation | |
| 973 | - | |
| 974 | -// In a storyboard-based application, you will often want to do a little preparation before navigation | |
| 975 | -- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { | |
| 976 | - // Get the new view controller using [segue destinationViewController]. | |
| 977 | - // Pass the selected object to the new view controller. | |
| 978 | -} | |
| 979 | -*/ | |
| 980 | - | |
| 981 | -@end |
CNLiveImagePickerController/CNImagePickerCommonDefine.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// CNImagePickerCommonDefine.h | |
| 3 | -// CNLiveImagePickerControllerExample | |
| 4 | -// | |
| 5 | -// Created by 梁星国 on 2018/10/25. | |
| 6 | -// Copyright © 2018年 梁星国. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#ifndef CNImagePickerCommonDefine_h | |
| 10 | -#define CNImagePickerCommonDefine_h | |
| 11 | - | |
| 12 | - | |
| 13 | -//////////////////////////////////////////////////////// | |
| 14 | -//////////// Color | |
| 15 | -//////////////////////////////////////////////////////// | |
| 16 | - | |
| 17 | -#define IP_RGBOF(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \ | |
| 18 | -green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \ | |
| 19 | -blue:((float)(rgbValue & 0xFF))/255.0 \ | |
| 20 | -alpha:1.0] | |
| 21 | - | |
| 22 | -#define IP_RGBA_OF(rgbValue) [UIColor colorWithRed:((float)(((rgbValue) & 0xFF000000) >> 24))/255.0 \ | |
| 23 | -green:((float)(((rgbValue) & 0x00FF0000) >> 16))/255.0 \ | |
| 24 | -blue:((float)(rgbValue & 0x0000FF00) >> 8)/255.0 \ | |
| 25 | -alpha:((float)(rgbValue & 0x000000FF))/255.0] | |
| 26 | - | |
| 27 | -#define IP_RGBAOF(v, a) [UIColor colorWithRed:((float)(((v) & 0xFF0000) >> 16))/255.0 \ | |
| 28 | -green:((float)(((v) & 0x00FF00) >> 8))/255.0 \ | |
| 29 | -blue:((float)(v & 0x0000FF))/255.0 \ | |
| 30 | -alpha:a] | |
| 31 | - | |
| 32 | - | |
| 33 | -//////////////////////////////////////////////////////// | |
| 34 | -//////////// 发送图片,视频限制 | |
| 35 | -//////////////////////////////////////////////////////// | |
| 36 | -#define kFriendsCircle_limit_photo 20*1024.0*1024.0 //朋友圈限制图片20M | |
| 37 | -#define kFirendsCircle_limit_video 30*1024.0*1024.0 //朋友圈限制视频30M | |
| 38 | -#define kTarentoComment_limit_photo 10*1024.0*1024.0 //达人评论10M | |
| 39 | -#define kSweepCode_limit_phoho 10*1024.0*1024.0 //扫码10M限制 | |
| 40 | -#define kChat_limit_photo 20*1024.0*1024.0 //聊天限制图片20M | |
| 41 | -#define kChat_limit_video 20*1024.0*1024.0 //聊天限制视频20M | |
| 42 | - | |
| 43 | -#define kChat_limit_video_length 5*60 //聊天限制视频5分钟 | |
| 44 | -#define kFriendsCircle_limit_video_maxEdit 5*60 //朋友圈限制视频5分钟 | |
| 45 | -#define kFriendsCircle_limit_video_max 10*60 //朋友圈限制最大视频编辑10分钟 | |
| 46 | - | |
| 47 | - | |
| 48 | - | |
| 49 | -//////////////////////////////////////////////////////// | |
| 50 | -//////////// SCreen | |
| 51 | -//////////////////////////////////////////////////////// | |
| 52 | -#define kIPScreenWidth ([UIScreen mainScreen].bounds.size.width > [UIScreen mainScreen].bounds.size.height ? [UIScreen mainScreen].bounds.size.height : [UIScreen mainScreen].bounds.size.width) | |
| 53 | -#define kIPScreenHeight ([UIScreen mainScreen].bounds.size.width > [UIScreen mainScreen].bounds.size.height ? [UIScreen mainScreen].bounds.size.width : [UIScreen mainScreen].bounds.size.height) | |
| 54 | - | |
| 55 | - | |
| 56 | -//判断iPHoneXr | |
| 57 | -#define IP_Device_Is_iPhoneXS_XR ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(828, 1792), [[UIScreen mainScreen] currentMode].size) : NO) | |
| 58 | - | |
| 59 | -//判断iPHoneX、iPHoneXs | |
| 60 | -#define IP_Device_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO) | |
| 61 | -#define IP_Device_Is_iPhoneXS ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO) | |
| 62 | - | |
| 63 | -//判断iPhoneXs Max | |
| 64 | -#define IP_Device_Is_iPhoneXS_MAX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2688), [[UIScreen mainScreen] currentMode].size) : NO) | |
| 65 | - | |
| 66 | -#define IP_IS_IPhoneX_All (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(414, 896)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(896, 414))) | |
| 67 | - | |
| 68 | - | |
| 69 | -#define kIPStatusHeight (int)[UIApplication sharedApplication].statusBarFrame.size.height //x44 非x20 | |
| 70 | -#define kIPNavigationBarHeight ((int)[UIApplication sharedApplication].statusBarFrame.size.height+44) //x88 非x64 | |
| 71 | -#define kIPVerticalNaviBarHeight ((IP_IS_IPhoneX_All > 0) ? 88 : 44) | |
| 72 | -#define kIPVerticalTabBarTotalHeight ((IP_IS_IPhoneX_All > 0) ? 83 : 49) | |
| 73 | -#define kIPVerticalBottomSafeHeight ((IP_IS_IPhoneX_All > 0) ? 34 : 0) | |
| 74 | -#define kIPVerticalStatusHeight ((IP_IS_IPhoneX_All > 0) ? 44 : 20) | |
| 75 | -#define kIPVerticalTopHeight ((IP_IS_IPhoneX_All > 0) ? 24 : 0) | |
| 76 | -#define kIPHorizontalTopNaviBarHeight 32 | |
| 77 | -#define kIPHorizontalBottomHeight ((IP_IS_IPhoneX_All > 0) ? 21 : 0) | |
| 78 | -#define kIPHorizontalLeftHeight ((IP_IS_IPhoneX_All > 0) ? 44 : 0) | |
| 79 | -#define kIPHorizontalRightHeight ((IP_IS_IPhoneX_All > 0) ? 44 : 0) | |
| 80 | -#define kIPHorizontalTopHeight ((IP_IS_IPhoneX_All > 0) ? 24 : 0) | |
| 81 | - | |
| 82 | -#endif /* CNImagePickerCommonDefine_h */ |
CNLiveImagePickerController/CNImagePickerController.h deleted
100644 → 0
| 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/CNImagePickerController.m deleted
100644 → 0
| 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 | -#import "CNImagePickerCommonDefine.h" | |
| 11 | -#import "UIImage+CNImagePicker.h" | |
| 12 | - | |
| 13 | -@interface CNImagePickerController () | |
| 14 | - | |
| 15 | -@end | |
| 16 | - | |
| 17 | -@implementation CNImagePickerController | |
| 18 | - | |
| 19 | -- (void)viewDidLoad { | |
| 20 | - [super viewDidLoad]; | |
| 21 | - | |
| 22 | -} | |
| 23 | - | |
| 24 | -/** | |
| 25 | - 配置 详情看TZImagePickerController | |
| 26 | - */ | |
| 27 | -- (void)configTZImagePicker{ | |
| 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 | - self.iconThemeColor = IP_RGBOF(0x00BBE06);// 主体颜色 | |
| 38 | - self.showPhotoCannotSelectLayer = YES;//达到上限是否有浮层 | |
| 39 | - self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];//设置达到上限的浮层 | |
| 40 | - | |
| 41 | - self.photoDefImage = [UIImage imageNamedFromMyBundle:@"photo_cell_normal"]; | |
| 42 | - self.photoSelImage = [UIImage ip_imageWithColor:IP_RGBOF(0x0BBE06) size:CGSizeMake(22, 22) radius:11]; | |
| 43 | - self.photoOriginDefImage = [UIImage imageNamedFromMyBundle:@"photo_original_nor"]; | |
| 44 | - | |
| 45 | - // 3. 设置是否可以选择视频/图片/原图/gif | |
| 46 | - self.allowPickingVideo = YES;// 显示视频 | |
| 47 | - self.allowPickingImage = YES;// 显示图片 | |
| 48 | - self.allowPickingOriginalPhoto = YES; //显示原图 | |
| 49 | - self.allowPickingGif = NO;// 显示GIF | |
| 50 | - self.allowPickingMultipleVideo = YES; // 是否可以多选视频 | |
| 51 | - | |
| 52 | - // 4. 照片排列按修改时间升序 | |
| 53 | - self.sortAscendingByModificationDate = YES; | |
| 54 | - | |
| 55 | - // imagePickerVc.minImagesCount = 3; | |
| 56 | - // imagePickerVc.alwaysEnableDoneBtn = YES; | |
| 57 | - | |
| 58 | - // imagePickerVc.minPhotoWidthSelectable = 3000; | |
| 59 | - // imagePickerVc.minPhotoHeightSelectable = 2000; | |
| 60 | - | |
| 61 | - /// 5. Single selection mode, valid when maxImagesCount = 1 | |
| 62 | - /// 5. 单选模式,maxImagesCount为1时才生效 | |
| 63 | - self.showSelectBtn = NO; | |
| 64 | - self.allowCrop = NO; | |
| 65 | - self.needCircleCrop = NO; | |
| 66 | - // 设置横屏下的裁剪尺寸 | |
| 67 | - // imagePickerVc.cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, left, widthHeight, widthHeight); | |
| 68 | - /* | |
| 69 | - [imagePickerVc setCropViewSettingBlock:^(UIView *cropView) { | |
| 70 | - cropView.layer.borderColor = [UIColor redColor].CGColor; | |
| 71 | - cropView.layer.borderWidth = 2.0; | |
| 72 | - }];*/ | |
| 73 | - | |
| 74 | - //imagePickerVc.allowPreview = NO; | |
| 75 | - // 自定义导航栏上的返回按钮 | |
| 76 | - /* | |
| 77 | - [imagePickerVc setNavLeftBarButtonSettingBlock:^(UIButton *leftButton){ | |
| 78 | - [leftButton setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal]; | |
| 79 | - [leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 20)]; | |
| 80 | - }]; | |
| 81 | - imagePickerVc.delegate = self; | |
| 82 | - */ | |
| 83 | - | |
| 84 | - self.statusBarStyle = UIStatusBarStyleDefault;//状态栏黑色 | |
| 85 | - | |
| 86 | - self.showSelectedIndex = YES; // 设置是否显示图片序号 | |
| 87 | - | |
| 88 | - self.naviBgColor = IP_RGBOF(0xFFFFFF);//导航栏颜色 | |
| 89 | - self.naviTitleColor = IP_RGBOF(0x282828);//相册title | |
| 90 | - self.naviTitleFont = [UIFont systemFontOfSize:18];//title文字大小 | |
| 91 | - [self setNavLeftBarButtonSettingBlock:^(UIButton *leftButton) {//设置返回按钮图标 | |
| 92 | - [leftButton setImage:[UIImage imageNamedFromMyBundle:@"photoback"] forState:UIControlStateNormal];//返回按钮图片 | |
| 93 | - [leftButton setTitle:@"返回" forState:UIControlStateNormal];//设置文字大小 | |
| 94 | - [leftButton setTitleColor:IP_RGBOF(0x282828) forState:UIControlStateNormal];//设置文字颜色 | |
| 95 | - leftButton.titleLabel.font = [UIFont systemFontOfSize:15];//设置文字大小 | |
| 96 | - leftButton.imageEdgeInsets = UIEdgeInsetsMake(0, -7, 0, +7);//设置图片边缘 | |
| 97 | - }]; | |
| 98 | - self.barItemTextColor = IP_RGBOF(0x282828);//设置barItem文字颜色 | |
| 99 | - self.barItemTextFont = [UIFont systemFontOfSize:15]; | |
| 100 | - | |
| 101 | - // 设置首选语言 / Set preferred language | |
| 102 | - // imagePickerVc.preferredLanguage = @"zh-Hans"; | |
| 103 | - | |
| 104 | - // 设置languageBundle以使用其它语言 / Set languageBundle to use other language | |
| 105 | - // imagePickerVc.languageBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"tz-ru" ofType:@"lproj"]]; | |
| 106 | - | |
| 107 | - /// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等 | |
| 108 | - //相册 | |
| 109 | - [self setPhotoPickerPageUIConfigBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) { | |
| 110 | - | |
| 111 | - //底部栏 | |
| 112 | - [bottomToolBar setBackgroundColor:IP_RGBOF(0xFFFFFF)]; | |
| 113 | - | |
| 114 | - //预览 | |
| 115 | - previewButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 116 | - [previewButton setTitleColor:IP_RGBOF(0xB3B3B3) forState:UIControlStateDisabled];//禁用 | |
| 117 | - [previewButton setTitleColor:IP_RGBOF(0x000000) forState:UIControlStateNormal];//默认 | |
| 118 | - | |
| 119 | - //原图按钮 | |
| 120 | - [originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用 | |
| 121 | - [originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_normal"] forState:UIControlStateNormal];//默认 | |
| 122 | - [originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_select"] forState:UIControlStateSelected];//选中 | |
| 123 | - originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 124 | - [originalPhotoButton setTitleColor:IP_RGBOF(0xB3B3B3) forState:UIControlStateDisabled]; | |
| 125 | - [originalPhotoButton setTitleColor:IP_RGBOF(0x000000) forState:UIControlStateNormal]; | |
| 126 | - | |
| 127 | - //原图文字提示 | |
| 128 | - originalPhotoLabel.font = [UIFont systemFontOfSize:16]; | |
| 129 | - originalPhotoLabel.textColor = IP_RGBOF(0xB3B3B3); | |
| 130 | - originalPhotoLabel.hidden = YES; | |
| 131 | - | |
| 132 | - //选中提示 | |
| 133 | - numberImageView = [UIImageView new]; | |
| 134 | - numberLabel = [UILabel new]; | |
| 135 | - | |
| 136 | - //完成按钮 | |
| 137 | - doneButton.titleLabel.font = [UIFont systemFontOfSize:13]; | |
| 138 | - [doneButton setTitle:@"完成" forState:UIControlStateDisabled]; | |
| 139 | - [doneButton setTitleColor:IP_RGBAOF(0xFFFFFF, 0.5) forState:UIControlStateDisabled]; | |
| 140 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateNormal]; | |
| 141 | - | |
| 142 | - //颜色绘制成图片 | |
| 143 | - UIImage *dis_image = [UIImage ip_imageWithColor:IP_RGBAOF(0x0BBE06, 0.5)]; | |
| 144 | - [doneButton setBackgroundImage:dis_image forState:UIControlStateDisabled]; | |
| 145 | - UIImage *nor_image = [UIImage ip_imageWithColor:IP_RGBOF(0x0BBE06)]; | |
| 146 | - [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal]; | |
| 147 | - doneButton.layer.masksToBounds = YES; | |
| 148 | - doneButton.layer.cornerRadius = 5; | |
| 149 | - | |
| 150 | - //分割线 | |
| 151 | - [divideLine setBackgroundColor:IP_RGBOF(0xDEDEDE)]; | |
| 152 | - | |
| 153 | - }]; | |
| 154 | - | |
| 155 | - //图片预览 | |
| 156 | - [self setPhotoPreviewPageUIConfigBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) { | |
| 157 | - | |
| 158 | - //返回按钮 | |
| 159 | - [backButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_back"] forState:UIControlStateNormal]; | |
| 160 | - //选择按钮 | |
| 161 | - [selectButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_nor"] forState:UIControlStateNormal]; | |
| 162 | - [selectButton setImage:[UIImage ip_imageWithColor:IP_RGBOF(0x0BBE06) size:CGSizeMake(28, 28) radius:14] forState:UIControlStateSelected]; | |
| 163 | - [selectButton setTitle:@"" forState:UIControlStateDisabled]; | |
| 164 | - | |
| 165 | - //原图按钮 | |
| 166 | - [originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用 | |
| 167 | - [originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_normal"] forState:UIControlStateNormal];//默认 | |
| 168 | - [originalPhotoButton setImage:[UIImage imageNamedFromMyBundle:@"photo_original_select"] forState:UIControlStateSelected];//选中 | |
| 169 | - originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 170 | - [originalPhotoButton setTitleColor:IP_RGBOF(0xB3B3B3) forState:UIControlStateDisabled]; | |
| 171 | - [originalPhotoButton setTitleColor:IP_RGBAOF(0xFFFFFF, 0.7) forState:UIControlStateNormal]; | |
| 172 | - //原图内容隐藏 | |
| 173 | - originalPhotoLabel.hidden = YES; | |
| 174 | - | |
| 175 | - //完成按钮 | |
| 176 | - doneButton.titleLabel.font = [UIFont systemFontOfSize:13]; | |
| 177 | - [doneButton setTitle:@"完成" forState:UIControlStateDisabled]; | |
| 178 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateDisabled]; | |
| 179 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateNormal]; | |
| 180 | - | |
| 181 | - //颜色绘制成图片 | |
| 182 | - UIImage *dis_image = [UIImage ip_imageWithColor:IP_RGBAOF(0x0BBE06, 0.5)]; | |
| 183 | - [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected]; | |
| 184 | - UIImage *nor_image = [UIImage ip_imageWithColor:IP_RGBOF(0x0BBE06)]; | |
| 185 | - [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal]; | |
| 186 | - doneButton.layer.masksToBounds = YES; | |
| 187 | - doneButton.layer.cornerRadius = 5; | |
| 188 | - }]; | |
| 189 | - | |
| 190 | - //视频预览 | |
| 191 | - [self setVideoPreviewPageUIConfigBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) { | |
| 192 | - | |
| 193 | - //完成按钮 | |
| 194 | - doneButton.titleLabel.font = [UIFont systemFontOfSize:13]; | |
| 195 | - [doneButton setTitle:@"完成" forState:UIControlStateDisabled]; | |
| 196 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateDisabled]; | |
| 197 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateNormal]; | |
| 198 | - | |
| 199 | - //颜色绘制成图片 | |
| 200 | - UIImage *dis_image = [UIImage ip_imageWithColor:IP_RGBAOF(0x0BBE06, 0.5)]; | |
| 201 | - [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected]; | |
| 202 | - UIImage *nor_image = [UIImage ip_imageWithColor:IP_RGBOF(0x0BBE06)]; | |
| 203 | - [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal]; | |
| 204 | - doneButton.layer.masksToBounds = YES; | |
| 205 | - doneButton.layer.cornerRadius = 5; | |
| 206 | - | |
| 207 | - }]; | |
| 208 | - | |
| 209 | - //gif预览 | |
| 210 | - [self setGifPreviewPageUIConfigBlock:^(UIView *toolBar, UIButton *doneButton) { | |
| 211 | - | |
| 212 | - //完成按钮 | |
| 213 | - doneButton.titleLabel.font = [UIFont systemFontOfSize:13]; | |
| 214 | - [doneButton setTitle:@"完成" forState:UIControlStateDisabled]; | |
| 215 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateDisabled]; | |
| 216 | - [doneButton setTitleColor:IP_RGBOF(0xFFFFFF) forState:UIControlStateNormal]; | |
| 217 | - | |
| 218 | - //颜色绘制成图片 | |
| 219 | - UIImage *dis_image = [UIImage ip_imageWithColor:IP_RGBAOF(0x0BBE06, 0.5)]; | |
| 220 | - [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected]; | |
| 221 | - UIImage *nor_image = [UIImage ip_imageWithColor:IP_RGBOF(0x0BBE06)]; | |
| 222 | - [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal]; | |
| 223 | - doneButton.layer.masksToBounds = YES; | |
| 224 | - doneButton.layer.cornerRadius = 5; | |
| 225 | - | |
| 226 | - }]; | |
| 227 | - //相册cell | |
| 228 | - [self setAssetCellDidSetModelBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) { | |
| 229 | - | |
| 230 | - | |
| 231 | - }]; | |
| 232 | - //相簿 | |
| 233 | - [self setAlbumCellDidSetModelBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) { | |
| 234 | - [posterImageView setBackgroundColor:[UIColor blueColor]]; | |
| 235 | - [posterImageView setBackgroundColor:[UIColor blueColor]]; | |
| 236 | - | |
| 237 | - }]; | |
| 238 | - | |
| 239 | - | |
| 240 | - /// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等 | |
| 241 | - //相册 | |
| 242 | - [self setPhotoPickerPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) { | |
| 243 | - | |
| 244 | - CGRect frame = bottomToolBar.frame; | |
| 245 | - doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kIPVerticalBottomSafeHeight /2), 60, 30); | |
| 246 | - | |
| 247 | - CGRect originalPhotoLabelFrame = originalPhotoLabel.frame; | |
| 248 | - CGFloat originalX = (bottomToolBar.frame.size.width - originalPhotoLabelFrame.size.width) /2; | |
| 249 | - CGFloat originalY = originalPhotoLabelFrame.origin.y; | |
| 250 | - originalPhotoButton.frame = CGRectMake(originalX, originalY, originalPhotoLabelFrame.size.width, originalPhotoLabelFrame.size.height); | |
| 251 | - | |
| 252 | - | |
| 253 | - }]; | |
| 254 | - //图片预览 | |
| 255 | - [self setPhotoPreviewPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) { | |
| 256 | - | |
| 257 | - CGRect frame = toolBar.frame; | |
| 258 | - doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kIPVerticalBottomSafeHeight /2), 60, 30); | |
| 259 | - | |
| 260 | - }]; | |
| 261 | - //视频预览 | |
| 262 | - [self setVideoPreviewPageDidLayoutSubviewsBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) { | |
| 263 | - | |
| 264 | - CGRect frame = toolBar.frame; | |
| 265 | - doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kIPVerticalBottomSafeHeight /2), 60, 30); | |
| 266 | - | |
| 267 | - }]; | |
| 268 | - //gif预览 | |
| 269 | - [self setGifPreviewPageDidLayoutSubviewsBlock:^(UIView *toolBar, UIButton *doneButton) { | |
| 270 | - | |
| 271 | - CGRect frame = toolBar.frame; | |
| 272 | - doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15 - (kIPVerticalBottomSafeHeight /2), 60, 30); | |
| 273 | - | |
| 274 | - }]; | |
| 275 | - //相册cell | |
| 276 | - | |
| 277 | - [self setAssetCellDidLayoutSubviewsBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) { | |
| 278 | - }]; | |
| 279 | - //相簿 | |
| 280 | - [self setAlbumCellDidLayoutSubviewsBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) { | |
| 281 | - | |
| 282 | - }]; | |
| 283 | - | |
| 284 | - //设置图片个数 | |
| 285 | - self.photoNumberIconImage = [UIImage new]; | |
| 286 | - | |
| 287 | -} | |
| 288 | - | |
| 289 | -- (void)didReceiveMemoryWarning { | |
| 290 | - [super didReceiveMemoryWarning]; | |
| 291 | - // Dispose of any resources that can be recreated. | |
| 292 | -} | |
| 293 | - | |
| 294 | - | |
| 295 | -@end |
CNLiveImagePickerController/CNImagePickerManager.h deleted
100644 → 0
| 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 | - | |
| 14 | -typedef void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);//选着图片返回 | |
| 15 | - | |
| 16 | -//typedef void (^failureBlock)(NSMutableArray* errorArray, NSError *error);//失败数组,错误 | |
| 17 | - | |
| 18 | -typedef NS_ENUM(NSUInteger, CNImagePickerEnterType) { | |
| 19 | - CNImagePickerEnterTypeFriendsCircle = 0,//朋友圈 | |
| 20 | - CNImagePickerEnterTypeComment = 1,//评论 | |
| 21 | - CNImagePickerEnterTypeSweepCode = 2,//扫码 | |
| 22 | - CNImagePickerEnterTypeChat = 3,//聊天 | |
| 23 | - CNImagePickerEnterTypeOther = 4,//其他 | |
| 24 | - CNImagePickerEnterTypeWitness = 5, //目击者 | |
| 25 | - | |
| 26 | -}; | |
| 27 | -@interface CNImagePickerManager : NSObject | |
| 28 | - | |
| 29 | - | |
| 30 | - | |
| 31 | -/** | |
| 32 | - 打开相册选择图片 | |
| 33 | - | |
| 34 | - @param maxImagesCount 最大图片 | |
| 35 | - @param columnNumber 列个数 | |
| 36 | - @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>) | |
| 37 | - @param pushPhotoPickerVc 是否跳转到相册 | |
| 38 | - @param isSelectOriginalPhoto 是否原图 | |
| 39 | - @param selectedAssets 选择图片 | |
| 40 | - @param enterType 进入方式 | |
| 41 | - @param pickingPhotosHandle 选择结束回调 | |
| 42 | - */ | |
| 43 | -+ (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; | |
| 44 | - | |
| 45 | -/** | |
| 46 | - 预览图片 | |
| 47 | - | |
| 48 | - @param maxImagesCount 最大限制 | |
| 49 | - @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>) | |
| 50 | - @param selectedAssets 选中Assets | |
| 51 | - @param selectedPhotos 选中Photos | |
| 52 | - @param index 选中第几个 | |
| 53 | - @param isSelectOriginalPhoto 是否原图 | |
| 54 | - @param enterType 进入方式 | |
| 55 | - @param pickingPhotosHandle 回调参数 | |
| 56 | - */ | |
| 57 | -+ (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; | |
| 58 | - | |
| 59 | - | |
| 60 | -/** | |
| 61 | - 预览单个视频 | |
| 62 | - | |
| 63 | - @param selectedAsset 选择视频 | |
| 64 | - @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>) | |
| 65 | - */ | |
| 66 | -+ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate; | |
| 67 | - | |
| 68 | - | |
| 69 | -/** | |
| 70 | - 保存图片 | |
| 71 | - | |
| 72 | - @param delegate 代理(UIViewController<TZImagePickerControllerDelegate>) | |
| 73 | - @param image 图片 | |
| 74 | - @param location 地点 | |
| 75 | - @param success 成功 | |
| 76 | - @param failure 失败 | |
| 77 | - | |
| 78 | - */ | |
| 79 | -+(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure; | |
| 80 | - | |
| 81 | - | |
| 82 | -/** | |
| 83 | - 判断Asset类型 | |
| 84 | - | |
| 85 | - @param asset asset | |
| 86 | - @return 返回类型 | |
| 87 | - */ | |
| 88 | -+ (TZAssetModelMediaType)getAssetType:(id)asset; | |
| 89 | - | |
| 90 | - | |
| 91 | -@end | |
| 92 | - |
CNLiveImagePickerController/CNImagePickerManager.m deleted
100644 → 0
| 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 | -#import "CNImagePickerCommonDefine.h" | |
| 12 | - | |
| 13 | -@implementation CNImagePickerManager | |
| 14 | - | |
| 15 | -/// 打开相册选择图片 | |
| 16 | -+ (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{ | |
| 17 | - | |
| 18 | - if (![delegate isKindOfClass:[UIViewController class]]) { | |
| 19 | - return; | |
| 20 | - } | |
| 21 | - UIViewController *vc = (UIViewController *)delegate; | |
| 22 | - | |
| 23 | - CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithMaxImagesCount:maxImagesCount columnNumber:columnNumber delegate:delegate pushPhotoPickerVc:pushPhotoPickerVc]; | |
| 24 | - [imagePickerVc configTZImagePicker];//基本配置 | |
| 25 | - //特殊配置 | |
| 26 | - switch (enterType) { | |
| 27 | - case CNImagePickerEnterTypeFriendsCircle: | |
| 28 | - imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度 | |
| 29 | - imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度 | |
| 30 | - // 3. 设置是否可以混选选择视频/图片/原图 | |
| 31 | - imagePickerVc.allowPickingMultipleVideo = NO; | |
| 32 | - break; | |
| 33 | - case CNImagePickerEnterTypeComment: | |
| 34 | - | |
| 35 | - break; | |
| 36 | - case CNImagePickerEnterTypeSweepCode: | |
| 37 | - | |
| 38 | - break; | |
| 39 | - case CNImagePickerEnterTypeChat: | |
| 40 | - imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度 | |
| 41 | - imagePickerVc.maxVideoDuration = kChat_limit_video_length;//编辑视频最大长度 | |
| 42 | - | |
| 43 | - break; | |
| 44 | - case CNImagePickerEnterTypeWitness: | |
| 45 | - imagePickerVc.allowPickingImage = NO;// 显示图片 | |
| 46 | - imagePickerVc.allowPickingMultipleVideo = NO; | |
| 47 | - imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度 | |
| 48 | - imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度 | |
| 49 | - break; | |
| 50 | - default://其他 | |
| 51 | - break; | |
| 52 | - } | |
| 53 | - | |
| 54 | - imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;//是否选择原图 | |
| 55 | - // 1.设置目前已经选中的图片数组 | |
| 56 | - imagePickerVc.selectedAssets = selectedAssets; // 目前已经选中的图片数组 | |
| 57 | - /// 5. Single selection mode, valid when maxImagesCount = 1 | |
| 58 | - /// 5. 单选模式,maxImagesCount为1时才生效 | |
| 59 | - // 设置竖屏下的裁剪尺寸 | |
| 60 | - NSInteger left = 30; | |
| 61 | - NSInteger widthHeight = vc.view.frame.size.width - 2 * left; | |
| 62 | - NSInteger top = (vc.view.frame.size.height - widthHeight) / 2; | |
| 63 | - imagePickerVc.cropRect = CGRectMake(left, top, widthHeight, widthHeight); | |
| 64 | - // 你可以通过block或者代理,来得到用户选择的照片. | |
| 65 | - [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) { | |
| 66 | - // 回调参数 | |
| 67 | - !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto); | |
| 68 | - | |
| 69 | - }]; | |
| 70 | - | |
| 71 | - [vc presentViewController:imagePickerVc animated:YES completion:nil]; | |
| 72 | -} | |
| 73 | - | |
| 74 | -/// 预览图片 | |
| 75 | -+ (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 { | |
| 76 | - | |
| 77 | - if (![delegate isKindOfClass:[UIViewController class]]) { | |
| 78 | - return; | |
| 79 | - } | |
| 80 | - UIViewController *vc = (UIViewController *)delegate; | |
| 81 | - | |
| 82 | - CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithSelectedAssets:selectedAssets selectedPhotos:selectedPhotos index:index]; | |
| 83 | - [imagePickerVc configTZImagePicker];//基本配置 | |
| 84 | - //特殊配置 | |
| 85 | - switch (enterType) { | |
| 86 | - case CNImagePickerEnterTypeFriendsCircle: | |
| 87 | - imagePickerVc.allowPickingGif = NO; | |
| 88 | - imagePickerVc.allowPickingOriginalPhoto = YES; | |
| 89 | - imagePickerVc.allowPickingMultipleVideo = NO; | |
| 90 | - break; | |
| 91 | - case CNImagePickerEnterTypeComment: | |
| 92 | -#pragma mark - TODO:根据不同设置 | |
| 93 | - break; | |
| 94 | - case CNImagePickerEnterTypeSweepCode: | |
| 95 | - | |
| 96 | - break; | |
| 97 | - case CNImagePickerEnterTypeChat: | |
| 98 | - | |
| 99 | - break; | |
| 100 | - case CNImagePickerEnterTypeOther: | |
| 101 | - break; | |
| 102 | - default://其他 | |
| 103 | - break; | |
| 104 | - } | |
| 105 | - | |
| 106 | - imagePickerVc.maxImagesCount = maxImagesCount; | |
| 107 | - imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto; | |
| 108 | - | |
| 109 | - [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) { | |
| 110 | - // 回调参数 | |
| 111 | - !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto); | |
| 112 | - | |
| 113 | - }]; | |
| 114 | - [vc presentViewController:imagePickerVc animated:YES completion:nil]; | |
| 115 | - | |
| 116 | -} | |
| 117 | - | |
| 118 | -/// 预览单个视频 | |
| 119 | -+ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate { | |
| 120 | - | |
| 121 | - if (![delegate isKindOfClass:[UIViewController class]]) { | |
| 122 | - return; | |
| 123 | - } | |
| 124 | - UIViewController *vc = (UIViewController *)delegate; | |
| 125 | - | |
| 126 | - TZVideoPlayerController *videoVC = [[TZVideoPlayerController alloc] init]; | |
| 127 | - TZAssetModel *model = [TZAssetModel modelWithAsset:selectedAsset type:TZAssetModelMediaTypeVideo timeLength:@""]; | |
| 128 | - videoVC.isOther = YES;//(LXG)相册外进入 | |
| 129 | - videoVC.model = model; | |
| 130 | - [vc presentViewController:videoVC animated:YES completion:nil]; | |
| 131 | - | |
| 132 | -} | |
| 133 | - | |
| 134 | -/// 返回类型 | |
| 135 | -+ (TZAssetModelMediaType)getAssetType:(id)asset { | |
| 136 | - | |
| 137 | - TZAssetModelMediaType type = TZAssetModelMediaTypePhoto; | |
| 138 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 139 | - PHAsset *phAsset = (PHAsset *)asset; | |
| 140 | - if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo; | |
| 141 | - else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio; | |
| 142 | - else if (phAsset.mediaType == PHAssetMediaTypeImage) { | |
| 143 | - if (iOS9_1Later) { | |
| 144 | - if (@available(iOS 9.1, *)) { | |
| 145 | - if (phAsset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) | |
| 146 | - { | |
| 147 | - type = TZAssetModelMediaTypeLivePhoto; | |
| 148 | - } | |
| 149 | - } else { | |
| 150 | - // Fallback on earlier versions | |
| 151 | - } | |
| 152 | - } | |
| 153 | - // Gif | |
| 154 | - if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) { | |
| 155 | - type = TZAssetModelMediaTypePhotoGif; | |
| 156 | - } | |
| 157 | - } | |
| 158 | - } else { | |
| 159 | - if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) { | |
| 160 | - type = TZAssetModelMediaTypeVideo; | |
| 161 | - } | |
| 162 | - } | |
| 163 | - return type; | |
| 164 | -} | |
| 165 | - | |
| 166 | - | |
| 167 | -+(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure { | |
| 168 | - | |
| 169 | - TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:delegate]; | |
| 170 | - tzImagePickerVc.sortAscendingByModificationDate = YES; | |
| 171 | - | |
| 172 | - [tzImagePickerVc showProgressHUD]; | |
| 173 | - // save photo and get asset / 保存图片,获取到asset | |
| 174 | - [[TZImageManager manager] savePhotoWithImage:image location:location completion:^(NSError *error){ | |
| 175 | - | |
| 176 | - if (error) { | |
| 177 | - [tzImagePickerVc hideProgressHUD]; | |
| 178 | - failure(error); | |
| 179 | - NSLog(@"图片保存失败 %@",error); | |
| 180 | - } else { | |
| 181 | - | |
| 182 | - [[TZImageManager manager] getCameraRollAlbum:NO allowPickingImage:YES needFetchAssets:YES completion:^(TZAlbumModel *model) { | |
| 183 | - [[TZImageManager manager] getAssetsFromFetchResult:model.result allowPickingVideo:NO allowPickingImage:YES completion:^(NSArray<TZAssetModel *> *models) { | |
| 184 | - [tzImagePickerVc hideProgressHUD]; | |
| 185 | - TZAssetModel *assetModel = [models firstObject]; | |
| 186 | - if (tzImagePickerVc.sortAscendingByModificationDate) { | |
| 187 | - assetModel = [models lastObject]; | |
| 188 | - } | |
| 189 | - success(assetModel); | |
| 190 | - }]; | |
| 191 | - | |
| 192 | - }]; | |
| 193 | - } | |
| 194 | - }]; | |
| 195 | - | |
| 196 | -} | |
| 197 | - | |
| 198 | - | |
| 199 | - | |
| 200 | - | |
| 201 | - | |
| 202 | - | |
| 203 | - | |
| 204 | - | |
| 205 | - | |
| 206 | -@end |
CNLiveImagePickerController/Classes/.gitkeep
0 → 100644
CNLiveImagePickerController/Classes/ReplaceMe.m
0 → 100644
CNLiveImagePickerController/NSBundle+TZImagePicker.h deleted
100755 → 0
| 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/NSBundle+TZImagePicker.m deleted
100755 → 0
| 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/TZAssetCell.h deleted
100755 → 0
| 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/TZAssetCell.m deleted
100755 → 0
| 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+Layout.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 | - int32_t imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 41 | - // Set the cell's thumbnail image if it's still showing the same asset. | |
| 42 | - if (!iOS8Later) { | |
| 43 | - self.imageView.image = photo; | |
| 44 | - self.model.cachedImage = photo; | |
| 45 | - [self hideProgressView]; | |
| 46 | - return; | |
| 47 | - } | |
| 48 | - if ([self.representedAssetIdentifier isEqualToString:[[TZImageManager manager] getAssetIdentifier:model.asset]]) { | |
| 49 | - self.imageView.image = photo; | |
| 50 | - self.model.cachedImage = photo; | |
| 51 | - } else { | |
| 52 | - // NSLog(@"this cell is showing other asset"); | |
| 53 | - [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; | |
| 54 | - } | |
| 55 | - if (!isDegraded) { | |
| 56 | - [self hideProgressView]; | |
| 57 | - self.imageRequestID = 0; | |
| 58 | - } | |
| 59 | - } progressHandler:nil networkAccessAllowed:NO]; | |
| 60 | - if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) { | |
| 61 | - [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; | |
| 62 | - // NSLog(@"cancelImageRequest %d",self.imageRequestID); | |
| 63 | - } | |
| 64 | - self.imageRequestID = imageRequestID; | |
| 65 | - } | |
| 66 | - self.selectPhotoButton.selected = model.isSelected; | |
| 67 | - self.selectImageView.image = self.selectPhotoButton.isSelected ? self.photoSelImage : self.photoDefImage; | |
| 68 | - self.indexLabel.hidden = !self.selectPhotoButton.isSelected; | |
| 69 | - | |
| 70 | - self.type = (NSInteger)model.type; | |
| 71 | - // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中 | |
| 72 | - if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) { | |
| 73 | - if (_selectImageView.hidden == NO) { | |
| 74 | - self.selectPhotoButton.hidden = YES; | |
| 75 | - _selectImageView.hidden = YES; | |
| 76 | - } | |
| 77 | - } | |
| 78 | - // 如果用户选中了该图片,提前获取一下大图 | |
| 79 | - if (model.isSelected) { | |
| 80 | - [self requestBigImage]; | |
| 81 | - } else { | |
| 82 | - [self cancelBigImageRequest]; | |
| 83 | - } | |
| 84 | - if (model.needOscillatoryAnimation) { | |
| 85 | - [UIView showOscillatoryAnimationWithLayer:self.selectImageView.layer type:TZOscillatoryAnimationToBigger]; | |
| 86 | - } | |
| 87 | - model.needOscillatoryAnimation = NO; | |
| 88 | - [self setNeedsLayout]; | |
| 89 | - | |
| 90 | - if (self.assetCellDidSetModelBlock) { | |
| 91 | - self.assetCellDidSetModelBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView); | |
| 92 | - } | |
| 93 | -} | |
| 94 | - | |
| 95 | -- (void)setIndex:(NSInteger)index { | |
| 96 | - _index = index; | |
| 97 | - self.indexLabel.text = [NSString stringWithFormat:@"%zd", index]; | |
| 98 | - [self.contentView bringSubviewToFront:self.indexLabel]; | |
| 99 | -} | |
| 100 | - | |
| 101 | -- (void)setShowSelectBtn:(BOOL)showSelectBtn { | |
| 102 | - _showSelectBtn = showSelectBtn; | |
| 103 | - BOOL selectable = [[TZImageManager manager] isPhotoSelectableWithAsset:self.model.asset]; | |
| 104 | - if (!self.selectPhotoButton.hidden) { | |
| 105 | - self.selectPhotoButton.hidden = !showSelectBtn || !selectable; | |
| 106 | - } | |
| 107 | - if (!self.selectImageView.hidden) { | |
| 108 | - self.selectImageView.hidden = !showSelectBtn || !selectable; | |
| 109 | - } | |
| 110 | -} | |
| 111 | - | |
| 112 | -- (void)setType:(TZAssetCellType)type { | |
| 113 | - _type = type; | |
| 114 | - if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif) || self.allowPickingMultipleVideo) { | |
| 115 | - _selectImageView.hidden = NO; | |
| 116 | - _selectPhotoButton.hidden = NO; | |
| 117 | - _bottomView.hidden = YES; | |
| 118 | - } else { // Video of Gif | |
| 119 | - _selectImageView.hidden = YES; | |
| 120 | - _selectPhotoButton.hidden = YES; | |
| 121 | - } | |
| 122 | - | |
| 123 | - if (type == TZAssetCellTypeVideo) { | |
| 124 | - self.bottomView.hidden = NO; | |
| 125 | - self.timeLength.text = _model.timeLength; | |
| 126 | - self.videoImgView.hidden = NO; | |
| 127 | - _timeLength.tz_left = self.videoImgView.tz_right; | |
| 128 | - _timeLength.textAlignment = NSTextAlignmentRight; | |
| 129 | - } else if (type == TZAssetCellTypePhotoGif && self.allowPickingGif) { | |
| 130 | - self.bottomView.hidden = NO; | |
| 131 | - self.timeLength.text = @"GIF"; | |
| 132 | - self.videoImgView.hidden = YES; | |
| 133 | - _timeLength.tz_left = 5; | |
| 134 | - _timeLength.textAlignment = NSTextAlignmentLeft; | |
| 135 | - } | |
| 136 | -} | |
| 137 | - | |
| 138 | -- (void)setAllowPreview:(BOOL)allowPreview { | |
| 139 | - _allowPreview = allowPreview; | |
| 140 | - if (allowPreview) { | |
| 141 | - _imageView.userInteractionEnabled = NO; | |
| 142 | - _tapGesture.enabled = NO; | |
| 143 | - } else { | |
| 144 | - _imageView.userInteractionEnabled = YES; | |
| 145 | - _tapGesture.enabled = YES; | |
| 146 | - } | |
| 147 | -} | |
| 148 | - | |
| 149 | -- (void)selectPhotoButtonClick:(UIButton *)sender { | |
| 150 | - if (self.didSelectPhotoBlock) { | |
| 151 | - self.didSelectPhotoBlock(sender.isSelected); | |
| 152 | - } | |
| 153 | - self.selectImageView.image = sender.isSelected ? self.photoSelImage : self.photoDefImage; | |
| 154 | - if (sender.isSelected) { | |
| 155 | - if (![TZImagePickerConfig sharedInstance].showSelectedIndex && ![TZImagePickerConfig sharedInstance].showPhotoCannotSelectLayer) { | |
| 156 | - [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger]; | |
| 157 | - } | |
| 158 | - // 用户选中了该图片,提前获取一下大图 | |
| 159 | - [self requestBigImage]; | |
| 160 | - } else { // 取消选中,取消大图的获取 | |
| 161 | - [self cancelBigImageRequest]; | |
| 162 | - } | |
| 163 | -} | |
| 164 | - | |
| 165 | -/// 只在单选状态且allowPreview为NO时会有该事件 | |
| 166 | -- (void)didTapImageView { | |
| 167 | - if (self.didSelectPhotoBlock) { | |
| 168 | - self.didSelectPhotoBlock(NO); | |
| 169 | - } | |
| 170 | -} | |
| 171 | - | |
| 172 | -- (void)hideProgressView { | |
| 173 | - if (_progressView) { | |
| 174 | - self.progressView.hidden = YES; | |
| 175 | - self.imageView.alpha = 1.0; | |
| 176 | - } | |
| 177 | -} | |
| 178 | - | |
| 179 | -- (void)requestBigImage { | |
| 180 | - if (_bigImageRequestID) { | |
| 181 | - [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID]; | |
| 182 | - } | |
| 183 | - | |
| 184 | - _bigImageRequestID = [[TZImageManager manager] requestImageDataForAsset:_model.asset completion:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { | |
| 185 | - [self hideProgressView]; | |
| 186 | - } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 187 | - if (self.model.isSelected) { | |
| 188 | - progress = progress > 0.02 ? progress : 0.02;; | |
| 189 | - self.progressView.progress = progress; | |
| 190 | - self.progressView.hidden = NO; | |
| 191 | - self.imageView.alpha = 0.4; | |
| 192 | - if (progress >= 1) { | |
| 193 | - [self hideProgressView]; | |
| 194 | - } | |
| 195 | - } else { | |
| 196 | - *stop = YES; | |
| 197 | - [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; | |
| 198 | - [self cancelBigImageRequest]; | |
| 199 | - } | |
| 200 | - }]; | |
| 201 | -} | |
| 202 | - | |
| 203 | -- (void)cancelBigImageRequest { | |
| 204 | - if (_bigImageRequestID) { | |
| 205 | - [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID]; | |
| 206 | - } | |
| 207 | - [self hideProgressView]; | |
| 208 | -} | |
| 209 | - | |
| 210 | -#pragma mark - Lazy load | |
| 211 | - | |
| 212 | -- (UIButton *)selectPhotoButton { | |
| 213 | - if (_selectPhotoButton == nil) { | |
| 214 | - UIButton *selectPhotoButton = [[UIButton alloc] init]; | |
| 215 | - [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside]; | |
| 216 | - [self.contentView addSubview:selectPhotoButton]; | |
| 217 | - _selectPhotoButton = selectPhotoButton; | |
| 218 | - } | |
| 219 | - return _selectPhotoButton; | |
| 220 | -} | |
| 221 | - | |
| 222 | -- (UIImageView *)imageView { | |
| 223 | - if (_imageView == nil) { | |
| 224 | - UIImageView *imageView = [[UIImageView alloc] init]; | |
| 225 | - imageView.contentMode = UIViewContentModeScaleAspectFill; | |
| 226 | - imageView.clipsToBounds = YES; | |
| 227 | - [self.contentView addSubview:imageView]; | |
| 228 | - _imageView = imageView; | |
| 229 | - | |
| 230 | - _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapImageView)]; | |
| 231 | - [_imageView addGestureRecognizer:_tapGesture]; | |
| 232 | - } | |
| 233 | - return _imageView; | |
| 234 | -} | |
| 235 | - | |
| 236 | -- (UIImageView *)selectImageView { | |
| 237 | - if (_selectImageView == nil) { | |
| 238 | - UIImageView *selectImageView = [[UIImageView alloc] init]; | |
| 239 | - selectImageView.contentMode = UIViewContentModeCenter; | |
| 240 | - selectImageView.clipsToBounds = YES; | |
| 241 | - [self.contentView addSubview:selectImageView]; | |
| 242 | - _selectImageView = selectImageView; | |
| 243 | - } | |
| 244 | - return _selectImageView; | |
| 245 | -} | |
| 246 | - | |
| 247 | -- (UIView *)bottomView { | |
| 248 | - if (_bottomView == nil) { | |
| 249 | - UIView *bottomView = [[UIView alloc] init]; | |
| 250 | - static NSInteger rgb = 0; | |
| 251 | - bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8]; | |
| 252 | - [self.contentView addSubview:bottomView]; | |
| 253 | - _bottomView = bottomView; | |
| 254 | - } | |
| 255 | - return _bottomView; | |
| 256 | -} | |
| 257 | - | |
| 258 | -- (UIButton *)cannotSelectLayerButton { | |
| 259 | - if (_cannotSelectLayerButton == nil) { | |
| 260 | - UIButton *cannotSelectLayerButton = [[UIButton alloc] init]; | |
| 261 | - [self.contentView addSubview:cannotSelectLayerButton]; | |
| 262 | - _cannotSelectLayerButton = cannotSelectLayerButton; | |
| 263 | - } | |
| 264 | - return _cannotSelectLayerButton; | |
| 265 | -} | |
| 266 | - | |
| 267 | -- (UIImageView *)videoImgView { | |
| 268 | - if (_videoImgView == nil) { | |
| 269 | - UIImageView *videoImgView = [[UIImageView alloc] init]; | |
| 270 | - [videoImgView setImage:[UIImage imageNamedFromMyBundle:@"VideoSendIcon"]]; | |
| 271 | - [self.bottomView addSubview:videoImgView]; | |
| 272 | - _videoImgView = videoImgView; | |
| 273 | - } | |
| 274 | - return _videoImgView; | |
| 275 | -} | |
| 276 | - | |
| 277 | -- (UILabel *)timeLength { | |
| 278 | - if (_timeLength == nil) { | |
| 279 | - UILabel *timeLength = [[UILabel alloc] init]; | |
| 280 | - timeLength.font = [UIFont boldSystemFontOfSize:11]; | |
| 281 | - timeLength.textColor = [UIColor whiteColor]; | |
| 282 | - timeLength.textAlignment = NSTextAlignmentRight; | |
| 283 | - [self.bottomView addSubview:timeLength]; | |
| 284 | - _timeLength = timeLength; | |
| 285 | - } | |
| 286 | - return _timeLength; | |
| 287 | -} | |
| 288 | - | |
| 289 | -- (UILabel *)indexLabel { | |
| 290 | - if (_indexLabel == nil) { | |
| 291 | - UILabel *indexLabel = [[UILabel alloc] init]; | |
| 292 | - indexLabel.font = [UIFont systemFontOfSize:14]; | |
| 293 | - indexLabel.textColor = [UIColor whiteColor]; | |
| 294 | - indexLabel.textAlignment = NSTextAlignmentCenter; | |
| 295 | - [self.contentView addSubview:indexLabel]; | |
| 296 | - _indexLabel = indexLabel; | |
| 297 | - } | |
| 298 | - return _indexLabel; | |
| 299 | -} | |
| 300 | - | |
| 301 | -- (TZProgressView *)progressView { | |
| 302 | - if (_progressView == nil) { | |
| 303 | - _progressView = [[TZProgressView alloc] init]; | |
| 304 | - _progressView.hidden = YES; | |
| 305 | - [self addSubview:_progressView]; | |
| 306 | - } | |
| 307 | - return _progressView; | |
| 308 | -} | |
| 309 | - | |
| 310 | -- (void)layoutSubviews { | |
| 311 | - [super layoutSubviews]; | |
| 312 | - _cannotSelectLayerButton.frame = self.bounds; | |
| 313 | - if (self.allowPreview) { | |
| 314 | - _selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44); | |
| 315 | - } else { | |
| 316 | - _selectPhotoButton.frame = self.bounds; | |
| 317 | - } | |
| 318 | - _selectImageView.frame = CGRectMake(self.tz_width - 27, 3, 24, 24); | |
| 319 | - if (_selectImageView.image.size.width <= 27) { | |
| 320 | - _selectImageView.contentMode = UIViewContentModeCenter; | |
| 321 | - } else { | |
| 322 | - _selectImageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 323 | - } | |
| 324 | - _indexLabel.frame = _selectImageView.frame; | |
| 325 | - _imageView.frame = CGRectMake(0, 0, self.tz_width, self.tz_height); | |
| 326 | - | |
| 327 | - static CGFloat progressWH = 20; | |
| 328 | - CGFloat progressXY = (self.tz_width - progressWH) / 2; | |
| 329 | - _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH); | |
| 330 | - | |
| 331 | - _bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17); | |
| 332 | - _videoImgView.frame = CGRectMake(8, 0, 17, 17); | |
| 333 | - _timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17); | |
| 334 | - | |
| 335 | - self.type = (NSInteger)self.model.type; | |
| 336 | - self.showSelectBtn = self.showSelectBtn; | |
| 337 | - | |
| 338 | - [self.contentView bringSubviewToFront:_bottomView]; | |
| 339 | - [self.contentView bringSubviewToFront:_cannotSelectLayerButton]; | |
| 340 | - [self.contentView bringSubviewToFront:_selectPhotoButton]; | |
| 341 | - [self.contentView bringSubviewToFront:_selectImageView]; | |
| 342 | - [self.contentView bringSubviewToFront:_indexLabel]; | |
| 343 | - | |
| 344 | - if (self.assetCellDidLayoutSubviewsBlock) { | |
| 345 | - self.assetCellDidLayoutSubviewsBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView); | |
| 346 | - } | |
| 347 | -} | |
| 348 | - | |
| 349 | -@end | |
| 350 | - | |
| 351 | -@interface TZAlbumCell () | |
| 352 | -@property (weak, nonatomic) UIImageView *posterImageView; | |
| 353 | -@property (weak, nonatomic) UILabel *titleLabel; | |
| 354 | -@end | |
| 355 | - | |
| 356 | -@implementation TZAlbumCell | |
| 357 | - | |
| 358 | -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { | |
| 359 | - self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; | |
| 360 | - self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; | |
| 361 | - return self; | |
| 362 | -} | |
| 363 | - | |
| 364 | -- (void)setModel:(TZAlbumModel *)model { | |
| 365 | - _model = model; | |
| 366 | - | |
| 367 | - NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor blackColor]}]; | |
| 368 | - NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}]; | |
| 369 | - [nameString appendAttributedString:countString]; | |
| 370 | - self.titleLabel.attributedText = nameString; | |
| 371 | - [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) { | |
| 372 | - self.posterImageView.image = postImage; | |
| 373 | - }]; | |
| 374 | - if (model.selectedCount) { | |
| 375 | - self.selectedCountButton.hidden = NO; | |
| 376 | - [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal]; | |
| 377 | - } else { | |
| 378 | - self.selectedCountButton.hidden = YES; | |
| 379 | - } | |
| 380 | - | |
| 381 | - if (self.albumCellDidSetModelBlock) { | |
| 382 | - self.albumCellDidSetModelBlock(self, _posterImageView, _titleLabel); | |
| 383 | - } | |
| 384 | -} | |
| 385 | - | |
| 386 | -/// For fitting iOS6 | |
| 387 | -- (void)layoutSubviews { | |
| 388 | - if (iOS7Later) [super layoutSubviews]; | |
| 389 | - _selectedCountButton.frame = CGRectMake(self.tz_width - 24 - 30, 23, 24, 24); | |
| 390 | - NSInteger titleHeight = ceil(self.titleLabel.font.lineHeight); | |
| 391 | - self.titleLabel.frame = CGRectMake(80, (self.tz_height - titleHeight) / 2, self.tz_width - 80 - 50, titleHeight); | |
| 392 | - self.posterImageView.frame = CGRectMake(0, 0, 70, 70); | |
| 393 | - | |
| 394 | - if (self.albumCellDidLayoutSubviewsBlock) { | |
| 395 | - self.albumCellDidLayoutSubviewsBlock(self, _posterImageView, _titleLabel); | |
| 396 | - } | |
| 397 | -} | |
| 398 | - | |
| 399 | -- (void)layoutSublayersOfLayer:(CALayer *)layer { | |
| 400 | - if (iOS7Later) [super layoutSublayersOfLayer:layer]; | |
| 401 | -} | |
| 402 | - | |
| 403 | -#pragma mark - Lazy load | |
| 404 | - | |
| 405 | -- (UIImageView *)posterImageView { | |
| 406 | - if (_posterImageView == nil) { | |
| 407 | - UIImageView *posterImageView = [[UIImageView alloc] init]; | |
| 408 | - posterImageView.contentMode = UIViewContentModeScaleAspectFill; | |
| 409 | - posterImageView.clipsToBounds = YES; | |
| 410 | - [self.contentView addSubview:posterImageView]; | |
| 411 | - _posterImageView = posterImageView; | |
| 412 | - } | |
| 413 | - return _posterImageView; | |
| 414 | -} | |
| 415 | - | |
| 416 | -- (UILabel *)titleLabel { | |
| 417 | - if (_titleLabel == nil) { | |
| 418 | - UILabel *titleLabel = [[UILabel alloc] init]; | |
| 419 | - titleLabel.font = [UIFont boldSystemFontOfSize:17]; | |
| 420 | - titleLabel.textColor = [UIColor blackColor]; | |
| 421 | - titleLabel.textAlignment = NSTextAlignmentLeft; | |
| 422 | - [self.contentView addSubview:titleLabel]; | |
| 423 | - _titleLabel = titleLabel; | |
| 424 | - } | |
| 425 | - return _titleLabel; | |
| 426 | -} | |
| 427 | - | |
| 428 | -- (UIButton *)selectedCountButton { | |
| 429 | - if (_selectedCountButton == nil) { | |
| 430 | - UIButton *selectedCountButton = [[UIButton alloc] init]; | |
| 431 | - selectedCountButton.layer.cornerRadius = 12; | |
| 432 | - selectedCountButton.clipsToBounds = YES; | |
| 433 | - selectedCountButton.backgroundColor = [UIColor redColor]; | |
| 434 | - [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
| 435 | - selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15]; | |
| 436 | - [self.contentView addSubview:selectedCountButton]; | |
| 437 | - _selectedCountButton = selectedCountButton; | |
| 438 | - } | |
| 439 | - return _selectedCountButton; | |
| 440 | -} | |
| 441 | - | |
| 442 | -@end | |
| 443 | - | |
| 444 | - | |
| 445 | - | |
| 446 | -@implementation TZAssetCameraCell | |
| 447 | - | |
| 448 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 449 | - self = [super initWithFrame:frame]; | |
| 450 | - if (self) { | |
| 451 | - self.backgroundColor = [UIColor whiteColor]; | |
| 452 | - _imageView = [[UIImageView alloc] init]; | |
| 453 | - _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; | |
| 454 | - _imageView.contentMode = UIViewContentModeScaleAspectFill; | |
| 455 | - [self.contentView addSubview:_imageView]; | |
| 456 | - self.clipsToBounds = YES; | |
| 457 | - } | |
| 458 | - return self; | |
| 459 | -} | |
| 460 | - | |
| 461 | -- (void)layoutSubviews { | |
| 462 | - [super layoutSubviews]; | |
| 463 | - _imageView.frame = self.bounds; | |
| 464 | -} | |
| 465 | - | |
| 466 | -@end |
CNLiveImagePickerController/TZAssetModel.h deleted
100755 → 0
| 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 | - | |
| 30 | -/// Init a photo dataModel With a asset | |
| 31 | -/// 用一个PHAsset/ALAsset实例,初始化一个照片模型 | |
| 32 | -+ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type; | |
| 33 | -+ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength; | |
| 34 | - | |
| 35 | -@end | |
| 36 | - | |
| 37 | - | |
| 38 | -@class PHFetchResult; | |
| 39 | -@interface TZAlbumModel : NSObject | |
| 40 | - | |
| 41 | -@property (nonatomic, strong) NSString *name; ///< The album name | |
| 42 | -@property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain | |
| 43 | -@property (nonatomic, strong) id result; ///< PHFetchResult<PHAsset> or ALAssetsGroup<ALAsset> | |
| 44 | - | |
| 45 | -@property (nonatomic, strong) NSArray *models; | |
| 46 | -@property (nonatomic, strong) NSArray *selectedModels; | |
| 47 | -@property (nonatomic, assign) NSUInteger selectedCount; | |
| 48 | - | |
| 49 | -@property (nonatomic, assign) BOOL isCameraRoll; | |
| 50 | - | |
| 51 | -- (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets; | |
| 52 | - | |
| 53 | -@end |
CNLiveImagePickerController/TZAssetModel.m deleted
100755 → 0
| 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 | - [[TZImageManager manager] getAssetsFromFetchResult:result completion:^(NSArray<TZAssetModel *> *models) { | |
| 38 | - self->_models = models; | |
| 39 | - if (self->_selectedModels) { | |
| 40 | - [self checkSelectedModels]; | |
| 41 | - } | |
| 42 | - }]; | |
| 43 | - } | |
| 44 | -} | |
| 45 | - | |
| 46 | -- (void)setSelectedModels:(NSArray *)selectedModels { | |
| 47 | - _selectedModels = selectedModels; | |
| 48 | - if (_models) { | |
| 49 | - [self checkSelectedModels]; | |
| 50 | - } | |
| 51 | -} | |
| 52 | - | |
| 53 | -- (void)checkSelectedModels { | |
| 54 | - self.selectedCount = 0; | |
| 55 | - NSMutableArray *selectedAssets = [NSMutableArray array]; | |
| 56 | - for (TZAssetModel *model in _selectedModels) { | |
| 57 | - [selectedAssets addObject:model.asset]; | |
| 58 | - } | |
| 59 | - for (TZAssetModel *model in _models) { | |
| 60 | - if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) { | |
| 61 | - self.selectedCount ++; | |
| 62 | - } | |
| 63 | - } | |
| 64 | -} | |
| 65 | - | |
| 66 | -- (NSString *)name { | |
| 67 | - if (_name) { | |
| 68 | - return _name; | |
| 69 | - } | |
| 70 | - return @""; | |
| 71 | -} | |
| 72 | - | |
| 73 | -@end |
CNLiveImagePickerController/TZGifPhotoPreviewController.h deleted
100755 → 0
| 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/TZGifPhotoPreviewController.m deleted
100755 → 0
| 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+Layout.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 | - if (self.navigationController) { | |
| 133 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 134 | - if (imagePickerVc.autoDismiss) { | |
| 135 | - [self.navigationController dismissViewControllerAnimated:YES completion:^{ | |
| 136 | - [self callDelegateMethod]; | |
| 137 | - }]; | |
| 138 | - } else { | |
| 139 | - [self callDelegateMethod]; | |
| 140 | - } | |
| 141 | - } else { | |
| 142 | - [self dismissViewControllerAnimated:YES completion:^{ | |
| 143 | - [self callDelegateMethod]; | |
| 144 | - }]; | |
| 145 | - } | |
| 146 | -} | |
| 147 | - | |
| 148 | -- (void)callDelegateMethod { | |
| 149 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 150 | - UIImage *animatedImage = _previewView.imageView.image; | |
| 151 | - if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) { | |
| 152 | - [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset]; | |
| 153 | - } | |
| 154 | - if (imagePickerVc.didFinishPickingGifImageHandle) { | |
| 155 | - imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset); | |
| 156 | - } | |
| 157 | -} | |
| 158 | - | |
| 159 | -#pragma clang diagnostic pop | |
| 160 | - | |
| 161 | -@end |
CNLiveImagePickerController/TZImageCropManager.h deleted
100755 → 0
| 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/TZImageCropManager.m deleted
100755 → 0
| 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+Layout.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/TZImageManager.h deleted
100755 → 0
| 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 - ADD: 原有逻辑-会话id(LXG) | |
| 27 | - | |
| 28 | -/// 导出路径 | |
| 29 | -@property (nonatomic, copy) NSString *outputPath; | |
| 30 | - | |
| 31 | -@property (nonatomic, assign) BOOL shouldFixOrientation; | |
| 32 | - | |
| 33 | -/// Default is 600px / 默认600像素宽 | |
| 34 | -@property (nonatomic, assign) CGFloat photoPreviewMaxWidth; | |
| 35 | -/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽 | |
| 36 | -@property (nonatomic, assign) CGFloat photoWidth; | |
| 37 | - | |
| 38 | -/// Default is 4, Use in photos collectionView in TZPhotoPickerController | |
| 39 | -/// 默认4列, TZPhotoPickerController中的照片collectionView | |
| 40 | -@property (nonatomic, assign) NSInteger columnNumber; | |
| 41 | - | |
| 42 | -/// Sort photos ascending by modificationDate,Default is YES | |
| 43 | -/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个 | |
| 44 | -@property (nonatomic, assign) BOOL sortAscendingByModificationDate; | |
| 45 | - | |
| 46 | -/// Minimum selectable photo width, Default is 0 | |
| 47 | -/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中 | |
| 48 | -@property (nonatomic, assign) NSInteger minPhotoWidthSelectable; | |
| 49 | -@property (nonatomic, assign) NSInteger minPhotoHeightSelectable; | |
| 50 | -@property (nonatomic, assign) BOOL hideWhenCanNotSelect; | |
| 51 | - | |
| 52 | -/// Return YES if Authorized 返回YES如果得到了授权 | |
| 53 | -- (BOOL)authorizationStatusAuthorized; | |
| 54 | -+ (NSInteger)authorizationStatus; | |
| 55 | -- (void)requestAuthorizationWithCompletion:(void (^)(void))completion; | |
| 56 | - | |
| 57 | -/// Get Album 获得相册/相册数组 | |
| 58 | -- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion; | |
| 59 | -- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *models))completion; | |
| 60 | - | |
| 61 | -/// Get Assets 获得Asset数组 | |
| 62 | -- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *models))completion; | |
| 63 | -- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *models))completion; | |
| 64 | -- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion; | |
| 65 | - | |
| 66 | -/// Get photo 获得照片 | |
| 67 | -- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion; | |
| 68 | - | |
| 69 | -- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; | |
| 70 | -- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; | |
| 71 | -- (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; | |
| 72 | -- (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; | |
| 73 | -- (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; | |
| 74 | - | |
| 75 | -/// Get full Image 获取原图 | |
| 76 | -/// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。 | |
| 77 | -- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion; | |
| 78 | -- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; | |
| 79 | -// 该方法中,completion只会走一次 | |
| 80 | -- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion; | |
| 81 | -- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion; | |
| 82 | - | |
| 83 | -/// Save photo 保存照片 | |
| 84 | -- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion; | |
| 85 | -- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion; | |
| 86 | - | |
| 87 | -/// Save video 保存视频 | |
| 88 | -- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion; | |
| 89 | -- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion; | |
| 90 | - | |
| 91 | -/// Get video 获得视频 | |
| 92 | -- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion; | |
| 93 | -- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion; | |
| 94 | - | |
| 95 | -/// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480 | |
| 96 | -- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure; | |
| 97 | -- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure; | |
| 98 | -/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success: | |
| 99 | -- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion __attribute__((deprecated("Use -getVideoOutputPathWithAsset:failure:success:"))); | |
| 100 | - | |
| 101 | -/// Get photo bytes 获得一组照片的大小 | |
| 102 | -- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion; | |
| 103 | - | |
| 104 | -/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset | |
| 105 | -- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset; | |
| 106 | - | |
| 107 | -- (NSString *)getAssetIdentifier:(id)asset; | |
| 108 | -- (BOOL)isCameraRollAlbum:(id)metadata; | |
| 109 | - | |
| 110 | -/// 检查照片大小是否满足最小要求 | |
| 111 | -- (BOOL)isPhotoSelectableWithAsset:(id)asset; | |
| 112 | -- (CGSize)photoSizeWithAsset:(id)asset; | |
| 113 | - | |
| 114 | -/// 修正图片转向 | |
| 115 | -- (UIImage *)fixOrientation:(UIImage *)aImage; | |
| 116 | - | |
| 117 | -/// 获取asset的资源类型 | |
| 118 | -- (TZAssetModelMediaType)getAssetType:(id)asset; | |
| 119 | -/// 缩放图片至新尺寸 | |
| 120 | -- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size; | |
| 121 | - | |
| 122 | -/// 判断asset是否是视频 | |
| 123 | -- (BOOL)isVideo:(id)asset; | |
| 124 | - | |
| 125 | -@end | |
| 126 | - | |
| 127 | -//@interface TZSortDescriptor : NSSortDescriptor | |
| 128 | -// | |
| 129 | -//@end |
CNLiveImagePickerController/TZImageManager.m deleted
100755 → 0
| 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 | - [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { | |
| 150 | - if ([group numberOfAssets] < 1) return; | |
| 151 | - if ([self isCameraRollAlbum:group]) { | |
| 152 | - NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; | |
| 153 | - model = [self modelWithResult:group name:name isCameraRoll:YES needFetchAssets:needFetchAssets]; | |
| 154 | - if (completion) completion(model); | |
| 155 | - *stop = YES; | |
| 156 | - } | |
| 157 | - } failureBlock:nil]; | |
| 158 | - } | |
| 159 | -} | |
| 160 | - | |
| 161 | -- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *))completion{ | |
| 162 | - NSMutableArray *albumArr = [NSMutableArray array]; | |
| 163 | - if (iOS8Later) { | |
| 164 | - PHFetchOptions *option = [[PHFetchOptions alloc] init]; | |
| 165 | - if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage]; | |
| 166 | - if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", | |
| 167 | - PHAssetMediaTypeVideo]; | |
| 168 | - // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]]; | |
| 169 | - if (!self.sortAscendingByModificationDate) { | |
| 170 | - option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]]; | |
| 171 | - } | |
| 172 | - // 我的照片流 1.6.10重新加入.. | |
| 173 | - PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil]; | |
| 174 | - PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; | |
| 175 | - PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil]; | |
| 176 | - PHFetchResult *syncedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumSyncedAlbum options:nil]; | |
| 177 | - PHFetchResult *sharedAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumCloudShared options:nil]; | |
| 178 | - NSArray *allAlbums = @[myPhotoStreamAlbum,smartAlbums,topLevelUserCollections,syncedAlbums,sharedAlbums]; | |
| 179 | - for (PHFetchResult *fetchResult in allAlbums) { | |
| 180 | - for (PHAssetCollection *collection in fetchResult) { | |
| 181 | - // 有可能是PHCollectionList类的的对象,过滤掉 | |
| 182 | - if (![collection isKindOfClass:[PHAssetCollection class]]) continue; | |
| 183 | - // 过滤空相册 | |
| 184 | - if (collection.estimatedAssetCount <= 0) continue; | |
| 185 | - PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option]; | |
| 186 | - if (fetchResult.count < 1) continue; | |
| 187 | - | |
| 188 | - if ([self.pickerDelegate respondsToSelector:@selector(isAlbumCanSelect:result:)]) { | |
| 189 | - if (![self.pickerDelegate isAlbumCanSelect:collection.localizedTitle result:fetchResult]) { | |
| 190 | - continue; | |
| 191 | - } | |
| 192 | - } | |
| 193 | - | |
| 194 | - if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumAllHidden) continue; | |
| 195 | - if (collection.assetCollectionSubtype == 1000000201) continue; //『最近删除』相册 | |
| 196 | - if ([self isCameraRollAlbum:collection]) { | |
| 197 | - [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0]; | |
| 198 | - } else { | |
| 199 | - [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:NO needFetchAssets:needFetchAssets]]; | |
| 200 | - } | |
| 201 | - } | |
| 202 | - } | |
| 203 | - if (completion && albumArr.count > 0) completion(albumArr); | |
| 204 | - } else { | |
| 205 | - [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { | |
| 206 | - if (group == nil) { | |
| 207 | - if (completion && albumArr.count > 0) completion(albumArr); | |
| 208 | - } | |
| 209 | - if ([group numberOfAssets] < 1) return; | |
| 210 | - NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; | |
| 211 | - | |
| 212 | - if ([self.pickerDelegate respondsToSelector:@selector(isAlbumCanSelect:result:)]) { | |
| 213 | - if (![self.pickerDelegate isAlbumCanSelect:name result:group]) { | |
| 214 | - return; | |
| 215 | - } | |
| 216 | - } | |
| 217 | - | |
| 218 | - if ([self isCameraRollAlbum:group]) { | |
| 219 | - [albumArr insertObject:[self modelWithResult:group name:name isCameraRoll:YES needFetchAssets:needFetchAssets] atIndex:0]; | |
| 220 | - } else if ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupPhotoStream) { | |
| 221 | - if (albumArr.count) { | |
| 222 | - [albumArr insertObject:[self modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets] atIndex:1]; | |
| 223 | - } else { | |
| 224 | - [albumArr addObject:[self modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets]]; | |
| 225 | - } | |
| 226 | - } else { | |
| 227 | - [albumArr addObject:[self modelWithResult:group name:name isCameraRoll:NO needFetchAssets:needFetchAssets]]; | |
| 228 | - } | |
| 229 | - } failureBlock:nil]; | |
| 230 | - } | |
| 231 | -} | |
| 232 | - | |
| 233 | -#pragma mark - Get Assets | |
| 234 | - | |
| 235 | -/// Get Assets 获得照片数组 | |
| 236 | -- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *))completion { | |
| 237 | - TZImagePickerConfig *config = [TZImagePickerConfig sharedInstance]; | |
| 238 | - return [self getAssetsFromFetchResult:result allowPickingVideo:config.allowPickingVideo allowPickingImage:config.allowPickingImage completion:completion]; | |
| 239 | -} | |
| 240 | - | |
| 241 | -- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *))completion { | |
| 242 | - NSMutableArray *photoArr = [NSMutableArray array]; | |
| 243 | - if ([result isKindOfClass:[PHFetchResult class]]) { | |
| 244 | - PHFetchResult *fetchResult = (PHFetchResult *)result; | |
| 245 | - [fetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | |
| 246 | - TZAssetModel *model = [self assetModelWithAsset:obj allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; | |
| 247 | - if (model) { | |
| 248 | - [photoArr addObject:model]; | |
| 249 | - } | |
| 250 | - }]; | |
| 251 | - if (completion) completion(photoArr); | |
| 252 | - } else if ([result isKindOfClass:[ALAssetsGroup class]]) { | |
| 253 | - ALAssetsGroup *group = (ALAssetsGroup *)result; | |
| 254 | - if (allowPickingImage && allowPickingVideo) { | |
| 255 | - [group setAssetsFilter:[ALAssetsFilter allAssets]]; | |
| 256 | - } else if (allowPickingVideo) { | |
| 257 | - [group setAssetsFilter:[ALAssetsFilter allVideos]]; | |
| 258 | - } else if (allowPickingImage) { | |
| 259 | - [group setAssetsFilter:[ALAssetsFilter allPhotos]]; | |
| 260 | - } | |
| 261 | - ALAssetsGroupEnumerationResultsBlock resultBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) { | |
| 262 | - if (result == nil) { | |
| 263 | - if (completion) completion(photoArr); | |
| 264 | - } | |
| 265 | - TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; | |
| 266 | - if (model) { | |
| 267 | - [photoArr addObject:model]; | |
| 268 | - } | |
| 269 | - }; | |
| 270 | - if (self.sortAscendingByModificationDate) { | |
| 271 | - [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { | |
| 272 | - if (resultBlock) { resultBlock(result,index,stop); } | |
| 273 | - }]; | |
| 274 | - } else { | |
| 275 | - [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { | |
| 276 | - if (resultBlock) {resultBlock(result,index,stop); } | |
| 277 | - }]; | |
| 278 | - } | |
| 279 | - } | |
| 280 | -} | |
| 281 | - | |
| 282 | -/// Get asset at index 获得下标为index的单个照片 | |
| 283 | -/// if index beyond bounds, return nil in callback 如果索引越界, 在回调中返回 nil | |
| 284 | -- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *))completion { | |
| 285 | - if ([result isKindOfClass:[PHFetchResult class]]) { | |
| 286 | - PHFetchResult *fetchResult = (PHFetchResult *)result; | |
| 287 | - PHAsset *asset; | |
| 288 | - @try { | |
| 289 | - asset = fetchResult[index]; | |
| 290 | - } | |
| 291 | - @catch (NSException* e) { | |
| 292 | - if (completion) completion(nil); | |
| 293 | - return; | |
| 294 | - } | |
| 295 | - TZAssetModel *model = [self assetModelWithAsset:asset allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; | |
| 296 | - if (completion) completion(model); | |
| 297 | - } else if ([result isKindOfClass:[ALAssetsGroup class]]) { | |
| 298 | - ALAssetsGroup *group = (ALAssetsGroup *)result; | |
| 299 | - if (allowPickingImage && allowPickingVideo) { | |
| 300 | - [group setAssetsFilter:[ALAssetsFilter allAssets]]; | |
| 301 | - } else if (allowPickingVideo) { | |
| 302 | - [group setAssetsFilter:[ALAssetsFilter allVideos]]; | |
| 303 | - } else if (allowPickingImage) { | |
| 304 | - [group setAssetsFilter:[ALAssetsFilter allPhotos]]; | |
| 305 | - } | |
| 306 | - NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:index]; | |
| 307 | - @try { | |
| 308 | - [group enumerateAssetsAtIndexes:indexSet options:NSEnumerationConcurrent usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { | |
| 309 | - if (!result) return; | |
| 310 | - TZAssetModel *model = [self assetModelWithAsset:result allowPickingVideo:allowPickingVideo allowPickingImage:allowPickingImage]; | |
| 311 | - if (completion) completion(model); | |
| 312 | - }]; | |
| 313 | - } | |
| 314 | - @catch (NSException* e) { | |
| 315 | - if (completion) completion(nil); | |
| 316 | - } | |
| 317 | - } | |
| 318 | -} | |
| 319 | - | |
| 320 | -- (TZAssetModel *)assetModelWithAsset:(id)asset allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage { | |
| 321 | - BOOL canSelect = YES; | |
| 322 | - if ([self.pickerDelegate respondsToSelector:@selector(isAssetCanSelect:)]) { | |
| 323 | - canSelect = [self.pickerDelegate isAssetCanSelect:asset]; | |
| 324 | - } | |
| 325 | - if (!canSelect) return nil; | |
| 326 | - | |
| 327 | - TZAssetModel *model; | |
| 328 | - TZAssetModelMediaType type = [self getAssetType:asset]; | |
| 329 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 330 | - if (!allowPickingVideo && type == TZAssetModelMediaTypeVideo) return nil; | |
| 331 | - if (!allowPickingImage && type == TZAssetModelMediaTypePhoto) return nil; | |
| 332 | - if (!allowPickingImage && type == TZAssetModelMediaTypePhotoGif) return nil; | |
| 333 | - | |
| 334 | - PHAsset *phAsset = (PHAsset *)asset; | |
| 335 | - if (self.hideWhenCanNotSelect) { | |
| 336 | - // 过滤掉尺寸不满足要求的图片 | |
| 337 | - if (![self isPhotoSelectableWithAsset:phAsset]) { | |
| 338 | - return nil; | |
| 339 | - } | |
| 340 | - } | |
| 341 | - NSString *timeLength = type == TZAssetModelMediaTypeVideo ? [NSString stringWithFormat:@"%0.0f",phAsset.duration] : @""; | |
| 342 | - timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue]; | |
| 343 | - model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength]; | |
| 344 | - } else { | |
| 345 | - if (!allowPickingVideo){ | |
| 346 | - model = [TZAssetModel modelWithAsset:asset type:type]; | |
| 347 | - return model; | |
| 348 | - } | |
| 349 | - /// Allow picking video | |
| 350 | - if (type == TZAssetModelMediaTypeVideo) { | |
| 351 | - NSTimeInterval duration = [[asset valueForProperty:ALAssetPropertyDuration] doubleValue]; | |
| 352 | - NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration]; | |
| 353 | - timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue]; | |
| 354 | - model = [TZAssetModel modelWithAsset:asset type:type timeLength:timeLength]; | |
| 355 | - } else { | |
| 356 | - if (self.hideWhenCanNotSelect) { | |
| 357 | - // 过滤掉尺寸不满足要求的图片 | |
| 358 | - if (![self isPhotoSelectableWithAsset:asset]) { | |
| 359 | - return nil; | |
| 360 | - } | |
| 361 | - } | |
| 362 | - model = [TZAssetModel modelWithAsset:asset type:type]; | |
| 363 | - } | |
| 364 | - } | |
| 365 | - return model; | |
| 366 | -} | |
| 367 | - | |
| 368 | -- (TZAssetModelMediaType)getAssetType:(id)asset { | |
| 369 | - TZAssetModelMediaType type = TZAssetModelMediaTypePhoto; | |
| 370 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 371 | - PHAsset *phAsset = (PHAsset *)asset; | |
| 372 | - if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo; | |
| 373 | - else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio; | |
| 374 | - else if (phAsset.mediaType == PHAssetMediaTypeImage) { | |
| 375 | - if (@available(iOS 9.1, *)) { | |
| 376 | - // if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto; | |
| 377 | - } | |
| 378 | - // Gif | |
| 379 | - if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) { | |
| 380 | - type = TZAssetModelMediaTypePhotoGif; | |
| 381 | - } | |
| 382 | - } | |
| 383 | - } else { | |
| 384 | - if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) { | |
| 385 | - type = TZAssetModelMediaTypeVideo; | |
| 386 | - } | |
| 387 | - } | |
| 388 | - return type; | |
| 389 | -} | |
| 390 | - | |
| 391 | -- (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration { | |
| 392 | - NSString *newTime; | |
| 393 | - if (duration < 10) { | |
| 394 | - newTime = [NSString stringWithFormat:@"0:0%zd",duration]; | |
| 395 | - } else if (duration < 60) { | |
| 396 | - newTime = [NSString stringWithFormat:@"0:%zd",duration]; | |
| 397 | - } else { | |
| 398 | - NSInteger min = duration / 60; | |
| 399 | - NSInteger sec = duration - (min * 60); | |
| 400 | - if (sec < 10) { | |
| 401 | - newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec]; | |
| 402 | - } else { | |
| 403 | - newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec]; | |
| 404 | - } | |
| 405 | - } | |
| 406 | - return newTime; | |
| 407 | -} | |
| 408 | - | |
| 409 | -/// Get photo bytes 获得一组照片的大小 | |
| 410 | -- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion { | |
| 411 | - if (!photos || !photos.count) { | |
| 412 | - if (completion) completion(@"0B"); | |
| 413 | - return; | |
| 414 | - } | |
| 415 | - __block NSInteger dataLength = 0; | |
| 416 | - __block NSInteger assetCount = 0; | |
| 417 | - for (NSInteger i = 0; i < photos.count; i++) { | |
| 418 | - TZAssetModel *model = photos[i]; | |
| 419 | - if ([model.asset isKindOfClass:[PHAsset class]]) { | |
| 420 | - PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; | |
| 421 | - options.resizeMode = PHImageRequestOptionsResizeModeFast; | |
| 422 | - options.networkAccessAllowed = YES; | |
| 423 | - if (model.type == TZAssetModelMediaTypePhotoGif) { | |
| 424 | - options.version = PHImageRequestOptionsVersionOriginal; | |
| 425 | - } | |
| 426 | - [[PHImageManager defaultManager] requestImageDataForAsset:model.asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { | |
| 427 | - if (model.type != TZAssetModelMediaTypeVideo) dataLength += imageData.length; | |
| 428 | - assetCount ++; | |
| 429 | - if (assetCount >= photos.count) { | |
| 430 | - NSString *bytes = [self getBytesFromDataLength:dataLength]; | |
| 431 | - if (completion) completion(bytes); | |
| 432 | - } | |
| 433 | - }]; | |
| 434 | - } else if ([model.asset isKindOfClass:[ALAsset class]]) { | |
| 435 | - ALAssetRepresentation *representation = [model.asset defaultRepresentation]; | |
| 436 | - if (model.type != TZAssetModelMediaTypeVideo) dataLength += (NSInteger)representation.size; | |
| 437 | - if (i >= photos.count - 1) { | |
| 438 | - NSString *bytes = [self getBytesFromDataLength:dataLength]; | |
| 439 | - if (completion) completion(bytes); | |
| 440 | - } | |
| 441 | - } | |
| 442 | - } | |
| 443 | -} | |
| 444 | - | |
| 445 | -- (NSString *)getBytesFromDataLength:(NSInteger)dataLength { | |
| 446 | - NSString *bytes; | |
| 447 | - if (dataLength >= 0.1 * (1024 * 1024)) { | |
| 448 | - bytes = [NSString stringWithFormat:@"%0.1fM",dataLength/1024/1024.0]; | |
| 449 | - } else if (dataLength >= 1024) { | |
| 450 | - bytes = [NSString stringWithFormat:@"%0.0fK",dataLength/1024.0]; | |
| 451 | - } else { | |
| 452 | - bytes = [NSString stringWithFormat:@"%zdB",dataLength]; | |
| 453 | - } | |
| 454 | - return bytes; | |
| 455 | -} | |
| 456 | - | |
| 457 | -#pragma mark - Get Photo | |
| 458 | - | |
| 459 | -/// Get photo 获得照片本身 | |
| 460 | -- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion { | |
| 461 | - CGFloat fullScreenWidth = TZScreenWidth; | |
| 462 | - if (fullScreenWidth > _photoPreviewMaxWidth) { | |
| 463 | - fullScreenWidth = _photoPreviewMaxWidth; | |
| 464 | - } | |
| 465 | - return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:nil networkAccessAllowed:YES]; | |
| 466 | -} | |
| 467 | - | |
| 468 | -- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion { | |
| 469 | - return [self getPhotoWithAsset:asset photoWidth:photoWidth completion:completion progressHandler:nil networkAccessAllowed:YES]; | |
| 470 | -} | |
| 471 | - | |
| 472 | -- (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 { | |
| 473 | - CGFloat fullScreenWidth = TZScreenWidth; | |
| 474 | - if (fullScreenWidth > _photoPreviewMaxWidth) { | |
| 475 | - fullScreenWidth = _photoPreviewMaxWidth; | |
| 476 | - } | |
| 477 | - return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion progressHandler:progressHandler networkAccessAllowed:networkAccessAllowed]; | |
| 478 | -} | |
| 479 | - | |
| 480 | -- (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 { | |
| 481 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 482 | - PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; | |
| 483 | - options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 484 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 485 | - if (progressHandler) { | |
| 486 | - progressHandler(progress, error, stop, info); | |
| 487 | - } | |
| 488 | - }); | |
| 489 | - }; | |
| 490 | - options.networkAccessAllowed = YES; | |
| 491 | - options.resizeMode = PHImageRequestOptionsResizeModeFast; | |
| 492 | - int32_t imageRequestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { | |
| 493 | - if (completion) completion(imageData,dataUTI,orientation,info); | |
| 494 | - }]; | |
| 495 | - return imageRequestID; | |
| 496 | - } else if ([asset isKindOfClass:[ALAsset class]]) { | |
| 497 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 498 | - dispatch_async(dispatch_get_global_queue(0,0), ^{ | |
| 499 | - ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; | |
| 500 | - CGImageRef fullScrennImageRef = [assetRep fullScreenImage]; | |
| 501 | - UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp]; | |
| 502 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 503 | - if (completion) completion(UIImageJPEGRepresentation(fullScrennImage, 0.83), nil, UIImageOrientationUp, nil); | |
| 504 | - }); | |
| 505 | - }); | |
| 506 | - } | |
| 507 | - return 0; | |
| 508 | -} | |
| 509 | - | |
| 510 | -- (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 { | |
| 511 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 512 | - CGSize imageSize; | |
| 513 | - if (photoWidth < TZScreenWidth && photoWidth < _photoPreviewMaxWidth) { | |
| 514 | - imageSize = AssetGridThumbnailSize; | |
| 515 | - } else { | |
| 516 | - PHAsset *phAsset = (PHAsset *)asset; | |
| 517 | - CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight; | |
| 518 | - CGFloat pixelWidth = photoWidth * TZScreenScale * 1.5; | |
| 519 | - // 超宽图片 | |
| 520 | - if (aspectRatio > 1.8) { | |
| 521 | - pixelWidth = pixelWidth * aspectRatio; | |
| 522 | - } | |
| 523 | - // 超高图片 | |
| 524 | - if (aspectRatio < 0.2) { | |
| 525 | - pixelWidth = pixelWidth * 0.5; | |
| 526 | - } | |
| 527 | - CGFloat pixelHeight = pixelWidth / aspectRatio; | |
| 528 | - imageSize = CGSizeMake(pixelWidth, pixelHeight); | |
| 529 | - } | |
| 530 | - | |
| 531 | - __block UIImage *image; | |
| 532 | - // 修复获取图片时出现的瞬间内存过高问题 | |
| 533 | - // 下面两行代码,来自hsjcom,他的github是:https://github.com/hsjcom 表示感谢 | |
| 534 | - PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init]; | |
| 535 | - option.resizeMode = PHImageRequestOptionsResizeModeFast; | |
| 536 | - int32_t imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage *result, NSDictionary *info) { | |
| 537 | - if (result) { | |
| 538 | - image = result; | |
| 539 | - } | |
| 540 | - BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); | |
| 541 | - if (downloadFinined && result) { | |
| 542 | - result = [self fixOrientation:result]; | |
| 543 | - if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); | |
| 544 | - } | |
| 545 | - // Download image from iCloud / 从iCloud下载图片 | |
| 546 | - if ([info objectForKey:PHImageResultIsInCloudKey] && !result && networkAccessAllowed) { | |
| 547 | - PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; | |
| 548 | - options.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 549 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 550 | - if (progressHandler) { | |
| 551 | - progressHandler(progress, error, stop, info); | |
| 552 | - } | |
| 553 | - }); | |
| 554 | - }; | |
| 555 | - options.networkAccessAllowed = YES; | |
| 556 | - options.resizeMode = PHImageRequestOptionsResizeModeFast; | |
| 557 | - [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { | |
| 558 | - UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1]; | |
| 559 | - if (![TZImagePickerConfig sharedInstance].notScaleImage) { | |
| 560 | - resultImage = [self scaleImage:resultImage toSize:imageSize]; | |
| 561 | - } | |
| 562 | - if (!resultImage) { | |
| 563 | - resultImage = image; | |
| 564 | - } | |
| 565 | - resultImage = [self fixOrientation:resultImage]; | |
| 566 | - if (completion) completion(resultImage,info,NO); | |
| 567 | - }]; | |
| 568 | - } | |
| 569 | - }]; | |
| 570 | - return imageRequestID; | |
| 571 | - } else if ([asset isKindOfClass:[ALAsset class]]) { | |
| 572 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 573 | - dispatch_async(dispatch_get_global_queue(0,0), ^{ | |
| 574 | - CGImageRef thumbnailImageRef = alAsset.thumbnail; | |
| 575 | - UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp]; | |
| 576 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 577 | - if (completion) completion(thumbnailImage,nil,YES); | |
| 578 | - | |
| 579 | - if (photoWidth == TZScreenWidth || photoWidth == self->_photoPreviewMaxWidth) { | |
| 580 | - dispatch_async(dispatch_get_global_queue(0,0), ^{ | |
| 581 | - ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; | |
| 582 | - CGImageRef fullScrennImageRef = [assetRep fullScreenImage]; | |
| 583 | - UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp]; | |
| 584 | - | |
| 585 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 586 | - if (completion) completion(fullScrennImage,nil,NO); | |
| 587 | - }); | |
| 588 | - }); | |
| 589 | - } | |
| 590 | - }); | |
| 591 | - }); | |
| 592 | - } | |
| 593 | - return 0; | |
| 594 | -} | |
| 595 | - | |
| 596 | -/// Get postImage / 获取封面图 | |
| 597 | -- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *))completion { | |
| 598 | - if (iOS8Later) { | |
| 599 | - id asset = [model.result lastObject]; | |
| 600 | - if (!self.sortAscendingByModificationDate) { | |
| 601 | - asset = [model.result firstObject]; | |
| 602 | - } | |
| 603 | - [[TZImageManager manager] getPhotoWithAsset:asset photoWidth:80 completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 604 | - if (completion) completion(photo); | |
| 605 | - }]; | |
| 606 | - } else { | |
| 607 | - ALAssetsGroup *group = model.result; | |
| 608 | - UIImage *postImage = [UIImage imageWithCGImage:group.posterImage]; | |
| 609 | - if (completion) completion(postImage); | |
| 610 | - } | |
| 611 | -} | |
| 612 | - | |
| 613 | -/// Get Original Photo / 获取原图 | |
| 614 | -- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion { | |
| 615 | - [self getOriginalPhotoWithAsset:asset newCompletion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 616 | - if (completion) { | |
| 617 | - completion(photo,info); | |
| 618 | - } | |
| 619 | - }]; | |
| 620 | -} | |
| 621 | - | |
| 622 | -- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion { | |
| 623 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 624 | - PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; | |
| 625 | - option.networkAccessAllowed = YES; | |
| 626 | - option.resizeMode = PHImageRequestOptionsResizeModeFast; | |
| 627 | - [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage *result, NSDictionary *info) { | |
| 628 | - BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); | |
| 629 | - if (downloadFinined && result) { | |
| 630 | - result = [self fixOrientation:result]; | |
| 631 | - BOOL isDegraded = [[info objectForKey:PHImageResultIsDegradedKey] boolValue]; | |
| 632 | - if (completion) completion(result,info,isDegraded); | |
| 633 | - } | |
| 634 | - }]; | |
| 635 | - } else if ([asset isKindOfClass:[ALAsset class]]) { | |
| 636 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 637 | - ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; | |
| 638 | - | |
| 639 | - dispatch_async(dispatch_get_global_queue(0,0), ^{ | |
| 640 | - CGImageRef originalImageRef = [assetRep fullResolutionImage]; | |
| 641 | - UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp]; | |
| 642 | - | |
| 643 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 644 | - if (completion) completion(originalImage,nil,NO); | |
| 645 | - }); | |
| 646 | - }); | |
| 647 | - } | |
| 648 | -} | |
| 649 | - | |
| 650 | -- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion { | |
| 651 | - [self getOriginalPhotoDataWithAsset:asset progressHandler:nil completion:completion]; | |
| 652 | -} | |
| 653 | - | |
| 654 | -- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion { | |
| 655 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 656 | - PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init]; | |
| 657 | - option.networkAccessAllowed = YES; | |
| 658 | - if ([[asset valueForKey:@"filename"] hasSuffix:@"GIF"]) { | |
| 659 | - // if version isn't PHImageRequestOptionsVersionOriginal, the gif may cann't play | |
| 660 | - option.version = PHImageRequestOptionsVersionOriginal; | |
| 661 | - } | |
| 662 | - [option setProgressHandler:progressHandler]; | |
| 663 | - option.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; | |
| 664 | - [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { | |
| 665 | - BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); | |
| 666 | - if (downloadFinined && imageData) { | |
| 667 | - if (completion) completion(imageData,info,NO); | |
| 668 | - } | |
| 669 | - }]; | |
| 670 | - } else if ([asset isKindOfClass:[ALAsset class]]) { | |
| 671 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 672 | - ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; | |
| 673 | - Byte *imageBuffer = (Byte *)malloc(assetRep.size); | |
| 674 | - NSUInteger bufferSize = [assetRep getBytes:imageBuffer fromOffset:0.0 length:assetRep.size error:nil]; | |
| 675 | - NSData *imageData = [NSData dataWithBytesNoCopy:imageBuffer length:bufferSize freeWhenDone:YES]; | |
| 676 | - if (completion) completion(imageData,nil,NO); | |
| 677 | - } | |
| 678 | -} | |
| 679 | - | |
| 680 | -#pragma mark - Save photo | |
| 681 | - | |
| 682 | -- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion { | |
| 683 | - [self savePhotoWithImage:image location:nil completion:completion]; | |
| 684 | -} | |
| 685 | - | |
| 686 | -- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion { | |
| 687 | - if (iOS8Later) { | |
| 688 | - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ | |
| 689 | - if (@available(iOS 9, *)) { | |
| 690 | - NSData *data = UIImageJPEGRepresentation(image, 0.9); | |
| 691 | - PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init]; | |
| 692 | - options.shouldMoveFile = YES; | |
| 693 | - PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset]; | |
| 694 | - [request addResourceWithType:PHAssetResourceTypePhoto data:data options:options]; | |
| 695 | - if (location) { | |
| 696 | - request.location = location; | |
| 697 | - } | |
| 698 | - request.creationDate = [NSDate date]; | |
| 699 | - } else { | |
| 700 | - PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image]; | |
| 701 | - if (location) { | |
| 702 | - request.location = location; | |
| 703 | - } | |
| 704 | - request.creationDate = [NSDate date]; | |
| 705 | - } | |
| 706 | - } completionHandler:^(BOOL success, NSError *error) { | |
| 707 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 708 | - if (success && completion) { | |
| 709 | - completion(nil); | |
| 710 | - } else if (error) { | |
| 711 | - NSLog(@"保存照片出错:%@",error.localizedDescription); | |
| 712 | - if (completion) { | |
| 713 | - completion(error); | |
| 714 | - } | |
| 715 | - } | |
| 716 | - }); | |
| 717 | - }]; | |
| 718 | - } else { | |
| 719 | - [self.assetLibrary writeImageToSavedPhotosAlbum:image.CGImage orientation:[self orientationFromImage:image] completionBlock:^(NSURL *assetURL, NSError *error) { | |
| 720 | - if (error) { | |
| 721 | - NSLog(@"保存图片失败:%@",error.localizedDescription); | |
| 722 | - if (completion) { | |
| 723 | - completion(error); | |
| 724 | - } | |
| 725 | - } else { | |
| 726 | - // 多给系统0.5秒的时间,让系统去更新相册数据 | |
| 727 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 728 | - if (completion) { | |
| 729 | - completion(nil); | |
| 730 | - } | |
| 731 | - }); | |
| 732 | - } | |
| 733 | - }]; | |
| 734 | - } | |
| 735 | -} | |
| 736 | - | |
| 737 | -#pragma mark - Save video | |
| 738 | - | |
| 739 | -- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion { | |
| 740 | - [self saveVideoWithUrl:url location:nil completion:completion]; | |
| 741 | -} | |
| 742 | - | |
| 743 | -- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion { | |
| 744 | - if (iOS8Later) { | |
| 745 | - [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ | |
| 746 | - if (@available(iOS 9, *)) { | |
| 747 | - PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init]; | |
| 748 | - options.shouldMoveFile = YES; | |
| 749 | - PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset]; | |
| 750 | - [request addResourceWithType:PHAssetResourceTypeVideo fileURL:url options:options]; | |
| 751 | - if (location) { | |
| 752 | - request.location = location; | |
| 753 | - } | |
| 754 | - request.creationDate = [NSDate date]; | |
| 755 | - } else { | |
| 756 | - PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:url]; | |
| 757 | - if (location) { | |
| 758 | - request.location = location; | |
| 759 | - } | |
| 760 | - request.creationDate = [NSDate date]; | |
| 761 | - } | |
| 762 | - } completionHandler:^(BOOL success, NSError *error) { | |
| 763 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 764 | - if (success && completion) { | |
| 765 | - completion(nil); | |
| 766 | - } else if (error) { | |
| 767 | - NSLog(@"保存视频出错:%@",error.localizedDescription); | |
| 768 | - if (completion) { | |
| 769 | - completion(error); | |
| 770 | - } | |
| 771 | - } | |
| 772 | - }); | |
| 773 | - }]; | |
| 774 | - } else { | |
| 775 | - [self.assetLibrary writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) { | |
| 776 | - if (error) { | |
| 777 | - NSLog(@"保存视频出错:%@",error.localizedDescription); | |
| 778 | - if (completion) { | |
| 779 | - completion(error); | |
| 780 | - } | |
| 781 | - } else { | |
| 782 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 783 | - if (completion) { | |
| 784 | - completion(nil); | |
| 785 | - } | |
| 786 | - }); | |
| 787 | - } | |
| 788 | - }]; | |
| 789 | - } | |
| 790 | -} | |
| 791 | - | |
| 792 | -#pragma mark - Get Video | |
| 793 | - | |
| 794 | -/// Get Video / 获取视频 | |
| 795 | -- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem *, NSDictionary *))completion { | |
| 796 | - [self getVideoWithAsset:asset progressHandler:nil completion:completion]; | |
| 797 | -} | |
| 798 | - | |
| 799 | -- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion { | |
| 800 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 801 | - PHVideoRequestOptions *option = [[PHVideoRequestOptions alloc] init]; | |
| 802 | - option.networkAccessAllowed = YES; | |
| 803 | - option.progressHandler = ^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 804 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 805 | - if (progressHandler) { | |
| 806 | - progressHandler(progress, error, stop, info); | |
| 807 | - } | |
| 808 | - }); | |
| 809 | - }; | |
| 810 | - [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:option resultHandler:^(AVPlayerItem *playerItem, NSDictionary *info) { | |
| 811 | - if (completion) completion(playerItem,info); | |
| 812 | - }]; | |
| 813 | - } else if ([asset isKindOfClass:[ALAsset class]]) { | |
| 814 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 815 | - ALAssetRepresentation *defaultRepresentation = [alAsset defaultRepresentation]; | |
| 816 | - NSString *uti = [defaultRepresentation UTI]; | |
| 817 | - NSURL *videoURL = [[asset valueForProperty:ALAssetPropertyURLs] valueForKey:uti]; | |
| 818 | - AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:videoURL]; | |
| 819 | - if (completion && playerItem) completion(playerItem,nil); | |
| 820 | - } | |
| 821 | -} | |
| 822 | - | |
| 823 | -#pragma mark - Export video | |
| 824 | - | |
| 825 | -/// Export Video / 导出视频 | |
| 826 | -- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure { | |
| 827 | - [self getVideoOutputPathWithAsset:asset presetName:AVAssetExportPreset640x480 success:success failure:failure]; | |
| 828 | -} | |
| 829 | - | |
| 830 | -- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure { | |
| 831 | - if ([asset isKindOfClass:[PHAsset class]]) { | |
| 832 | - PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init]; | |
| 833 | - options.version = PHVideoRequestOptionsVersionOriginal; | |
| 834 | - options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; | |
| 835 | - options.networkAccessAllowed = YES; | |
| 836 | - [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){ | |
| 837 | - // NSLog(@"Info:\n%@",info); | |
| 838 | - AVURLAsset *videoAsset = (AVURLAsset*)avasset; | |
| 839 | - // NSLog(@"AVAsset URL: %@",myAsset.URL); | |
| 840 | - [self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure]; | |
| 841 | - }]; | |
| 842 | - } else if ([asset isKindOfClass:[ALAsset class]]) { | |
| 843 | - NSURL *videoURL =[asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs | |
| 844 | - AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil]; | |
| 845 | - [self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure]; | |
| 846 | - } | |
| 847 | -} | |
| 848 | - | |
| 849 | -/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success: | |
| 850 | -- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion { | |
| 851 | - [self getVideoOutputPathWithAsset:asset success:completion failure:nil]; | |
| 852 | -} | |
| 853 | - | |
| 854 | -- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure { | |
| 855 | - // Find compatible presets by video asset. | |
| 856 | - NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset]; | |
| 857 | - | |
| 858 | - // Begin to compress video | |
| 859 | - // Now we just compress to low resolution if it supports | |
| 860 | - // If you need to upload to the server, but server does't support to upload by streaming, | |
| 861 | - // You can compress the resolution to lower. Or you can support more higher resolution. | |
| 862 | - if ([presets containsObject:presetName]) { | |
| 863 | - AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:presetName]; | |
| 864 | - | |
| 865 | - NSDateFormatter *formater = [[NSDateFormatter alloc] init]; | |
| 866 | - [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss-SSS"]; | |
| 867 | -#pragma mark - ADD: 原有逻辑-根据会话id取得path(LXG) | |
| 868 | - NSString *outputPath = @""; | |
| 869 | - if (self.outputPath.length <= 0) { | |
| 870 | - outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]]; | |
| 871 | - }else { | |
| 872 | - NSString *filaName = [NSString stringWithFormat:@"output-%@_fileType=videoType.mp4",[formater stringFromDate:[NSDate date]]]; | |
| 873 | - outputPath = [self.outputPath stringByAppendingString:filaName]; | |
| 874 | - } | |
| 875 | - | |
| 876 | - NSLog(@"video outputPath = %@",outputPath); | |
| 877 | - | |
| 878 | - session.outputURL = [NSURL fileURLWithPath:outputPath]; | |
| 879 | - | |
| 880 | - // Optimize for network use. | |
| 881 | - session.shouldOptimizeForNetworkUse = true; | |
| 882 | - | |
| 883 | - NSArray *supportedTypeArray = session.supportedFileTypes; | |
| 884 | - if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) { | |
| 885 | - session.outputFileType = AVFileTypeMPEG4; | |
| 886 | - } else if (supportedTypeArray.count == 0) { | |
| 887 | - if (failure) { | |
| 888 | - failure(@"该视频类型暂不支持导出", nil); | |
| 889 | - } | |
| 890 | - NSLog(@"No supported file types 视频类型暂不支持导出"); | |
| 891 | - return; | |
| 892 | - } else { | |
| 893 | - session.outputFileType = [supportedTypeArray objectAtIndex:0]; | |
| 894 | - } | |
| 895 | - | |
| 896 | - if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) { | |
| 897 | - [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil]; | |
| 898 | - } | |
| 899 | - | |
| 900 | - if ([TZImagePickerConfig sharedInstance].needFixComposition) { | |
| 901 | - AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset]; | |
| 902 | - if (videoComposition.renderSize.width) { | |
| 903 | - // 修正视频转向 | |
| 904 | - session.videoComposition = videoComposition; | |
| 905 | - } | |
| 906 | - } | |
| 907 | - | |
| 908 | - // Begin to export video to the output path asynchronously. | |
| 909 | -#pragma mark - ADD: 原有逻辑-会话id置空(LXG) | |
| 910 | - [session exportAsynchronouslyWithCompletionHandler:^(void) { | |
| 911 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 912 | - | |
| 913 | - switch (session.status) { | |
| 914 | - case AVAssetExportSessionStatusUnknown: { | |
| 915 | - NSLog(@"AVAssetExportSessionStatusUnknown"); | |
| 916 | - } break; | |
| 917 | - case AVAssetExportSessionStatusWaiting: { | |
| 918 | - NSLog(@"AVAssetExportSessionStatusWaiting"); | |
| 919 | - } break; | |
| 920 | - case AVAssetExportSessionStatusExporting: { | |
| 921 | - NSLog(@"AVAssetExportSessionStatusExporting"); | |
| 922 | - } break; | |
| 923 | - case AVAssetExportSessionStatusCompleted: { | |
| 924 | - NSLog(@"AVAssetExportSessionStatusCompleted"); | |
| 925 | - if (success) { | |
| 926 | - success(outputPath); | |
| 927 | - } | |
| 928 | - } break; | |
| 929 | - case AVAssetExportSessionStatusFailed: { | |
| 930 | - NSLog(@"AVAssetExportSessionStatusFailed"); | |
| 931 | - if (failure) { | |
| 932 | - failure(@"视频导出失败", session.error); | |
| 933 | - } | |
| 934 | - } break; | |
| 935 | - case AVAssetExportSessionStatusCancelled: { | |
| 936 | - NSLog(@"AVAssetExportSessionStatusCancelled"); | |
| 937 | - if (failure) { | |
| 938 | - failure(@"导出任务已被取消", nil); | |
| 939 | - } | |
| 940 | - } break; | |
| 941 | - default: | |
| 942 | - NSLog(@"未知错误"); | |
| 943 | - break; | |
| 944 | - } | |
| 945 | - }); | |
| 946 | - }]; | |
| 947 | - } else { | |
| 948 | - if (failure) { | |
| 949 | - NSString *errorMessage = [NSString stringWithFormat:@"当前设备不支持该预设:%@", presetName]; | |
| 950 | - failure(errorMessage, nil); | |
| 951 | - } | |
| 952 | - } | |
| 953 | -} | |
| 954 | - | |
| 955 | -/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset | |
| 956 | -- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset { | |
| 957 | - if (iOS8Later) { | |
| 958 | - return [assets containsObject:asset]; | |
| 959 | - } else { | |
| 960 | - NSMutableArray *selectedAssetUrls = [NSMutableArray array]; | |
| 961 | - for (ALAsset *asset_item in assets) { | |
| 962 | - [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]]; | |
| 963 | - } | |
| 964 | - return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]]; | |
| 965 | - } | |
| 966 | -} | |
| 967 | - | |
| 968 | -- (BOOL)isCameraRollAlbum:(id)metadata { | |
| 969 | - if ([metadata isKindOfClass:[PHAssetCollection class]]) { | |
| 970 | - NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; | |
| 971 | - if (versionStr.length <= 1) { | |
| 972 | - versionStr = [versionStr stringByAppendingString:@"00"]; | |
| 973 | - } else if (versionStr.length <= 2) { | |
| 974 | - versionStr = [versionStr stringByAppendingString:@"0"]; | |
| 975 | - } | |
| 976 | - CGFloat version = versionStr.floatValue; | |
| 977 | - // 目前已知8.0.0 ~ 8.0.2系统,拍照后的图片会保存在最近添加中 | |
| 978 | - if (version >= 800 && version <= 802) { | |
| 979 | - return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded; | |
| 980 | - } else { | |
| 981 | - return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary; | |
| 982 | - } | |
| 983 | - } | |
| 984 | - if ([metadata isKindOfClass:[ALAssetsGroup class]]) { | |
| 985 | - ALAssetsGroup *group = metadata; | |
| 986 | - return ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupSavedPhotos); | |
| 987 | - } | |
| 988 | - | |
| 989 | - return NO; | |
| 990 | -} | |
| 991 | - | |
| 992 | -- (NSString *)getAssetIdentifier:(id)asset { | |
| 993 | - if (iOS8Later) { | |
| 994 | - PHAsset *phAsset = (PHAsset *)asset; | |
| 995 | - return phAsset.localIdentifier; | |
| 996 | - } else { | |
| 997 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 998 | - NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL]; | |
| 999 | - return assetUrl.absoluteString; | |
| 1000 | - } | |
| 1001 | -} | |
| 1002 | - | |
| 1003 | -/// 检查照片大小是否满足最小要求 | |
| 1004 | -- (BOOL)isPhotoSelectableWithAsset:(id)asset { | |
| 1005 | - CGSize photoSize = [self photoSizeWithAsset:asset]; | |
| 1006 | - if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) { | |
| 1007 | - return NO; | |
| 1008 | - } | |
| 1009 | - return YES; | |
| 1010 | -} | |
| 1011 | - | |
| 1012 | -- (CGSize)photoSizeWithAsset:(id)asset { | |
| 1013 | - if (iOS8Later) { | |
| 1014 | - PHAsset *phAsset = (PHAsset *)asset; | |
| 1015 | - return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight); | |
| 1016 | - } else { | |
| 1017 | - ALAsset *alAsset = (ALAsset *)asset; | |
| 1018 | - return alAsset.defaultRepresentation.dimensions; | |
| 1019 | - } | |
| 1020 | -} | |
| 1021 | - | |
| 1022 | -#pragma mark - Private Method | |
| 1023 | - | |
| 1024 | -- (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name isCameraRoll:(BOOL)isCameraRoll needFetchAssets:(BOOL)needFetchAssets { | |
| 1025 | - TZAlbumModel *model = [[TZAlbumModel alloc] init]; | |
| 1026 | - [model setResult:result needFetchAssets:needFetchAssets]; | |
| 1027 | - model.name = name; | |
| 1028 | - model.isCameraRoll = isCameraRoll; | |
| 1029 | - if ([result isKindOfClass:[PHFetchResult class]]) { | |
| 1030 | - PHFetchResult *fetchResult = (PHFetchResult *)result; | |
| 1031 | - model.count = fetchResult.count; | |
| 1032 | - } else if ([result isKindOfClass:[ALAssetsGroup class]]) { | |
| 1033 | - ALAssetsGroup *group = (ALAssetsGroup *)result; | |
| 1034 | - model.count = [group numberOfAssets]; | |
| 1035 | - } | |
| 1036 | - return model; | |
| 1037 | -} | |
| 1038 | - | |
| 1039 | -/// 缩放图片至新尺寸 | |
| 1040 | -- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size { | |
| 1041 | - if (image.size.width > size.width) { | |
| 1042 | - UIGraphicsBeginImageContext(size); | |
| 1043 | - [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; | |
| 1044 | - UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); | |
| 1045 | - UIGraphicsEndImageContext(); | |
| 1046 | - return newImage; | |
| 1047 | - | |
| 1048 | - /* 好像不怎么管用:https://mp.weixin.qq.com/s/CiqMlEIp1Ir2EJSDGgMooQ | |
| 1049 | - CGFloat maxPixelSize = MAX(size.width, size.height); | |
| 1050 | - CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)UIImageJPEGRepresentation(image, 0.9), nil); | |
| 1051 | - NSDictionary *options = @{(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways:(__bridge id)kCFBooleanTrue, | |
| 1052 | - (__bridge id)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithFloat:maxPixelSize] | |
| 1053 | - }; | |
| 1054 | - CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options); | |
| 1055 | - UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:2 orientation:image.imageOrientation]; | |
| 1056 | - CGImageRelease(imageRef); | |
| 1057 | - CFRelease(sourceRef); | |
| 1058 | - return newImage; | |
| 1059 | - */ | |
| 1060 | - } else { | |
| 1061 | - return image; | |
| 1062 | - } | |
| 1063 | -} | |
| 1064 | - | |
| 1065 | -/// 判断asset是否是视频 | |
| 1066 | -- (BOOL)isVideo:(id)asset { | |
| 1067 | - if (iOS8Later) { | |
| 1068 | - PHAsset *phAsset = asset; | |
| 1069 | - return phAsset.mediaType == PHAssetMediaTypeVideo; | |
| 1070 | - } else { | |
| 1071 | - ALAsset *alAsset = asset; | |
| 1072 | - NSString *alAssetType = [[alAsset valueForProperty:ALAssetPropertyType] stringValue]; | |
| 1073 | - return [alAssetType isEqualToString:ALAssetTypeVideo]; | |
| 1074 | - } | |
| 1075 | -} | |
| 1076 | - | |
| 1077 | -- (ALAssetOrientation)orientationFromImage:(UIImage *)image { | |
| 1078 | - NSInteger orientation = image.imageOrientation; | |
| 1079 | - return orientation; | |
| 1080 | -} | |
| 1081 | - | |
| 1082 | -/// 获取优化后的视频转向信息 | |
| 1083 | -- (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset { | |
| 1084 | - AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; | |
| 1085 | - // 视频转向 | |
| 1086 | - int degrees = [self degressFromVideoFileWithAsset:videoAsset]; | |
| 1087 | - if (degrees != 0) { | |
| 1088 | - CGAffineTransform translateToCenter; | |
| 1089 | - CGAffineTransform mixedTransform; | |
| 1090 | - videoComposition.frameDuration = CMTimeMake(1, 30); | |
| 1091 | - | |
| 1092 | - NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo]; | |
| 1093 | - AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; | |
| 1094 | - | |
| 1095 | - AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; | |
| 1096 | - roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]); | |
| 1097 | - AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; | |
| 1098 | - | |
| 1099 | - if (degrees == 90) { | |
| 1100 | - // 顺时针旋转90° | |
| 1101 | - translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0); | |
| 1102 | - mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2); | |
| 1103 | - videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width); | |
| 1104 | - [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero]; | |
| 1105 | - } else if(degrees == 180){ | |
| 1106 | - // 顺时针旋转180° | |
| 1107 | - translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height); | |
| 1108 | - mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI); | |
| 1109 | - videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height); | |
| 1110 | - [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero]; | |
| 1111 | - } else if(degrees == 270){ | |
| 1112 | - // 顺时针旋转270° | |
| 1113 | - translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width); | |
| 1114 | - mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0); | |
| 1115 | - videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width); | |
| 1116 | - [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero]; | |
| 1117 | - } | |
| 1118 | - | |
| 1119 | - roateInstruction.layerInstructions = @[roateLayerInstruction]; | |
| 1120 | - // 加入视频方向信息 | |
| 1121 | - videoComposition.instructions = @[roateInstruction]; | |
| 1122 | - } | |
| 1123 | - return videoComposition; | |
| 1124 | -} | |
| 1125 | - | |
| 1126 | -/// 获取视频角度 | |
| 1127 | -- (int)degressFromVideoFileWithAsset:(AVAsset *)asset { | |
| 1128 | - int degress = 0; | |
| 1129 | - NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; | |
| 1130 | - if([tracks count] > 0) { | |
| 1131 | - AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; | |
| 1132 | - CGAffineTransform t = videoTrack.preferredTransform; | |
| 1133 | - if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){ | |
| 1134 | - // Portrait | |
| 1135 | - degress = 90; | |
| 1136 | - } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){ | |
| 1137 | - // PortraitUpsideDown | |
| 1138 | - degress = 270; | |
| 1139 | - } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){ | |
| 1140 | - // LandscapeRight | |
| 1141 | - degress = 0; | |
| 1142 | - } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){ | |
| 1143 | - // LandscapeLeft | |
| 1144 | - degress = 180; | |
| 1145 | - } | |
| 1146 | - } | |
| 1147 | - return degress; | |
| 1148 | -} | |
| 1149 | - | |
| 1150 | -/// 修正图片转向 | |
| 1151 | -- (UIImage *)fixOrientation:(UIImage *)aImage { | |
| 1152 | - if (!self.shouldFixOrientation) return aImage; | |
| 1153 | - | |
| 1154 | - // No-op if the orientation is already correct | |
| 1155 | - if (aImage.imageOrientation == UIImageOrientationUp) | |
| 1156 | - return aImage; | |
| 1157 | - | |
| 1158 | - // We need to calculate the proper transformation to make the image upright. | |
| 1159 | - // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. | |
| 1160 | - CGAffineTransform transform = CGAffineTransformIdentity; | |
| 1161 | - | |
| 1162 | - switch (aImage.imageOrientation) { | |
| 1163 | - case UIImageOrientationDown: | |
| 1164 | - case UIImageOrientationDownMirrored: | |
| 1165 | - transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height); | |
| 1166 | - transform = CGAffineTransformRotate(transform, M_PI); | |
| 1167 | - break; | |
| 1168 | - | |
| 1169 | - case UIImageOrientationLeft: | |
| 1170 | - case UIImageOrientationLeftMirrored: | |
| 1171 | - transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); | |
| 1172 | - transform = CGAffineTransformRotate(transform, M_PI_2); | |
| 1173 | - break; | |
| 1174 | - | |
| 1175 | - case UIImageOrientationRight: | |
| 1176 | - case UIImageOrientationRightMirrored: | |
| 1177 | - transform = CGAffineTransformTranslate(transform, 0, aImage.size.height); | |
| 1178 | - transform = CGAffineTransformRotate(transform, -M_PI_2); | |
| 1179 | - break; | |
| 1180 | - default: | |
| 1181 | - break; | |
| 1182 | - } | |
| 1183 | - | |
| 1184 | - switch (aImage.imageOrientation) { | |
| 1185 | - case UIImageOrientationUpMirrored: | |
| 1186 | - case UIImageOrientationDownMirrored: | |
| 1187 | - transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); | |
| 1188 | - transform = CGAffineTransformScale(transform, -1, 1); | |
| 1189 | - break; | |
| 1190 | - | |
| 1191 | - case UIImageOrientationLeftMirrored: | |
| 1192 | - case UIImageOrientationRightMirrored: | |
| 1193 | - transform = CGAffineTransformTranslate(transform, aImage.size.height, 0); | |
| 1194 | - transform = CGAffineTransformScale(transform, -1, 1); | |
| 1195 | - break; | |
| 1196 | - default: | |
| 1197 | - break; | |
| 1198 | - } | |
| 1199 | - | |
| 1200 | - // Now we draw the underlying CGImage into a new context, applying the transform | |
| 1201 | - // calculated above. | |
| 1202 | - CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, | |
| 1203 | - CGImageGetBitsPerComponent(aImage.CGImage), 0, | |
| 1204 | - CGImageGetColorSpace(aImage.CGImage), | |
| 1205 | - CGImageGetBitmapInfo(aImage.CGImage)); | |
| 1206 | - CGContextConcatCTM(ctx, transform); | |
| 1207 | - switch (aImage.imageOrientation) { | |
| 1208 | - case UIImageOrientationLeft: | |
| 1209 | - case UIImageOrientationLeftMirrored: | |
| 1210 | - case UIImageOrientationRight: | |
| 1211 | - case UIImageOrientationRightMirrored: | |
| 1212 | - // Grr... | |
| 1213 | - CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage); | |
| 1214 | - break; | |
| 1215 | - | |
| 1216 | - default: | |
| 1217 | - CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage); | |
| 1218 | - break; | |
| 1219 | - } | |
| 1220 | - | |
| 1221 | - // And now we just create a new UIImage from the drawing context | |
| 1222 | - CGImageRef cgimg = CGBitmapContextCreateImage(ctx); | |
| 1223 | - UIImage *img = [UIImage imageWithCGImage:cgimg]; | |
| 1224 | - CGContextRelease(ctx); | |
| 1225 | - CGImageRelease(cgimg); | |
| 1226 | - return img; | |
| 1227 | -} | |
| 1228 | - | |
| 1229 | -#pragma clang diagnostic pop | |
| 1230 | - | |
| 1231 | -@end | |
| 1232 | - | |
| 1233 | - | |
| 1234 | -//@implementation TZSortDescriptor | |
| 1235 | -// | |
| 1236 | -//- (id)reversedSortDescriptor { | |
| 1237 | -// return [NSNumber numberWithBool:![TZImageManager manager].sortAscendingByModificationDate]; | |
| 1238 | -//} | |
| 1239 | -// | |
| 1240 | -//@end |
CNLiveImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png deleted
100755 → 0
3.56 KB
CNLiveImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png deleted
100755 → 0
3.56 KB
CNLiveImagePickerController/TZImagePickerController.bundle/Root.plist deleted
100755 → 0
| 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/TZImagePickerController.bundle/VideoSendIcon@2x.png deleted
100755 → 0
223 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings deleted
100755 → 0
CNLiveImagePickerController/TZImagePickerController.bundle/fb_quxiao@2x.png deleted
100755 → 0
1.16 KB
CNLiveImagePickerController/TZImagePickerController.bundle/navi_back@2x.png deleted
100755 → 0
116 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/ph_select@2x.png deleted
100755 → 0
1.31 KB
CNLiveImagePickerController/TZImagePickerController.bundle/ph_unselect@2x.png deleted
100755 → 0
902 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_cell_normal.png deleted
100644 → 0
641 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_cell_normal@2x.png deleted
100644 → 0
1.35 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_cell_normal@3x.png deleted
100644 → 0
2.57 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png deleted
100755 → 0
1.13 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png deleted
100755 → 0
1.13 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png deleted
100755 → 0
501 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_back.png deleted
100644 → 0
234 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_back@2x.png deleted
100644 → 0
384 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_back@3x.png deleted
100644 → 0
726 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png deleted
100755 → 0
1.56 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_nor.png deleted
100644 → 0
1.04 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_nor@2x.png deleted
100644 → 0
2.12 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_nor@3x.png deleted
100644 → 0
6.27 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_normal.png deleted
100644 → 0
453 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_normal@2x.png deleted
100644 → 0
902 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_normal@3x.png deleted
100644 → 0
1.77 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png deleted
100755 → 0
620 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_select.png deleted
100644 → 0
713 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_select@2x.png deleted
100644 → 0
1.31 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_original_select@3x.png deleted
100644 → 0
3.56 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png deleted
100755 → 0
1006 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png deleted
100755 → 0
1.16 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photoback.png deleted
100644 → 0
1.01 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photoback@2x.png deleted
100644 → 0
1.16 KB
CNLiveImagePickerController/TZImagePickerController.bundle/photoback@3x.png deleted
100644 → 0
1.23 KB
CNLiveImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png deleted
100755 → 0
501 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png deleted
100755 → 0
392 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/takePicture80@2x.png deleted
100755 → 0
1.25 KB
CNLiveImagePickerController/TZImagePickerController.bundle/takePicture@2x.png deleted
100755 → 0
2.98 KB
CNLiveImagePickerController/TZImagePickerController.bundle/upload_selection1@2x.png deleted
100755 → 0
1.35 KB
CNLiveImagePickerController/TZImagePickerController.bundle/vi.lproj/Localizable.strings deleted
100755 → 0
| 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/TZImagePickerController.bundle/video_edit_left@2x.png deleted
100644 → 0
203 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/video_edit_left@3x.png deleted
100644 → 0
514 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/video_edit_right@2x.png deleted
100644 → 0
208 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/video_edit_right@3x.png deleted
100644 → 0
502 Bytes
CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings deleted
100755 → 0
CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings deleted
100755 → 0
CNLiveImagePickerController/TZImagePickerController.h deleted
100755 → 0
| 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 - | |
| 49 | - | |
| 50 | -#pragma mark - ADD:视频编辑(LXG) | |
| 51 | -///** | |
| 52 | -// 是否允许编辑视频,选择一张时候才允许编辑,默认NO | |
| 53 | -// */ | |
| 54 | -//@property (nonatomic, assign) BOOL allowEditVideo; | |
| 55 | - | |
| 56 | -/** | |
| 57 | - 编辑视频时最大裁剪时间,单位:秒,默认10s 且最低10s | |
| 58 | - | |
| 59 | - @discussion 当该参数为10s时,所选视频时长必须大于等于10s才允许进行编辑 | |
| 60 | - */ | |
| 61 | -@property (nonatomic, assign) NSInteger maxEditVideoTime; | |
| 62 | - | |
| 63 | -/** | |
| 64 | - 允许选择视频的最大时长,单位:秒, 默认 120s | |
| 65 | - */ | |
| 66 | -@property (nonatomic, assign) NSInteger maxVideoDuration; | |
| 67 | - | |
| 68 | -/// Default is 9 / 默认最大可选9张图片 | |
| 69 | -@property (nonatomic, assign) NSInteger maxImagesCount; | |
| 70 | - | |
| 71 | -/// The minimum count photos user must pick, Default is 0 | |
| 72 | -/// 最小照片必选张数,默认是0 | |
| 73 | -@property (nonatomic, assign) NSInteger minImagesCount; | |
| 74 | - | |
| 75 | -/// Always enale the done button, not require minimum 1 photo be picked | |
| 76 | -/// 让完成按钮一直可以点击,无须最少选择一张图片 | |
| 77 | -@property (nonatomic, assign) BOOL alwaysEnableDoneBtn; | |
| 78 | - | |
| 79 | -/// Sort photos ascending by modificationDate,Default is YES | |
| 80 | -/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个 | |
| 81 | -@property (nonatomic, assign) BOOL sortAscendingByModificationDate; | |
| 82 | - | |
| 83 | -/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽 | |
| 84 | -@property (nonatomic, assign) CGFloat photoWidth; | |
| 85 | - | |
| 86 | -/// Default is 600px / 默认600像素宽 | |
| 87 | -@property (nonatomic, assign) CGFloat photoPreviewMaxWidth; | |
| 88 | - | |
| 89 | -/// Default is 15, While fetching photo, HUD will dismiss automatic if timeout; | |
| 90 | -/// 超时时间,默认为15秒,当取图片时间超过15秒还没有取成功时,会自动dismiss HUD; | |
| 91 | -@property (nonatomic, assign) NSInteger timeout; | |
| 92 | - | |
| 93 | -/// Default is YES, if set NO, the original photo button will hide. user can't picking original photo. | |
| 94 | -/// 默认为YES,如果设置为NO,原图按钮将隐藏,用户不能选择发送原图 | |
| 95 | -@property (nonatomic, assign) BOOL allowPickingOriginalPhoto; | |
| 96 | - | |
| 97 | -/// Default is YES, if set NO, user can't picking video. | |
| 98 | -/// 默认为YES,如果设置为NO,用户将不能选择视频 | |
| 99 | -@property (nonatomic, assign) BOOL allowPickingVideo; | |
| 100 | -/// Default is NO / 默认为NO,为YES时可以多选视频/gif/图片,和照片共享最大可选张数maxImagesCount的限制 | |
| 101 | -@property (nonatomic, assign) BOOL allowPickingMultipleVideo; | |
| 102 | - | |
| 103 | -/// Default is NO, if set YES, user can picking gif image. | |
| 104 | -/// 默认为NO,如果设置为YES,用户可以选择gif图片 | |
| 105 | -@property (nonatomic, assign) BOOL allowPickingGif; | |
| 106 | - | |
| 107 | -/// Default is YES, if set NO, user can't picking image. | |
| 108 | -/// 默认为YES,如果设置为NO,用户将不能选择发送图片 | |
| 109 | -@property (nonatomic, assign) BOOL allowPickingImage; | |
| 110 | - | |
| 111 | -/// Default is YES, if set NO, user can't take picture. | |
| 112 | -/// 默认为YES,如果设置为NO, 用户将不能拍摄照片 | |
| 113 | -@property (nonatomic, assign) BOOL allowTakePicture; | |
| 114 | -@property (nonatomic, assign) BOOL allowCameraLocation; | |
| 115 | - | |
| 116 | -/// Default is YES, if set NO, user can't take video. | |
| 117 | -/// 默认为YES,如果设置为NO, 用户将不能拍摄视频 | |
| 118 | -@property(nonatomic, assign) BOOL allowTakeVideo; | |
| 119 | -/// Default value is 10 minutes / 视频最大拍摄时间,默认是10分钟,单位是秒 | |
| 120 | -@property (assign, nonatomic) NSTimeInterval videoMaximumDuration; | |
| 121 | -/// Customizing UIImagePickerController's other properties, such as videoQuality / 定制UIImagePickerController的其它属性,比如视频拍摄质量videoQuality | |
| 122 | -@property (nonatomic, copy) void(^uiImagePickerControllerSettingBlock)(UIImagePickerController *imagePickerController); | |
| 123 | - | |
| 124 | -/// 首选语言,如果设置了就用该语言,不设则取当前系统语言。 | |
| 125 | -/// 由于目前只支持中文、繁体中文、英文、越南语。故该属性只支持zh-Hans、zh-Hant、en、vi四种值,其余值无效。 | |
| 126 | -@property (copy, nonatomic) NSString *preferredLanguage; | |
| 127 | - | |
| 128 | -/// 语言bundle,preferredLanguage变化时languageBundle会变化 | |
| 129 | -/// 可通过手动设置bundle,让选择器支持新的的语言(需要在设置preferredLanguage后设置languageBundle)。欢迎提交PR把语言文件提交上来~ | |
| 130 | -@property (strong, nonatomic) NSBundle *languageBundle; | |
| 131 | - | |
| 132 | -/// Default is YES, if set NO, user can't preview photo. | |
| 133 | -/// 默认为YES,如果设置为NO,预览按钮将隐藏,用户将不能去预览照片 | |
| 134 | -@property (nonatomic, assign) BOOL allowPreview; | |
| 135 | - | |
| 136 | -/// Default is YES, if set NO, the picker don't dismiss itself. | |
| 137 | -/// 默认为YES,如果设置为NO, 选择器将不会自己dismiss | |
| 138 | -@property(nonatomic, assign) BOOL autoDismiss; | |
| 139 | - | |
| 140 | -/// Default is NO, if set YES, in the delegate method the photos and infos will be nil, only assets hava value. | |
| 141 | -/// 默认为NO,如果设置为YES,代理方法里photos和infos会是nil,只返回assets | |
| 142 | -@property (assign, nonatomic) BOOL onlyReturnAsset; | |
| 143 | - | |
| 144 | -/// Default is NO, if set YES, will show the image's selected index. | |
| 145 | -/// 默认为NO,如果设置为YES,会显示照片的选中序号 | |
| 146 | -@property (assign, nonatomic) BOOL showSelectedIndex; | |
| 147 | - | |
| 148 | -/// 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. | |
| 149 | -/// 默认是NO,如果设置为YES,当照片选择张数达到maxImagesCount时,其它照片会显示颜色为cannotSelectLayerColor的浮层 | |
| 150 | -@property (assign, nonatomic) BOOL showPhotoCannotSelectLayer; | |
| 151 | -/// Default is white color with 0.8 alpha; | |
| 152 | -@property (strong, nonatomic) UIColor *cannotSelectLayerColor; | |
| 153 | - | |
| 154 | -/// Default is No, if set YES, the result photo will not be scaled to photoWidth pixel width. The photoWidth default is 828px | |
| 155 | -/// 默认是NO,如果设置为YES,内部不会缩放图片到photoWidth像素宽 | |
| 156 | -@property (assign, nonatomic) BOOL notScaleImage; | |
| 157 | - | |
| 158 | -/// 默认是NO,如果设置为YES,导出视频时会修正转向(慎重设为YES,可能导致部分安卓下拍的视频导出失败) | |
| 159 | -@property (assign, nonatomic) BOOL needFixComposition; | |
| 160 | - | |
| 161 | -/// The photos user have selected | |
| 162 | -/// 用户选中过的图片数组 | |
| 163 | -@property (nonatomic, strong) NSMutableArray *selectedAssets; | |
| 164 | -@property (nonatomic, strong) NSMutableArray<TZAssetModel *> *selectedModels; | |
| 165 | -@property (nonatomic, strong) NSMutableArray *selectedAssetIds; | |
| 166 | -- (void)addSelectedModel:(TZAssetModel *)model; | |
| 167 | -- (void)removeSelectedModel:(TZAssetModel *)model; | |
| 168 | - | |
| 169 | -/// Minimum selectable photo width, Default is 0 | |
| 170 | -/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中 | |
| 171 | -@property (nonatomic, assign) NSInteger minPhotoWidthSelectable; | |
| 172 | -@property (nonatomic, assign) NSInteger minPhotoHeightSelectable; | |
| 173 | -/// Hide the photo what can not be selected, Default is NO | |
| 174 | -/// 隐藏不可以选中的图片,默认是NO,不推荐将其设置为YES | |
| 175 | -@property (nonatomic, assign) BOOL hideWhenCanNotSelect; | |
| 176 | -/// Deprecated, Use statusBarStyle (顶部statusBar 是否为系统默认的黑色,默认为NO) | |
| 177 | -@property (nonatomic, assign) BOOL isStatusBarDefault __attribute__((deprecated("Use -statusBarStyle."))); | |
| 178 | -/// statusBar的样式,默认为UIStatusBarStyleLightContent | |
| 179 | -@property (assign, nonatomic) UIStatusBarStyle statusBarStyle; | |
| 180 | - | |
| 181 | -#pragma mark - | |
| 182 | -/// Single selection mode, valid when maxImagesCount = 1 | |
| 183 | -/// 单选模式,maxImagesCount为1时才生效 | |
| 184 | -@property (nonatomic, assign) BOOL showSelectBtn; ///< 在单选模式下,照片列表页中,显示选择按钮,默认为NO | |
| 185 | -@property (nonatomic, assign) BOOL allowCrop; ///< 允许裁剪,默认为YES,showSelectBtn为NO才生效 | |
| 186 | -@property (nonatomic, assign) CGRect cropRect; ///< 裁剪框的尺寸 | |
| 187 | -@property (nonatomic, assign) CGRect cropRectPortrait; ///< 裁剪框的尺寸(竖屏) | |
| 188 | -@property (nonatomic, assign) CGRect cropRectLandscape; ///< 裁剪框的尺寸(横屏) | |
| 189 | -@property (nonatomic, assign) BOOL needCircleCrop; ///< 需要圆形裁剪框 | |
| 190 | -@property (nonatomic, assign) NSInteger circleCropRadius; ///< 圆形裁剪框半径大小 | |
| 191 | -@property (nonatomic, copy) void (^cropViewSettingBlock)(UIView *cropView); ///< 自定义裁剪框的其他属性 | |
| 192 | -@property (nonatomic, copy) void (^navLeftBarButtonSettingBlock)(UIButton *leftButton); ///< 自定义返回按钮样式及其属性 | |
| 193 | - | |
| 194 | -/// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等 | |
| 195 | -@property (nonatomic, copy) void (^photoPickerPageUIConfigBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine); | |
| 196 | -@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); | |
| 197 | -@property (nonatomic, copy) void (^videoPreviewPageUIConfigBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton); | |
| 198 | -@property (nonatomic, copy) void (^gifPreviewPageUIConfigBlock)(UIView *toolBar, UIButton *doneButton); | |
| 199 | -@property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView); | |
| 200 | -@property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel); | |
| 201 | -/// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等 | |
| 202 | -@property (nonatomic, copy) void (^photoPickerPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine); | |
| 203 | -@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); | |
| 204 | -@property (nonatomic, copy) void (^videoPreviewPageDidLayoutSubviewsBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton); | |
| 205 | -@property (nonatomic, copy) void (^gifPreviewPageDidLayoutSubviewsBlock)(UIView *toolBar, UIButton *doneButton); | |
| 206 | -@property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView); | |
| 207 | -@property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel); | |
| 208 | - | |
| 209 | -#pragma mark - | |
| 210 | -- (id)showAlertWithTitle:(NSString *)title; | |
| 211 | -- (void)hideAlertView:(id)alertView; | |
| 212 | -- (void)showProgressHUD; | |
| 213 | -- (void)hideProgressHUD; | |
| 214 | -@property (nonatomic, assign) BOOL isSelectOriginalPhoto; | |
| 215 | -@property (assign, nonatomic) BOOL needShowStatusBar; | |
| 216 | - | |
| 217 | -#pragma mark - | |
| 218 | -@property (nonatomic, copy) NSString *takePictureImageName __attribute__((deprecated("Use -takePictureImage."))); | |
| 219 | -@property (nonatomic, copy) NSString *photoSelImageName __attribute__((deprecated("Use -photoSelImage."))); | |
| 220 | -@property (nonatomic, copy) NSString *photoDefImageName __attribute__((deprecated("Use -photoDefImage."))); | |
| 221 | -@property (nonatomic, copy) NSString *photoOriginSelImageName __attribute__((deprecated("Use -photoOriginSelImage."))); | |
| 222 | -@property (nonatomic, copy) NSString *photoOriginDefImageName __attribute__((deprecated("Use -photoOriginDefImage."))); | |
| 223 | -@property (nonatomic, copy) NSString *photoPreviewOriginDefImageName __attribute__((deprecated("Use -photoPreviewOriginDefImage."))); | |
| 224 | -@property (nonatomic, copy) NSString *photoNumberIconImageName __attribute__((deprecated("Use -photoNumberIconImage."))); | |
| 225 | -@property (nonatomic, strong) UIImage *takePictureImage; | |
| 226 | -@property (nonatomic, strong) UIImage *photoSelImage; | |
| 227 | -@property (nonatomic, strong) UIImage *photoDefImage; | |
| 228 | -@property (nonatomic, strong) UIImage *photoOriginSelImage; | |
| 229 | -@property (nonatomic, strong) UIImage *photoOriginDefImage; | |
| 230 | -@property (nonatomic, strong) UIImage *photoPreviewOriginDefImage; | |
| 231 | -@property (nonatomic, strong) UIImage *photoNumberIconImage; | |
| 232 | - | |
| 233 | -#pragma mark - | |
| 234 | -/// Appearance / 外观颜色 + 按钮文字 | |
| 235 | -@property (nonatomic, strong) UIColor *oKButtonTitleColorNormal; | |
| 236 | -@property (nonatomic, strong) UIColor *oKButtonTitleColorDisabled; | |
| 237 | -@property (nonatomic, strong) UIColor *naviBgColor; | |
| 238 | -@property (nonatomic, strong) UIColor *naviTitleColor; | |
| 239 | -@property (nonatomic, strong) UIFont *naviTitleFont; | |
| 240 | -@property (nonatomic, strong) UIColor *barItemTextColor; | |
| 241 | -@property (nonatomic, strong) UIFont *barItemTextFont; | |
| 242 | -@property (nonatomic, strong) UIColor *editBtnTitleColor;///LXG编辑按钮title颜色 | |
| 243 | - | |
| 244 | -@property (nonatomic, copy) NSString *doneBtnTitleStr; | |
| 245 | -@property (nonatomic, copy) NSString *cancelBtnTitleStr; | |
| 246 | -@property (nonatomic, copy) NSString *previewBtnTitleStr; | |
| 247 | -@property (nonatomic, copy) NSString *fullImageBtnTitleStr; | |
| 248 | -@property (nonatomic, copy) NSString *settingBtnTitleStr; | |
| 249 | -@property (nonatomic, copy) NSString *processHintStr; | |
| 250 | -@property (nonatomic, copy) NSString *editBtnTitleStr;///LXG编辑按钮 | |
| 251 | - | |
| 252 | - | |
| 253 | - | |
| 254 | -/// 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 | |
| 255 | -/// icon主题色,默认是微信的绿色,值是r:31 g:185 b:34。目前仅支持showSelectedIndex为YES时的图片选中icon。如需要,请尽早设置它。 | |
| 256 | -@property (strong, nonatomic) UIColor *iconThemeColor; | |
| 257 | - | |
| 258 | -#pragma mark - | |
| 259 | -- (void)cancelButtonClick; | |
| 260 | - | |
| 261 | -// The picker should dismiss itself; when it dismissed these handle will be called. | |
| 262 | -// You can also set autoDismiss to NO, then the picker don't dismiss itself. | |
| 263 | -// If isOriginalPhoto is YES, user picked the original photo. | |
| 264 | -// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:]. | |
| 265 | -// The UIImage Object in photos default width is 828px, you can set it by photoWidth property. | |
| 266 | -// 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的handle | |
| 267 | -// 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了 | |
| 268 | -// 如果isSelectOriginalPhoto为YES,表明用户选择了原图 | |
| 269 | -// 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] | |
| 270 | -// photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它 | |
| 271 | -@property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto); | |
| 272 | -@property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray<NSDictionary *> *infos); | |
| 273 | -@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(void); | |
| 274 | - | |
| 275 | -// If user picking a video, this handle will be called. | |
| 276 | -// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class. | |
| 277 | -// 如果用户选择了一个视频,下面的handle会被执行 | |
| 278 | -// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象 | |
| 279 | -@property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,id asset); | |
| 280 | - | |
| 281 | -// If user picking a gif image, this callback will be called. | |
| 282 | -// 如果用户选择了一个gif图片,下面的handle会被执行 | |
| 283 | -@property (nonatomic, copy) void (^didFinishPickingGifImageHandle)(UIImage *animatedImage,id sourceAssets); | |
| 284 | - | |
| 285 | -@property (nonatomic, weak) id<TZImagePickerControllerDelegate> pickerDelegate; | |
| 286 | - | |
| 287 | -@end | |
| 288 | - | |
| 289 | - | |
| 290 | -@protocol TZImagePickerControllerDelegate <NSObject> | |
| 291 | -@optional | |
| 292 | -// The picker should dismiss itself; when it dismissed these handle will be called. | |
| 293 | -// You can also set autoDismiss to NO, then the picker don't dismiss itself. | |
| 294 | -// If isOriginalPhoto is YES, user picked the original photo. | |
| 295 | -// You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:]. | |
| 296 | -// The UIImage Object in photos default width is 828px, you can set it by photoWidth property. | |
| 297 | -// 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的handle | |
| 298 | -// 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了 | |
| 299 | -// 如果isSelectOriginalPhoto为YES,表明用户选择了原图 | |
| 300 | -// 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] | |
| 301 | -// photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它 | |
| 302 | -- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto; | |
| 303 | -- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray<UIImage *> *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray<NSDictionary *> *)infos; | |
| 304 | -//- (void)imagePickerControllerDidCancel:(TZImagePickerController *)picker __attribute__((deprecated("Use -tz_imagePickerControllerDidCancel:."))); | |
| 305 | -- (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker; | |
| 306 | - | |
| 307 | -// If user picking a video, this callback will be called. | |
| 308 | -// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class. | |
| 309 | -// 如果用户选择了一个视频,下面的handle会被执行 | |
| 310 | -// 如果系统版本大于iOS8,asset是PHAsset类的对象,否则是ALAsset类的对象 | |
| 311 | -- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(id)asset; | |
| 312 | - | |
| 313 | -// If user picking a gif image, this callback will be called. | |
| 314 | -// 如果用户选择了一个gif图片,下面的handle会被执行 | |
| 315 | -- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(id)asset; | |
| 316 | - | |
| 317 | -// Decide album show or not't | |
| 318 | -// 决定相册显示与否 albumName:相册名字 result:相册原始数据 | |
| 319 | -- (BOOL)isAlbumCanSelect:(NSString *)albumName result:(id)result; | |
| 320 | - | |
| 321 | -// Decide asset show or not't | |
| 322 | -// 决定照片显示与否 | |
| 323 | -- (BOOL)isAssetCanSelect:(id)asset; | |
| 324 | -@end | |
| 325 | - | |
| 326 | - | |
| 327 | -@interface TZAlbumPickerController : UIViewController | |
| 328 | -@property (nonatomic, assign) NSInteger columnNumber; | |
| 329 | -@property (assign, nonatomic) BOOL isFirstAppear; | |
| 330 | -- (void)configTableView; | |
| 331 | -@end | |
| 332 | - | |
| 333 | - | |
| 334 | -@interface UIImage (MyBundle) | |
| 335 | -+ (UIImage *)imageNamedFromMyBundle:(NSString *)name; | |
| 336 | -@end | |
| 337 | - | |
| 338 | - | |
| 339 | -@interface NSString (TzExtension) | |
| 340 | -- (BOOL)tz_containsString:(NSString *)string; | |
| 341 | -- (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize; | |
| 342 | -@end | |
| 343 | - | |
| 344 | - | |
| 345 | -@interface TZCommonTools : NSObject | |
| 346 | -+ (BOOL)tz_isIPhoneX; | |
| 347 | -+ (CGFloat)tz_statusBarHeight; | |
| 348 | -// 获得Info.plist数据字典 | |
| 349 | -+ (NSDictionary *)tz_getInfoDictionary; | |
| 350 | -@end | |
| 351 | - | |
| 352 | - | |
| 353 | -@interface TZImagePickerConfig : NSObject | |
| 354 | -+ (instancetype)sharedInstance; | |
| 355 | -@property (copy, nonatomic) NSString *preferredLanguage; | |
| 356 | -@property(nonatomic, assign) BOOL allowPickingImage; | |
| 357 | -@property (nonatomic, assign) BOOL allowPickingVideo; | |
| 358 | -@property (strong, nonatomic) NSBundle *languageBundle; | |
| 359 | -/// 默认是200,如果一个GIF过大,里面图片个数可能超过1000,会导致内存飙升而崩溃 | |
| 360 | -@property (assign, nonatomic) NSInteger gifPreviewMaxImagesCount; | |
| 361 | -@property (assign, nonatomic) BOOL showSelectedIndex; | |
| 362 | -@property (assign, nonatomic) BOOL showPhotoCannotSelectLayer; | |
| 363 | -@property (assign, nonatomic) BOOL notScaleImage; | |
| 364 | -@property (assign, nonatomic) BOOL needFixComposition; | |
| 365 | -@end |
CNLiveImagePickerController/TZImagePickerController.m deleted
100755 → 0
| 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+Layout.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 | -#pragma mark - ADD:视频编辑(LXG) | |
| 169 | - self.maxEditVideoTime = 10; | |
| 170 | - self.maxVideoDuration = 120; | |
| 171 | - // Allow user picking original photo and video, you also can set No after this method | |
| 172 | - // 默认准许用户选择原图和视频, 你也可以在这个方法后置为NO | |
| 173 | - self.allowPickingOriginalPhoto = YES; | |
| 174 | - self.allowPickingVideo = YES; | |
| 175 | - self.allowPickingImage = YES; | |
| 176 | - self.allowTakePicture = YES; | |
| 177 | - self.allowTakeVideo = YES; | |
| 178 | - self.videoMaximumDuration = 10 * 60; | |
| 179 | - self.sortAscendingByModificationDate = YES; | |
| 180 | - self.autoDismiss = YES; | |
| 181 | - self.columnNumber = columnNumber; | |
| 182 | - [self configDefaultSetting]; | |
| 183 | - | |
| 184 | - if (![[TZImageManager manager] authorizationStatusAuthorized]) { | |
| 185 | - _tipLabel = [[UILabel alloc] init]; | |
| 186 | - _tipLabel.frame = CGRectMake(8, 120, self.view.tz_width - 16, 60); | |
| 187 | - _tipLabel.textAlignment = NSTextAlignmentCenter; | |
| 188 | - _tipLabel.numberOfLines = 0; | |
| 189 | - _tipLabel.font = [UIFont systemFontOfSize:16]; | |
| 190 | - _tipLabel.textColor = [UIColor blackColor]; | |
| 191 | - | |
| 192 | - NSDictionary *infoDict = [TZCommonTools tz_getInfoDictionary]; | |
| 193 | - NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"]; | |
| 194 | - if (!appName) appName = [infoDict valueForKey:@"CFBundleName"]; | |
| 195 | - NSString *tipText = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Allow %@ to access your album in \"Settings -> Privacy -> Photos\""],appName]; | |
| 196 | - _tipLabel.text = tipText; | |
| 197 | - [self.view addSubview:_tipLabel]; | |
| 198 | - | |
| 199 | - if (iOS8Later) { | |
| 200 | - _settingBtn = [UIButton buttonWithType:UIButtonTypeSystem]; | |
| 201 | - [_settingBtn setTitle:self.settingBtnTitleStr forState:UIControlStateNormal]; | |
| 202 | - _settingBtn.frame = CGRectMake(0, 180, self.view.tz_width, 44); | |
| 203 | - _settingBtn.titleLabel.font = [UIFont systemFontOfSize:18]; | |
| 204 | - [_settingBtn addTarget:self action:@selector(settingBtnClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 205 | - [self.view addSubview:_settingBtn]; | |
| 206 | - } | |
| 207 | - | |
| 208 | - if ([TZImageManager authorizationStatus] == 0) { | |
| 209 | - _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO]; | |
| 210 | - } | |
| 211 | - } else { | |
| 212 | - [self pushPhotoPickerVc]; | |
| 213 | - } | |
| 214 | - } | |
| 215 | - return self; | |
| 216 | -} | |
| 217 | - | |
| 218 | -/// This init method just for previewing photos / 用这个初始化方法以预览图片 | |
| 219 | -- (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index{ | |
| 220 | - TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init]; | |
| 221 | - self = [super initWithRootViewController:previewVc]; | |
| 222 | - if (self) { | |
| 223 | - self.selectedAssets = [NSMutableArray arrayWithArray:selectedAssets]; | |
| 224 | - self.allowPickingOriginalPhoto = self.allowPickingOriginalPhoto; | |
| 225 | - [self configDefaultSetting]; | |
| 226 | - | |
| 227 | - previewVc.photos = [NSMutableArray arrayWithArray:selectedPhotos]; | |
| 228 | - previewVc.currentIndex = index; | |
| 229 | - __weak typeof(self) weakSelf = self; | |
| 230 | - [previewVc setDoneButtonClickBlockWithPreviewType:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) { | |
| 231 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 232 | - [strongSelf dismissViewControllerAnimated:YES completion:^{ | |
| 233 | - if (!strongSelf) return; | |
| 234 | - if (strongSelf.didFinishPickingPhotosHandle) { | |
| 235 | - strongSelf.didFinishPickingPhotosHandle(photos,assets,isSelectOriginalPhoto); | |
| 236 | - } | |
| 237 | - }]; | |
| 238 | - }]; | |
| 239 | - } | |
| 240 | - return self; | |
| 241 | -} | |
| 242 | - | |
| 243 | -/// This init method for crop photo / 用这个初始化方法以裁剪图片 | |
| 244 | -- (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion { | |
| 245 | - TZPhotoPreviewController *previewVc = [[TZPhotoPreviewController alloc] init]; | |
| 246 | - self = [super initWithRootViewController:previewVc]; | |
| 247 | - if (self) { | |
| 248 | - self.maxImagesCount = 1; | |
| 249 | - self.allowCrop = YES; | |
| 250 | - self.selectedAssets = [NSMutableArray arrayWithArray:@[asset]]; | |
| 251 | - [self configDefaultSetting]; | |
| 252 | - | |
| 253 | - previewVc.photos = [NSMutableArray arrayWithArray:@[photo]]; | |
| 254 | - previewVc.isCropImage = YES; | |
| 255 | - previewVc.currentIndex = 0; | |
| 256 | - __weak typeof(self) weakSelf = self; | |
| 257 | - [previewVc setDoneButtonClickBlockCropMode:^(UIImage *cropImage, id asset) { | |
| 258 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 259 | - [strongSelf dismissViewControllerAnimated:YES completion:^{ | |
| 260 | - if (completion) { | |
| 261 | - completion(cropImage,asset); | |
| 262 | - } | |
| 263 | - }]; | |
| 264 | - }]; | |
| 265 | - } | |
| 266 | - return self; | |
| 267 | -} | |
| 268 | - | |
| 269 | -- (void)configDefaultSetting { | |
| 270 | - self.timeout = 15; | |
| 271 | - self.photoWidth = 828.0; | |
| 272 | - self.photoPreviewMaxWidth = 600; | |
| 273 | - self.naviTitleColor = [UIColor whiteColor]; | |
| 274 | - self.naviTitleFont = [UIFont systemFontOfSize:17]; | |
| 275 | - self.barItemTextFont = [UIFont systemFontOfSize:15]; | |
| 276 | - self.barItemTextColor = [UIColor whiteColor]; | |
| 277 | - self.allowPreview = YES; | |
| 278 | - // 2.2.26版本,不主动缩放图片,降低内存占用 | |
| 279 | - self.notScaleImage = YES; | |
| 280 | - self.needFixComposition = NO; | |
| 281 | - self.statusBarStyle = UIStatusBarStyleLightContent; | |
| 282 | - self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8]; | |
| 283 | - self.allowCameraLocation = YES; | |
| 284 | - | |
| 285 | - self.iconThemeColor = [UIColor colorWithRed:31 / 255.0 green:185 / 255.0 blue:34 / 255.0 alpha:1.0]; | |
| 286 | - [self configDefaultBtnTitle]; | |
| 287 | - | |
| 288 | - CGFloat cropViewWH = MIN(self.view.tz_width, self.view.tz_height) / 3 * 2; | |
| 289 | - self.cropRect = CGRectMake((self.view.tz_width - cropViewWH) / 2, (self.view.tz_height - cropViewWH) / 2, cropViewWH, cropViewWH); | |
| 290 | -} | |
| 291 | - | |
| 292 | -- (void)configDefaultImageName { | |
| 293 | - self.takePictureImageName = @"takePicture80"; | |
| 294 | - self.photoSelImageName = @"photo_sel_photoPickerVc"; | |
| 295 | - self.photoDefImageName = @"photo_def_photoPickerVc"; | |
| 296 | - self.photoNumberIconImage = [self createImageWithColor:nil size:CGSizeMake(24, 24) radius:12]; // @"photo_number_icon"; | |
| 297 | - self.photoPreviewOriginDefImageName = @"preview_original_def"; | |
| 298 | - self.photoOriginDefImageName = @"photo_original_def"; | |
| 299 | - self.photoOriginSelImageName = @"photo_original_sel"; | |
| 300 | -} | |
| 301 | - | |
| 302 | -- (void)setTakePictureImageName:(NSString *)takePictureImageName { | |
| 303 | - _takePictureImageName = takePictureImageName; | |
| 304 | - _takePictureImage = [UIImage imageNamedFromMyBundle:takePictureImageName]; | |
| 305 | -} | |
| 306 | - | |
| 307 | -- (void)setPhotoSelImageName:(NSString *)photoSelImageName { | |
| 308 | - _photoSelImageName = photoSelImageName; | |
| 309 | - _photoSelImage = [UIImage imageNamedFromMyBundle:photoSelImageName]; | |
| 310 | -} | |
| 311 | - | |
| 312 | -- (void)setPhotoDefImageName:(NSString *)photoDefImageName { | |
| 313 | - _photoDefImageName = photoDefImageName; | |
| 314 | - _photoDefImage = [UIImage imageNamedFromMyBundle:photoDefImageName]; | |
| 315 | -} | |
| 316 | - | |
| 317 | -- (void)setPhotoNumberIconImageName:(NSString *)photoNumberIconImageName { | |
| 318 | - _photoNumberIconImageName = photoNumberIconImageName; | |
| 319 | - _photoNumberIconImage = [UIImage imageNamedFromMyBundle:photoNumberIconImageName]; | |
| 320 | -} | |
| 321 | - | |
| 322 | -- (void)setPhotoPreviewOriginDefImageName:(NSString *)photoPreviewOriginDefImageName { | |
| 323 | - _photoPreviewOriginDefImageName = photoPreviewOriginDefImageName; | |
| 324 | - _photoPreviewOriginDefImage = [UIImage imageNamedFromMyBundle:photoPreviewOriginDefImageName]; | |
| 325 | -} | |
| 326 | - | |
| 327 | -- (void)setPhotoOriginDefImageName:(NSString *)photoOriginDefImageName { | |
| 328 | - _photoOriginDefImageName = photoOriginDefImageName; | |
| 329 | - _photoOriginDefImage = [UIImage imageNamedFromMyBundle:photoOriginDefImageName]; | |
| 330 | -} | |
| 331 | - | |
| 332 | -- (void)setPhotoOriginSelImageName:(NSString *)photoOriginSelImageName { | |
| 333 | - _photoOriginSelImageName = photoOriginSelImageName; | |
| 334 | - _photoOriginSelImage = [UIImage imageNamedFromMyBundle:photoOriginSelImageName]; | |
| 335 | -} | |
| 336 | - | |
| 337 | -- (void)setIconThemeColor:(UIColor *)iconThemeColor { | |
| 338 | - _iconThemeColor = iconThemeColor; | |
| 339 | - [self configDefaultImageName]; | |
| 340 | -} | |
| 341 | - | |
| 342 | -- (void)configDefaultBtnTitle { | |
| 343 | - self.doneBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Done"]; | |
| 344 | - self.cancelBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Cancel"]; | |
| 345 | - self.previewBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Preview"]; | |
| 346 | - self.fullImageBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Full image"]; | |
| 347 | - self.settingBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Setting"]; | |
| 348 | - self.processHintStr = [NSBundle tz_localizedStringForKey:@"Processing..."]; | |
| 349 | - self.editBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Edit"]; | |
| 350 | -} | |
| 351 | - | |
| 352 | -- (void)setShowSelectedIndex:(BOOL)showSelectedIndex { | |
| 353 | - _showSelectedIndex = showSelectedIndex; | |
| 354 | - if (showSelectedIndex) { | |
| 355 | - self.photoSelImage = [self createImageWithColor:nil size:CGSizeMake(24, 24) radius:12]; | |
| 356 | - } | |
| 357 | - [TZImagePickerConfig sharedInstance].showSelectedIndex = showSelectedIndex; | |
| 358 | -} | |
| 359 | - | |
| 360 | -- (void)setShowPhotoCannotSelectLayer:(BOOL)showPhotoCannotSelectLayer { | |
| 361 | - _showPhotoCannotSelectLayer = showPhotoCannotSelectLayer; | |
| 362 | - [TZImagePickerConfig sharedInstance].showPhotoCannotSelectLayer = showPhotoCannotSelectLayer; | |
| 363 | -} | |
| 364 | - | |
| 365 | -- (void)setNotScaleImage:(BOOL)notScaleImage { | |
| 366 | - _notScaleImage = notScaleImage; | |
| 367 | - [TZImagePickerConfig sharedInstance].notScaleImage = notScaleImage; | |
| 368 | -} | |
| 369 | - | |
| 370 | -- (void)setNeedFixComposition:(BOOL)needFixComposition { | |
| 371 | - _needFixComposition = needFixComposition; | |
| 372 | - [TZImagePickerConfig sharedInstance].needFixComposition = needFixComposition; | |
| 373 | -} | |
| 374 | - | |
| 375 | -- (void)observeAuthrizationStatusChange { | |
| 376 | - [_timer invalidate]; | |
| 377 | - _timer = nil; | |
| 378 | - if ([TZImageManager authorizationStatus] == 0) { | |
| 379 | - _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:NO]; | |
| 380 | - } | |
| 381 | - | |
| 382 | - if ([[TZImageManager manager] authorizationStatusAuthorized]) { | |
| 383 | - [_tipLabel removeFromSuperview]; | |
| 384 | - [_settingBtn removeFromSuperview]; | |
| 385 | - | |
| 386 | - [self pushPhotoPickerVc]; | |
| 387 | - | |
| 388 | - TZAlbumPickerController *albumPickerVc = (TZAlbumPickerController *)self.visibleViewController; | |
| 389 | - if ([albumPickerVc isKindOfClass:[TZAlbumPickerController class]]) { | |
| 390 | - [albumPickerVc configTableView]; | |
| 391 | - } | |
| 392 | - } | |
| 393 | -} | |
| 394 | - | |
| 395 | -- (void)pushPhotoPickerVc { | |
| 396 | - _didPushPhotoPickerVc = NO; | |
| 397 | - // 1.6.8 判断是否需要push到照片选择页,如果_pushPhotoPickerVc为NO,则不push | |
| 398 | - if (!_didPushPhotoPickerVc && _pushPhotoPickerVc) { | |
| 399 | - TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init]; | |
| 400 | - photoPickerVc.isFirstAppear = YES; | |
| 401 | - photoPickerVc.columnNumber = self.columnNumber; | |
| 402 | - [[TZImageManager manager] getCameraRollAlbum:self.allowPickingVideo allowPickingImage:self.allowPickingImage needFetchAssets:NO completion:^(TZAlbumModel *model) { | |
| 403 | - photoPickerVc.model = model; | |
| 404 | - [self pushViewController:photoPickerVc animated:YES]; | |
| 405 | - self->_didPushPhotoPickerVc = YES; | |
| 406 | - }]; | |
| 407 | - } | |
| 408 | -} | |
| 409 | - | |
| 410 | -- (id)showAlertWithTitle:(NSString *)title { | |
| 411 | - if (iOS8Later) { | |
| 412 | - UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleAlert]; | |
| 413 | - [alertController addAction:[UIAlertAction actionWithTitle:[NSBundle tz_localizedStringForKey:@"OK"] style:UIAlertActionStyleDefault handler:nil]]; | |
| 414 | - [self presentViewController:alertController animated:YES completion:nil]; | |
| 415 | - return alertController; | |
| 416 | - } else { | |
| 417 | - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:nil delegate:nil cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles:nil, nil]; | |
| 418 | - [alertView show]; | |
| 419 | - return alertView; | |
| 420 | - } | |
| 421 | -} | |
| 422 | - | |
| 423 | -- (void)hideAlertView:(id)alertView { | |
| 424 | - if ([alertView isKindOfClass:[UIAlertController class]]) { | |
| 425 | - UIAlertController *alertC = alertView; | |
| 426 | - [alertC dismissViewControllerAnimated:YES completion:nil]; | |
| 427 | - } else if ([alertView isKindOfClass:[UIAlertView class]]) { | |
| 428 | - UIAlertView *alertV = alertView; | |
| 429 | - [alertV dismissWithClickedButtonIndex:0 animated:YES]; | |
| 430 | - } | |
| 431 | - alertView = nil; | |
| 432 | -} | |
| 433 | - | |
| 434 | -- (void)showProgressHUD { | |
| 435 | - if (!_progressHUD) { | |
| 436 | - _progressHUD = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 437 | - [_progressHUD setBackgroundColor:[UIColor clearColor]]; | |
| 438 | - _progressHUD.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);///解决多次点击内存溢出问题(lxg) | |
| 439 | - | |
| 440 | - _HUDContainer = [[UIView alloc] init]; | |
| 441 | - _HUDContainer.layer.cornerRadius = 8; | |
| 442 | - _HUDContainer.clipsToBounds = YES; | |
| 443 | - _HUDContainer.backgroundColor = [UIColor darkGrayColor]; | |
| 444 | - _HUDContainer.alpha = 0.7; | |
| 445 | - | |
| 446 | - _HUDIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; | |
| 447 | - | |
| 448 | - _HUDLabel = [[UILabel alloc] init]; | |
| 449 | - _HUDLabel.textAlignment = NSTextAlignmentCenter; | |
| 450 | - _HUDLabel.text = self.processHintStr; | |
| 451 | - _HUDLabel.font = [UIFont systemFontOfSize:15]; | |
| 452 | - _HUDLabel.textColor = [UIColor whiteColor]; | |
| 453 | - | |
| 454 | - [_HUDContainer addSubview:_HUDLabel]; | |
| 455 | - [_HUDContainer addSubview:_HUDIndicatorView]; | |
| 456 | - [_progressHUD addSubview:_HUDContainer]; | |
| 457 | - } | |
| 458 | - [_HUDIndicatorView startAnimating]; | |
| 459 | - [[UIApplication sharedApplication].keyWindow addSubview:_progressHUD]; | |
| 460 | - | |
| 461 | - // if over time, dismiss HUD automatic | |
| 462 | - __weak typeof(self) weakSelf = self; | |
| 463 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 464 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 465 | - [strongSelf hideProgressHUD]; | |
| 466 | - }); | |
| 467 | -} | |
| 468 | - | |
| 469 | -- (void)hideProgressHUD { | |
| 470 | - if (_progressHUD) { | |
| 471 | - [_HUDIndicatorView stopAnimating]; | |
| 472 | - [_progressHUD removeFromSuperview]; | |
| 473 | - } | |
| 474 | -} | |
| 475 | - | |
| 476 | -- (void)setMaxImagesCount:(NSInteger)maxImagesCount { | |
| 477 | - _maxImagesCount = maxImagesCount; | |
| 478 | - if (maxImagesCount > 1) { | |
| 479 | - _showSelectBtn = YES; | |
| 480 | - _allowCrop = NO; | |
| 481 | - } | |
| 482 | -} | |
| 483 | - | |
| 484 | -- (void)setShowSelectBtn:(BOOL)showSelectBtn { | |
| 485 | - _showSelectBtn = showSelectBtn; | |
| 486 | - // 多选模式下,不允许让showSelectBtn为NO | |
| 487 | - if (!showSelectBtn && _maxImagesCount > 1) { | |
| 488 | - _showSelectBtn = YES; | |
| 489 | - } | |
| 490 | -} | |
| 491 | - | |
| 492 | -- (void)setAllowCrop:(BOOL)allowCrop { | |
| 493 | - _allowCrop = _maxImagesCount > 1 ? NO : allowCrop; | |
| 494 | - if (allowCrop) { // 允许裁剪的时候,不能选原图和GIF | |
| 495 | - self.allowPickingOriginalPhoto = NO; | |
| 496 | - self.allowPickingGif = NO; | |
| 497 | - } | |
| 498 | -} | |
| 499 | - | |
| 500 | -- (void)setCircleCropRadius:(NSInteger)circleCropRadius { | |
| 501 | - _circleCropRadius = circleCropRadius; | |
| 502 | - self.cropRect = CGRectMake(self.view.tz_width / 2 - circleCropRadius, self.view.tz_height / 2 - _circleCropRadius, _circleCropRadius * 2, _circleCropRadius * 2); | |
| 503 | -} | |
| 504 | - | |
| 505 | -- (void)setCropRect:(CGRect)cropRect { | |
| 506 | - _cropRect = cropRect; | |
| 507 | - _cropRectPortrait = cropRect; | |
| 508 | - CGFloat widthHeight = cropRect.size.width; | |
| 509 | - _cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, cropRect.origin.x, widthHeight, widthHeight); | |
| 510 | -} | |
| 511 | - | |
| 512 | -- (void)setTimeout:(NSInteger)timeout { | |
| 513 | - _timeout = timeout; | |
| 514 | - if (timeout < 5) { | |
| 515 | - _timeout = 5; | |
| 516 | - } else if (_timeout > 60) { | |
| 517 | - _timeout = 60; | |
| 518 | - } | |
| 519 | -} | |
| 520 | - | |
| 521 | -- (void)setPickerDelegate:(id<TZImagePickerControllerDelegate>)pickerDelegate { | |
| 522 | - _pickerDelegate = pickerDelegate; | |
| 523 | - [TZImageManager manager].pickerDelegate = pickerDelegate; | |
| 524 | -} | |
| 525 | - | |
| 526 | -- (void)setColumnNumber:(NSInteger)columnNumber { | |
| 527 | - _columnNumber = columnNumber; | |
| 528 | - if (columnNumber <= 2) { | |
| 529 | - _columnNumber = 2; | |
| 530 | - } else if (columnNumber >= 6) { | |
| 531 | - _columnNumber = 6; | |
| 532 | - } | |
| 533 | - | |
| 534 | - TZAlbumPickerController *albumPickerVc = [self.childViewControllers firstObject]; | |
| 535 | - albumPickerVc.columnNumber = _columnNumber; | |
| 536 | - [TZImageManager manager].columnNumber = _columnNumber; | |
| 537 | -} | |
| 538 | - | |
| 539 | -- (void)setMinPhotoWidthSelectable:(NSInteger)minPhotoWidthSelectable { | |
| 540 | - _minPhotoWidthSelectable = minPhotoWidthSelectable; | |
| 541 | - [TZImageManager manager].minPhotoWidthSelectable = minPhotoWidthSelectable; | |
| 542 | -} | |
| 543 | - | |
| 544 | -- (void)setMinPhotoHeightSelectable:(NSInteger)minPhotoHeightSelectable { | |
| 545 | - _minPhotoHeightSelectable = minPhotoHeightSelectable; | |
| 546 | - [TZImageManager manager].minPhotoHeightSelectable = minPhotoHeightSelectable; | |
| 547 | -} | |
| 548 | - | |
| 549 | -- (void)setHideWhenCanNotSelect:(BOOL)hideWhenCanNotSelect { | |
| 550 | - _hideWhenCanNotSelect = hideWhenCanNotSelect; | |
| 551 | - [TZImageManager manager].hideWhenCanNotSelect = hideWhenCanNotSelect; | |
| 552 | -} | |
| 553 | - | |
| 554 | -- (void)setPhotoPreviewMaxWidth:(CGFloat)photoPreviewMaxWidth { | |
| 555 | - _photoPreviewMaxWidth = photoPreviewMaxWidth; | |
| 556 | - if (photoPreviewMaxWidth > 800) { | |
| 557 | - _photoPreviewMaxWidth = 800; | |
| 558 | - } else if (photoPreviewMaxWidth < 500) { | |
| 559 | - _photoPreviewMaxWidth = 500; | |
| 560 | - } | |
| 561 | - [TZImageManager manager].photoPreviewMaxWidth = _photoPreviewMaxWidth; | |
| 562 | -} | |
| 563 | - | |
| 564 | -- (void)setPhotoWidth:(CGFloat)photoWidth { | |
| 565 | - _photoWidth = photoWidth; | |
| 566 | - [TZImageManager manager].photoWidth = photoWidth; | |
| 567 | -} | |
| 568 | - | |
| 569 | -- (void)setSelectedAssets:(NSMutableArray *)selectedAssets { | |
| 570 | - _selectedAssets = selectedAssets; | |
| 571 | - _selectedModels = [NSMutableArray array]; | |
| 572 | - _selectedAssetIds = [NSMutableArray array]; | |
| 573 | - for (id asset in selectedAssets) { | |
| 574 | - TZAssetModel *model = [TZAssetModel modelWithAsset:asset type:[[TZImageManager manager] getAssetType:asset]]; | |
| 575 | - model.isSelected = YES; | |
| 576 | - [self addSelectedModel:model]; | |
| 577 | - } | |
| 578 | -} | |
| 579 | - | |
| 580 | -- (void)setAllowPickingImage:(BOOL)allowPickingImage { | |
| 581 | - _allowPickingImage = allowPickingImage; | |
| 582 | - [TZImagePickerConfig sharedInstance].allowPickingImage = allowPickingImage; | |
| 583 | - if (!allowPickingImage) { | |
| 584 | - _allowTakePicture = NO; | |
| 585 | - } | |
| 586 | -} | |
| 587 | - | |
| 588 | -- (void)setAllowPickingVideo:(BOOL)allowPickingVideo { | |
| 589 | - _allowPickingVideo = allowPickingVideo; | |
| 590 | - [TZImagePickerConfig sharedInstance].allowPickingVideo = allowPickingVideo; | |
| 591 | - if (!allowPickingVideo) { | |
| 592 | - _allowTakeVideo = NO; | |
| 593 | - } | |
| 594 | -} | |
| 595 | - | |
| 596 | -- (void)setPreferredLanguage:(NSString *)preferredLanguage { | |
| 597 | - _preferredLanguage = preferredLanguage; | |
| 598 | - [TZImagePickerConfig sharedInstance].preferredLanguage = preferredLanguage; | |
| 599 | - [self configDefaultBtnTitle]; | |
| 600 | -} | |
| 601 | - | |
| 602 | -- (void)setLanguageBundle:(NSBundle *)languageBundle { | |
| 603 | - _languageBundle = languageBundle; | |
| 604 | - [TZImagePickerConfig sharedInstance].languageBundle = languageBundle; | |
| 605 | - [self configDefaultBtnTitle]; | |
| 606 | -} | |
| 607 | - | |
| 608 | -- (void)setSortAscendingByModificationDate:(BOOL)sortAscendingByModificationDate { | |
| 609 | - _sortAscendingByModificationDate = sortAscendingByModificationDate; | |
| 610 | - [TZImageManager manager].sortAscendingByModificationDate = sortAscendingByModificationDate; | |
| 611 | -} | |
| 612 | - | |
| 613 | -- (void)settingBtnClick { | |
| 614 | - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; | |
| 615 | -} | |
| 616 | - | |
| 617 | -- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { | |
| 618 | - if (iOS7Later) { | |
| 619 | - viewController.automaticallyAdjustsScrollViewInsets = NO; | |
| 620 | - } | |
| 621 | - [super pushViewController:viewController animated:animated]; | |
| 622 | -} | |
| 623 | - | |
| 624 | -- (void)dealloc { | |
| 625 | - // NSLog(@"%@ dealloc",NSStringFromClass(self.class)); | |
| 626 | -} | |
| 627 | - | |
| 628 | -- (void)addSelectedModel:(TZAssetModel *)model { | |
| 629 | - [_selectedModels addObject:model]; | |
| 630 | - NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset]; | |
| 631 | - [_selectedAssetIds addObject:assetId]; | |
| 632 | -} | |
| 633 | - | |
| 634 | -- (void)removeSelectedModel:(TZAssetModel *)model { | |
| 635 | - [_selectedModels removeObject:model]; | |
| 636 | - NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset]; | |
| 637 | - [_selectedAssetIds removeObject:assetId]; | |
| 638 | -} | |
| 639 | - | |
| 640 | -- (UIImage *)createImageWithColor:(UIColor *)color size:(CGSize)size radius:(CGFloat)radius { | |
| 641 | - if (!color) { | |
| 642 | - color = self.iconThemeColor; | |
| 643 | - } | |
| 644 | - CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); | |
| 645 | - UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale); | |
| 646 | - CGContextRef context = UIGraphicsGetCurrentContext(); | |
| 647 | - CGContextSetFillColorWithColor(context, [color CGColor]); | |
| 648 | - UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius]; | |
| 649 | - CGContextAddPath(context, path.CGPath); | |
| 650 | - CGContextFillPath(context); | |
| 651 | - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); | |
| 652 | - UIGraphicsEndImageContext(); | |
| 653 | - return image; | |
| 654 | -} | |
| 655 | - | |
| 656 | -#pragma mark - UIContentContainer | |
| 657 | - | |
| 658 | -- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { | |
| 659 | - [self willInterfaceOrientionChange]; | |
| 660 | - if (size.width > size.height) { | |
| 661 | - _cropRect = _cropRectLandscape; | |
| 662 | - } else { | |
| 663 | - _cropRect = _cropRectPortrait; | |
| 664 | - } | |
| 665 | -} | |
| 666 | - | |
| 667 | -- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { | |
| 668 | - [self willInterfaceOrientionChange]; | |
| 669 | - if (toInterfaceOrientation >= 3) { | |
| 670 | - _cropRect = _cropRectLandscape; | |
| 671 | - } else { | |
| 672 | - _cropRect = _cropRectPortrait; | |
| 673 | - } | |
| 674 | -} | |
| 675 | - | |
| 676 | -- (void)willInterfaceOrientionChange { | |
| 677 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 678 | - if (![UIApplication sharedApplication].statusBarHidden) { | |
| 679 | - if (iOS7Later && self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO; | |
| 680 | - } | |
| 681 | - }); | |
| 682 | -} | |
| 683 | - | |
| 684 | -#pragma mark - Layout | |
| 685 | - | |
| 686 | -- (void)viewDidLayoutSubviews { | |
| 687 | - [super viewDidLayoutSubviews]; | |
| 688 | - | |
| 689 | - _HUDContainer.frame = CGRectMake((self.view.tz_width - 120) / 2, (self.view.tz_height - 90) / 2, 120, 90); | |
| 690 | - _HUDIndicatorView.frame = CGRectMake(45, 15, 30, 30); | |
| 691 | - _HUDLabel.frame = CGRectMake(0,40, 120, 50); | |
| 692 | -} | |
| 693 | - | |
| 694 | -#pragma mark - Public | |
| 695 | - | |
| 696 | -- (void)cancelButtonClick { | |
| 697 | - if (self.autoDismiss) { | |
| 698 | - [self dismissViewControllerAnimated:YES completion:^{ | |
| 699 | - [self callDelegateMethod]; | |
| 700 | - }]; | |
| 701 | - } else { | |
| 702 | - [self callDelegateMethod]; | |
| 703 | - } | |
| 704 | -} | |
| 705 | - | |
| 706 | -- (void)callDelegateMethod { | |
| 707 | - if ([self.pickerDelegate respondsToSelector:@selector(tz_imagePickerControllerDidCancel:)]) { | |
| 708 | - [self.pickerDelegate tz_imagePickerControllerDidCancel:self]; | |
| 709 | - } | |
| 710 | - if (self.imagePickerControllerDidCancelHandle) { | |
| 711 | - self.imagePickerControllerDidCancelHandle(); | |
| 712 | - } | |
| 713 | -} | |
| 714 | - | |
| 715 | -@end | |
| 716 | - | |
| 717 | - | |
| 718 | -@interface TZAlbumPickerController ()<UITableViewDataSource,UITableViewDelegate> { | |
| 719 | - UITableView *_tableView; | |
| 720 | -} | |
| 721 | -@property (nonatomic, strong) NSMutableArray *albumArr; | |
| 722 | -@end | |
| 723 | - | |
| 724 | -@implementation TZAlbumPickerController | |
| 725 | - | |
| 726 | -- (void)viewDidLoad { | |
| 727 | - [super viewDidLoad]; | |
| 728 | - self.isFirstAppear = YES; | |
| 729 | - self.view.backgroundColor = [UIColor whiteColor]; | |
| 730 | - | |
| 731 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 732 | - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:imagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:imagePickerVc action:@selector(cancelButtonClick)]; | |
| 733 | -} | |
| 734 | - | |
| 735 | -- (void)viewWillAppear:(BOOL)animated { | |
| 736 | - [super viewWillAppear:animated]; | |
| 737 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 738 | - [imagePickerVc hideProgressHUD]; | |
| 739 | - if (imagePickerVc.allowPickingImage) { | |
| 740 | - self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Photos"]; | |
| 741 | - } else if (imagePickerVc.allowPickingVideo) { | |
| 742 | - self.navigationItem.title = [NSBundle tz_localizedStringForKey:@"Videos"]; | |
| 743 | - } | |
| 744 | - | |
| 745 | - if (self.isFirstAppear && !imagePickerVc.navLeftBarButtonSettingBlock) { | |
| 746 | - self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Back"] style:UIBarButtonItemStylePlain target:nil action:nil]; | |
| 747 | - } | |
| 748 | - | |
| 749 | - [self configTableView]; | |
| 750 | -} | |
| 751 | - | |
| 752 | -- (void)configTableView { | |
| 753 | - if (![[TZImageManager manager] authorizationStatusAuthorized]) { | |
| 754 | - return; | |
| 755 | - } | |
| 756 | - | |
| 757 | - if (self.isFirstAppear) { | |
| 758 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 759 | - [imagePickerVc showProgressHUD]; | |
| 760 | - } | |
| 761 | - | |
| 762 | - dispatch_async(dispatch_get_global_queue(0, 0), ^{ | |
| 763 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 764 | - [[TZImageManager manager] getAllAlbums:imagePickerVc.allowPickingVideo allowPickingImage:imagePickerVc.allowPickingImage needFetchAssets:!self.isFirstAppear completion:^(NSArray<TZAlbumModel *> *models) { | |
| 765 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 766 | - self->_albumArr = [NSMutableArray arrayWithArray:models]; | |
| 767 | - for (TZAlbumModel *albumModel in self->_albumArr) { | |
| 768 | - albumModel.selectedModels = imagePickerVc.selectedModels; | |
| 769 | - } | |
| 770 | - [imagePickerVc hideProgressHUD]; | |
| 771 | - | |
| 772 | - if (self.isFirstAppear) { | |
| 773 | - self.isFirstAppear = NO; | |
| 774 | - [self configTableView]; | |
| 775 | - } | |
| 776 | - | |
| 777 | - if (!self->_tableView) { | |
| 778 | - self->_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; | |
| 779 | - self->_tableView.rowHeight = 70; | |
| 780 | - self->_tableView.tableFooterView = [[UIView alloc] init]; | |
| 781 | - self->_tableView.dataSource = self; | |
| 782 | - self->_tableView.delegate = self; | |
| 783 | - [self->_tableView registerClass:[TZAlbumCell class] forCellReuseIdentifier:@"TZAlbumCell"]; | |
| 784 | - [self.view addSubview:self->_tableView]; | |
| 785 | - } else { | |
| 786 | - [self->_tableView reloadData]; | |
| 787 | - } | |
| 788 | - }); | |
| 789 | - }]; | |
| 790 | - }); | |
| 791 | -} | |
| 792 | - | |
| 793 | -- (void)dealloc { | |
| 794 | - // NSLog(@"%@ dealloc",NSStringFromClass(self.class)); | |
| 795 | -} | |
| 796 | - | |
| 797 | -#pragma mark - Layout | |
| 798 | - | |
| 799 | -- (void)viewDidLayoutSubviews { | |
| 800 | - [super viewDidLayoutSubviews]; | |
| 801 | - | |
| 802 | - CGFloat top = 0; | |
| 803 | - CGFloat tableViewHeight = 0; | |
| 804 | - CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height; | |
| 805 | - BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden; | |
| 806 | - if (self.navigationController.navigationBar.isTranslucent) { | |
| 807 | - top = naviBarHeight; | |
| 808 | - if (iOS7Later && !isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight]; | |
| 809 | - tableViewHeight = self.view.tz_height - top; | |
| 810 | - } else { | |
| 811 | - tableViewHeight = self.view.tz_height; | |
| 812 | - } | |
| 813 | - _tableView.frame = CGRectMake(0, top, self.view.tz_width, tableViewHeight); | |
| 814 | -} | |
| 815 | - | |
| 816 | -#pragma mark - UITableViewDataSource && Delegate | |
| 817 | - | |
| 818 | -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { | |
| 819 | - return _albumArr.count; | |
| 820 | -} | |
| 821 | - | |
| 822 | -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { | |
| 823 | - TZAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TZAlbumCell"]; | |
| 824 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 825 | - cell.albumCellDidLayoutSubviewsBlock = imagePickerVc.albumCellDidLayoutSubviewsBlock; | |
| 826 | - cell.albumCellDidSetModelBlock = imagePickerVc.albumCellDidSetModelBlock; | |
| 827 | - cell.selectedCountButton.backgroundColor = imagePickerVc.iconThemeColor; | |
| 828 | - cell.model = _albumArr[indexPath.row]; | |
| 829 | - cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; | |
| 830 | - return cell; | |
| 831 | -} | |
| 832 | - | |
| 833 | -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { | |
| 834 | - TZPhotoPickerController *photoPickerVc = [[TZPhotoPickerController alloc] init]; | |
| 835 | - photoPickerVc.columnNumber = self.columnNumber; | |
| 836 | - TZAlbumModel *model = _albumArr[indexPath.row]; | |
| 837 | - photoPickerVc.model = model; | |
| 838 | - [self.navigationController pushViewController:photoPickerVc animated:YES]; | |
| 839 | - [tableView deselectRowAtIndexPath:indexPath animated:NO]; | |
| 840 | -} | |
| 841 | - | |
| 842 | -#pragma clang diagnostic pop | |
| 843 | - | |
| 844 | -@end | |
| 845 | - | |
| 846 | - | |
| 847 | -@implementation UIImage (MyBundle) | |
| 848 | - | |
| 849 | -+ (UIImage *)imageNamedFromMyBundle:(NSString *)name { | |
| 850 | - NSBundle *imageBundle = [NSBundle tz_imagePickerBundle]; | |
| 851 | - name = [name stringByAppendingString:@"@2x"]; | |
| 852 | - NSString *imagePath = [imageBundle pathForResource:name ofType:@"png"]; | |
| 853 | - UIImage *image = [UIImage imageWithContentsOfFile:imagePath]; | |
| 854 | - if (!image) { | |
| 855 | - // 兼容业务方自己设置图片的方式 | |
| 856 | - name = [name stringByReplacingOccurrencesOfString:@"@2x" withString:@""]; | |
| 857 | - image = [UIImage imageNamed:name]; | |
| 858 | - } | |
| 859 | - return image; | |
| 860 | -} | |
| 861 | - | |
| 862 | -@end | |
| 863 | - | |
| 864 | - | |
| 865 | -@implementation NSString (TzExtension) | |
| 866 | - | |
| 867 | -- (BOOL)tz_containsString:(NSString *)string { | |
| 868 | - if (iOS8Later) { | |
| 869 | - return [self containsString:string]; | |
| 870 | - } else { | |
| 871 | - NSRange range = [self rangeOfString:string]; | |
| 872 | - return range.location != NSNotFound; | |
| 873 | - } | |
| 874 | -} | |
| 875 | - | |
| 876 | -#pragma clang diagnostic push | |
| 877 | -#pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
| 878 | -- (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize { | |
| 879 | - CGSize size; | |
| 880 | - if (iOS7Later) { | |
| 881 | - size = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size; | |
| 882 | - } else { | |
| 883 | - size = [self sizeWithFont:attributes[NSFontAttributeName] constrainedToSize:maxSize]; | |
| 884 | - } | |
| 885 | - return size; | |
| 886 | -} | |
| 887 | -#pragma clang diagnostic pop | |
| 888 | - | |
| 889 | -@end | |
| 890 | - | |
| 891 | - | |
| 892 | -@implementation TZCommonTools | |
| 893 | - | |
| 894 | -+ (BOOL)tz_isIPhoneX { | |
| 895 | - return (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(414, 896)) ||CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(896, 414))); | |
| 896 | -} | |
| 897 | - | |
| 898 | -+ (CGFloat)tz_statusBarHeight { | |
| 899 | - return [self tz_isIPhoneX] ? 44 : 20; | |
| 900 | -} | |
| 901 | - | |
| 902 | -// 获得Info.plist数据字典 | |
| 903 | -+ (NSDictionary *)tz_getInfoDictionary { | |
| 904 | - NSDictionary *infoDict = [NSBundle mainBundle].localizedInfoDictionary; | |
| 905 | - if (!infoDict || !infoDict.count) { | |
| 906 | - infoDict = [NSBundle mainBundle].infoDictionary; | |
| 907 | - } | |
| 908 | - if (!infoDict || !infoDict.count) { | |
| 909 | - NSString *path = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"]; | |
| 910 | - infoDict = [NSDictionary dictionaryWithContentsOfFile:path]; | |
| 911 | - } | |
| 912 | - return infoDict ? infoDict : @{}; | |
| 913 | -} | |
| 914 | -@end | |
| 915 | - | |
| 916 | - | |
| 917 | -@implementation TZImagePickerConfig | |
| 918 | - | |
| 919 | -+ (instancetype)sharedInstance { | |
| 920 | - static dispatch_once_t onceToken; | |
| 921 | - static TZImagePickerConfig *config = nil; | |
| 922 | - dispatch_once(&onceToken, ^{ | |
| 923 | - if (config == nil) { | |
| 924 | - config = [[TZImagePickerConfig alloc] init]; | |
| 925 | - config.preferredLanguage = nil; | |
| 926 | - config.gifPreviewMaxImagesCount = 200; | |
| 927 | - } | |
| 928 | - }); | |
| 929 | - return config; | |
| 930 | -} | |
| 931 | - | |
| 932 | -- (void)setPreferredLanguage:(NSString *)preferredLanguage { | |
| 933 | - _preferredLanguage = preferredLanguage; | |
| 934 | - | |
| 935 | - if (!preferredLanguage || !preferredLanguage.length) { | |
| 936 | - preferredLanguage = [NSLocale preferredLanguages].firstObject; | |
| 937 | - } | |
| 938 | - if ([preferredLanguage rangeOfString:@"zh-Hans"].location != NSNotFound) { | |
| 939 | - preferredLanguage = @"zh-Hans"; | |
| 940 | - } else if ([preferredLanguage rangeOfString:@"zh-Hant"].location != NSNotFound) { | |
| 941 | - preferredLanguage = @"zh-Hant"; | |
| 942 | - } else if ([preferredLanguage rangeOfString:@"vi"].location != NSNotFound) { | |
| 943 | - preferredLanguage = @"vi"; | |
| 944 | - } else { | |
| 945 | - preferredLanguage = @"en"; | |
| 946 | - } | |
| 947 | - _languageBundle = [NSBundle bundleWithPath:[[NSBundle tz_imagePickerBundle] pathForResource:preferredLanguage ofType:@"lproj"]]; | |
| 948 | -} | |
| 949 | - | |
| 950 | -@end |
CNLiveImagePickerController/TZLocationManager.h deleted
100755 → 0
| 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/TZLocationManager.m deleted
100755 → 0
| 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/TZPhotoPickerController.h deleted
100755 → 0
| 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/TZPhotoPickerController.m deleted
100755 → 0
| 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+Layout.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 | - | |
| 22 | -@interface TZPhotoPickerController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIAlertViewDelegate> { | |
| 23 | - NSMutableArray *_models; | |
| 24 | - | |
| 25 | - UIView *_bottomToolBar; | |
| 26 | - UIButton *_previewButton; | |
| 27 | - UIButton *_doneButton; | |
| 28 | - UIImageView *_numberImageView; | |
| 29 | - UILabel *_numberLabel; | |
| 30 | - UIButton *_originalPhotoButton; | |
| 31 | - UILabel *_originalPhotoLabel; | |
| 32 | - UIView *_divideLine; | |
| 33 | - | |
| 34 | - BOOL _shouldScrollToBottom; | |
| 35 | - BOOL _showTakePhotoBtn; | |
| 36 | - | |
| 37 | - CGFloat _offsetItemCount; | |
| 38 | - | |
| 39 | - BOOL _isClickDone;///防止多次点击(LXG) | |
| 40 | -} | |
| 41 | -@property CGRect previousPreheatRect; | |
| 42 | -@property (nonatomic, assign) BOOL isSelectOriginalPhoto; | |
| 43 | -@property (nonatomic, strong) TZCollectionView *collectionView; | |
| 44 | -@property (strong, nonatomic) UICollectionViewFlowLayout *layout; | |
| 45 | -@property (nonatomic, strong) UIImagePickerController *imagePickerVc; | |
| 46 | -@property (strong, nonatomic) CLLocation *location; | |
| 47 | -@property (assign, nonatomic) BOOL useCachedImage; | |
| 48 | -@end | |
| 49 | - | |
| 50 | -static CGSize AssetGridThumbnailSize; | |
| 51 | -static CGFloat itemMargin = 5; | |
| 52 | - | |
| 53 | -@implementation TZPhotoPickerController | |
| 54 | - | |
| 55 | -#pragma clang diagnostic push | |
| 56 | -#pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
| 57 | -- (UIImagePickerController *)imagePickerVc { | |
| 58 | - if (_imagePickerVc == nil) { | |
| 59 | - _imagePickerVc = [[UIImagePickerController alloc] init]; | |
| 60 | - _imagePickerVc.delegate = self; | |
| 61 | - // set appearance / 改变相册选择页的导航栏外观 | |
| 62 | - if (iOS7Later) { | |
| 63 | - _imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor; | |
| 64 | - } | |
| 65 | - _imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor; | |
| 66 | - UIBarButtonItem *tzBarItem, *BarItem; | |
| 67 | - if (@available(iOS 9, *)) { | |
| 68 | - tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]]; | |
| 69 | - BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]]; | |
| 70 | - } else { | |
| 71 | - tzBarItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil]; | |
| 72 | - BarItem = [UIBarButtonItem appearanceWhenContainedIn:[UIImagePickerController class], nil]; | |
| 73 | - } | |
| 74 | - NSDictionary *titleTextAttributes = [tzBarItem titleTextAttributesForState:UIControlStateNormal]; | |
| 75 | - [BarItem setTitleTextAttributes:titleTextAttributes forState:UIControlStateNormal]; | |
| 76 | - } | |
| 77 | - return _imagePickerVc; | |
| 78 | -} | |
| 79 | - | |
| 80 | -- (void)viewDidLoad { | |
| 81 | - [super viewDidLoad]; | |
| 82 | - _isClickDone = NO; | |
| 83 | - self.isFirstAppear = YES; | |
| 84 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 85 | - _isSelectOriginalPhoto = tzImagePickerVc.isSelectOriginalPhoto; | |
| 86 | - _shouldScrollToBottom = YES; | |
| 87 | - self.view.backgroundColor = [UIColor whiteColor]; | |
| 88 | - self.navigationItem.title = _model.name; | |
| 89 | - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:tzImagePickerVc.cancelBtnTitleStr style:UIBarButtonItemStylePlain target:tzImagePickerVc action:@selector(cancelButtonClick)]; | |
| 90 | - if (tzImagePickerVc.navLeftBarButtonSettingBlock) { | |
| 91 | - UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 92 | - leftButton.frame = CGRectMake(0, 0, 44, 44); | |
| 93 | - [leftButton addTarget:self action:@selector(navLeftBarButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 94 | - tzImagePickerVc.navLeftBarButtonSettingBlock(leftButton); | |
| 95 | - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:leftButton]; | |
| 96 | - } else if (tzImagePickerVc.childViewControllers.count) { | |
| 97 | - [tzImagePickerVc.childViewControllers firstObject].navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Back"] style:UIBarButtonItemStylePlain target:nil action:nil]; | |
| 98 | - } | |
| 99 | - _showTakePhotoBtn = _model.isCameraRoll && ((tzImagePickerVc.allowTakePicture && tzImagePickerVc.allowPickingImage) || (tzImagePickerVc.allowTakeVideo && tzImagePickerVc.allowPickingVideo)); | |
| 100 | - // [self resetCachedAssets]; | |
| 101 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; | |
| 102 | -} | |
| 103 | - | |
| 104 | -- (void)fetchAssetModels { | |
| 105 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 106 | - if (_isFirstAppear && !_model.models.count) { | |
| 107 | - [tzImagePickerVc showProgressHUD]; | |
| 108 | - } | |
| 109 | - dispatch_async(dispatch_get_global_queue(0, 0), ^{ | |
| 110 | - if (!tzImagePickerVc.sortAscendingByModificationDate && self->_isFirstAppear && iOS8Later && self->_model.isCameraRoll) { | |
| 111 | - [[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage needFetchAssets:YES completion:^(TZAlbumModel *model) { | |
| 112 | - self->_model = model; | |
| 113 | - self->_models = [NSMutableArray arrayWithArray:self->_model.models]; | |
| 114 | - [self initSubviews]; | |
| 115 | - }]; | |
| 116 | - } else { | |
| 117 | - if (self->_showTakePhotoBtn || !iOS8Later || self->_isFirstAppear) { | |
| 118 | - [[TZImageManager manager] getAssetsFromFetchResult:self->_model.result completion:^(NSArray<TZAssetModel *> *models) { | |
| 119 | - self->_models = [NSMutableArray arrayWithArray:models]; | |
| 120 | - [self initSubviews]; | |
| 121 | - }]; | |
| 122 | - } else { | |
| 123 | - self->_models = [NSMutableArray arrayWithArray:self->_model.models]; | |
| 124 | - [self initSubviews]; | |
| 125 | - } | |
| 126 | - } | |
| 127 | - }); | |
| 128 | -} | |
| 129 | - | |
| 130 | -- (void)initSubviews { | |
| 131 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 132 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 133 | - [tzImagePickerVc hideProgressHUD]; | |
| 134 | - | |
| 135 | - [self checkSelectedModels]; | |
| 136 | - [self configCollectionView]; | |
| 137 | - self->_collectionView.hidden = YES; | |
| 138 | - [self configBottomToolBar]; | |
| 139 | - | |
| 140 | - [self scrollCollectionViewToBottom]; | |
| 141 | - }); | |
| 142 | -} | |
| 143 | - | |
| 144 | -- (void)viewWillDisappear:(BOOL)animated { | |
| 145 | - [super viewWillDisappear:animated]; | |
| 146 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 147 | - tzImagePickerVc.isSelectOriginalPhoto = _isSelectOriginalPhoto; | |
| 148 | -} | |
| 149 | - | |
| 150 | -- (BOOL)prefersStatusBarHidden { | |
| 151 | - return NO; | |
| 152 | -} | |
| 153 | - | |
| 154 | -- (void)configCollectionView { | |
| 155 | - _layout = [[UICollectionViewFlowLayout alloc] init]; | |
| 156 | - _collectionView = [[TZCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout]; | |
| 157 | - _collectionView.backgroundColor = [UIColor whiteColor]; | |
| 158 | - _collectionView.dataSource = self; | |
| 159 | - _collectionView.delegate = self; | |
| 160 | - _collectionView.alwaysBounceHorizontal = NO; | |
| 161 | - _collectionView.contentInset = UIEdgeInsetsMake(itemMargin, itemMargin, itemMargin, itemMargin); | |
| 162 | - | |
| 163 | - if (_showTakePhotoBtn) { | |
| 164 | - _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber) / self.columnNumber) * self.view.tz_width); | |
| 165 | - } else { | |
| 166 | - _collectionView.contentSize = CGSizeMake(self.view.tz_width, ((_model.count + self.columnNumber - 1) / self.columnNumber) * self.view.tz_width); | |
| 167 | - } | |
| 168 | - [self.view addSubview:_collectionView]; | |
| 169 | - [_collectionView registerClass:[TZAssetCell class] forCellWithReuseIdentifier:@"TZAssetCell"]; | |
| 170 | - [_collectionView registerClass:[TZAssetCameraCell class] forCellWithReuseIdentifier:@"TZAssetCameraCell"]; | |
| 171 | -} | |
| 172 | - | |
| 173 | -- (void)viewWillAppear:(BOOL)animated { | |
| 174 | - [super viewWillAppear:animated]; | |
| 175 | - // Determine the size of the thumbnails to request from the PHCachingImageManager | |
| 176 | - CGFloat scale = 2.0; | |
| 177 | - if ([UIScreen mainScreen].bounds.size.width > 600) { | |
| 178 | - scale = 1.0; | |
| 179 | - } | |
| 180 | - CGSize cellSize = ((UICollectionViewFlowLayout *)_collectionView.collectionViewLayout).itemSize; | |
| 181 | - AssetGridThumbnailSize = CGSizeMake(cellSize.width * scale, cellSize.height * scale); | |
| 182 | - | |
| 183 | - if (!_models) { | |
| 184 | - [self fetchAssetModels]; | |
| 185 | - } | |
| 186 | -} | |
| 187 | - | |
| 188 | -- (void)viewDidAppear:(BOOL)animated { | |
| 189 | - [super viewDidAppear:animated]; | |
| 190 | - if (iOS8Later) { | |
| 191 | - // [self updateCachedAssets]; | |
| 192 | - } | |
| 193 | -} | |
| 194 | - | |
| 195 | -- (void)configBottomToolBar { | |
| 196 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 197 | - if (!tzImagePickerVc.showSelectBtn) return; | |
| 198 | - | |
| 199 | - _bottomToolBar = [[UIView alloc] initWithFrame:CGRectZero]; | |
| 200 | - CGFloat rgb = 253 / 255.0; | |
| 201 | - _bottomToolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0]; | |
| 202 | - | |
| 203 | - _previewButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 204 | - [_previewButton addTarget:self action:@selector(previewButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 205 | - _previewButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 206 | - [_previewButton setTitle:tzImagePickerVc.previewBtnTitleStr forState:UIControlStateNormal]; | |
| 207 | - [_previewButton setTitle:tzImagePickerVc.previewBtnTitleStr forState:UIControlStateDisabled]; | |
| 208 | - [_previewButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; | |
| 209 | - [_previewButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled]; | |
| 210 | - _previewButton.enabled = tzImagePickerVc.selectedModels.count; | |
| 211 | - | |
| 212 | - if (tzImagePickerVc.allowPickingOriginalPhoto) { | |
| 213 | - _originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 214 | - _originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); | |
| 215 | - [_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 216 | - _originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 217 | - [_originalPhotoButton setTitle:tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateNormal]; | |
| 218 | - [_originalPhotoButton setTitle:tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateSelected]; | |
| 219 | - [_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; | |
| 220 | - [_originalPhotoButton setTitleColor:[UIColor blackColor] forState:UIControlStateSelected]; | |
| 221 | - [_originalPhotoButton setImage:tzImagePickerVc.photoOriginDefImage forState:UIControlStateNormal]; | |
| 222 | - [_originalPhotoButton setImage:tzImagePickerVc.photoOriginSelImage forState:UIControlStateSelected]; | |
| 223 | - _originalPhotoButton.imageView.clipsToBounds = YES; | |
| 224 | - _originalPhotoButton.imageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 225 | - _originalPhotoButton.selected = _isSelectOriginalPhoto; | |
| 226 | - _originalPhotoButton.enabled = tzImagePickerVc.selectedModels.count > 0; | |
| 227 | - | |
| 228 | - _originalPhotoLabel = [[UILabel alloc] init]; | |
| 229 | - _originalPhotoLabel.textAlignment = NSTextAlignmentLeft; | |
| 230 | - _originalPhotoLabel.font = [UIFont systemFontOfSize:16]; | |
| 231 | - _originalPhotoLabel.textColor = [UIColor blackColor]; | |
| 232 | - if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes]; | |
| 233 | - } | |
| 234 | - | |
| 235 | - _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 236 | - _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 237 | - [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 238 | - [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; | |
| 239 | - [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateDisabled]; | |
| 240 | - [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; | |
| 241 | - [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled]; | |
| 242 | - _doneButton.enabled = tzImagePickerVc.selectedModels.count || tzImagePickerVc.alwaysEnableDoneBtn; | |
| 243 | - | |
| 244 | - _numberImageView = [[UIImageView alloc] initWithImage:tzImagePickerVc.photoNumberIconImage]; | |
| 245 | - _numberImageView.hidden = tzImagePickerVc.selectedModels.count <= 0; | |
| 246 | - _numberImageView.clipsToBounds = YES; | |
| 247 | - _numberImageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 248 | - _numberImageView.backgroundColor = [UIColor clearColor]; | |
| 249 | - | |
| 250 | - _numberLabel = [[UILabel alloc] init]; | |
| 251 | - _numberLabel.font = [UIFont systemFontOfSize:15]; | |
| 252 | - _numberLabel.textColor = [UIColor whiteColor]; | |
| 253 | - _numberLabel.textAlignment = NSTextAlignmentCenter; | |
| 254 | - _numberLabel.text = [NSString stringWithFormat:@"%zd",tzImagePickerVc.selectedModels.count]; | |
| 255 | - _numberLabel.hidden = tzImagePickerVc.selectedModels.count <= 0; | |
| 256 | - _numberLabel.backgroundColor = [UIColor clearColor]; | |
| 257 | -#pragma mark - ADD: 选择图片个数显示(LXG) | |
| 258 | - _numberImageView.hidden = YES; | |
| 259 | - _numberLabel.hidden = YES; | |
| 260 | - [_doneButton setTitle:[NSString stringWithFormat:@"完成(%zd)",tzImagePickerVc.selectedModels.count] forState:UIControlStateNormal]; | |
| 261 | - | |
| 262 | - _divideLine = [[UIView alloc] init]; | |
| 263 | - CGFloat rgb2 = 222 / 255.0; | |
| 264 | - _divideLine.backgroundColor = [UIColor colorWithRed:rgb2 green:rgb2 blue:rgb2 alpha:1.0]; | |
| 265 | - | |
| 266 | - [_bottomToolBar addSubview:_divideLine]; | |
| 267 | - [_bottomToolBar addSubview:_previewButton]; | |
| 268 | - [_bottomToolBar addSubview:_doneButton]; | |
| 269 | - [_bottomToolBar addSubview:_numberImageView]; | |
| 270 | - [_bottomToolBar addSubview:_numberLabel]; | |
| 271 | - [_bottomToolBar addSubview:_originalPhotoButton]; | |
| 272 | - [self.view addSubview:_bottomToolBar]; | |
| 273 | - [_originalPhotoButton addSubview:_originalPhotoLabel]; | |
| 274 | - | |
| 275 | - if (tzImagePickerVc.photoPickerPageUIConfigBlock) { | |
| 276 | - tzImagePickerVc.photoPickerPageUIConfigBlock(_collectionView, _bottomToolBar, _previewButton, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel, _divideLine); | |
| 277 | - } | |
| 278 | -} | |
| 279 | - | |
| 280 | -#pragma mark - Layout | |
| 281 | - | |
| 282 | -- (void)viewDidLayoutSubviews { | |
| 283 | - [super viewDidLayoutSubviews]; | |
| 284 | - | |
| 285 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 286 | - | |
| 287 | - CGFloat top = 0; | |
| 288 | - CGFloat collectionViewHeight = 0; | |
| 289 | - CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height; | |
| 290 | - BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden; | |
| 291 | - CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 50 + (83 - 49) : 50; | |
| 292 | - if (self.navigationController.navigationBar.isTranslucent) { | |
| 293 | - top = naviBarHeight; | |
| 294 | - if (iOS7Later && !isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight]; | |
| 295 | - collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - toolBarHeight - top : self.view.tz_height - top;; | |
| 296 | - } else { | |
| 297 | - collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - toolBarHeight : self.view.tz_height; | |
| 298 | - } | |
| 299 | - _collectionView.frame = CGRectMake(0, top, self.view.tz_width, collectionViewHeight); | |
| 300 | - CGFloat itemWH = (self.view.tz_width - (self.columnNumber + 1) * itemMargin) / self.columnNumber; | |
| 301 | - _layout.itemSize = CGSizeMake(itemWH, itemWH); | |
| 302 | - _layout.minimumInteritemSpacing = itemMargin; | |
| 303 | - _layout.minimumLineSpacing = itemMargin; | |
| 304 | - [_collectionView setCollectionViewLayout:_layout]; | |
| 305 | - if (_offsetItemCount > 0) { | |
| 306 | - CGFloat offsetY = _offsetItemCount * (_layout.itemSize.height + _layout.minimumLineSpacing); | |
| 307 | - [_collectionView setContentOffset:CGPointMake(0, offsetY)]; | |
| 308 | - } | |
| 309 | - | |
| 310 | - CGFloat toolBarTop = 0; | |
| 311 | - if (!self.navigationController.navigationBar.isHidden) { | |
| 312 | - toolBarTop = self.view.tz_height - toolBarHeight; | |
| 313 | - } else { | |
| 314 | - CGFloat navigationHeight = naviBarHeight; | |
| 315 | - if (iOS7Later) navigationHeight += [TZCommonTools tz_statusBarHeight]; | |
| 316 | - toolBarTop = self.view.tz_height - toolBarHeight - navigationHeight; | |
| 317 | - } | |
| 318 | - _bottomToolBar.frame = CGRectMake(0, toolBarTop, self.view.tz_width, toolBarHeight); | |
| 319 | - CGFloat previewWidth = [tzImagePickerVc.previewBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width + 2; | |
| 320 | - if (!tzImagePickerVc.allowPreview) { | |
| 321 | - previewWidth = 0.0; | |
| 322 | - } | |
| 323 | - _previewButton.frame = CGRectMake(10, 3, previewWidth, 44); | |
| 324 | - _previewButton.tz_width = !tzImagePickerVc.showSelectBtn ? 0 : previewWidth; | |
| 325 | - if (tzImagePickerVc.allowPickingOriginalPhoto) { | |
| 326 | - CGFloat fullImageWidth = [tzImagePickerVc.fullImageBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width; | |
| 327 | - _originalPhotoButton.frame = CGRectMake(CGRectGetMaxX(_previewButton.frame), 0, fullImageWidth + 56, 50); | |
| 328 | - _originalPhotoLabel.frame = CGRectMake(fullImageWidth + 46, 0, 80, 50); | |
| 329 | - } | |
| 330 | - [_doneButton sizeToFit]; | |
| 331 | - _doneButton.frame = CGRectMake(self.view.tz_width - _doneButton.tz_width - 12, 0, _doneButton.tz_width, 50); | |
| 332 | - _numberImageView.frame = CGRectMake(_doneButton.tz_left - 24 - 5, 13, 24, 24); | |
| 333 | - _numberLabel.frame = _numberImageView.frame; | |
| 334 | - _divideLine.frame = CGRectMake(0, 0, self.view.tz_width, 1); | |
| 335 | - | |
| 336 | - [TZImageManager manager].columnNumber = [TZImageManager manager].columnNumber; | |
| 337 | - [self.collectionView reloadData]; | |
| 338 | - | |
| 339 | - if (tzImagePickerVc.photoPickerPageDidLayoutSubviewsBlock) { | |
| 340 | - tzImagePickerVc.photoPickerPageDidLayoutSubviewsBlock(_collectionView, _bottomToolBar, _previewButton, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel, _divideLine); | |
| 341 | - } | |
| 342 | -} | |
| 343 | - | |
| 344 | -#pragma mark - Notification | |
| 345 | - | |
| 346 | -- (void)didChangeStatusBarOrientationNotification:(NSNotification *)noti { | |
| 347 | - _offsetItemCount = _collectionView.contentOffset.y / (_layout.itemSize.height + _layout.minimumLineSpacing); | |
| 348 | -} | |
| 349 | - | |
| 350 | -#pragma mark - Click Event | |
| 351 | -- (void)navLeftBarButtonClick{ | |
| 352 | - [self.navigationController popViewControllerAnimated:YES]; | |
| 353 | -} | |
| 354 | -- (void)previewButtonClick { | |
| 355 | - TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; | |
| 356 | - [self pushPhotoPrevireViewController:photoPreviewVc needCheckSelectedModels:YES]; | |
| 357 | -} | |
| 358 | - | |
| 359 | -- (void)originalPhotoButtonClick { | |
| 360 | - _originalPhotoButton.selected = !_originalPhotoButton.isSelected; | |
| 361 | - _isSelectOriginalPhoto = _originalPhotoButton.isSelected; | |
| 362 | - _originalPhotoLabel.hidden = YES; ///lxg添加 | |
| 363 | -// _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected;///lxg注释 | |
| 364 | - if (_isSelectOriginalPhoto) { | |
| 365 | - [self getSelectedPhotoBytes]; | |
| 366 | - } | |
| 367 | -} | |
| 368 | - | |
| 369 | -- (void)doneButtonClick { | |
| 370 | - | |
| 371 | - if (!_isClickDone) { | |
| 372 | - _isClickDone = YES; | |
| 373 | - }else{ | |
| 374 | - return; | |
| 375 | - } | |
| 376 | - | |
| 377 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 378 | - // 1.6.8 判断是否满足最小必选张数的限制 | |
| 379 | - if (tzImagePickerVc.minImagesCount && tzImagePickerVc.selectedModels.count < tzImagePickerVc.minImagesCount) { | |
| 380 | - NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a minimum of %zd photos"], tzImagePickerVc.minImagesCount]; | |
| 381 | - [tzImagePickerVc showAlertWithTitle:title]; | |
| 382 | - return; | |
| 383 | - } | |
| 384 | - | |
| 385 | - [tzImagePickerVc showProgressHUD]; | |
| 386 | - NSMutableArray *assets = [NSMutableArray array]; | |
| 387 | - NSMutableArray *photos; | |
| 388 | - NSMutableArray *infoArr; | |
| 389 | - if (tzImagePickerVc.onlyReturnAsset) { // not fetch image | |
| 390 | - for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) { | |
| 391 | - TZAssetModel *model = tzImagePickerVc.selectedModels[i]; | |
| 392 | - [assets addObject:model.asset]; | |
| 393 | - } | |
| 394 | - } else { // fetch image | |
| 395 | - photos = [NSMutableArray array]; | |
| 396 | - infoArr = [NSMutableArray array]; | |
| 397 | - for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) { [photos addObject:@1];[assets addObject:@1];[infoArr addObject:@1]; } | |
| 398 | - | |
| 399 | - __block BOOL havenotShowAlert = YES; | |
| 400 | - [TZImageManager manager].shouldFixOrientation = YES; | |
| 401 | - __block id alertView; | |
| 402 | - for (NSInteger i = 0; i < tzImagePickerVc.selectedModels.count; i++) { | |
| 403 | - TZAssetModel *model = tzImagePickerVc.selectedModels[i]; | |
| 404 | - [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 405 | - if (isDegraded) return; | |
| 406 | - if (photo) { | |
| 407 | - if (![TZImagePickerConfig sharedInstance].notScaleImage) { | |
| 408 | - photo = [[TZImageManager manager] scaleImage:photo toSize:CGSizeMake(tzImagePickerVc.photoWidth, (int)(tzImagePickerVc.photoWidth * photo.size.height / photo.size.width))]; | |
| 409 | - } | |
| 410 | - [photos replaceObjectAtIndex:i withObject:photo]; | |
| 411 | - } | |
| 412 | - if (info) [infoArr replaceObjectAtIndex:i withObject:info]; | |
| 413 | - [assets replaceObjectAtIndex:i withObject:model.asset]; | |
| 414 | -// [self getPhotoMetadataWithAsset:model.asset]; | |
| 415 | - for (id item in photos) { if ([item isKindOfClass:[NSNumber class]]) return; } | |
| 416 | - | |
| 417 | - if (havenotShowAlert) { | |
| 418 | - [tzImagePickerVc hideAlertView:alertView]; | |
| 419 | - [self didGetAllPhotos:photos assets:assets infoArr:infoArr]; | |
| 420 | - } | |
| 421 | - } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 422 | - // 如果图片正在从iCloud同步中,提醒用户 | |
| 423 | - if (progress < 1 && havenotShowAlert && !alertView) { | |
| 424 | - [tzImagePickerVc hideProgressHUD]; | |
| 425 | - alertView = [tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]]; | |
| 426 | - havenotShowAlert = NO; | |
| 427 | - return; | |
| 428 | - } | |
| 429 | - if (progress >= 1) { | |
| 430 | - havenotShowAlert = YES; | |
| 431 | - } | |
| 432 | - } networkAccessAllowed:YES]; | |
| 433 | - } | |
| 434 | - } | |
| 435 | - if (tzImagePickerVc.selectedModels.count <= 0 || tzImagePickerVc.onlyReturnAsset) { | |
| 436 | - [self didGetAllPhotos:photos assets:assets infoArr:infoArr]; | |
| 437 | - } | |
| 438 | -} | |
| 439 | - | |
| 440 | -//- (void)getPhotoMetadataWithAsset:(PHAsset *)asset | |
| 441 | -//{ | |
| 442 | -// PHImageRequestOptions *request = [PHImageRequestOptions new]; | |
| 443 | -// request.version = PHImageRequestOptionsVersionCurrent; | |
| 444 | -// request.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; | |
| 445 | -// request.resizeMode = PHImageRequestOptionsResizeModeNone; | |
| 446 | -// request.synchronous = YES; | |
| 447 | -// NSData *data1 = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"file:///var/mobile/Media/DCIM/100APPLE/IMG_0178.JPG"]]; | |
| 448 | -// UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"file:///var/mobile/Media/DCIM/100APPLE/1.JPG"]]]; | |
| 449 | -// [[PHImageManager defaultManager] requestImageDataForAsset:asset options: request resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { | |
| 450 | -// NSURL *url = [info valueForKey:@"PHImageFileURLKey"]; | |
| 451 | -// NSString *str = [url absoluteString]; //url>string | |
| 452 | -// NSArray *arr = [str componentsSeparatedByString:@"/"]; | |
| 453 | -// NSString *imgName = [arr lastObject]; | |
| 454 | -// NSLog(@"imgName:%@",imgName); | |
| 455 | -// | |
| 456 | -// CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); | |
| 457 | -// if (NULL != source) { | |
| 458 | -// NSDictionary * metadataDic = (NSDictionary *)CFBridgingRelease(CGImageSourceCopyPropertiesAtIndex(source, 0, NULL)); | |
| 459 | -// NSLog(@"metada:%@",metadataDic); | |
| 460 | -// CFRelease(source); | |
| 461 | -// } | |
| 462 | -// }]; | |
| 463 | -//} | |
| 464 | - | |
| 465 | -- (void)didGetAllPhotos:(NSArray *)photos assets:(NSArray *)assets infoArr:(NSArray *)infoArr { | |
| 466 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 467 | - [tzImagePickerVc hideProgressHUD]; | |
| 468 | - | |
| 469 | - if (tzImagePickerVc.autoDismiss) { | |
| 470 | - [self.navigationController dismissViewControllerAnimated:YES completion:^{ | |
| 471 | - [self callDelegateMethodWithPhotos:photos assets:assets infoArr:infoArr]; | |
| 472 | - }]; | |
| 473 | - } else { | |
| 474 | - [self callDelegateMethodWithPhotos:photos assets:assets infoArr:infoArr]; | |
| 475 | - } | |
| 476 | -} | |
| 477 | - | |
| 478 | -- (void)callDelegateMethodWithPhotos:(NSArray *)photos assets:(NSArray *)assets infoArr:(NSArray *)infoArr { | |
| 479 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 480 | - if (tzImagePickerVc.allowPickingVideo && tzImagePickerVc.maxImagesCount == 1) { | |
| 481 | - if ([[TZImageManager manager] isVideo:[assets firstObject]]) { | |
| 482 | - if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) { | |
| 483 | - [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingVideo:[photos firstObject] sourceAssets:[assets firstObject]]; | |
| 484 | - } | |
| 485 | - if (tzImagePickerVc.didFinishPickingVideoHandle) { | |
| 486 | - tzImagePickerVc.didFinishPickingVideoHandle([photos firstObject], [assets firstObject]); | |
| 487 | - } | |
| 488 | - return; | |
| 489 | - } | |
| 490 | - } | |
| 491 | - | |
| 492 | - if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:)]) { | |
| 493 | - [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:_isSelectOriginalPhoto]; | |
| 494 | - } | |
| 495 | - if ([tzImagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:infos:)]) { | |
| 496 | - [tzImagePickerVc.pickerDelegate imagePickerController:tzImagePickerVc didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:_isSelectOriginalPhoto infos:infoArr]; | |
| 497 | - } | |
| 498 | - if (tzImagePickerVc.didFinishPickingPhotosHandle) { | |
| 499 | - tzImagePickerVc.didFinishPickingPhotosHandle(photos,assets,_isSelectOriginalPhoto); | |
| 500 | - } | |
| 501 | - if (tzImagePickerVc.didFinishPickingPhotosWithInfosHandle) { | |
| 502 | - tzImagePickerVc.didFinishPickingPhotosWithInfosHandle(photos,assets,_isSelectOriginalPhoto,infoArr); | |
| 503 | - } | |
| 504 | -} | |
| 505 | - | |
| 506 | -#pragma mark - UICollectionViewDataSource && Delegate | |
| 507 | - | |
| 508 | -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { | |
| 509 | - if (_showTakePhotoBtn) { | |
| 510 | - return _models.count + 1; | |
| 511 | - } | |
| 512 | - return _models.count; | |
| 513 | -} | |
| 514 | - | |
| 515 | -- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { | |
| 516 | - // the cell lead to take a picture / 去拍照的cell | |
| 517 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 518 | - if (((tzImagePickerVc.sortAscendingByModificationDate && indexPath.item >= _models.count) || (!tzImagePickerVc.sortAscendingByModificationDate && indexPath.item == 0)) && _showTakePhotoBtn) { | |
| 519 | - TZAssetCameraCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCameraCell" forIndexPath:indexPath]; | |
| 520 | - cell.imageView.image = tzImagePickerVc.takePictureImage; | |
| 521 | - if ([tzImagePickerVc.takePictureImageName isEqualToString:@"takePicture80"]) { | |
| 522 | - cell.imageView.contentMode = UIViewContentModeCenter; | |
| 523 | - CGFloat rgb = 223 / 255.0; | |
| 524 | - cell.imageView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:1.0]; | |
| 525 | - } else { | |
| 526 | - cell.imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; | |
| 527 | - } | |
| 528 | - return cell; | |
| 529 | - } | |
| 530 | - // the cell dipaly photo or video / 展示照片或视频的cell | |
| 531 | - TZAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZAssetCell" forIndexPath:indexPath]; | |
| 532 | - cell.allowPickingMultipleVideo = tzImagePickerVc.allowPickingMultipleVideo; | |
| 533 | - cell.photoDefImage = tzImagePickerVc.photoDefImage; | |
| 534 | - cell.photoSelImage = tzImagePickerVc.photoSelImage; | |
| 535 | - cell.useCachedImage = self.useCachedImage; | |
| 536 | - cell.assetCellDidSetModelBlock = tzImagePickerVc.assetCellDidSetModelBlock; | |
| 537 | - cell.assetCellDidLayoutSubviewsBlock = tzImagePickerVc.assetCellDidLayoutSubviewsBlock; | |
| 538 | - TZAssetModel *model; | |
| 539 | - if (tzImagePickerVc.sortAscendingByModificationDate || !_showTakePhotoBtn) { | |
| 540 | - model = _models[indexPath.item]; | |
| 541 | - } else { | |
| 542 | - model = _models[indexPath.item - 1]; | |
| 543 | - } | |
| 544 | - cell.allowPickingGif = tzImagePickerVc.allowPickingGif; | |
| 545 | - cell.model = model; | |
| 546 | - if (model.isSelected && tzImagePickerVc.showSelectedIndex) { | |
| 547 | - NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset]; | |
| 548 | - cell.index = [tzImagePickerVc.selectedAssetIds indexOfObject:assetId] + 1; | |
| 549 | - } | |
| 550 | - cell.showSelectBtn = tzImagePickerVc.showSelectBtn; | |
| 551 | - cell.allowPreview = tzImagePickerVc.allowPreview; | |
| 552 | - | |
| 553 | - if (tzImagePickerVc.selectedModels.count >= tzImagePickerVc.maxImagesCount && tzImagePickerVc.showPhotoCannotSelectLayer && !model.isSelected) { | |
| 554 | - cell.cannotSelectLayerButton.backgroundColor = tzImagePickerVc.cannotSelectLayerColor; | |
| 555 | - cell.cannotSelectLayerButton.hidden = NO; | |
| 556 | - } else { | |
| 557 | - cell.cannotSelectLayerButton.hidden = YES; | |
| 558 | - } | |
| 559 | - | |
| 560 | - __weak typeof(cell) weakCell = cell; | |
| 561 | - __weak typeof(self) weakSelf = self; | |
| 562 | - __weak typeof(_numberImageView.layer) weakLayer = _numberImageView.layer; | |
| 563 | - cell.didSelectPhotoBlock = ^(BOOL isSelected) { | |
| 564 | - __strong typeof(weakCell) strongCell = weakCell; | |
| 565 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 566 | - __strong typeof(weakLayer) strongLayer = weakLayer; | |
| 567 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)strongSelf.navigationController; | |
| 568 | - // 1. cancel select / 取消选择 | |
| 569 | - if (isSelected) { | |
| 570 | - strongCell.selectPhotoButton.selected = NO; | |
| 571 | - model.isSelected = NO; | |
| 572 | - NSArray *selectedModels = [NSArray arrayWithArray:tzImagePickerVc.selectedModels]; | |
| 573 | - for (TZAssetModel *model_item in selectedModels) { | |
| 574 | - if ([[[TZImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[TZImageManager manager] getAssetIdentifier:model_item.asset]]) { | |
| 575 | - [tzImagePickerVc removeSelectedModel:model_item]; | |
| 576 | - break; | |
| 577 | - } | |
| 578 | - } | |
| 579 | - [strongSelf refreshBottomToolBarStatus]; | |
| 580 | - if (tzImagePickerVc.showSelectedIndex || tzImagePickerVc.showPhotoCannotSelectLayer) { | |
| 581 | - [strongSelf setUseCachedImageAndReloadData]; | |
| 582 | - } | |
| 583 | - [UIView showOscillatoryAnimationWithLayer:strongLayer type:TZOscillatoryAnimationToSmaller]; | |
| 584 | - } else { | |
| 585 | - // 2. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制 | |
| 586 | - if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) { | |
| 587 | - ///lxg禁止选中限制时长视频 | |
| 588 | - NSTimeInterval duration = 0.0; | |
| 589 | - if ([model.asset isKindOfClass:[PHAsset class]]) { | |
| 590 | - PHAsset *asset = model.asset; | |
| 591 | - duration = asset.duration; | |
| 592 | - }else if ([model.asset isKindOfClass:[ALAsset class]]){ | |
| 593 | - duration = [[model.asset valueForProperty:ALAssetPropertyDuration] doubleValue]; | |
| 594 | - } | |
| 595 | - if (model.type == TZAssetModelMediaTypeVideo | |
| 596 | - && tzImagePickerVc.allowPickingMultipleVideo | |
| 597 | - && duration > tzImagePickerVc.maxVideoDuration) {//视频,支持混选,时长超过最大时长限制 | |
| 598 | - NSInteger minutes = tzImagePickerVc.maxVideoDuration / 60; | |
| 599 | - NSInteger seconds = tzImagePickerVc.maxVideoDuration % 60; | |
| 600 | - NSString *timeStr = [NSString string]; | |
| 601 | - if (minutes == 0) { | |
| 602 | - timeStr = [NSString stringWithFormat:@"不能选择超过%li秒视频",(long)seconds]; | |
| 603 | - }else if (seconds == 0){ | |
| 604 | - timeStr = [NSString stringWithFormat:@"不能选择超过%li分视频",(long)minutes]; | |
| 605 | - }else{ | |
| 606 | - timeStr = [NSString stringWithFormat:@"不能选择超过%li分%li秒视频",(long)minutes,(long)seconds]; | |
| 607 | - } | |
| 608 | - [tzImagePickerVc showAlertWithTitle:timeStr]; | |
| 609 | - | |
| 610 | - return; | |
| 611 | - } | |
| 612 | - | |
| 613 | - | |
| 614 | - if (tzImagePickerVc.maxImagesCount == 1 && !tzImagePickerVc.allowPreview) { | |
| 615 | - model.isSelected = YES; | |
| 616 | - [tzImagePickerVc addSelectedModel:model]; | |
| 617 | - [strongSelf doneButtonClick]; | |
| 618 | - return; | |
| 619 | - } | |
| 620 | - strongCell.selectPhotoButton.selected = YES; | |
| 621 | - model.isSelected = YES; | |
| 622 | - if (tzImagePickerVc.showSelectedIndex || tzImagePickerVc.showPhotoCannotSelectLayer) { | |
| 623 | - model.needOscillatoryAnimation = YES; | |
| 624 | - [strongSelf setUseCachedImageAndReloadData]; | |
| 625 | - } | |
| 626 | - [tzImagePickerVc addSelectedModel:model]; | |
| 627 | - [strongSelf refreshBottomToolBarStatus]; | |
| 628 | - [UIView showOscillatoryAnimationWithLayer:strongLayer type:TZOscillatoryAnimationToSmaller]; | |
| 629 | - } else { | |
| 630 | - NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], tzImagePickerVc.maxImagesCount]; | |
| 631 | - [tzImagePickerVc showAlertWithTitle:title]; | |
| 632 | - } | |
| 633 | - } | |
| 634 | - }; | |
| 635 | - return cell; | |
| 636 | -} | |
| 637 | - | |
| 638 | -- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { | |
| 639 | - // take a photo / 去拍照 | |
| 640 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 641 | - if (((tzImagePickerVc.sortAscendingByModificationDate && indexPath.item >= _models.count) || (!tzImagePickerVc.sortAscendingByModificationDate && indexPath.item == 0)) && _showTakePhotoBtn) { | |
| 642 | - [self takePhoto]; return; | |
| 643 | - } | |
| 644 | - // preview phote or video / 预览照片或视频 | |
| 645 | - NSInteger index = indexPath.item; | |
| 646 | - if (!tzImagePickerVc.sortAscendingByModificationDate && _showTakePhotoBtn) { | |
| 647 | - index = indexPath.item - 1; | |
| 648 | - } | |
| 649 | -// TZAssetModel *model = _models[index]; | |
| 650 | - | |
| 651 | -#pragma mark - 聊天里面进入和朋友圈中进入LXG | |
| 652 | - | |
| 653 | - TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; | |
| 654 | - photoPreviewVc.currentIndex = index; | |
| 655 | - photoPreviewVc.models = _models; | |
| 656 | - photoPreviewVc.isSelectOriginalPhoto = tzImagePickerVc.isSelectOriginalPhoto; | |
| 657 | - [self pushPhotoPrevireViewController:photoPreviewVc]; | |
| 658 | - | |
| 659 | - | |
| 660 | -// ///LXG进行 注释 | |
| 661 | -// if (model.type == TZAssetModelMediaTypeVideo && !tzImagePickerVc.allowPickingMultipleVideo) {///支持混选+点击视频 | |
| 662 | -// if (tzImagePickerVc.selectedModels.count > 0) { | |
| 663 | -// TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 664 | -// [imagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Can not choose both video and photo"]]; | |
| 665 | -// } else { | |
| 666 | -// TZVideoPlayerController *videoPlayerVc = [[TZVideoPlayerController alloc] init]; | |
| 667 | -// videoPlayerVc.model = model; | |
| 668 | -// videoPlayerVc.isOther = NO;//相册内部进入(LXG) | |
| 669 | -// [self.navigationController pushViewController:videoPlayerVc animated:YES]; | |
| 670 | -// } | |
| 671 | -// } else if (model.type == TZAssetModelMediaTypePhotoGif && tzImagePickerVc.allowPickingGif && !tzImagePickerVc.allowPickingMultipleVideo) {//支持混选+GIF | |
| 672 | -// if (tzImagePickerVc.selectedModels.count > 0) { | |
| 673 | -// TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 674 | -// [imagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Can not choose both photo and GIF"]]; | |
| 675 | -// } else { | |
| 676 | -// TZGifPhotoPreviewController *gifPreviewVc = [[TZGifPhotoPreviewController alloc] init]; | |
| 677 | -// gifPreviewVc.model = model; | |
| 678 | -// [self.navigationController pushViewController:gifPreviewVc animated:YES]; | |
| 679 | -// } | |
| 680 | -// } else { | |
| 681 | -//#pragma mark - 当可以混选 | |
| 682 | -// TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; | |
| 683 | -// photoPreviewVc.currentIndex = index; | |
| 684 | -// photoPreviewVc.models = _models; | |
| 685 | -// [self pushPhotoPrevireViewController:photoPreviewVc]; | |
| 686 | -// } | |
| 687 | -} | |
| 688 | - | |
| 689 | -#pragma mark - UIScrollViewDelegate | |
| 690 | - | |
| 691 | -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { | |
| 692 | - if (iOS8Later) { | |
| 693 | - // [self updateCachedAssets]; | |
| 694 | - } | |
| 695 | -} | |
| 696 | - | |
| 697 | -#pragma mark - Private Method | |
| 698 | - | |
| 699 | -- (void)setUseCachedImageAndReloadData { | |
| 700 | - self.useCachedImage = YES; | |
| 701 | - [self.collectionView reloadData]; | |
| 702 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 703 | - self.useCachedImage = NO; | |
| 704 | - }); | |
| 705 | -} | |
| 706 | - | |
| 707 | -/// 拍照按钮点击事件 | |
| 708 | -- (void)takePhoto { | |
| 709 | - AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; | |
| 710 | - if ((authStatus == AVAuthorizationStatusRestricted || authStatus ==AVAuthorizationStatusDenied) && iOS7Later) { | |
| 711 | - | |
| 712 | - NSDictionary *infoDict = [TZCommonTools tz_getInfoDictionary]; | |
| 713 | - // 无权限 做一个友好的提示 | |
| 714 | - NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"]; | |
| 715 | - if (!appName) appName = [infoDict valueForKey:@"CFBundleName"]; | |
| 716 | - | |
| 717 | - NSString *message = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\""],appName]; | |
| 718 | - if (iOS8Later) { | |
| 719 | - 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]; | |
| 720 | - [alert show]; | |
| 721 | - } else { | |
| 722 | - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[NSBundle tz_localizedStringForKey:@"Can not use camera"] message:message delegate:self cancelButtonTitle:[NSBundle tz_localizedStringForKey:@"OK"] otherButtonTitles:nil]; | |
| 723 | - [alert show]; | |
| 724 | - } | |
| 725 | - } else if (authStatus == AVAuthorizationStatusNotDetermined) { | |
| 726 | - // fix issue 466, 防止用户首次拍照拒绝授权时相机页黑屏 | |
| 727 | - if (iOS7Later) { | |
| 728 | - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { | |
| 729 | - if (granted) { | |
| 730 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 731 | - [self pushImagePickerController]; | |
| 732 | - }); | |
| 733 | - } | |
| 734 | - }]; | |
| 735 | - } else { | |
| 736 | - [self pushImagePickerController]; | |
| 737 | - } | |
| 738 | - } else { | |
| 739 | - [self pushImagePickerController]; | |
| 740 | - } | |
| 741 | -} | |
| 742 | - | |
| 743 | -// 调用相机 | |
| 744 | -- (void)pushImagePickerController { | |
| 745 | - // 提前定位 | |
| 746 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 747 | - if (tzImagePickerVc.allowCameraLocation) { | |
| 748 | - __weak typeof(self) weakSelf = self; | |
| 749 | - [[TZLocationManager manager] startLocationWithSuccessBlock:^(NSArray<CLLocation *> *locations) { | |
| 750 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 751 | - strongSelf.location = [locations firstObject]; | |
| 752 | - } failureBlock:^(NSError *error) { | |
| 753 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 754 | - strongSelf.location = nil; | |
| 755 | - }]; | |
| 756 | - } | |
| 757 | - | |
| 758 | - UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; | |
| 759 | - if ([UIImagePickerController isSourceTypeAvailable: sourceType]) { | |
| 760 | - self.imagePickerVc.sourceType = sourceType; | |
| 761 | - NSMutableArray *mediaTypes = [NSMutableArray array]; | |
| 762 | - if (tzImagePickerVc.allowTakePicture) { | |
| 763 | - [mediaTypes addObject:(NSString *)kUTTypeImage]; | |
| 764 | - } | |
| 765 | - if (tzImagePickerVc.allowTakeVideo) { | |
| 766 | - [mediaTypes addObject:(NSString *)kUTTypeMovie]; | |
| 767 | - self.imagePickerVc.videoMaximumDuration = tzImagePickerVc.videoMaximumDuration; | |
| 768 | - } | |
| 769 | - self.imagePickerVc.mediaTypes= mediaTypes; | |
| 770 | - if (iOS8Later) { | |
| 771 | - _imagePickerVc.modalPresentationStyle = UIModalPresentationOverCurrentContext; | |
| 772 | - } | |
| 773 | - if (tzImagePickerVc.uiImagePickerControllerSettingBlock) { | |
| 774 | - tzImagePickerVc.uiImagePickerControllerSettingBlock(_imagePickerVc); | |
| 775 | - } | |
| 776 | - [self presentViewController:_imagePickerVc animated:YES completion:nil]; | |
| 777 | - } else { | |
| 778 | - NSLog(@"模拟器中无法打开照相机,请在真机中使用"); | |
| 779 | - } | |
| 780 | -} | |
| 781 | - | |
| 782 | -- (void)refreshBottomToolBarStatus { | |
| 783 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 784 | - | |
| 785 | - _previewButton.enabled = tzImagePickerVc.selectedModels.count > 0; | |
| 786 | - _doneButton.enabled = tzImagePickerVc.selectedModels.count > 0 || tzImagePickerVc.alwaysEnableDoneBtn; | |
| 787 | - | |
| 788 | - _numberImageView.hidden = tzImagePickerVc.selectedModels.count <= 0; | |
| 789 | - _numberLabel.hidden = tzImagePickerVc.selectedModels.count <= 0; | |
| 790 | - _numberLabel.text = [NSString stringWithFormat:@"%zd",tzImagePickerVc.selectedModels.count]; | |
| 791 | -#pragma mark - ADD: 选择图片个数显示(LXG) | |
| 792 | - _numberImageView.hidden = YES; | |
| 793 | - _numberLabel.hidden = YES; | |
| 794 | - [_doneButton setTitle:[NSString stringWithFormat:@"完成(%zd)",tzImagePickerVc.selectedModels.count] forState:UIControlStateNormal]; | |
| 795 | - | |
| 796 | - _originalPhotoButton.enabled = tzImagePickerVc.selectedModels.count > 0; | |
| 797 | - _originalPhotoButton.selected = (_isSelectOriginalPhoto && _originalPhotoButton.enabled); | |
| 798 | - _originalPhotoLabel.hidden = YES;///lxg添加 | |
| 799 | -// _originalPhotoLabel.hidden = (!_originalPhotoButton.isSelected);///lxg注释 | |
| 800 | - if (_isSelectOriginalPhoto) [self getSelectedPhotoBytes]; | |
| 801 | -} | |
| 802 | - | |
| 803 | -- (void)pushPhotoPrevireViewController:(TZPhotoPreviewController *)photoPreviewVc { | |
| 804 | - [self pushPhotoPrevireViewController:photoPreviewVc needCheckSelectedModels:NO]; | |
| 805 | -} | |
| 806 | - | |
| 807 | -- (void)pushPhotoPrevireViewController:(TZPhotoPreviewController *)photoPreviewVc needCheckSelectedModels:(BOOL)needCheckSelectedModels { | |
| 808 | - __weak typeof(self) weakSelf = self; | |
| 809 | - photoPreviewVc.isSelectOriginalPhoto = _isSelectOriginalPhoto; | |
| 810 | - [photoPreviewVc setBackButtonClickBlock:^(BOOL isSelectOriginalPhoto) { | |
| 811 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 812 | - strongSelf.isSelectOriginalPhoto = isSelectOriginalPhoto; | |
| 813 | - if (needCheckSelectedModels) { | |
| 814 | - [strongSelf checkSelectedModels]; | |
| 815 | - } | |
| 816 | - [strongSelf.collectionView reloadData]; | |
| 817 | - [strongSelf refreshBottomToolBarStatus]; | |
| 818 | - }]; | |
| 819 | - [photoPreviewVc setDoneButtonClickBlock:^(BOOL isSelectOriginalPhoto) { | |
| 820 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 821 | - strongSelf.isSelectOriginalPhoto = isSelectOriginalPhoto; | |
| 822 | - [strongSelf doneButtonClick]; | |
| 823 | - }]; | |
| 824 | - [photoPreviewVc setDoneButtonClickBlockCropMode:^(UIImage *cropedImage, id asset) { | |
| 825 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 826 | - [strongSelf didGetAllPhotos:@[cropedImage] assets:@[asset] infoArr:nil]; | |
| 827 | - }]; | |
| 828 | - [self.navigationController pushViewController:photoPreviewVc animated:YES]; | |
| 829 | -} | |
| 830 | - | |
| 831 | -- (void)getSelectedPhotoBytes { | |
| 832 | - // 越南语 && 5屏幕时会显示不下,暂时这样处理 | |
| 833 | - if ([[TZImagePickerConfig sharedInstance].preferredLanguage isEqualToString:@"vi"] && self.view.tz_width <= 320) { | |
| 834 | - return; | |
| 835 | - } | |
| 836 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 837 | - [[TZImageManager manager] getPhotosBytesWithArray:imagePickerVc.selectedModels completion:^(NSString *totalBytes) { | |
| 838 | - self->_originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes]; | |
| 839 | - self->_originalPhotoLabel.hidden = YES;///lxg添加 | |
| 840 | - }]; | |
| 841 | -} | |
| 842 | - | |
| 843 | -- (void)scrollCollectionViewToBottom { | |
| 844 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 845 | - if (_shouldScrollToBottom && _models.count > 0) { | |
| 846 | - NSInteger item = 0; | |
| 847 | - if (tzImagePickerVc.sortAscendingByModificationDate) { | |
| 848 | - item = _models.count - 1; | |
| 849 | - if (_showTakePhotoBtn) { | |
| 850 | - item += 1; | |
| 851 | - } | |
| 852 | - } | |
| 853 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 854 | - [self->_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; | |
| 855 | - self->_shouldScrollToBottom = NO; | |
| 856 | - self->_collectionView.hidden = NO; | |
| 857 | - }); | |
| 858 | - } else { | |
| 859 | - _collectionView.hidden = NO; | |
| 860 | - } | |
| 861 | -} | |
| 862 | - | |
| 863 | -- (void)checkSelectedModels { | |
| 864 | - NSMutableArray *selectedAssets = [NSMutableArray array]; | |
| 865 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 866 | - for (TZAssetModel *model in tzImagePickerVc.selectedModels) { | |
| 867 | - [selectedAssets addObject:model.asset]; | |
| 868 | - } | |
| 869 | - for (TZAssetModel *model in _models) { | |
| 870 | - model.isSelected = NO; | |
| 871 | - if ([[TZImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) { | |
| 872 | - model.isSelected = YES; | |
| 873 | - } | |
| 874 | - } | |
| 875 | -} | |
| 876 | - | |
| 877 | -#pragma mark - UIAlertViewDelegate | |
| 878 | - | |
| 879 | -- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { | |
| 880 | - if (buttonIndex == 1) { // 去设置界面,开启相机访问权限 | |
| 881 | - if (iOS8Later) { | |
| 882 | - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; | |
| 883 | - } | |
| 884 | - } | |
| 885 | -} | |
| 886 | - | |
| 887 | -#pragma mark - UIImagePickerControllerDelegate | |
| 888 | - | |
| 889 | -- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { | |
| 890 | - [picker dismissViewControllerAnimated:YES completion:nil]; | |
| 891 | - NSString *type = [info objectForKey:UIImagePickerControllerMediaType]; | |
| 892 | - if ([type isEqualToString:@"public.image"]) { | |
| 893 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 894 | - [imagePickerVc showProgressHUD]; | |
| 895 | - UIImage *photo = [info objectForKey:UIImagePickerControllerOriginalImage]; | |
| 896 | - if (photo) { | |
| 897 | - [[TZImageManager manager] savePhotoWithImage:photo location:self.location completion:^(NSError *error){ | |
| 898 | - if (!error) { | |
| 899 | - [self reloadPhotoArrayWithMediaType:type]; | |
| 900 | - } | |
| 901 | - }]; | |
| 902 | - self.location = nil; | |
| 903 | - } | |
| 904 | - } else if ([type isEqualToString:@"public.movie"]) { | |
| 905 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 906 | - [imagePickerVc showProgressHUD]; | |
| 907 | - NSURL *videoUrl = [info objectForKey:UIImagePickerControllerMediaURL]; | |
| 908 | - if (videoUrl) { | |
| 909 | - [[TZImageManager manager] saveVideoWithUrl:videoUrl location:self.location completion:^(NSError *error) { | |
| 910 | - if (!error) { | |
| 911 | - [self reloadPhotoArrayWithMediaType:type]; | |
| 912 | - } | |
| 913 | - }]; | |
| 914 | - self.location = nil; | |
| 915 | - } | |
| 916 | - } | |
| 917 | -} | |
| 918 | - | |
| 919 | -- (void)reloadPhotoArrayWithMediaType:(NSString *)mediaType { | |
| 920 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 921 | - [[TZImageManager manager] getCameraRollAlbum:tzImagePickerVc.allowPickingVideo allowPickingImage:tzImagePickerVc.allowPickingImage needFetchAssets:NO completion:^(TZAlbumModel *model) { | |
| 922 | - self->_model = model; | |
| 923 | - [[TZImageManager manager] getAssetsFromFetchResult:self->_model.result completion:^(NSArray<TZAssetModel *> *models) { | |
| 924 | - [tzImagePickerVc hideProgressHUD]; | |
| 925 | - | |
| 926 | - TZAssetModel *assetModel; | |
| 927 | - if (tzImagePickerVc.sortAscendingByModificationDate) { | |
| 928 | - assetModel = [models lastObject]; | |
| 929 | - [self->_models addObject:assetModel]; | |
| 930 | - } else { | |
| 931 | - assetModel = [models firstObject]; | |
| 932 | - [self->_models insertObject:assetModel atIndex:0]; | |
| 933 | - } | |
| 934 | - | |
| 935 | - if (tzImagePickerVc.maxImagesCount <= 1) { | |
| 936 | - if (tzImagePickerVc.allowCrop) { | |
| 937 | - TZPhotoPreviewController *photoPreviewVc = [[TZPhotoPreviewController alloc] init]; | |
| 938 | - if (tzImagePickerVc.sortAscendingByModificationDate) { | |
| 939 | - photoPreviewVc.currentIndex = self->_models.count - 1; | |
| 940 | - } else { | |
| 941 | - photoPreviewVc.currentIndex = 0; | |
| 942 | - } | |
| 943 | - photoPreviewVc.models = self->_models; | |
| 944 | - [self pushPhotoPrevireViewController:photoPreviewVc]; | |
| 945 | - } else { | |
| 946 | - [tzImagePickerVc addSelectedModel:assetModel]; | |
| 947 | - [self doneButtonClick]; | |
| 948 | - } | |
| 949 | - return; | |
| 950 | - } | |
| 951 | - | |
| 952 | - if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) { | |
| 953 | - if ([mediaType isEqualToString:@"public.movie"] && !tzImagePickerVc.allowPickingMultipleVideo) { | |
| 954 | - // 不能多选视频的情况下,不选中拍摄的视频 | |
| 955 | - } else { | |
| 956 | - assetModel.isSelected = YES; | |
| 957 | - [tzImagePickerVc addSelectedModel:assetModel]; | |
| 958 | - [self refreshBottomToolBarStatus]; | |
| 959 | - } | |
| 960 | - } | |
| 961 | - self->_collectionView.hidden = YES; | |
| 962 | - [self->_collectionView reloadData]; | |
| 963 | - | |
| 964 | - self->_shouldScrollToBottom = YES; | |
| 965 | - [self scrollCollectionViewToBottom]; | |
| 966 | - }]; | |
| 967 | - }]; | |
| 968 | -} | |
| 969 | - | |
| 970 | -- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { | |
| 971 | - [picker dismissViewControllerAnimated:YES completion:nil]; | |
| 972 | -} | |
| 973 | - | |
| 974 | -- (void)dealloc { | |
| 975 | - // NSLog(@"%@ dealloc",NSStringFromClass(self.class)); | |
| 976 | -} | |
| 977 | - | |
| 978 | -#pragma mark - Asset Caching | |
| 979 | - | |
| 980 | -- (void)resetCachedAssets { | |
| 981 | - [[TZImageManager manager].cachingImageManager stopCachingImagesForAllAssets]; | |
| 982 | - self.previousPreheatRect = CGRectZero; | |
| 983 | -} | |
| 984 | - | |
| 985 | -- (void)updateCachedAssets { | |
| 986 | - BOOL isViewVisible = [self isViewLoaded] && [[self view] window] != nil; | |
| 987 | - if (!isViewVisible) { return; } | |
| 988 | - | |
| 989 | - // The preheat window is twice the height of the visible rect. | |
| 990 | - CGRect preheatRect = _collectionView.bounds; | |
| 991 | - preheatRect = CGRectInset(preheatRect, 0.0f, -0.5f * CGRectGetHeight(preheatRect)); | |
| 992 | - | |
| 993 | - /* | |
| 994 | - Check if the collection view is showing an area that is significantly | |
| 995 | - different to the last preheated area. | |
| 996 | - */ | |
| 997 | - CGFloat delta = ABS(CGRectGetMidY(preheatRect) - CGRectGetMidY(self.previousPreheatRect)); | |
| 998 | - if (delta > CGRectGetHeight(_collectionView.bounds) / 3.0f) { | |
| 999 | - | |
| 1000 | - // Compute the assets to start caching and to stop caching. | |
| 1001 | - NSMutableArray *addedIndexPaths = [NSMutableArray array]; | |
| 1002 | - NSMutableArray *removedIndexPaths = [NSMutableArray array]; | |
| 1003 | - | |
| 1004 | - [self computeDifferenceBetweenRect:self.previousPreheatRect andRect:preheatRect removedHandler:^(CGRect removedRect) { | |
| 1005 | - NSArray *indexPaths = [self aapl_indexPathsForElementsInRect:removedRect]; | |
| 1006 | - [removedIndexPaths addObjectsFromArray:indexPaths]; | |
| 1007 | - } addedHandler:^(CGRect addedRect) { | |
| 1008 | - NSArray *indexPaths = [self aapl_indexPathsForElementsInRect:addedRect]; | |
| 1009 | - [addedIndexPaths addObjectsFromArray:indexPaths]; | |
| 1010 | - }]; | |
| 1011 | - | |
| 1012 | - NSArray *assetsToStartCaching = [self assetsAtIndexPaths:addedIndexPaths]; | |
| 1013 | - NSArray *assetsToStopCaching = [self assetsAtIndexPaths:removedIndexPaths]; | |
| 1014 | - | |
| 1015 | - // Update the assets the PHCachingImageManager is caching. | |
| 1016 | - [[TZImageManager manager].cachingImageManager startCachingImagesForAssets:assetsToStartCaching | |
| 1017 | - targetSize:AssetGridThumbnailSize | |
| 1018 | - contentMode:PHImageContentModeAspectFill | |
| 1019 | - options:nil]; | |
| 1020 | - [[TZImageManager manager].cachingImageManager stopCachingImagesForAssets:assetsToStopCaching | |
| 1021 | - targetSize:AssetGridThumbnailSize | |
| 1022 | - contentMode:PHImageContentModeAspectFill | |
| 1023 | - options:nil]; | |
| 1024 | - | |
| 1025 | - // Store the preheat rect to compare against in the future. | |
| 1026 | - self.previousPreheatRect = preheatRect; | |
| 1027 | - } | |
| 1028 | -} | |
| 1029 | - | |
| 1030 | -- (void)computeDifferenceBetweenRect:(CGRect)oldRect andRect:(CGRect)newRect removedHandler:(void (^)(CGRect removedRect))removedHandler addedHandler:(void (^)(CGRect addedRect))addedHandler { | |
| 1031 | - if (CGRectIntersectsRect(newRect, oldRect)) { | |
| 1032 | - CGFloat oldMaxY = CGRectGetMaxY(oldRect); | |
| 1033 | - CGFloat oldMinY = CGRectGetMinY(oldRect); | |
| 1034 | - CGFloat newMaxY = CGRectGetMaxY(newRect); | |
| 1035 | - CGFloat newMinY = CGRectGetMinY(newRect); | |
| 1036 | - | |
| 1037 | - if (newMaxY > oldMaxY) { | |
| 1038 | - CGRect rectToAdd = CGRectMake(newRect.origin.x, oldMaxY, newRect.size.width, (newMaxY - oldMaxY)); | |
| 1039 | - addedHandler(rectToAdd); | |
| 1040 | - } | |
| 1041 | - | |
| 1042 | - if (oldMinY > newMinY) { | |
| 1043 | - CGRect rectToAdd = CGRectMake(newRect.origin.x, newMinY, newRect.size.width, (oldMinY - newMinY)); | |
| 1044 | - addedHandler(rectToAdd); | |
| 1045 | - } | |
| 1046 | - | |
| 1047 | - if (newMaxY < oldMaxY) { | |
| 1048 | - CGRect rectToRemove = CGRectMake(newRect.origin.x, newMaxY, newRect.size.width, (oldMaxY - newMaxY)); | |
| 1049 | - removedHandler(rectToRemove); | |
| 1050 | - } | |
| 1051 | - | |
| 1052 | - if (oldMinY < newMinY) { | |
| 1053 | - CGRect rectToRemove = CGRectMake(newRect.origin.x, oldMinY, newRect.size.width, (newMinY - oldMinY)); | |
| 1054 | - removedHandler(rectToRemove); | |
| 1055 | - } | |
| 1056 | - } else { | |
| 1057 | - addedHandler(newRect); | |
| 1058 | - removedHandler(oldRect); | |
| 1059 | - } | |
| 1060 | -} | |
| 1061 | - | |
| 1062 | -- (NSArray *)assetsAtIndexPaths:(NSArray *)indexPaths { | |
| 1063 | - if (indexPaths.count == 0) { return nil; } | |
| 1064 | - | |
| 1065 | - NSMutableArray *assets = [NSMutableArray arrayWithCapacity:indexPaths.count]; | |
| 1066 | - for (NSIndexPath *indexPath in indexPaths) { | |
| 1067 | - if (indexPath.item < _models.count) { | |
| 1068 | - TZAssetModel *model = _models[indexPath.item]; | |
| 1069 | - [assets addObject:model.asset]; | |
| 1070 | - } | |
| 1071 | - } | |
| 1072 | - | |
| 1073 | - return assets; | |
| 1074 | -} | |
| 1075 | - | |
| 1076 | -- (NSArray *)aapl_indexPathsForElementsInRect:(CGRect)rect { | |
| 1077 | - NSArray *allLayoutAttributes = [_collectionView.collectionViewLayout layoutAttributesForElementsInRect:rect]; | |
| 1078 | - if (allLayoutAttributes.count == 0) { return nil; } | |
| 1079 | - NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:allLayoutAttributes.count]; | |
| 1080 | - for (UICollectionViewLayoutAttributes *layoutAttributes in allLayoutAttributes) { | |
| 1081 | - NSIndexPath *indexPath = layoutAttributes.indexPath; | |
| 1082 | - [indexPaths addObject:indexPath]; | |
| 1083 | - } | |
| 1084 | - return indexPaths; | |
| 1085 | -} | |
| 1086 | -#pragma clang diagnostic pop | |
| 1087 | - | |
| 1088 | -@end | |
| 1089 | - | |
| 1090 | - | |
| 1091 | - | |
| 1092 | -@implementation TZCollectionView | |
| 1093 | - | |
| 1094 | -- (BOOL)touchesShouldCancelInContentView:(UIView *)view { | |
| 1095 | - if ([view isKindOfClass:[UIControl class]]) { | |
| 1096 | - return YES; | |
| 1097 | - } | |
| 1098 | - return [super touchesShouldCancelInContentView:view]; | |
| 1099 | -} | |
| 1100 | - | |
| 1101 | -@end |
CNLiveImagePickerController/TZPhotoPreviewCell.h deleted
100755 → 0
| 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 | -- (void)pausePlayerAndShowNaviBar; | |
| 62 | -@end | |
| 63 | - | |
| 64 | - | |
| 65 | -@interface TZGifPreviewCell : TZAssetPreviewCell | |
| 66 | -@property (strong, nonatomic) TZPhotoPreviewView *previewView; | |
| 67 | -@end |
CNLiveImagePickerController/TZPhotoPreviewCell.m deleted
100755 → 0
| 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+Layout.h" | |
| 12 | -#import "TZImageManager.h" | |
| 13 | -#import "TZProgressView.h" | |
| 14 | -#import "TZImageCropManager.h" | |
| 15 | -#import <MediaPlayer/MediaPlayer.h> | |
| 16 | -#import "TZImagePickerController.h" | |
| 17 | - | |
| 18 | -@implementation TZAssetPreviewCell | |
| 19 | - | |
| 20 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 21 | - self = [super initWithFrame:frame]; | |
| 22 | - if (self) { | |
| 23 | - self.backgroundColor = [UIColor blackColor]; | |
| 24 | - [self configSubviews]; | |
| 25 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(photoPreviewCollectionViewDidScroll) name:@"photoPreviewCollectionViewDidScroll" object:nil]; | |
| 26 | - } | |
| 27 | - return self; | |
| 28 | -} | |
| 29 | - | |
| 30 | -- (void)configSubviews { | |
| 31 | - | |
| 32 | -} | |
| 33 | - | |
| 34 | -#pragma mark - Notification | |
| 35 | - | |
| 36 | -- (void)photoPreviewCollectionViewDidScroll { | |
| 37 | - | |
| 38 | -} | |
| 39 | - | |
| 40 | -- (void)dealloc { | |
| 41 | - [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 42 | -} | |
| 43 | - | |
| 44 | -@end | |
| 45 | - | |
| 46 | - | |
| 47 | -@implementation TZPhotoPreviewCell | |
| 48 | - | |
| 49 | -- (void)configSubviews { | |
| 50 | - self.previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero]; | |
| 51 | - __weak typeof(self) weakSelf = self; | |
| 52 | - [self.previewView setSingleTapGestureBlock:^{ | |
| 53 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 54 | - if (strongSelf.singleTapGestureBlock) { | |
| 55 | - strongSelf.singleTapGestureBlock(); | |
| 56 | - } | |
| 57 | - }]; | |
| 58 | - [self.previewView setImageProgressUpdateBlock:^(double progress) { | |
| 59 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 60 | - if (strongSelf.imageProgressUpdateBlock) { | |
| 61 | - strongSelf.imageProgressUpdateBlock(progress); | |
| 62 | - } | |
| 63 | - }]; | |
| 64 | - [self addSubview:self.previewView]; | |
| 65 | -} | |
| 66 | - | |
| 67 | -- (void)setModel:(TZAssetModel *)model { | |
| 68 | - [super setModel:model]; | |
| 69 | - _previewView.asset = model.asset; | |
| 70 | -} | |
| 71 | - | |
| 72 | -- (void)recoverSubviews { | |
| 73 | - [_previewView recoverSubviews]; | |
| 74 | -} | |
| 75 | - | |
| 76 | -- (void)setAllowCrop:(BOOL)allowCrop { | |
| 77 | - _allowCrop = allowCrop; | |
| 78 | - _previewView.allowCrop = allowCrop; | |
| 79 | -} | |
| 80 | - | |
| 81 | -- (void)setCropRect:(CGRect)cropRect { | |
| 82 | - _cropRect = cropRect; | |
| 83 | - _previewView.cropRect = cropRect; | |
| 84 | -} | |
| 85 | - | |
| 86 | -- (void)layoutSubviews { | |
| 87 | - [super layoutSubviews]; | |
| 88 | - self.previewView.frame = self.bounds; | |
| 89 | -} | |
| 90 | - | |
| 91 | -@end | |
| 92 | - | |
| 93 | - | |
| 94 | -@interface TZPhotoPreviewView ()<UIScrollViewDelegate> | |
| 95 | -@property (assign, nonatomic) BOOL isRequestingGIF; | |
| 96 | -@end | |
| 97 | - | |
| 98 | -@implementation TZPhotoPreviewView | |
| 99 | - | |
| 100 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 101 | - self = [super initWithFrame:frame]; | |
| 102 | - if (self) { | |
| 103 | - _scrollView = [[UIScrollView alloc] init]; | |
| 104 | - _scrollView.bouncesZoom = YES; | |
| 105 | - _scrollView.maximumZoomScale = 2.5; | |
| 106 | - _scrollView.minimumZoomScale = 1.0; | |
| 107 | - _scrollView.multipleTouchEnabled = YES; | |
| 108 | - _scrollView.delegate = self; | |
| 109 | - _scrollView.scrollsToTop = NO; | |
| 110 | - _scrollView.showsHorizontalScrollIndicator = NO; | |
| 111 | - _scrollView.showsVerticalScrollIndicator = YES; | |
| 112 | - _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | |
| 113 | - _scrollView.delaysContentTouches = NO; | |
| 114 | - _scrollView.canCancelContentTouches = YES; | |
| 115 | - _scrollView.alwaysBounceVertical = NO; | |
| 116 | - if (@available(iOS 11, *)) { | |
| 117 | - _scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; | |
| 118 | - } | |
| 119 | - [self addSubview:_scrollView]; | |
| 120 | - | |
| 121 | - _imageContainerView = [[UIView alloc] init]; | |
| 122 | - _imageContainerView.clipsToBounds = YES; | |
| 123 | - _imageContainerView.contentMode = UIViewContentModeScaleAspectFill; | |
| 124 | - [_scrollView addSubview:_imageContainerView]; | |
| 125 | - | |
| 126 | - _imageView = [[UIImageView alloc] init]; | |
| 127 | - _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; | |
| 128 | - _imageView.contentMode = UIViewContentModeScaleAspectFill; | |
| 129 | - _imageView.clipsToBounds = YES; | |
| 130 | - [_imageContainerView addSubview:_imageView]; | |
| 131 | - | |
| 132 | - UITapGestureRecognizer *tap1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)]; | |
| 133 | - [self addGestureRecognizer:tap1]; | |
| 134 | - UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; | |
| 135 | - tap2.numberOfTapsRequired = 2; | |
| 136 | - [tap1 requireGestureRecognizerToFail:tap2]; | |
| 137 | - [self addGestureRecognizer:tap2]; | |
| 138 | - | |
| 139 | - [self configProgressView]; | |
| 140 | - } | |
| 141 | - return self; | |
| 142 | -} | |
| 143 | - | |
| 144 | -- (void)configProgressView { | |
| 145 | - _progressView = [[TZProgressView alloc] init]; | |
| 146 | - _progressView.hidden = YES; | |
| 147 | - [self addSubview:_progressView]; | |
| 148 | -} | |
| 149 | - | |
| 150 | -- (void)setModel:(TZAssetModel *)model { | |
| 151 | - _model = model; | |
| 152 | - self.isRequestingGIF = NO; | |
| 153 | - [_scrollView setZoomScale:1.0 animated:NO]; | |
| 154 | - if (model.type == TZAssetModelMediaTypePhotoGif) { | |
| 155 | - // 先显示缩略图 | |
| 156 | - [[TZImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 157 | - self.imageView.image = photo; | |
| 158 | - [self resizeSubviews]; | |
| 159 | - if (self.isRequestingGIF) { | |
| 160 | - return; | |
| 161 | - } | |
| 162 | - // 再显示gif动图 | |
| 163 | - self.isRequestingGIF = YES; | |
| 164 | - [[TZImageManager manager] getOriginalPhotoDataWithAsset:model.asset progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 165 | - progress = progress > 0.02 ? progress : 0.02; | |
| 166 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 167 | - self.progressView.progress = progress; | |
| 168 | - if (progress >= 1) { | |
| 169 | - self.progressView.hidden = YES; | |
| 170 | - } else { | |
| 171 | - self.progressView.hidden = NO; | |
| 172 | - } | |
| 173 | - }); | |
| 174 | -#ifdef DEBUG | |
| 175 | - NSLog(@"[TZImagePickerController] getOriginalPhotoDataWithAsset:%f error:%@", progress, error); | |
| 176 | -#endif | |
| 177 | - } completion:^(NSData *data, NSDictionary *info, BOOL isDegraded) { | |
| 178 | - if (!isDegraded) { | |
| 179 | - self.isRequestingGIF = NO; | |
| 180 | - self.progressView.hidden = YES; | |
| 181 | - self.imageView.image = [UIImage sd_tz_animatedGIFWithData:data]; | |
| 182 | - [self resizeSubviews]; | |
| 183 | - } | |
| 184 | - }]; | |
| 185 | - } progressHandler:nil networkAccessAllowed:NO]; | |
| 186 | - } else { | |
| 187 | - self.asset = model.asset; | |
| 188 | - } | |
| 189 | -} | |
| 190 | - | |
| 191 | -- (void)setAsset:(id)asset { | |
| 192 | - if (_asset && self.imageRequestID) { | |
| 193 | - [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; | |
| 194 | - } | |
| 195 | - | |
| 196 | - _asset = asset; | |
| 197 | - self.imageRequestID = [[TZImageManager manager] getPhotoWithAsset:asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 198 | - if (![asset isEqual:self->_asset]) return; | |
| 199 | - self.imageView.image = photo; | |
| 200 | - [self resizeSubviews]; | |
| 201 | - self->_progressView.hidden = YES; | |
| 202 | - if (self.imageProgressUpdateBlock) { | |
| 203 | - self.imageProgressUpdateBlock(1); | |
| 204 | - } | |
| 205 | - if (!isDegraded) { | |
| 206 | - self.imageRequestID = 0; | |
| 207 | - } | |
| 208 | - } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { | |
| 209 | - if (![asset isEqual:self->_asset]) return; | |
| 210 | - self->_progressView.hidden = NO; | |
| 211 | - [self bringSubviewToFront:self->_progressView]; | |
| 212 | - progress = progress > 0.02 ? progress : 0.02; | |
| 213 | - self->_progressView.progress = progress; | |
| 214 | - if (self.imageProgressUpdateBlock && progress < 1) { | |
| 215 | - self.imageProgressUpdateBlock(progress); | |
| 216 | - } | |
| 217 | - | |
| 218 | - if (progress >= 1) { | |
| 219 | - self->_progressView.hidden = YES; | |
| 220 | - self.imageRequestID = 0; | |
| 221 | - } | |
| 222 | - } networkAccessAllowed:YES]; | |
| 223 | -} | |
| 224 | - | |
| 225 | -- (void)recoverSubviews { | |
| 226 | - [_scrollView setZoomScale:1.0 animated:NO]; | |
| 227 | - [self resizeSubviews]; | |
| 228 | -} | |
| 229 | - | |
| 230 | -- (void)resizeSubviews { | |
| 231 | - _imageContainerView.tz_origin = CGPointZero; | |
| 232 | - _imageContainerView.tz_width = self.scrollView.tz_width; | |
| 233 | - | |
| 234 | - UIImage *image = _imageView.image; | |
| 235 | - if (image.size.height / image.size.width > self.tz_height / self.scrollView.tz_width) { | |
| 236 | - _imageContainerView.tz_height = floor(image.size.height / (image.size.width / self.scrollView.tz_width)); | |
| 237 | - } else { | |
| 238 | - CGFloat height = image.size.height / image.size.width * self.scrollView.tz_width; | |
| 239 | - if (height < 1 || isnan(height)) height = self.tz_height; | |
| 240 | - height = floor(height); | |
| 241 | - _imageContainerView.tz_height = height; | |
| 242 | - _imageContainerView.tz_centerY = self.tz_height / 2; | |
| 243 | - } | |
| 244 | - if (_imageContainerView.tz_height > self.tz_height && _imageContainerView.tz_height - self.tz_height <= 1) { | |
| 245 | - _imageContainerView.tz_height = self.tz_height; | |
| 246 | - } | |
| 247 | - CGFloat contentSizeH = MAX(_imageContainerView.tz_height, self.tz_height); | |
| 248 | - _scrollView.contentSize = CGSizeMake(self.scrollView.tz_width, contentSizeH); | |
| 249 | - [_scrollView scrollRectToVisible:self.bounds animated:NO]; | |
| 250 | - _scrollView.alwaysBounceVertical = _imageContainerView.tz_height <= self.tz_height ? NO : YES; | |
| 251 | - _imageView.frame = _imageContainerView.bounds; | |
| 252 | - | |
| 253 | - [self refreshScrollViewContentSize]; | |
| 254 | -} | |
| 255 | - | |
| 256 | -- (void)setAllowCrop:(BOOL)allowCrop { | |
| 257 | - _allowCrop = allowCrop; | |
| 258 | - _scrollView.maximumZoomScale = allowCrop ? 4.0 : 2.5; | |
| 259 | - | |
| 260 | - if ([self.asset isKindOfClass:[PHAsset class]]) { | |
| 261 | - PHAsset *phAsset = (PHAsset *)self.asset; | |
| 262 | - CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight; | |
| 263 | - // 优化超宽图片的显示 | |
| 264 | - if (aspectRatio > 1.5) { | |
| 265 | - self.scrollView.maximumZoomScale *= aspectRatio / 1.5; | |
| 266 | - } | |
| 267 | - } | |
| 268 | -} | |
| 269 | - | |
| 270 | -- (void)refreshScrollViewContentSize { | |
| 271 | - if (_allowCrop) { | |
| 272 | - // 1.7.2 如果允许裁剪,需要让图片的任意部分都能在裁剪框内,于是对_scrollView做了如下处理: | |
| 273 | - // 1.让contentSize增大(裁剪框右下角的图片部分) | |
| 274 | - CGFloat contentWidthAdd = self.scrollView.tz_width - CGRectGetMaxX(_cropRect); | |
| 275 | - CGFloat contentHeightAdd = (MIN(_imageContainerView.tz_height, self.tz_height) - self.cropRect.size.height) / 2; | |
| 276 | - CGFloat newSizeW = self.scrollView.contentSize.width + contentWidthAdd; | |
| 277 | - CGFloat newSizeH = MAX(self.scrollView.contentSize.height, self.tz_height) + contentHeightAdd; | |
| 278 | - _scrollView.contentSize = CGSizeMake(newSizeW, newSizeH); | |
| 279 | - _scrollView.alwaysBounceVertical = YES; | |
| 280 | - // 2.让scrollView新增滑动区域(裁剪框左上角的图片部分) | |
| 281 | - if (contentHeightAdd > 0 || contentWidthAdd > 0) { | |
| 282 | - _scrollView.contentInset = UIEdgeInsetsMake(contentHeightAdd, _cropRect.origin.x, 0, 0); | |
| 283 | - } else { | |
| 284 | - _scrollView.contentInset = UIEdgeInsetsZero; | |
| 285 | - } | |
| 286 | - } | |
| 287 | -} | |
| 288 | - | |
| 289 | -- (void)layoutSubviews { | |
| 290 | - [super layoutSubviews]; | |
| 291 | - _scrollView.frame = CGRectMake(10, 0, self.tz_width - 20, self.tz_height); | |
| 292 | - static CGFloat progressWH = 40; | |
| 293 | - CGFloat progressX = (self.tz_width - progressWH) / 2; | |
| 294 | - CGFloat progressY = (self.tz_height - progressWH) / 2; | |
| 295 | - _progressView.frame = CGRectMake(progressX, progressY, progressWH, progressWH); | |
| 296 | - | |
| 297 | - [self recoverSubviews]; | |
| 298 | -} | |
| 299 | - | |
| 300 | -#pragma mark - UITapGestureRecognizer Event | |
| 301 | - | |
| 302 | -- (void)doubleTap:(UITapGestureRecognizer *)tap { | |
| 303 | - if (_scrollView.zoomScale > 1.0) { | |
| 304 | - _scrollView.contentInset = UIEdgeInsetsZero; | |
| 305 | - [_scrollView setZoomScale:1.0 animated:YES]; | |
| 306 | - } else { | |
| 307 | - CGPoint touchPoint = [tap locationInView:self.imageView]; | |
| 308 | - CGFloat newZoomScale = _scrollView.maximumZoomScale; | |
| 309 | - CGFloat xsize = self.frame.size.width / newZoomScale; | |
| 310 | - CGFloat ysize = self.frame.size.height / newZoomScale; | |
| 311 | - [_scrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES]; | |
| 312 | - } | |
| 313 | -} | |
| 314 | - | |
| 315 | -- (void)singleTap:(UITapGestureRecognizer *)tap { | |
| 316 | - if (self.singleTapGestureBlock) { | |
| 317 | - self.singleTapGestureBlock(); | |
| 318 | - } | |
| 319 | -} | |
| 320 | - | |
| 321 | -#pragma mark - UIScrollViewDelegate | |
| 322 | - | |
| 323 | -- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { | |
| 324 | - return _imageContainerView; | |
| 325 | -} | |
| 326 | - | |
| 327 | -- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { | |
| 328 | - scrollView.contentInset = UIEdgeInsetsZero; | |
| 329 | -} | |
| 330 | - | |
| 331 | -- (void)scrollViewDidZoom:(UIScrollView *)scrollView { | |
| 332 | - [self refreshImageContainerViewCenter]; | |
| 333 | -} | |
| 334 | - | |
| 335 | -- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale { | |
| 336 | - [self refreshScrollViewContentSize]; | |
| 337 | -} | |
| 338 | - | |
| 339 | -#pragma mark - Private | |
| 340 | - | |
| 341 | -- (void)refreshImageContainerViewCenter { | |
| 342 | - CGFloat offsetX = (_scrollView.tz_width > _scrollView.contentSize.width) ? ((_scrollView.tz_width - _scrollView.contentSize.width) * 0.5) : 0.0; | |
| 343 | - CGFloat offsetY = (_scrollView.tz_height > _scrollView.contentSize.height) ? ((_scrollView.tz_height - _scrollView.contentSize.height) * 0.5) : 0.0; | |
| 344 | - self.imageContainerView.center = CGPointMake(_scrollView.contentSize.width * 0.5 + offsetX, _scrollView.contentSize.height * 0.5 + offsetY); | |
| 345 | -} | |
| 346 | - | |
| 347 | -@end | |
| 348 | - | |
| 349 | - | |
| 350 | -@implementation TZVideoPreviewCell | |
| 351 | - | |
| 352 | -- (void)configSubviews { | |
| 353 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil]; | |
| 354 | -} | |
| 355 | - | |
| 356 | -- (void)configPlayButton { | |
| 357 | - if (_playButton) { | |
| 358 | - [_playButton removeFromSuperview]; | |
| 359 | - } | |
| 360 | - _playButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 361 | - [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal]; | |
| 362 | - [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted]; | |
| 363 | - [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 364 | - [self addSubview:_playButton]; | |
| 365 | -} | |
| 366 | - | |
| 367 | -- (void)setModel:(TZAssetModel *)model { | |
| 368 | - [super setModel:model]; | |
| 369 | - [self configMoviePlayer]; | |
| 370 | -} | |
| 371 | - | |
| 372 | -- (void)configMoviePlayer { | |
| 373 | - if (_player) { | |
| 374 | - [_playerLayer removeFromSuperlayer]; | |
| 375 | - _playerLayer = nil; | |
| 376 | - [_player pause]; | |
| 377 | - _player = nil; | |
| 378 | - } | |
| 379 | - | |
| 380 | - [[TZImageManager manager] getPhotoWithAsset:self.model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 381 | - self->_cover = photo; | |
| 382 | - }]; | |
| 383 | - [[TZImageManager manager] getVideoWithAsset:self.model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) { | |
| 384 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 385 | - self->_player = [AVPlayer playerWithPlayerItem:playerItem]; | |
| 386 | - self->_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self->_player]; | |
| 387 | - self->_playerLayer.backgroundColor = [UIColor blackColor].CGColor; | |
| 388 | - self->_playerLayer.frame = self.bounds; | |
| 389 | - [self.layer addSublayer:self->_playerLayer]; | |
| 390 | - [self configPlayButton]; | |
| 391 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem]; | |
| 392 | - }); | |
| 393 | - }]; | |
| 394 | -} | |
| 395 | - | |
| 396 | -- (void)layoutSubviews { | |
| 397 | - [super layoutSubviews]; | |
| 398 | - _playerLayer.frame = self.bounds; | |
| 399 | - _playButton.frame = CGRectMake(0, 64, self.tz_width, self.tz_height - 64 - 44); | |
| 400 | -} | |
| 401 | - | |
| 402 | -- (void)photoPreviewCollectionViewDidScroll { | |
| 403 | - [self pausePlayerAndShowNaviBar]; | |
| 404 | -} | |
| 405 | - | |
| 406 | -#pragma mark - Click Event | |
| 407 | - | |
| 408 | -- (void)playButtonClick { | |
| 409 | - CMTime currentTime = _player.currentItem.currentTime; | |
| 410 | - CMTime durationTime = _player.currentItem.duration; | |
| 411 | - if (_player.rate == 0.0f) { | |
| 412 | - if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; | |
| 413 | - [_player play]; | |
| 414 | - [_playButton setImage:nil forState:UIControlStateNormal]; | |
| 415 | - if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES; | |
| 416 | - if (self.singleTapGestureBlock) { | |
| 417 | - self.singleTapGestureBlock(); | |
| 418 | - } | |
| 419 | - } else { | |
| 420 | - [self pausePlayerAndShowNaviBar]; | |
| 421 | - } | |
| 422 | -} | |
| 423 | - | |
| 424 | -- (void)pausePlayerAndShowNaviBar { | |
| 425 | - if (_player.rate != 0.0) { | |
| 426 | - [_player pause]; | |
| 427 | - [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal]; | |
| 428 | - if (self.singleTapGestureBlock) { | |
| 429 | - self.singleTapGestureBlock(); | |
| 430 | - } | |
| 431 | - } | |
| 432 | -} | |
| 433 | - | |
| 434 | -@end | |
| 435 | - | |
| 436 | - | |
| 437 | -@implementation TZGifPreviewCell | |
| 438 | - | |
| 439 | -- (void)configSubviews { | |
| 440 | - [self configPreviewView]; | |
| 441 | -} | |
| 442 | - | |
| 443 | -- (void)configPreviewView { | |
| 444 | - _previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero]; | |
| 445 | - __weak typeof(self) weakSelf = self; | |
| 446 | - [_previewView setSingleTapGestureBlock:^{ | |
| 447 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 448 | - [strongSelf signleTapAction]; | |
| 449 | - }]; | |
| 450 | - [self addSubview:_previewView]; | |
| 451 | -} | |
| 452 | - | |
| 453 | -- (void)setModel:(TZAssetModel *)model { | |
| 454 | - [super setModel:model]; | |
| 455 | - _previewView.model = self.model; | |
| 456 | -} | |
| 457 | - | |
| 458 | -- (void)layoutSubviews { | |
| 459 | - [super layoutSubviews]; | |
| 460 | - _previewView.frame = self.bounds; | |
| 461 | -} | |
| 462 | - | |
| 463 | -#pragma mark - Click Event | |
| 464 | - | |
| 465 | -- (void)signleTapAction { | |
| 466 | - if (self.singleTapGestureBlock) { | |
| 467 | - self.singleTapGestureBlock(); | |
| 468 | - } | |
| 469 | -} | |
| 470 | - | |
| 471 | -@end |
CNLiveImagePickerController/TZPhotoPreviewController.h deleted
100755 → 0
| 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 | -@interface TZPhotoPreviewController : UIViewController | |
| 12 | - | |
| 13 | -@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组 | |
| 14 | -@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组 | |
| 15 | -@property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / 用户点击的图片的索引 | |
| 16 | -@property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / 是否返回原图 | |
| 17 | -@property (nonatomic, assign) BOOL isCropImage; | |
| 18 | - | |
| 19 | -/// Return the new selected photos / 返回最新的选中图片数组 | |
| 20 | -@property (nonatomic, copy) void (^backButtonClickBlock)(BOOL isSelectOriginalPhoto); | |
| 21 | -@property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto); | |
| 22 | -@property (nonatomic, copy) void (^doneButtonClickBlockCropMode)(UIImage *cropedImage,id asset); | |
| 23 | -@property (nonatomic, copy) void (^doneButtonClickBlockWithPreviewType)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto); | |
| 24 | - | |
| 25 | -@end |
CNLiveImagePickerController/TZPhotoPreviewController.m deleted
100755 → 0
| 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+Layout.h" | |
| 13 | -#import "TZImagePickerController.h" | |
| 14 | -#import "TZImageManager.h" | |
| 15 | -#import "TZImageCropManager.h" | |
| 16 | -#import <AssetsLibrary/AssetsLibrary.h>///lxg | |
| 17 | -#import "CNEditVideoController.h" | |
| 18 | - | |
| 19 | -@interface TZPhotoPreviewController ()<UICollectionViewDataSource,UICollectionViewDelegate,UIScrollViewDelegate> { | |
| 20 | - UICollectionView *_collectionView; | |
| 21 | - UICollectionViewFlowLayout *_layout; | |
| 22 | - NSArray *_photosTemp; | |
| 23 | - NSArray *_assetsTemp; | |
| 24 | - | |
| 25 | - UIView *_naviBar; | |
| 26 | - UIButton *_backButton; | |
| 27 | - UIButton *_selectButton; | |
| 28 | - UILabel *_indexLabel; | |
| 29 | - UIView *_navBarLine;///LXG线 | |
| 30 | - | |
| 31 | - UIView *_tipBar;///LXG添加提示视图 | |
| 32 | - UILabel *_tipContentLabel;///LXG添加提示内容 | |
| 33 | - | |
| 34 | - | |
| 35 | - UIView *_toolBar; | |
| 36 | - UIButton *_doneButton; | |
| 37 | - UIImageView *_numberImageView; | |
| 38 | - UILabel *_numberLabel; | |
| 39 | - UIButton *_originalPhotoButton; | |
| 40 | - UILabel *_originalPhotoLabel; | |
| 41 | - UILabel *_editTipLable;//LXG底部提示 | |
| 42 | - UIButton *_editTipButton;//LXG编辑按钮 | |
| 43 | - | |
| 44 | - | |
| 45 | - CGFloat _offsetItemCount; | |
| 46 | - | |
| 47 | - BOOL _didSetIsSelectOriginalPhoto; | |
| 48 | -} | |
| 49 | -@property (nonatomic, assign) BOOL isHideNaviBar; | |
| 50 | -@property (nonatomic, strong) UIView *cropBgView; | |
| 51 | -@property (nonatomic, strong) UIView *cropView; | |
| 52 | - | |
| 53 | -@property (nonatomic, assign) double progress; | |
| 54 | -@property (strong, nonatomic) id alertView; | |
| 55 | -@end | |
| 56 | - | |
| 57 | -@implementation TZPhotoPreviewController | |
| 58 | - | |
| 59 | -- (void)viewDidLoad { | |
| 60 | - [super viewDidLoad]; | |
| 61 | - [TZImageManager manager].shouldFixOrientation = YES; | |
| 62 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 63 | - if (!_didSetIsSelectOriginalPhoto) { | |
| 64 | - _isSelectOriginalPhoto = _tzImagePickerVc.isSelectOriginalPhoto; | |
| 65 | - } | |
| 66 | - if (!self.models.count) { | |
| 67 | - self.models = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedModels]; | |
| 68 | - _assetsTemp = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedAssets]; | |
| 69 | - } | |
| 70 | - [self configCollectionView]; | |
| 71 | - [self configCustomNaviBar]; | |
| 72 | - [self configCustomTipBar];///lxg 添加提示 | |
| 73 | - [self configBottomToolBar]; | |
| 74 | - self.view.clipsToBounds = YES; | |
| 75 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; | |
| 76 | -} | |
| 77 | - | |
| 78 | -- (void)setIsSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto { | |
| 79 | - _isSelectOriginalPhoto = isSelectOriginalPhoto; | |
| 80 | - _didSetIsSelectOriginalPhoto = YES; | |
| 81 | -} | |
| 82 | - | |
| 83 | -- (void)setPhotos:(NSMutableArray *)photos { | |
| 84 | - _photos = photos; | |
| 85 | - _photosTemp = [NSArray arrayWithArray:photos]; | |
| 86 | -} | |
| 87 | - | |
| 88 | -- (void)viewWillAppear:(BOOL)animated { | |
| 89 | - [super viewWillAppear:animated]; | |
| 90 | - [self.navigationController setNavigationBarHidden:YES animated:YES]; | |
| 91 | - if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES; | |
| 92 | - if (_currentIndex) [_collectionView setContentOffset:CGPointMake((self.view.tz_width + 20) * _currentIndex, 0) animated:NO]; | |
| 93 | - [self refreshNaviBarAndBottomBarState]; | |
| 94 | -} | |
| 95 | - | |
| 96 | -- (void)viewWillDisappear:(BOOL)animated { | |
| 97 | - [super viewWillDisappear:animated]; | |
| 98 | - [self.navigationController setNavigationBarHidden:NO animated:YES]; | |
| 99 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 100 | - if (tzImagePickerVc.needShowStatusBar && iOS7Later) { | |
| 101 | - [UIApplication sharedApplication].statusBarHidden = NO; | |
| 102 | - } | |
| 103 | - [TZImageManager manager].shouldFixOrientation = NO; | |
| 104 | -} | |
| 105 | - | |
| 106 | -- (BOOL)prefersStatusBarHidden { | |
| 107 | - return YES; | |
| 108 | -} | |
| 109 | - | |
| 110 | -- (void)configCustomNaviBar { | |
| 111 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 112 | - | |
| 113 | - _naviBar = [[UIView alloc] initWithFrame:CGRectZero]; | |
| 114 | - _naviBar.backgroundColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:0.7]; | |
| 115 | - | |
| 116 | - _backButton = [[UIButton alloc] initWithFrame:CGRectZero]; | |
| 117 | - [_backButton setImage:[UIImage imageNamedFromMyBundle:@"navi_back"] forState:UIControlStateNormal]; | |
| 118 | - [_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
| 119 | - [_backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 120 | - | |
| 121 | - _selectButton = [[UIButton alloc] initWithFrame:CGRectZero]; | |
| 122 | - [_selectButton setImage:tzImagePickerVc.photoDefImage forState:UIControlStateNormal]; | |
| 123 | - [_selectButton setImage:tzImagePickerVc.photoSelImage forState:UIControlStateSelected]; | |
| 124 | - _selectButton.imageView.clipsToBounds = YES; | |
| 125 | - _selectButton.imageEdgeInsets = UIEdgeInsetsMake(10, 0, 10, 0); | |
| 126 | - _selectButton.imageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 127 | - [_selectButton addTarget:self action:@selector(select:) forControlEvents:UIControlEventTouchUpInside]; | |
| 128 | - _selectButton.hidden = !tzImagePickerVc.showSelectBtn; | |
| 129 | - | |
| 130 | - _indexLabel = [[UILabel alloc] init]; | |
| 131 | - _indexLabel.font = [UIFont systemFontOfSize:14]; | |
| 132 | - _indexLabel.textColor = [UIColor whiteColor]; | |
| 133 | - _indexLabel.textAlignment = NSTextAlignmentCenter; | |
| 134 | - ///lxg 导航栏线 | |
| 135 | - _navBarLine = [[UIView alloc]init]; | |
| 136 | - _navBarLine.backgroundColor = [UIColor colorWithWhite:0.5 alpha:1]; | |
| 137 | - _navBarLine.hidden = YES; | |
| 138 | - | |
| 139 | - [_naviBar addSubview:_selectButton]; | |
| 140 | - [_naviBar addSubview:_indexLabel]; | |
| 141 | - [_naviBar addSubview:_backButton]; | |
| 142 | - [_naviBar addSubview:_navBarLine];///lxg 添加线 | |
| 143 | - [self.view addSubview:_naviBar]; | |
| 144 | -} | |
| 145 | - | |
| 146 | -/// 添加提示条(LXG) | |
| 147 | -- (void)configCustomTipBar { | |
| 148 | - _tipBar = [[UIView alloc] initWithFrame:CGRectZero]; | |
| 149 | - static CGFloat rgb = 34 / 255.0; | |
| 150 | - _tipBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; | |
| 151 | - _tipBar.hidden = YES; | |
| 152 | - | |
| 153 | - _tipContentLabel = [[UILabel alloc] init]; | |
| 154 | - _tipContentLabel.font = [UIFont systemFontOfSize:15]; | |
| 155 | - _tipContentLabel.textColor = [UIColor whiteColor]; | |
| 156 | - _tipContentLabel.textAlignment = NSTextAlignmentLeft; | |
| 157 | - _tipContentLabel.backgroundColor = [UIColor clearColor]; | |
| 158 | - | |
| 159 | - [_tipBar addSubview:_tipContentLabel]; | |
| 160 | - [self.view addSubview:_tipBar]; | |
| 161 | - | |
| 162 | - | |
| 163 | -} | |
| 164 | - | |
| 165 | -- (void)configBottomToolBar { | |
| 166 | - _toolBar = [[UIView alloc] initWithFrame:CGRectZero]; | |
| 167 | - static CGFloat rgb = 34 / 255.0; | |
| 168 | - _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; | |
| 169 | - | |
| 170 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 171 | - if (_tzImagePickerVc.allowPickingOriginalPhoto) { | |
| 172 | - _originalPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 173 | - _originalPhotoButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); | |
| 174 | - _originalPhotoButton.backgroundColor = [UIColor clearColor]; | |
| 175 | - [_originalPhotoButton addTarget:self action:@selector(originalPhotoButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 176 | - _originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:13]; | |
| 177 | - [_originalPhotoButton setTitle:_tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateNormal]; | |
| 178 | - [_originalPhotoButton setTitle:_tzImagePickerVc.fullImageBtnTitleStr forState:UIControlStateSelected]; | |
| 179 | - [_originalPhotoButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; | |
| 180 | - [_originalPhotoButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; | |
| 181 | - [_originalPhotoButton setImage:_tzImagePickerVc.photoPreviewOriginDefImage forState:UIControlStateNormal]; | |
| 182 | - [_originalPhotoButton setImage:_tzImagePickerVc.photoOriginSelImage forState:UIControlStateSelected]; | |
| 183 | - | |
| 184 | - _originalPhotoLabel = [[UILabel alloc] init]; | |
| 185 | - _originalPhotoLabel.textAlignment = NSTextAlignmentLeft; | |
| 186 | - _originalPhotoLabel.font = [UIFont systemFontOfSize:13]; | |
| 187 | - _originalPhotoLabel.textColor = [UIColor whiteColor]; | |
| 188 | - _originalPhotoLabel.backgroundColor = [UIColor clearColor]; | |
| 189 | - if (_isSelectOriginalPhoto) [self showPhotoBytes]; | |
| 190 | - } | |
| 191 | - | |
| 192 | - _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 193 | - _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 194 | - [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 195 | - [_doneButton setTitle:_tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; | |
| 196 | - [_doneButton setTitleColor:_tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; | |
| 197 | - | |
| 198 | - _numberImageView = [[UIImageView alloc] initWithImage:_tzImagePickerVc.photoNumberIconImage]; | |
| 199 | - _numberImageView.backgroundColor = [UIColor clearColor]; | |
| 200 | - _numberImageView.clipsToBounds = YES; | |
| 201 | - _numberImageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 202 | - _numberImageView.hidden = _tzImagePickerVc.selectedModels.count <= 0; | |
| 203 | - | |
| 204 | - _numberLabel = [[UILabel alloc] init]; | |
| 205 | - _numberLabel.font = [UIFont systemFontOfSize:15]; | |
| 206 | - _numberLabel.textColor = [UIColor whiteColor]; | |
| 207 | - _numberLabel.textAlignment = NSTextAlignmentCenter; | |
| 208 | - _numberLabel.text = [NSString stringWithFormat:@"%zd",_tzImagePickerVc.selectedModels.count]; | |
| 209 | - _numberLabel.hidden = _tzImagePickerVc.selectedModels.count <= 0; | |
| 210 | - _numberLabel.backgroundColor = [UIColor clearColor]; | |
| 211 | -#pragma mark - ADD: 选择图片个数显示(LXG) | |
| 212 | - _numberImageView.hidden = YES; | |
| 213 | - _numberLabel.hidden = YES; | |
| 214 | - NSString *titleStr = _tzImagePickerVc.selectedModels.count > 0 ? [NSString stringWithFormat:@"完成(%zd)",_tzImagePickerVc.selectedModels.count] : @"完成"; | |
| 215 | - [_doneButton setTitle:titleStr forState:UIControlStateNormal]; | |
| 216 | - | |
| 217 | - ///LXG 添加视频编辑 | |
| 218 | - _editTipLable = [[UILabel alloc] init]; | |
| 219 | - _editTipLable.font = [UIFont systemFontOfSize:15]; | |
| 220 | - _editTipLable.textAlignment = NSTextAlignmentLeft; | |
| 221 | - _editTipLable.hidden = YES; | |
| 222 | - _editTipLable.textColor = [UIColor whiteColor]; | |
| 223 | - _editTipLable.backgroundColor = [UIColor clearColor]; | |
| 224 | - _editTipButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 225 | - _editTipButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 226 | - [_editTipButton addTarget:self action:@selector(editVideoButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 227 | - _editTipButton.hidden = YES; | |
| 228 | - [_editTipButton setTitle:_tzImagePickerVc.editBtnTitleStr forState:UIControlStateNormal]; | |
| 229 | - [_editTipButton setTitleColor:_tzImagePickerVc.editBtnTitleColor forState:UIControlStateNormal]; | |
| 230 | - | |
| 231 | - [_originalPhotoButton addSubview:_originalPhotoLabel]; | |
| 232 | - [_toolBar addSubview:_doneButton]; | |
| 233 | - [_toolBar addSubview:_originalPhotoButton]; | |
| 234 | - [_toolBar addSubview:_numberImageView]; | |
| 235 | - [_toolBar addSubview:_numberLabel]; | |
| 236 | - [_toolBar addSubview:_editTipLable];///LXG | |
| 237 | - [_toolBar addSubview:_editTipButton];///LXG | |
| 238 | - [self.view addSubview:_toolBar]; | |
| 239 | - | |
| 240 | - if (_tzImagePickerVc.photoPreviewPageUIConfigBlock) { | |
| 241 | - _tzImagePickerVc.photoPreviewPageUIConfigBlock(_collectionView, _naviBar, _backButton, _selectButton, _indexLabel, _toolBar, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel); | |
| 242 | - } | |
| 243 | -} | |
| 244 | - | |
| 245 | -- (void)configCollectionView { | |
| 246 | - _layout = [[UICollectionViewFlowLayout alloc] init]; | |
| 247 | - _layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; | |
| 248 | - _collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:_layout]; | |
| 249 | - _collectionView.backgroundColor = [UIColor blackColor]; | |
| 250 | - _collectionView.dataSource = self; | |
| 251 | - _collectionView.delegate = self; | |
| 252 | - _collectionView.pagingEnabled = YES; | |
| 253 | - _collectionView.scrollsToTop = NO; | |
| 254 | - _collectionView.showsHorizontalScrollIndicator = NO; | |
| 255 | - _collectionView.contentOffset = CGPointMake(0, 0); | |
| 256 | - _collectionView.contentSize = CGSizeMake(self.models.count * (self.view.tz_width + 20), 0); | |
| 257 | - [self.view addSubview:_collectionView]; | |
| 258 | - [_collectionView registerClass:[TZPhotoPreviewCell class] forCellWithReuseIdentifier:@"TZPhotoPreviewCell"]; | |
| 259 | - [_collectionView registerClass:[TZVideoPreviewCell class] forCellWithReuseIdentifier:@"TZVideoPreviewCell"]; | |
| 260 | - [_collectionView registerClass:[TZGifPreviewCell class] forCellWithReuseIdentifier:@"TZGifPreviewCell"]; | |
| 261 | -} | |
| 262 | - | |
| 263 | -- (void)configCropView { | |
| 264 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 265 | - if (_tzImagePickerVc.maxImagesCount <= 1 && _tzImagePickerVc.allowCrop) { | |
| 266 | - [_cropView removeFromSuperview]; | |
| 267 | - [_cropBgView removeFromSuperview]; | |
| 268 | - | |
| 269 | - _cropBgView = [UIView new]; | |
| 270 | - _cropBgView.userInteractionEnabled = NO; | |
| 271 | - _cropBgView.frame = self.view.bounds; | |
| 272 | - _cropBgView.backgroundColor = [UIColor clearColor]; | |
| 273 | - [self.view addSubview:_cropBgView]; | |
| 274 | - [TZImageCropManager overlayClippingWithView:_cropBgView cropRect:_tzImagePickerVc.cropRect containerView:self.view needCircleCrop:_tzImagePickerVc.needCircleCrop]; | |
| 275 | - | |
| 276 | - _cropView = [UIView new]; | |
| 277 | - _cropView.userInteractionEnabled = NO; | |
| 278 | - _cropView.frame = _tzImagePickerVc.cropRect; | |
| 279 | - _cropView.backgroundColor = [UIColor clearColor]; | |
| 280 | - _cropView.layer.borderColor = [UIColor whiteColor].CGColor; | |
| 281 | - _cropView.layer.borderWidth = 1.0; | |
| 282 | - if (_tzImagePickerVc.needCircleCrop) { | |
| 283 | - _cropView.layer.cornerRadius = _tzImagePickerVc.cropRect.size.width / 2; | |
| 284 | - _cropView.clipsToBounds = YES; | |
| 285 | - } | |
| 286 | - [self.view addSubview:_cropView]; | |
| 287 | - if (_tzImagePickerVc.cropViewSettingBlock) { | |
| 288 | - _tzImagePickerVc.cropViewSettingBlock(_cropView); | |
| 289 | - } | |
| 290 | - | |
| 291 | - [self.view bringSubviewToFront:_naviBar]; | |
| 292 | - [self.view bringSubviewToFront:_tipBar]; | |
| 293 | - [self.view bringSubviewToFront:_toolBar]; | |
| 294 | - } | |
| 295 | -} | |
| 296 | - | |
| 297 | -#pragma mark - Layout | |
| 298 | - | |
| 299 | -- (void)viewDidLayoutSubviews { | |
| 300 | - [super viewDidLayoutSubviews]; | |
| 301 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 302 | - | |
| 303 | - CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight]; | |
| 304 | - CGFloat statusBarHeightInterval = statusBarHeight - 20; | |
| 305 | - CGFloat naviBarHeight = statusBarHeight + _tzImagePickerVc.navigationBar.tz_height; | |
| 306 | - _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight); | |
| 307 | - _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44); | |
| 308 | - _selectButton.frame = CGRectMake(self.view.tz_width - 56, 10 + statusBarHeightInterval, 44, 44); | |
| 309 | - _indexLabel.frame = _selectButton.frame; | |
| 310 | - _navBarLine.frame = CGRectMake(0, _naviBar.tz_height - 0.5, _naviBar.tz_width, 0.5); | |
| 311 | - | |
| 312 | - ///Lxg 提示视图约束 | |
| 313 | - CGFloat tipBarHeight = _tzImagePickerVc.navigationBar.tz_height; | |
| 314 | - _tipBar.frame = CGRectMake(0, _naviBar.tz_bottom, _naviBar.tz_width, tipBarHeight); | |
| 315 | - _tipContentLabel.frame = CGRectMake(12, 0, _tipBar.tz_width - 24, tipBarHeight); | |
| 316 | - | |
| 317 | - _layout.itemSize = CGSizeMake(self.view.tz_width + 20, self.view.tz_height); | |
| 318 | - _layout.minimumInteritemSpacing = 0; | |
| 319 | - _layout.minimumLineSpacing = 0; | |
| 320 | - _collectionView.frame = CGRectMake(-10, 0, self.view.tz_width + 20, self.view.tz_height); | |
| 321 | - [_collectionView setCollectionViewLayout:_layout]; | |
| 322 | - if (_offsetItemCount > 0) { | |
| 323 | - CGFloat offsetX = _offsetItemCount * _layout.itemSize.width; | |
| 324 | - [_collectionView setContentOffset:CGPointMake(offsetX, 0)]; | |
| 325 | - } | |
| 326 | - if (_tzImagePickerVc.allowCrop) { | |
| 327 | - [_collectionView reloadData]; | |
| 328 | - } | |
| 329 | - | |
| 330 | - CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44; | |
| 331 | - CGFloat toolBarTop = self.view.tz_height - toolBarHeight; | |
| 332 | - _toolBar.frame = CGRectMake(0, toolBarTop, self.view.tz_width, toolBarHeight); | |
| 333 | - if (_tzImagePickerVc.allowPickingOriginalPhoto) { | |
| 334 | - CGFloat fullImageWidth = [_tzImagePickerVc.fullImageBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width; | |
| 335 | - _originalPhotoButton.frame = CGRectMake(0, 0, fullImageWidth + 56, 44); | |
| 336 | - _originalPhotoLabel.frame = CGRectMake(fullImageWidth + 42, 0, 80, 44); | |
| 337 | - } | |
| 338 | - [_doneButton sizeToFit]; | |
| 339 | - _doneButton.frame = CGRectMake(self.view.tz_width - _doneButton.tz_width - 12, 0, _doneButton.tz_width, 44); | |
| 340 | - _numberImageView.frame = CGRectMake(_doneButton.tz_left - 24 - 5, 10, 24, 24); | |
| 341 | - _numberLabel.frame = _numberImageView.frame; | |
| 342 | - ///LXG | |
| 343 | - [_editTipButton sizeToFit]; | |
| 344 | - _editTipButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); | |
| 345 | - _editTipLable.frame = CGRectMake(12, 10, self.view.tz_width - 24 - _editTipButton.tz_width, 24); | |
| 346 | - | |
| 347 | - [self configCropView]; | |
| 348 | - | |
| 349 | - if (_tzImagePickerVc.photoPreviewPageDidLayoutSubviewsBlock) { | |
| 350 | - _tzImagePickerVc.photoPreviewPageDidLayoutSubviewsBlock(_collectionView, _naviBar, _backButton, _selectButton, _indexLabel, _toolBar, _originalPhotoButton, _originalPhotoLabel, _doneButton, _numberImageView, _numberLabel); | |
| 351 | - } | |
| 352 | -} | |
| 353 | - | |
| 354 | -#pragma mark - Notification | |
| 355 | - | |
| 356 | -- (void)didChangeStatusBarOrientationNotification:(NSNotification *)noti { | |
| 357 | - _offsetItemCount = _collectionView.contentOffset.x / _layout.itemSize.width; | |
| 358 | -} | |
| 359 | - | |
| 360 | -#pragma mark - Click Event | |
| 361 | - | |
| 362 | -- (void)select:(UIButton *)selectButton { | |
| 363 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 364 | - TZAssetModel *model = _models[_currentIndex]; | |
| 365 | - ///LXG:加入当点击选择时 滑动到另一个页面 选中为当前页面判断是否可选 | |
| 366 | - if (!selectButton.enabled) { | |
| 367 | - return; | |
| 368 | - } | |
| 369 | - | |
| 370 | - if (!selectButton.isSelected) { | |
| 371 | - // 1. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制 | |
| 372 | - if (_tzImagePickerVc.selectedModels.count >= _tzImagePickerVc.maxImagesCount) { | |
| 373 | - NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], _tzImagePickerVc.maxImagesCount]; | |
| 374 | - [_tzImagePickerVc showAlertWithTitle:title]; | |
| 375 | - return; | |
| 376 | - // 2. if not over the maxImagesCount / 如果没有超过最大个数限制 | |
| 377 | - } else { | |
| 378 | - [_tzImagePickerVc addSelectedModel:model]; | |
| 379 | - if (self.photos) { | |
| 380 | - [_tzImagePickerVc.selectedAssets addObject:_assetsTemp[_currentIndex]]; | |
| 381 | - [self.photos addObject:_photosTemp[_currentIndex]]; | |
| 382 | - } | |
| 383 | - if (model.type == TZAssetModelMediaTypeVideo && !_tzImagePickerVc.allowPickingMultipleVideo) { | |
| 384 | - [_tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Select the video when in multi state, we will handle the video as a photo"]]; | |
| 385 | - } | |
| 386 | - } | |
| 387 | - } else { | |
| 388 | - NSArray *selectedModels = [NSArray arrayWithArray:_tzImagePickerVc.selectedModels]; | |
| 389 | - for (TZAssetModel *model_item in selectedModels) { | |
| 390 | - if ([[[TZImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[TZImageManager manager] getAssetIdentifier:model_item.asset]]) { | |
| 391 | - // 1.6.7版本更新:防止有多个一样的model,一次性被移除了 | |
| 392 | - NSArray *selectedModelsTmp = [NSArray arrayWithArray:_tzImagePickerVc.selectedModels]; | |
| 393 | - for (NSInteger i = 0; i < selectedModelsTmp.count; i++) { | |
| 394 | - TZAssetModel *model = selectedModelsTmp[i]; | |
| 395 | - if ([model isEqual:model_item]) { | |
| 396 | - [_tzImagePickerVc removeSelectedModel:model]; | |
| 397 | - // [_tzImagePickerVc.selectedModels removeObjectAtIndex:i]; | |
| 398 | - break; | |
| 399 | - } | |
| 400 | - } | |
| 401 | - if (self.photos) { | |
| 402 | - // 1.6.7版本更新:防止有多个一样的asset,一次性被移除了 | |
| 403 | - NSArray *selectedAssetsTmp = [NSArray arrayWithArray:_tzImagePickerVc.selectedAssets]; | |
| 404 | - for (NSInteger i = 0; i < selectedAssetsTmp.count; i++) { | |
| 405 | - id asset = selectedAssetsTmp[i]; | |
| 406 | - if ([asset isEqual:_assetsTemp[_currentIndex]]) { | |
| 407 | - [_tzImagePickerVc.selectedAssets removeObjectAtIndex:i]; | |
| 408 | - break; | |
| 409 | - } | |
| 410 | - } | |
| 411 | - // [_tzImagePickerVc.selectedAssets removeObject:_assetsTemp[_currentIndex]]; | |
| 412 | - [self.photos removeObject:_photosTemp[_currentIndex]]; | |
| 413 | - } | |
| 414 | - break; | |
| 415 | - } | |
| 416 | - } | |
| 417 | - } | |
| 418 | - | |
| 419 | - model.isSelected = !selectButton.isSelected; | |
| 420 | - [self refreshNaviBarAndBottomBarState]; | |
| 421 | - if (model.isSelected) { | |
| 422 | - [UIView showOscillatoryAnimationWithLayer:selectButton.imageView.layer type:TZOscillatoryAnimationToBigger]; | |
| 423 | - } | |
| 424 | - [UIView showOscillatoryAnimationWithLayer:_numberImageView.layer type:TZOscillatoryAnimationToSmaller]; | |
| 425 | -} | |
| 426 | - | |
| 427 | -- (void)backButtonClick { | |
| 428 | - if (self.navigationController.childViewControllers.count < 2) { | |
| 429 | - [self.navigationController dismissViewControllerAnimated:YES completion:nil]; | |
| 430 | - if ([self.navigationController isKindOfClass: [TZImagePickerController class]]) { | |
| 431 | - TZImagePickerController *nav = (TZImagePickerController *)self.navigationController; | |
| 432 | - if (nav.imagePickerControllerDidCancelHandle) { | |
| 433 | - nav.imagePickerControllerDidCancelHandle(); | |
| 434 | - } | |
| 435 | - } | |
| 436 | - return; | |
| 437 | - } | |
| 438 | - [self.navigationController popViewControllerAnimated:YES]; | |
| 439 | - if (self.backButtonClickBlock) { | |
| 440 | - self.backButtonClickBlock(_isSelectOriginalPhoto); | |
| 441 | - } | |
| 442 | -} | |
| 443 | - | |
| 444 | -- (void)doneButtonClick { | |
| 445 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 446 | - // 如果图片正在从iCloud同步中,提醒用户 | |
| 447 | - if (_progress > 0 && _progress < 1 && (_selectButton.isSelected || !_tzImagePickerVc.selectedModels.count )) { | |
| 448 | - _alertView = [_tzImagePickerVc showAlertWithTitle:[NSBundle tz_localizedStringForKey:@"Synchronizing photos from iCloud"]]; | |
| 449 | - return; | |
| 450 | - } | |
| 451 | - | |
| 452 | - // 如果没有选中过照片 点击确定时选中当前预览的照片 | |
| 453 | - if (_tzImagePickerVc.selectedModels.count == 0 && _tzImagePickerVc.minImagesCount <= 0) { | |
| 454 | - TZAssetModel *model = _models[_currentIndex]; | |
| 455 | - [_tzImagePickerVc addSelectedModel:model]; | |
| 456 | - } | |
| 457 | - if (_tzImagePickerVc.allowCrop) { // 裁剪状态 | |
| 458 | - NSIndexPath *indexPath = [NSIndexPath indexPathForItem:_currentIndex inSection:0]; | |
| 459 | - TZPhotoPreviewCell *cell = (TZPhotoPreviewCell *)[_collectionView cellForItemAtIndexPath:indexPath]; | |
| 460 | - UIImage *cropedImage = [TZImageCropManager cropImageView:cell.previewView.imageView toRect:_tzImagePickerVc.cropRect zoomScale:cell.previewView.scrollView.zoomScale containerView:self.view]; | |
| 461 | - if (_tzImagePickerVc.needCircleCrop) { | |
| 462 | - cropedImage = [TZImageCropManager circularClipImage:cropedImage]; | |
| 463 | - } | |
| 464 | - if (self.doneButtonClickBlockCropMode) { | |
| 465 | - TZAssetModel *model = _models[_currentIndex]; | |
| 466 | - self.doneButtonClickBlockCropMode(cropedImage,model.asset); | |
| 467 | - } | |
| 468 | - } else if (self.doneButtonClickBlock) { // 非裁剪状态 | |
| 469 | - self.doneButtonClickBlock(_isSelectOriginalPhoto); | |
| 470 | - } | |
| 471 | - if (self.doneButtonClickBlockWithPreviewType) { | |
| 472 | - self.doneButtonClickBlockWithPreviewType(self.photos,_tzImagePickerVc.selectedAssets,self.isSelectOriginalPhoto); | |
| 473 | - } | |
| 474 | -} | |
| 475 | - | |
| 476 | -///lxg 编辑按钮实现 | |
| 477 | -- (void)editVideoButtonClick{ | |
| 478 | - | |
| 479 | - NSLog(@"开始编辑视频了"); | |
| 480 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 481 | - CNEditVideoController *editVideoVC = [[CNEditVideoController alloc]init]; | |
| 482 | - TZAssetModel *model = _models[_currentIndex]; | |
| 483 | - editVideoVC.model = model; | |
| 484 | - editVideoVC.models = _models; | |
| 485 | - editVideoVC.currentIndex = _currentIndex; | |
| 486 | - editVideoVC.isCropImage = _isCropImage; | |
| 487 | - __weak typeof(self) weakSelf = self; | |
| 488 | - | |
| 489 | - editVideoVC.doneButtonEditClickBlock = ^(BOOL isSelectOriginalPhoto) { | |
| 490 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 491 | - strongSelf.doneButtonClickBlock(isSelectOriginalPhoto); | |
| 492 | - | |
| 493 | - }; | |
| 494 | - | |
| 495 | - [_tzImagePickerVc pushViewController:editVideoVC animated:NO]; | |
| 496 | -} | |
| 497 | - | |
| 498 | -- (void)originalPhotoButtonClick { | |
| 499 | - _originalPhotoButton.selected = !_originalPhotoButton.isSelected; | |
| 500 | - _isSelectOriginalPhoto = _originalPhotoButton.isSelected; | |
| 501 | - _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected; | |
| 502 | - if (_isSelectOriginalPhoto) { | |
| 503 | - [self showPhotoBytes]; | |
| 504 | - if (!_selectButton.isSelected) { | |
| 505 | - // 如果当前已选择照片张数 < 最大可选张数 && 最大可选张数大于1,就选中该张图 | |
| 506 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 507 | - if (_tzImagePickerVc.selectedModels.count < _tzImagePickerVc.maxImagesCount && _tzImagePickerVc.showSelectBtn) { | |
| 508 | - [self select:_selectButton]; | |
| 509 | - } | |
| 510 | - } | |
| 511 | - } | |
| 512 | -} | |
| 513 | - | |
| 514 | -- (void)didTapPreviewCell { | |
| 515 | - self.isHideNaviBar = !self.isHideNaviBar; | |
| 516 | - _naviBar.hidden = self.isHideNaviBar; | |
| 517 | - _toolBar.hidden = self.isHideNaviBar; | |
| 518 | - | |
| 519 | - if (_naviBar.hidden && _toolBar.hidden) { | |
| 520 | - _tipBar.hidden = YES; | |
| 521 | - }else{ | |
| 522 | - [self refreshNaviBarAndBottomBarState]; | |
| 523 | - } | |
| 524 | - | |
| 525 | -} | |
| 526 | - | |
| 527 | -#pragma mark - UIScrollViewDelegate | |
| 528 | - | |
| 529 | -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { | |
| 530 | - CGFloat offSetWidth = scrollView.contentOffset.x; | |
| 531 | - offSetWidth = offSetWidth + ((self.view.tz_width + 20) * 0.5); | |
| 532 | - | |
| 533 | - NSInteger currentIndex = offSetWidth / (self.view.tz_width + 20); | |
| 534 | - | |
| 535 | - if (currentIndex < _models.count && _currentIndex != currentIndex) { | |
| 536 | - _currentIndex = currentIndex; | |
| 537 | - [self refreshNaviBarAndBottomBarState]; | |
| 538 | - } | |
| 539 | - | |
| 540 | - [[NSNotificationCenter defaultCenter] postNotificationName:@"photoPreviewCollectionViewDidScroll" object:nil]; | |
| 541 | -} | |
| 542 | - | |
| 543 | -#pragma mark - UICollectionViewDataSource && Delegate | |
| 544 | - | |
| 545 | -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { | |
| 546 | - return _models.count; | |
| 547 | -} | |
| 548 | - | |
| 549 | -- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { | |
| 550 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 551 | - TZAssetModel *model = _models[indexPath.item]; | |
| 552 | - | |
| 553 | - TZAssetPreviewCell *cell; | |
| 554 | - __weak typeof(self) weakSelf = self; | |
| 555 | -#pragma mark - 更改视频,GIF,显示 | |
| 556 | - if (model.type == TZAssetModelMediaTypeVideo) { | |
| 557 | - cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZVideoPreviewCell" forIndexPath:indexPath]; | |
| 558 | - } else if (model.type == TZAssetModelMediaTypePhotoGif && _tzImagePickerVc.allowPickingGif) { | |
| 559 | - cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZGifPreviewCell" forIndexPath:indexPath]; | |
| 560 | - } else { | |
| 561 | - cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"TZPhotoPreviewCell" forIndexPath:indexPath]; | |
| 562 | - TZPhotoPreviewCell *photoPreviewCell = (TZPhotoPreviewCell *)cell; | |
| 563 | - photoPreviewCell.cropRect = _tzImagePickerVc.cropRect; | |
| 564 | - photoPreviewCell.allowCrop = _tzImagePickerVc.allowCrop; | |
| 565 | - __weak typeof(_tzImagePickerVc) weakTzImagePickerVc = _tzImagePickerVc; | |
| 566 | - __weak typeof(_collectionView) weakCollectionView = _collectionView; | |
| 567 | - __weak typeof(photoPreviewCell) weakCell = photoPreviewCell; | |
| 568 | - [photoPreviewCell setImageProgressUpdateBlock:^(double progress) { | |
| 569 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 570 | - __strong typeof(weakTzImagePickerVc) strongTzImagePickerVc = weakTzImagePickerVc; | |
| 571 | - __strong typeof(weakCollectionView) strongCollectionView = weakCollectionView; | |
| 572 | - __strong typeof(weakCell) strongCell = weakCell; | |
| 573 | - strongSelf.progress = progress; | |
| 574 | - if (progress >= 1) { | |
| 575 | - if (strongSelf.isSelectOriginalPhoto) [strongSelf showPhotoBytes]; | |
| 576 | - if (strongSelf.alertView && [strongCollectionView.visibleCells containsObject:strongCell]) { | |
| 577 | - [strongTzImagePickerVc hideAlertView:strongSelf.alertView]; | |
| 578 | - strongSelf.alertView = nil; | |
| 579 | - [strongSelf doneButtonClick]; | |
| 580 | - } | |
| 581 | - } | |
| 582 | - }]; | |
| 583 | - } | |
| 584 | - | |
| 585 | - cell.model = model; | |
| 586 | - [cell setSingleTapGestureBlock:^{ | |
| 587 | - __strong typeof(weakSelf) strongSelf = weakSelf; | |
| 588 | - [strongSelf didTapPreviewCell]; | |
| 589 | - }]; | |
| 590 | - return cell; | |
| 591 | -} | |
| 592 | - | |
| 593 | -- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { | |
| 594 | - if ([cell isKindOfClass:[TZPhotoPreviewCell class]]) { | |
| 595 | - [(TZPhotoPreviewCell *)cell recoverSubviews]; | |
| 596 | - } | |
| 597 | -} | |
| 598 | - | |
| 599 | -- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath { | |
| 600 | - if ([cell isKindOfClass:[TZPhotoPreviewCell class]]) { | |
| 601 | - [(TZPhotoPreviewCell *)cell recoverSubviews]; | |
| 602 | - } else if ([cell isKindOfClass:[TZVideoPreviewCell class]]) { | |
| 603 | - [(TZVideoPreviewCell *)cell pausePlayerAndShowNaviBar]; | |
| 604 | - } | |
| 605 | -} | |
| 606 | - | |
| 607 | -#pragma mark - Private Method | |
| 608 | - | |
| 609 | -- (void)dealloc { | |
| 610 | - // NSLog(@"%@ dealloc",NSStringFromClass(self.class)); | |
| 611 | -} | |
| 612 | - | |
| 613 | -- (void)refreshNaviBarAndBottomBarState { | |
| 614 | - | |
| 615 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 616 | - TZAssetModel *model = _models[_currentIndex]; | |
| 617 | - _selectButton.selected = model.isSelected; | |
| 618 | - [self refreshSelectButtonImageViewContentMode]; | |
| 619 | - if (_selectButton.isSelected && _tzImagePickerVc.showSelectedIndex && _tzImagePickerVc.showSelectBtn) { | |
| 620 | - NSString *assetId = [[TZImageManager manager] getAssetIdentifier:model.asset]; | |
| 621 | - NSString *index = [NSString stringWithFormat:@"%zd", [_tzImagePickerVc.selectedAssetIds indexOfObject:assetId] + 1]; | |
| 622 | - _indexLabel.text = index; | |
| 623 | - _indexLabel.hidden = NO; | |
| 624 | - } else { | |
| 625 | - _indexLabel.hidden = YES; | |
| 626 | - } | |
| 627 | - _numberLabel.text = [NSString stringWithFormat:@"%zd",_tzImagePickerVc.selectedModels.count]; | |
| 628 | - _numberImageView.hidden = (_tzImagePickerVc.selectedModels.count <= 0 || _isHideNaviBar || _isCropImage); | |
| 629 | - _numberLabel.hidden = (_tzImagePickerVc.selectedModels.count <= 0 || _isHideNaviBar || _isCropImage); | |
| 630 | -#pragma mark - ADD: 选择图片个数显示(LXG) | |
| 631 | - //隐藏图标 | |
| 632 | - _numberLabel.hidden = YES; | |
| 633 | - _numberImageView.hidden = YES; | |
| 634 | - NSString *titleStr = _tzImagePickerVc.selectedModels.count > 0 ? [NSString stringWithFormat:@"完成(%zd)",_tzImagePickerVc.selectedModels.count] : @"完成"; | |
| 635 | - [_doneButton setTitle:titleStr forState:UIControlStateNormal]; | |
| 636 | - _originalPhotoButton.selected = _isSelectOriginalPhoto; | |
| 637 | - _originalPhotoLabel.hidden = !_originalPhotoButton.isSelected; | |
| 638 | - if (_isSelectOriginalPhoto) [self showPhotoBytes]; | |
| 639 | - | |
| 640 | - // If is previewing video, hide original photo button | |
| 641 | - // 如果正在预览的是视频,隐藏原图按钮 | |
| 642 | - if (!_isHideNaviBar) { | |
| 643 | - if (model.type == TZAssetModelMediaTypeVideo) { | |
| 644 | - _originalPhotoButton.hidden = YES; | |
| 645 | - _originalPhotoLabel.hidden = YES; | |
| 646 | - } else { | |
| 647 | - _originalPhotoButton.hidden = NO; | |
| 648 | - if (_isSelectOriginalPhoto) _originalPhotoLabel.hidden = NO; | |
| 649 | - } | |
| 650 | - } | |
| 651 | - | |
| 652 | - _doneButton.hidden = NO; | |
| 653 | - _selectButton.hidden = !_tzImagePickerVc.showSelectBtn; | |
| 654 | - // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中 | |
| 655 | - if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) { | |
| 656 | - _numberLabel.hidden = YES; | |
| 657 | - _numberImageView.hidden = YES; | |
| 658 | - _selectButton.hidden = YES; | |
| 659 | - _originalPhotoButton.hidden = YES; | |
| 660 | - _originalPhotoLabel.hidden = YES; | |
| 661 | - _doneButton.hidden = YES; | |
| 662 | - } | |
| 663 | - | |
| 664 | -#pragma mark - ADD: 视频显示操作(LXG) | |
| 665 | - //多选状态下**不允许**图片和视频混选 | |
| 666 | - if (!_tzImagePickerVc.allowPickingMultipleVideo) { | |
| 667 | - | |
| 668 | - if (model.type == TZAssetModelMediaTypeVideo) {//多选状态下**不允许**图片和视频混选 -> 视频 | |
| 669 | - | |
| 670 | - TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 671 | - if (_tzImagePickerVc.selectedModels.count > 0) {//当选择图片大于0时 | |
| 672 | - TZAssetModel *model = _tzImagePickerVc.selectedModels[0]; | |
| 673 | - if (model.type == TZAssetModelMediaTypePhoto | |
| 674 | - || model.type == TZAssetModelMediaTypePhotoGif | |
| 675 | - ||model.type == TZAssetModelMediaTypeLivePhoto) {//选择为图片时 | |
| 676 | - | |
| 677 | - _selectButton.hidden = YES; | |
| 678 | - _selectButton.enabled = NO; | |
| 679 | - _navBarLine.hidden = NO; | |
| 680 | - _tipBar.hidden = NO; | |
| 681 | - _tipContentLabel.text = @"选择照片时不能选择视频"; | |
| 682 | - _doneButton.hidden = NO; | |
| 683 | - _doneButton.enabled = YES; | |
| 684 | - _editTipButton.hidden = YES; | |
| 685 | - _editTipLable.hidden = YES; | |
| 686 | - | |
| 687 | - }else{//未来可能是语音 | |
| 688 | - | |
| 689 | - _selectButton.hidden = YES; | |
| 690 | - _selectButton.enabled = NO; | |
| 691 | - _navBarLine.hidden = NO; | |
| 692 | - _tipBar.hidden = NO; | |
| 693 | - _tipContentLabel.text = @"选择照片时不能选择音频"; | |
| 694 | - _doneButton.hidden = NO; | |
| 695 | - _doneButton.enabled = YES; | |
| 696 | - _editTipButton.hidden = YES; | |
| 697 | - _editTipLable.hidden = YES; | |
| 698 | - | |
| 699 | - } | |
| 700 | - }else{//当选择图片==0时 | |
| 701 | - | |
| 702 | - NSTimeInterval duration = 0.0; | |
| 703 | - if ([model.asset isKindOfClass:[PHAsset class]]) { | |
| 704 | - PHAsset *asset = model.asset; | |
| 705 | - duration = asset.duration; | |
| 706 | - }else if ([model.asset isKindOfClass:[ALAsset class]]){ | |
| 707 | - duration = [[model.asset valueForProperty:ALAssetPropertyDuration] doubleValue]; | |
| 708 | - } | |
| 709 | - | |
| 710 | - if (duration > _tzImagePickerVc.maxVideoDuration) {//视频长度>最大限制长度 | |
| 711 | - | |
| 712 | - NSInteger minutes = _tzImagePickerVc.maxVideoDuration / 60; | |
| 713 | - NSInteger seconds = _tzImagePickerVc.maxVideoDuration % 60; | |
| 714 | - NSString *timeStr = [NSString string]; | |
| 715 | - if (minutes == 0) { | |
| 716 | - timeStr = [NSString stringWithFormat:@"不能分享超过%li秒视频",(long)seconds]; | |
| 717 | - }else if (seconds == 0){ | |
| 718 | - timeStr = [NSString stringWithFormat:@"不能分享超过%li分视频",(long)minutes]; | |
| 719 | - }else{ | |
| 720 | - timeStr = [NSString stringWithFormat:@"不能分享超过%li分%li秒视频",(long)minutes,(long)seconds]; | |
| 721 | - } | |
| 722 | - _tipContentLabel.text = timeStr; | |
| 723 | - | |
| 724 | - //当选择图片==0时,视频长度>最大限制长度 | |
| 725 | - _selectButton.hidden = YES; | |
| 726 | - _selectButton.enabled = NO; | |
| 727 | - _navBarLine.hidden = NO; | |
| 728 | - _tipBar.hidden = NO; | |
| 729 | - _tipContentLabel.text = timeStr; | |
| 730 | - _doneButton.hidden = NO; | |
| 731 | - if (_tzImagePickerVc.selectedModels.count > 0) { | |
| 732 | - _doneButton.enabled = YES; | |
| 733 | - }else{ | |
| 734 | - _doneButton.enabled = NO; | |
| 735 | - } | |
| 736 | - _editTipButton.hidden = YES; | |
| 737 | - _editTipLable.hidden = YES; | |
| 738 | - | |
| 739 | - }else if(duration <= _tzImagePickerVc.maxVideoDuration && duration > _tzImagePickerVc.maxEditVideoTime){//视频长度<=最大限制长度,视频长度>=最小限制长度 | |
| 740 | - | |
| 741 | - NSInteger minutes = _tzImagePickerVc.maxEditVideoTime / 60; | |
| 742 | - NSInteger seconds = _tzImagePickerVc.maxEditVideoTime % 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 | - _editTipLable.text = timeStr; | |
| 752 | - //当选择图片==0时,视频长度<=最大限制长度,视频长度>最大分享长度 | |
| 753 | - _selectButton.hidden = YES; | |
| 754 | - _selectButton.enabled = NO; | |
| 755 | - _navBarLine.hidden = YES; | |
| 756 | - _tipBar.hidden = YES; | |
| 757 | - _tipContentLabel.text = timeStr; | |
| 758 | - _doneButton.hidden = YES; | |
| 759 | - _doneButton.enabled = YES; | |
| 760 | - _editTipButton.hidden = NO; | |
| 761 | - _editTipLable.hidden = NO; | |
| 762 | - | |
| 763 | - }else{//视频长度<=最大分享长度 | |
| 764 | - //当选择图片==0时,视频长度<=最大分享长度 | |
| 765 | - _selectButton.hidden = YES; | |
| 766 | - _selectButton.enabled = NO; | |
| 767 | - _navBarLine.hidden = YES; | |
| 768 | - _tipBar.hidden = YES; | |
| 769 | - _doneButton.hidden = NO; | |
| 770 | - _doneButton.enabled = YES; | |
| 771 | - _editTipButton.hidden = YES; | |
| 772 | - _editTipLable.hidden = YES; | |
| 773 | - } | |
| 774 | - } | |
| 775 | - | |
| 776 | - } else {//滑动到不是视频时 | |
| 777 | - //滑动到不是视频时 | |
| 778 | - _selectButton.hidden = NO; | |
| 779 | - _selectButton.enabled = YES; | |
| 780 | - _navBarLine.hidden = YES; | |
| 781 | - _tipBar.hidden = YES; | |
| 782 | - _doneButton.hidden = NO; | |
| 783 | - _doneButton.enabled = YES; | |
| 784 | - _editTipButton.hidden = YES; | |
| 785 | - _editTipLable.hidden = YES; | |
| 786 | - | |
| 787 | - } | |
| 788 | - }else{///多选状态下**允许**图片和视频混选(lxg) | |
| 789 | - NSTimeInterval duration = 0.0; | |
| 790 | - if ([model.asset isKindOfClass:[PHAsset class]]) { | |
| 791 | - PHAsset *asset = model.asset; | |
| 792 | - duration = asset.duration; | |
| 793 | - }else if([model.asset isKindOfClass:[ALAsset class]]) { | |
| 794 | - duration = [[model.asset valueForProperty:ALAssetPropertyDuration] doubleValue]; | |
| 795 | - } | |
| 796 | - if (model.type == TZAssetModelMediaTypeVideo | |
| 797 | - && duration > _tzImagePickerVc.maxVideoDuration) {//视频,支持混选,时长超过最大时长限制 | |
| 798 | - NSInteger minutes = _tzImagePickerVc.maxVideoDuration / 60; | |
| 799 | - NSInteger seconds = _tzImagePickerVc.maxVideoDuration % 60; | |
| 800 | - NSString *timeStr = [NSString string]; | |
| 801 | - if (minutes == 0) { | |
| 802 | - timeStr = [NSString stringWithFormat:@"不能选择超过%li秒视频",(long)seconds]; | |
| 803 | - }else if (seconds == 0){ | |
| 804 | - timeStr = [NSString stringWithFormat:@"不能选择超过%li分视频",(long)minutes]; | |
| 805 | - }else{ | |
| 806 | - timeStr = [NSString stringWithFormat:@"不能选择超过%li分%li秒视频",(long)minutes,(long)seconds]; | |
| 807 | - } | |
| 808 | - | |
| 809 | - _selectButton.hidden = YES; | |
| 810 | - _selectButton.enabled = NO; | |
| 811 | - _selectButton.enabled = NO; | |
| 812 | - _navBarLine.hidden = NO; | |
| 813 | - _tipBar.hidden = NO; | |
| 814 | - _tipContentLabel.text = timeStr; | |
| 815 | - _doneButton.hidden = NO; | |
| 816 | - if (_tzImagePickerVc.selectedModels.count > 0) { | |
| 817 | - _doneButton.enabled = YES; | |
| 818 | - }else{ | |
| 819 | - _doneButton.enabled = NO; | |
| 820 | - } | |
| 821 | - _editTipButton.hidden = YES; | |
| 822 | - _editTipLable.hidden = YES; | |
| 823 | - | |
| 824 | - | |
| 825 | - }else{///多选状态下**允许**图片和视频混选(lxg) - 不是视频 || 视频<= _tzImagePickerVc.maxVideoDuration 最大时长限制 | |
| 826 | - | |
| 827 | - _selectButton.hidden = NO; | |
| 828 | - _selectButton.enabled = YES; | |
| 829 | - _navBarLine.hidden = YES; | |
| 830 | - _tipBar.hidden = YES; | |
| 831 | - _doneButton.hidden = NO; | |
| 832 | - _doneButton.enabled = YES; | |
| 833 | - _editTipButton.hidden = YES; | |
| 834 | - _editTipLable.hidden = YES; | |
| 835 | - | |
| 836 | - } | |
| 837 | - } | |
| 838 | - | |
| 839 | -} | |
| 840 | - | |
| 841 | -- (void)refreshSelectButtonImageViewContentMode { | |
| 842 | - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |
| 843 | - if (self->_selectButton.imageView.image.size.width <= 27) { | |
| 844 | - self->_selectButton.imageView.contentMode = UIViewContentModeCenter; | |
| 845 | - } else { | |
| 846 | - self->_selectButton.imageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 847 | - } | |
| 848 | - }); | |
| 849 | -} | |
| 850 | - | |
| 851 | -- (void)showPhotoBytes { | |
| 852 | - [[TZImageManager manager] getPhotosBytesWithArray:@[_models[_currentIndex]] completion:^(NSString *totalBytes) { | |
| 853 | - self->_originalPhotoLabel.text = [NSString stringWithFormat:@"(%@)",totalBytes]; | |
| 854 | - }]; | |
| 855 | -} | |
| 856 | - | |
| 857 | -@end |
CNLiveImagePickerController/TZProgressView.h deleted
100755 → 0
| 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/TZProgressView.m deleted
100755 → 0
| 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/TZVideoPlayerController.h deleted
100755 → 0
| 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, strong) TZAssetModel *model; | |
| 15 | -///其他进入和相册进入(lxg) | |
| 16 | -@property (nonatomic, assign) BOOL isOther; | |
| 17 | - | |
| 18 | -@end |
CNLiveImagePickerController/TZVideoPlayerController.m deleted
100755 → 0
| 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+Layout.h" | |
| 12 | -#import "TZImageManager.h" | |
| 13 | -#import "TZAssetModel.h" | |
| 14 | -#import "TZImagePickerController.h" | |
| 15 | -#import "TZPhotoPreviewController.h" | |
| 16 | - | |
| 17 | -@interface TZVideoPlayerController () { | |
| 18 | - AVPlayer *_player; | |
| 19 | - AVPlayerLayer *_playerLayer; | |
| 20 | - UIButton *_playButton; | |
| 21 | - UIImage *_cover; | |
| 22 | - ///LXG nav属性 | |
| 23 | - UIView *_naviBar; | |
| 24 | - UIButton *_backButton; | |
| 25 | - | |
| 26 | - UIView *_toolBar; | |
| 27 | - UIButton *_doneButton; | |
| 28 | - UIProgressView *_progress; | |
| 29 | - | |
| 30 | - UIStatusBarStyle _originStatusBarStyle; | |
| 31 | -} | |
| 32 | -@property (assign, nonatomic) BOOL needShowStatusBar; | |
| 33 | -@end | |
| 34 | - | |
| 35 | -#pragma clang diagnostic push | |
| 36 | -#pragma clang diagnostic ignored "-Wdeprecated-declarations" | |
| 37 | - | |
| 38 | -@implementation TZVideoPlayerController | |
| 39 | - | |
| 40 | -- (void)viewDidLoad { | |
| 41 | - [super viewDidLoad]; | |
| 42 | - ///LXG 注释 | |
| 43 | -// self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden; | |
| 44 | - self.view.backgroundColor = [UIColor blackColor]; | |
| 45 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 46 | - if (tzImagePickerVc) { | |
| 47 | - self.navigationItem.title = tzImagePickerVc.previewBtnTitleStr; | |
| 48 | - } | |
| 49 | - [self configMoviePlayer]; | |
| 50 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil]; | |
| 51 | -} | |
| 52 | -#pragma mark - ADD: 导航栏(LXG) | |
| 53 | -- (void)viewWillAppear:(BOOL)animated { | |
| 54 | - [super viewWillAppear:animated]; | |
| 55 | - _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; | |
| 56 | - ///LXG 导航栏隐藏 | |
| 57 | - [UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque; | |
| 58 | - [self.navigationController setNavigationBarHidden:YES animated:YES]; | |
| 59 | - if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES; | |
| 60 | -} | |
| 61 | - | |
| 62 | -- (void)viewWillDisappear:(BOOL)animated { | |
| 63 | - [super viewWillDisappear:animated]; | |
| 64 | - ///LXG 导航栏显示 | |
| 65 | - [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; | |
| 66 | - [self.navigationController setNavigationBarHidden:NO animated:YES]; | |
| 67 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 68 | - if (tzImagePickerVc.needShowStatusBar && iOS7Later) { | |
| 69 | - [UIApplication sharedApplication].statusBarHidden = NO; | |
| 70 | - } | |
| 71 | - [TZImageManager manager].shouldFixOrientation = NO; | |
| 72 | -} | |
| 73 | -///LXG iOS7之后使用 | |
| 74 | -- (BOOL)prefersStatusBarHidden { | |
| 75 | - return YES; | |
| 76 | -} | |
| 77 | - | |
| 78 | -- (void)configMoviePlayer { | |
| 79 | - [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { | |
| 80 | - if (!isDegraded && photo) { | |
| 81 | - self->_cover = photo; | |
| 82 | - self->_doneButton.enabled = YES; | |
| 83 | - } | |
| 84 | - }]; | |
| 85 | - [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) { | |
| 86 | - dispatch_async(dispatch_get_main_queue(), ^{ | |
| 87 | - self->_player = [AVPlayer playerWithPlayerItem:playerItem]; | |
| 88 | - self->_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self->_player]; | |
| 89 | - self->_playerLayer.frame = self.view.bounds; | |
| 90 | - [self.view.layer addSublayer:self->_playerLayer]; | |
| 91 | - [self addProgressObserver]; | |
| 92 | - [self configCustomNaviBar]; | |
| 93 | - [self configPlayButton]; | |
| 94 | - [self configBottomToolBar]; | |
| 95 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem]; | |
| 96 | - }); | |
| 97 | - }]; | |
| 98 | -} | |
| 99 | - | |
| 100 | -/// Show progress,do it next time / 给播放器添加进度更新,下次加上 | |
| 101 | -- (void)addProgressObserver{ | |
| 102 | - AVPlayerItem *playerItem = _player.currentItem; | |
| 103 | - UIProgressView *progress = _progress; | |
| 104 | - [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { | |
| 105 | - float current = CMTimeGetSeconds(time); | |
| 106 | - float total = CMTimeGetSeconds([playerItem duration]); | |
| 107 | - if (current) { | |
| 108 | - [progress setProgress:(current/total) animated:YES]; | |
| 109 | - } | |
| 110 | - }]; | |
| 111 | -} | |
| 112 | - | |
| 113 | -- (void)configPlayButton { | |
| 114 | - _playButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 115 | - [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal]; | |
| 116 | - [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted]; | |
| 117 | - [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 118 | - [self.view addSubview:_playButton]; | |
| 119 | -} | |
| 120 | -///XLG 自定义NAV | |
| 121 | -- (void)configCustomNaviBar { | |
| 122 | - | |
| 123 | - _naviBar = [[UIView alloc] initWithFrame:CGRectZero]; | |
| 124 | - _naviBar.backgroundColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:0.7]; | |
| 125 | - | |
| 126 | - _backButton = [[UIButton alloc] initWithFrame:CGRectZero]; | |
| 127 | - [_backButton setImage:[UIImage imageNamedFromMyBundle:@"navi_back"] forState:UIControlStateNormal]; | |
| 128 | - [_backButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
| 129 | - [_backButton addTarget:self action:@selector(backButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 130 | - | |
| 131 | - [_naviBar addSubview:_backButton]; | |
| 132 | - [self.view addSubview:_naviBar]; | |
| 133 | -} | |
| 134 | - | |
| 135 | - | |
| 136 | - | |
| 137 | -- (void)configBottomToolBar { | |
| 138 | - _toolBar = [[UIView alloc] initWithFrame:CGRectZero]; | |
| 139 | - CGFloat rgb = 34 / 255.0; | |
| 140 | - _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; | |
| 141 | - | |
| 142 | - _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 143 | - _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; | |
| 144 | - if (!_cover) { | |
| 145 | - _doneButton.enabled = NO; | |
| 146 | - } | |
| 147 | - [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; | |
| 148 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 149 | - if (tzImagePickerVc) { | |
| 150 | - [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; | |
| 151 | - [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; | |
| 152 | - } else { | |
| 153 | - [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal]; | |
| 154 | - [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal]; | |
| 155 | - } | |
| 156 | - [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled]; | |
| 157 | - [_toolBar addSubview:_doneButton]; | |
| 158 | - [self.view addSubview:_toolBar]; | |
| 159 | - | |
| 160 | - if (tzImagePickerVc.videoPreviewPageUIConfigBlock) { | |
| 161 | - tzImagePickerVc.videoPreviewPageUIConfigBlock(_playButton, _toolBar, _doneButton); | |
| 162 | - } | |
| 163 | -} | |
| 164 | - | |
| 165 | -#pragma mark - Layout | |
| 166 | - | |
| 167 | -- (void)viewDidLayoutSubviews { | |
| 168 | - [super viewDidLayoutSubviews]; | |
| 169 | - | |
| 170 | - CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight]; | |
| 171 | - CGFloat statusBarAndNaviBarHeight = statusBarHeight + self.navigationController.navigationBar.tz_height; | |
| 172 | - _playerLayer.frame = self.view.bounds; | |
| 173 | - CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44; | |
| 174 | - _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight); | |
| 175 | - _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); | |
| 176 | - _playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight); | |
| 177 | - | |
| 178 | - TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 179 | - ///LXG NAV布局 | |
| 180 | - if (_isOther) { | |
| 181 | - CGFloat statusBarHeightInterval = statusBarHeight - 20; | |
| 182 | - CGFloat naviBarHeight = statusBarHeight + 44; | |
| 183 | - _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight); | |
| 184 | - _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44); | |
| 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:RGBOF(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 | - CGRect frame = _toolBar.frame; | |
| 199 | - _doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30); | |
| 200 | - | |
| 201 | - }else{ | |
| 202 | - CGFloat statusBarHeightInterval = statusBarHeight - 20; | |
| 203 | - CGFloat naviBarHeight = statusBarHeight + tzImagePickerVc.navigationBar.tz_height; | |
| 204 | - _naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight); | |
| 205 | - _backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44); | |
| 206 | - } | |
| 207 | - [self.view bringSubviewToFront:_naviBar]; | |
| 208 | - if (tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock) { | |
| 209 | - tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock(_playButton, _toolBar, _doneButton); | |
| 210 | - } | |
| 211 | -} | |
| 212 | - | |
| 213 | -#pragma mark - Click Event | |
| 214 | - | |
| 215 | -- (void)playButtonClick { | |
| 216 | - CMTime currentTime = _player.currentItem.currentTime; | |
| 217 | - CMTime durationTime = _player.currentItem.duration; | |
| 218 | - if (_player.rate == 0.0f) { | |
| 219 | - if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; | |
| 220 | - [_player play]; | |
| 221 | - [self.navigationController setNavigationBarHidden:YES]; | |
| 222 | - _toolBar.hidden = YES; | |
| 223 | - ///LXG 隐藏NAV | |
| 224 | - _naviBar.hidden = YES; | |
| 225 | - [_playButton setImage:nil forState:UIControlStateNormal]; | |
| 226 | - if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES; | |
| 227 | - } else { | |
| 228 | - [self pausePlayerAndShowNaviBar]; | |
| 229 | - } | |
| 230 | -} | |
| 231 | - | |
| 232 | -- (void)doneButtonClick { | |
| 233 | - if (self.navigationController) { | |
| 234 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 235 | - if (imagePickerVc.autoDismiss) { | |
| 236 | - [self.navigationController dismissViewControllerAnimated:YES completion:^{ | |
| 237 | - [self callDelegateMethod]; | |
| 238 | - }]; | |
| 239 | - } else { | |
| 240 | - [self callDelegateMethod]; | |
| 241 | - } | |
| 242 | - } else { | |
| 243 | - [self dismissViewControllerAnimated:YES completion:^{ | |
| 244 | - [self callDelegateMethod]; | |
| 245 | - }]; | |
| 246 | - } | |
| 247 | -} | |
| 248 | - | |
| 249 | -- (void)callDelegateMethod { | |
| 250 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 251 | - if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) { | |
| 252 | - [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset]; | |
| 253 | - } | |
| 254 | - if (imagePickerVc.didFinishPickingVideoHandle) { | |
| 255 | - imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset); | |
| 256 | - } | |
| 257 | -} | |
| 258 | - | |
| 259 | -///LXG 返回实现 | |
| 260 | -- (void)backButtonClick { | |
| 261 | - if (self.navigationController) { | |
| 262 | - TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; | |
| 263 | - [imagePickerVc popViewControllerAnimated:YES]; | |
| 264 | - } else { | |
| 265 | - [self dismissViewControllerAnimated:YES completion:^{ | |
| 266 | - | |
| 267 | - }]; | |
| 268 | - } | |
| 269 | -} | |
| 270 | - | |
| 271 | - | |
| 272 | -#pragma mark - Notification Method | |
| 273 | - | |
| 274 | -- (void)pausePlayerAndShowNaviBar { | |
| 275 | - [_player pause]; | |
| 276 | - _toolBar.hidden = NO; | |
| 277 | - _naviBar.hidden = NO; | |
| 278 | -// [self.navigationController setNavigationBarHidden:NO]; | |
| 279 | - [_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal]; | |
| 280 | - ///LXG 注释 | |
| 281 | -// if (self.needShowStatusBar && iOS7Later) { | |
| 282 | -// [UIApplication sharedApplication].statusBarHidden = NO; | |
| 283 | -// } | |
| 284 | -} | |
| 285 | - | |
| 286 | -- (void)dealloc { | |
| 287 | - [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 288 | -} | |
| 289 | - | |
| 290 | -#pragma clang diagnostic pop | |
| 291 | - | |
| 292 | -@end |
CNLiveImagePickerController/UIImage+CNImagePicker.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// UIImage+CNImagePicker.h | |
| 3 | -// CNLiveImagePickerControllerExample | |
| 4 | -// | |
| 5 | -// Created by 梁星国 on 2018/10/25. | |
| 6 | -// Copyright © 2018年 梁星国. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface UIImage (CNImagePicker) | |
| 14 | - | |
| 15 | - | |
| 16 | -/** | |
| 17 | - 颜色t转图片 | |
| 18 | - | |
| 19 | - @param color 颜色 | |
| 20 | - @return 返回f图片 | |
| 21 | - */ | |
| 22 | -+ (UIImage *)ip_imageWithColor:(UIColor *)color; | |
| 23 | - | |
| 24 | -/** | |
| 25 | - 颜色转图片 | |
| 26 | - | |
| 27 | - @param color 颜色 | |
| 28 | - @param size 大小 | |
| 29 | - @param radius 圆角 | |
| 30 | - @return 返回图片 | |
| 31 | - */ | |
| 32 | -+ (UIImage *)ip_imageWithColor:(UIColor *)color size:(CGSize)size radius:(CGFloat)radius; | |
| 33 | - | |
| 34 | - | |
| 35 | - | |
| 36 | -@end | |
| 37 | - | |
| 38 | -NS_ASSUME_NONNULL_END |
CNLiveImagePickerController/UIImage+CNImagePicker.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// UIImage+CNImagePicker.m | |
| 3 | -// CNLiveImagePickerControllerExample | |
| 4 | -// | |
| 5 | -// Created by 梁星国 on 2018/10/25. | |
| 6 | -// Copyright © 2018年 梁星国. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "UIImage+CNImagePicker.h" | |
| 10 | - | |
| 11 | -@implementation UIImage (CNImagePicker) | |
| 12 | - | |
| 13 | -+ (UIImage *)ip_imageWithColor:(UIColor *)color { | |
| 14 | - return [UIImage ip_imageWithColor:color size:CGSizeMake(4, 4) radius:0]; | |
| 15 | -} | |
| 16 | - | |
| 17 | -/** | |
| 18 | - 颜色转图片 | |
| 19 | - | |
| 20 | - @param color 颜色 | |
| 21 | - @param size 大小 | |
| 22 | - @param radius 圆角 | |
| 23 | - @return 返回图片 | |
| 24 | - */ | |
| 25 | -+ (UIImage *)ip_imageWithColor:(UIColor *)color size:(CGSize)size radius:(CGFloat)radius { | |
| 26 | - CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); | |
| 27 | - UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale); | |
| 28 | - CGContextRef context = UIGraphicsGetCurrentContext(); | |
| 29 | - CGContextSetFillColorWithColor(context, [color CGColor]); | |
| 30 | - UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius]; | |
| 31 | - CGContextAddPath(context, path.CGPath); | |
| 32 | - CGContextFillPath(context); | |
| 33 | - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); | |
| 34 | - UIGraphicsEndImageContext(); | |
| 35 | - return image; | |
| 36 | -} | |
| 37 | - | |
| 38 | - | |
| 39 | - | |
| 40 | - | |
| 41 | - | |
| 42 | -@end |
CNLiveImagePickerController/UIView+Layout.h deleted
100755 → 0
| 1 | -// | |
| 2 | -// UIView+Layout.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 (Layout) | |
| 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/UIView+Layout.m deleted
100755 → 0
| 1 | -// | |
| 2 | -// UIView+Layout.m | |
| 3 | -// | |
| 4 | -// Created by 谭真 on 15/2/24. | |
| 5 | -// Copyright © 2015年 谭真. All rights reserved. | |
| 6 | -// | |
| 7 | - | |
| 8 | -#import "UIView+Layout.h" | |
| 9 | - | |
| 10 | -@implementation UIView (Layout) | |
| 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 |
Example/CNLiveImagePickerController.xcodeproj/project.pbxproj
0 → 100644
| 1 | +// !$*UTF8*$! | |
| 2 | +{ | |
| 3 | + archiveVersion = 1; | |
| 4 | + classes = { | |
| 5 | + }; | |
| 6 | + objectVersion = 46; | |
| 7 | + objects = { | |
| 8 | + | |
| 9 | +/* Begin PBXBuildFile section */ | |
| 10 | + 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; | |
| 11 | + 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58F195388D20070C39A /* CoreGraphics.framework */; }; | |
| 12 | + 6003F592195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; | |
| 13 | + 6003F598195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F596195388D20070C39A /* InfoPlist.strings */; }; | |
| 14 | + 6003F59A195388D20070C39A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F599195388D20070C39A /* main.m */; }; | |
| 15 | + 6003F59E195388D20070C39A /* CNLiveAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F59D195388D20070C39A /* CNLiveAppDelegate.m */; }; | |
| 16 | + 6003F5A7195388D20070C39A /* CNLiveViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5A6195388D20070C39A /* CNLiveViewController.m */; }; | |
| 17 | + 6003F5A9195388D20070C39A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5A8195388D20070C39A /* Images.xcassets */; }; | |
| 18 | + 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F5AF195388D20070C39A /* XCTest.framework */; }; | |
| 19 | + 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F58D195388D20070C39A /* Foundation.framework */; }; | |
| 20 | + 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6003F591195388D20070C39A /* UIKit.framework */; }; | |
| 21 | + 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6003F5B8195388D20070C39A /* InfoPlist.strings */; }; | |
| 22 | + 6003F5BC195388D20070C39A /* Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6003F5BB195388D20070C39A /* Tests.m */; }; | |
| 23 | + 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */; }; | |
| 24 | + 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */; }; | |
| 25 | + 92BF8970BCB1F2976CC0C9C9 /* Pods_CNLiveImagePickerController_Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6774261442B1D13201144A37 /* Pods_CNLiveImagePickerController_Tests.framework */; }; | |
| 26 | + FE74180484D7CEEF4A25A61A /* Pods_CNLiveImagePickerController_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4BA720C67B8EEEF52848A79 /* Pods_CNLiveImagePickerController_Example.framework */; }; | |
| 27 | +/* End PBXBuildFile section */ | |
| 28 | + | |
| 29 | +/* Begin PBXContainerItemProxy section */ | |
| 30 | + 6003F5B3195388D20070C39A /* PBXContainerItemProxy */ = { | |
| 31 | + isa = PBXContainerItemProxy; | |
| 32 | + containerPortal = 6003F582195388D10070C39A /* Project object */; | |
| 33 | + proxyType = 1; | |
| 34 | + remoteGlobalIDString = 6003F589195388D20070C39A; | |
| 35 | + remoteInfo = CNLiveImagePickerController; | |
| 36 | + }; | |
| 37 | +/* End PBXContainerItemProxy section */ | |
| 38 | + | |
| 39 | +/* Begin PBXFileReference section */ | |
| 40 | + 1E186CDE862673840D64652F /* CNLiveImagePickerController.podspec */ = {isa = PBXFileReference; includeInIndex = 1; name = CNLiveImagePickerController.podspec; path = ../CNLiveImagePickerController.podspec; sourceTree = "<group>"; }; | |
| 41 | + 251D01DF472ED3B34CCF79D7 /* Pods-CNLiveImagePickerController_Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CNLiveImagePickerController_Tests.release.xcconfig"; path = "Target Support Files/Pods-CNLiveImagePickerController_Tests/Pods-CNLiveImagePickerController_Tests.release.xcconfig"; sourceTree = "<group>"; }; | |
| 42 | + 2EFBCF51E613A31E4CA39B49 /* Pods-CNLiveImagePickerController_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CNLiveImagePickerController_Example.debug.xcconfig"; path = "Target Support Files/Pods-CNLiveImagePickerController_Example/Pods-CNLiveImagePickerController_Example.debug.xcconfig"; sourceTree = "<group>"; }; | |
| 43 | + 6003F58A195388D20070C39A /* CNLiveImagePickerController_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CNLiveImagePickerController_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; | |
| 44 | + 6003F58D195388D20070C39A /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; | |
| 45 | + 6003F58F195388D20070C39A /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; | |
| 46 | + 6003F591195388D20070C39A /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; | |
| 47 | + 6003F595195388D20070C39A /* CNLiveImagePickerController-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "CNLiveImagePickerController-Info.plist"; sourceTree = "<group>"; }; | |
| 48 | + 6003F597195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; | |
| 49 | + 6003F599195388D20070C39A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; | |
| 50 | + 6003F59B195388D20070C39A /* CNLiveImagePickerController-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "CNLiveImagePickerController-Prefix.pch"; sourceTree = "<group>"; }; | |
| 51 | + 6003F59C195388D20070C39A /* CNLiveAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNLiveAppDelegate.h; sourceTree = "<group>"; }; | |
| 52 | + 6003F59D195388D20070C39A /* CNLiveAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNLiveAppDelegate.m; sourceTree = "<group>"; }; | |
| 53 | + 6003F5A5195388D20070C39A /* CNLiveViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNLiveViewController.h; sourceTree = "<group>"; }; | |
| 54 | + 6003F5A6195388D20070C39A /* CNLiveViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNLiveViewController.m; sourceTree = "<group>"; }; | |
| 55 | + 6003F5A8195388D20070C39A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; }; | |
| 56 | + 6003F5AE195388D20070C39A /* CNLiveImagePickerController_Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CNLiveImagePickerController_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; | |
| 57 | + 6003F5AF195388D20070C39A /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; | |
| 58 | + 6003F5B7195388D20070C39A /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = "<group>"; }; | |
| 59 | + 6003F5B9195388D20070C39A /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; }; | |
| 60 | + 6003F5BB195388D20070C39A /* Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Tests.m; sourceTree = "<group>"; }; | |
| 61 | + 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Tests-Prefix.pch"; sourceTree = "<group>"; }; | |
| 62 | + 6774261442B1D13201144A37 /* Pods_CNLiveImagePickerController_Tests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CNLiveImagePickerController_Tests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; | |
| 63 | + 71719F9E1E33DC2100824A3D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; | |
| 64 | + 804602CE4E7E104F5222073B /* README.md */ = {isa = PBXFileReference; includeInIndex = 1; name = README.md; path = ../README.md; sourceTree = "<group>"; }; | |
| 65 | + 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = Main.storyboard; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; | |
| 66 | + BF0D4829B7327822E0C4146E /* LICENSE */ = {isa = PBXFileReference; includeInIndex = 1; name = LICENSE; path = ../LICENSE; sourceTree = "<group>"; }; | |
| 67 | + C188B280A1A26E9C6D19D5C6 /* Pods-CNLiveImagePickerController_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CNLiveImagePickerController_Example.release.xcconfig"; path = "Target Support Files/Pods-CNLiveImagePickerController_Example/Pods-CNLiveImagePickerController_Example.release.xcconfig"; sourceTree = "<group>"; }; | |
| 68 | + E4BA720C67B8EEEF52848A79 /* Pods_CNLiveImagePickerController_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_CNLiveImagePickerController_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; | |
| 69 | + F2CA825BC87A414FD6AF3A37 /* Pods-CNLiveImagePickerController_Tests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CNLiveImagePickerController_Tests.debug.xcconfig"; path = "Target Support Files/Pods-CNLiveImagePickerController_Tests/Pods-CNLiveImagePickerController_Tests.debug.xcconfig"; sourceTree = "<group>"; }; | |
| 70 | +/* End PBXFileReference section */ | |
| 71 | + | |
| 72 | +/* Begin PBXFrameworksBuildPhase section */ | |
| 73 | + 6003F587195388D20070C39A /* Frameworks */ = { | |
| 74 | + isa = PBXFrameworksBuildPhase; | |
| 75 | + buildActionMask = 2147483647; | |
| 76 | + files = ( | |
| 77 | + 6003F590195388D20070C39A /* CoreGraphics.framework in Frameworks */, | |
| 78 | + 6003F592195388D20070C39A /* UIKit.framework in Frameworks */, | |
| 79 | + 6003F58E195388D20070C39A /* Foundation.framework in Frameworks */, | |
| 80 | + FE74180484D7CEEF4A25A61A /* Pods_CNLiveImagePickerController_Example.framework in Frameworks */, | |
| 81 | + ); | |
| 82 | + runOnlyForDeploymentPostprocessing = 0; | |
| 83 | + }; | |
| 84 | + 6003F5AB195388D20070C39A /* Frameworks */ = { | |
| 85 | + isa = PBXFrameworksBuildPhase; | |
| 86 | + buildActionMask = 2147483647; | |
| 87 | + files = ( | |
| 88 | + 6003F5B0195388D20070C39A /* XCTest.framework in Frameworks */, | |
| 89 | + 6003F5B2195388D20070C39A /* UIKit.framework in Frameworks */, | |
| 90 | + 6003F5B1195388D20070C39A /* Foundation.framework in Frameworks */, | |
| 91 | + 92BF8970BCB1F2976CC0C9C9 /* Pods_CNLiveImagePickerController_Tests.framework in Frameworks */, | |
| 92 | + ); | |
| 93 | + runOnlyForDeploymentPostprocessing = 0; | |
| 94 | + }; | |
| 95 | +/* End PBXFrameworksBuildPhase section */ | |
| 96 | + | |
| 97 | +/* Begin PBXGroup section */ | |
| 98 | + 6003F581195388D10070C39A = { | |
| 99 | + isa = PBXGroup; | |
| 100 | + children = ( | |
| 101 | + 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */, | |
| 102 | + 6003F593195388D20070C39A /* Example for CNLiveImagePickerController */, | |
| 103 | + 6003F5B5195388D20070C39A /* Tests */, | |
| 104 | + 6003F58C195388D20070C39A /* Frameworks */, | |
| 105 | + 6003F58B195388D20070C39A /* Products */, | |
| 106 | + B0A737C78E5A24C5402B3679 /* Pods */, | |
| 107 | + ); | |
| 108 | + sourceTree = "<group>"; | |
| 109 | + }; | |
| 110 | + 6003F58B195388D20070C39A /* Products */ = { | |
| 111 | + isa = PBXGroup; | |
| 112 | + children = ( | |
| 113 | + 6003F58A195388D20070C39A /* CNLiveImagePickerController_Example.app */, | |
| 114 | + 6003F5AE195388D20070C39A /* CNLiveImagePickerController_Tests.xctest */, | |
| 115 | + ); | |
| 116 | + name = Products; | |
| 117 | + sourceTree = "<group>"; | |
| 118 | + }; | |
| 119 | + 6003F58C195388D20070C39A /* Frameworks */ = { | |
| 120 | + isa = PBXGroup; | |
| 121 | + children = ( | |
| 122 | + 6003F58D195388D20070C39A /* Foundation.framework */, | |
| 123 | + 6003F58F195388D20070C39A /* CoreGraphics.framework */, | |
| 124 | + 6003F591195388D20070C39A /* UIKit.framework */, | |
| 125 | + 6003F5AF195388D20070C39A /* XCTest.framework */, | |
| 126 | + E4BA720C67B8EEEF52848A79 /* Pods_CNLiveImagePickerController_Example.framework */, | |
| 127 | + 6774261442B1D13201144A37 /* Pods_CNLiveImagePickerController_Tests.framework */, | |
| 128 | + ); | |
| 129 | + name = Frameworks; | |
| 130 | + sourceTree = "<group>"; | |
| 131 | + }; | |
| 132 | + 6003F593195388D20070C39A /* Example for CNLiveImagePickerController */ = { | |
| 133 | + isa = PBXGroup; | |
| 134 | + children = ( | |
| 135 | + 6003F59C195388D20070C39A /* CNLiveAppDelegate.h */, | |
| 136 | + 6003F59D195388D20070C39A /* CNLiveAppDelegate.m */, | |
| 137 | + 873B8AEA1B1F5CCA007FD442 /* Main.storyboard */, | |
| 138 | + 6003F5A5195388D20070C39A /* CNLiveViewController.h */, | |
| 139 | + 6003F5A6195388D20070C39A /* CNLiveViewController.m */, | |
| 140 | + 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */, | |
| 141 | + 6003F5A8195388D20070C39A /* Images.xcassets */, | |
| 142 | + 6003F594195388D20070C39A /* Supporting Files */, | |
| 143 | + ); | |
| 144 | + name = "Example for CNLiveImagePickerController"; | |
| 145 | + path = CNLiveImagePickerController; | |
| 146 | + sourceTree = "<group>"; | |
| 147 | + }; | |
| 148 | + 6003F594195388D20070C39A /* Supporting Files */ = { | |
| 149 | + isa = PBXGroup; | |
| 150 | + children = ( | |
| 151 | + 6003F595195388D20070C39A /* CNLiveImagePickerController-Info.plist */, | |
| 152 | + 6003F596195388D20070C39A /* InfoPlist.strings */, | |
| 153 | + 6003F599195388D20070C39A /* main.m */, | |
| 154 | + 6003F59B195388D20070C39A /* CNLiveImagePickerController-Prefix.pch */, | |
| 155 | + ); | |
| 156 | + name = "Supporting Files"; | |
| 157 | + sourceTree = "<group>"; | |
| 158 | + }; | |
| 159 | + 6003F5B5195388D20070C39A /* Tests */ = { | |
| 160 | + isa = PBXGroup; | |
| 161 | + children = ( | |
| 162 | + 6003F5BB195388D20070C39A /* Tests.m */, | |
| 163 | + 6003F5B6195388D20070C39A /* Supporting Files */, | |
| 164 | + ); | |
| 165 | + path = Tests; | |
| 166 | + sourceTree = "<group>"; | |
| 167 | + }; | |
| 168 | + 6003F5B6195388D20070C39A /* Supporting Files */ = { | |
| 169 | + isa = PBXGroup; | |
| 170 | + children = ( | |
| 171 | + 6003F5B7195388D20070C39A /* Tests-Info.plist */, | |
| 172 | + 6003F5B8195388D20070C39A /* InfoPlist.strings */, | |
| 173 | + 606FC2411953D9B200FFA9A0 /* Tests-Prefix.pch */, | |
| 174 | + ); | |
| 175 | + name = "Supporting Files"; | |
| 176 | + sourceTree = "<group>"; | |
| 177 | + }; | |
| 178 | + 60FF7A9C1954A5C5007DD14C /* Podspec Metadata */ = { | |
| 179 | + isa = PBXGroup; | |
| 180 | + children = ( | |
| 181 | + 1E186CDE862673840D64652F /* CNLiveImagePickerController.podspec */, | |
| 182 | + 804602CE4E7E104F5222073B /* README.md */, | |
| 183 | + BF0D4829B7327822E0C4146E /* LICENSE */, | |
| 184 | + ); | |
| 185 | + name = "Podspec Metadata"; | |
| 186 | + sourceTree = "<group>"; | |
| 187 | + }; | |
| 188 | + B0A737C78E5A24C5402B3679 /* Pods */ = { | |
| 189 | + isa = PBXGroup; | |
| 190 | + children = ( | |
| 191 | + 2EFBCF51E613A31E4CA39B49 /* Pods-CNLiveImagePickerController_Example.debug.xcconfig */, | |
| 192 | + C188B280A1A26E9C6D19D5C6 /* Pods-CNLiveImagePickerController_Example.release.xcconfig */, | |
| 193 | + F2CA825BC87A414FD6AF3A37 /* Pods-CNLiveImagePickerController_Tests.debug.xcconfig */, | |
| 194 | + 251D01DF472ED3B34CCF79D7 /* Pods-CNLiveImagePickerController_Tests.release.xcconfig */, | |
| 195 | + ); | |
| 196 | + name = Pods; | |
| 197 | + path = Pods; | |
| 198 | + sourceTree = "<group>"; | |
| 199 | + }; | |
| 200 | +/* End PBXGroup section */ | |
| 201 | + | |
| 202 | +/* Begin PBXNativeTarget section */ | |
| 203 | + 6003F589195388D20070C39A /* CNLiveImagePickerController_Example */ = { | |
| 204 | + isa = PBXNativeTarget; | |
| 205 | + buildConfigurationList = 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "CNLiveImagePickerController_Example" */; | |
| 206 | + buildPhases = ( | |
| 207 | + FC3031E958514B32A46A8C4B /* [CP] Check Pods Manifest.lock */, | |
| 208 | + 6003F586195388D20070C39A /* Sources */, | |
| 209 | + 6003F587195388D20070C39A /* Frameworks */, | |
| 210 | + 6003F588195388D20070C39A /* Resources */, | |
| 211 | + 483530E695F873EC8CF99467 /* [CP] Embed Pods Frameworks */, | |
| 212 | + ); | |
| 213 | + buildRules = ( | |
| 214 | + ); | |
| 215 | + dependencies = ( | |
| 216 | + ); | |
| 217 | + name = CNLiveImagePickerController_Example; | |
| 218 | + productName = CNLiveImagePickerController; | |
| 219 | + productReference = 6003F58A195388D20070C39A /* CNLiveImagePickerController_Example.app */; | |
| 220 | + productType = "com.apple.product-type.application"; | |
| 221 | + }; | |
| 222 | + 6003F5AD195388D20070C39A /* CNLiveImagePickerController_Tests */ = { | |
| 223 | + isa = PBXNativeTarget; | |
| 224 | + buildConfigurationList = 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "CNLiveImagePickerController_Tests" */; | |
| 225 | + buildPhases = ( | |
| 226 | + ADCF8E65BB0A5C262C53995E /* [CP] Check Pods Manifest.lock */, | |
| 227 | + 6003F5AA195388D20070C39A /* Sources */, | |
| 228 | + 6003F5AB195388D20070C39A /* Frameworks */, | |
| 229 | + 6003F5AC195388D20070C39A /* Resources */, | |
| 230 | + ); | |
| 231 | + buildRules = ( | |
| 232 | + ); | |
| 233 | + dependencies = ( | |
| 234 | + 6003F5B4195388D20070C39A /* PBXTargetDependency */, | |
| 235 | + ); | |
| 236 | + name = CNLiveImagePickerController_Tests; | |
| 237 | + productName = CNLiveImagePickerControllerTests; | |
| 238 | + productReference = 6003F5AE195388D20070C39A /* CNLiveImagePickerController_Tests.xctest */; | |
| 239 | + productType = "com.apple.product-type.bundle.unit-test"; | |
| 240 | + }; | |
| 241 | +/* End PBXNativeTarget section */ | |
| 242 | + | |
| 243 | +/* Begin PBXProject section */ | |
| 244 | + 6003F582195388D10070C39A /* Project object */ = { | |
| 245 | + isa = PBXProject; | |
| 246 | + attributes = { | |
| 247 | + CLASSPREFIX = CNLive; | |
| 248 | + LastUpgradeCheck = 0720; | |
| 249 | + ORGANIZATIONNAME = jyyjkt; | |
| 250 | + TargetAttributes = { | |
| 251 | + 6003F5AD195388D20070C39A = { | |
| 252 | + TestTargetID = 6003F589195388D20070C39A; | |
| 253 | + }; | |
| 254 | + }; | |
| 255 | + }; | |
| 256 | + buildConfigurationList = 6003F585195388D10070C39A /* Build configuration list for PBXProject "CNLiveImagePickerController" */; | |
| 257 | + compatibilityVersion = "Xcode 3.2"; | |
| 258 | + developmentRegion = English; | |
| 259 | + hasScannedForEncodings = 0; | |
| 260 | + knownRegions = ( | |
| 261 | + en, | |
| 262 | + Base, | |
| 263 | + ); | |
| 264 | + mainGroup = 6003F581195388D10070C39A; | |
| 265 | + productRefGroup = 6003F58B195388D20070C39A /* Products */; | |
| 266 | + projectDirPath = ""; | |
| 267 | + projectRoot = ""; | |
| 268 | + targets = ( | |
| 269 | + 6003F589195388D20070C39A /* CNLiveImagePickerController_Example */, | |
| 270 | + 6003F5AD195388D20070C39A /* CNLiveImagePickerController_Tests */, | |
| 271 | + ); | |
| 272 | + }; | |
| 273 | +/* End PBXProject section */ | |
| 274 | + | |
| 275 | +/* Begin PBXResourcesBuildPhase section */ | |
| 276 | + 6003F588195388D20070C39A /* Resources */ = { | |
| 277 | + isa = PBXResourcesBuildPhase; | |
| 278 | + buildActionMask = 2147483647; | |
| 279 | + files = ( | |
| 280 | + 873B8AEB1B1F5CCA007FD442 /* Main.storyboard in Resources */, | |
| 281 | + 71719F9F1E33DC2100824A3D /* LaunchScreen.storyboard in Resources */, | |
| 282 | + 6003F5A9195388D20070C39A /* Images.xcassets in Resources */, | |
| 283 | + 6003F598195388D20070C39A /* InfoPlist.strings in Resources */, | |
| 284 | + ); | |
| 285 | + runOnlyForDeploymentPostprocessing = 0; | |
| 286 | + }; | |
| 287 | + 6003F5AC195388D20070C39A /* Resources */ = { | |
| 288 | + isa = PBXResourcesBuildPhase; | |
| 289 | + buildActionMask = 2147483647; | |
| 290 | + files = ( | |
| 291 | + 6003F5BA195388D20070C39A /* InfoPlist.strings in Resources */, | |
| 292 | + ); | |
| 293 | + runOnlyForDeploymentPostprocessing = 0; | |
| 294 | + }; | |
| 295 | +/* End PBXResourcesBuildPhase section */ | |
| 296 | + | |
| 297 | +/* Begin PBXShellScriptBuildPhase section */ | |
| 298 | + 483530E695F873EC8CF99467 /* [CP] Embed Pods Frameworks */ = { | |
| 299 | + isa = PBXShellScriptBuildPhase; | |
| 300 | + buildActionMask = 2147483647; | |
| 301 | + files = ( | |
| 302 | + ); | |
| 303 | + inputPaths = ( | |
| 304 | + "${PODS_ROOT}/Target Support Files/Pods-CNLiveImagePickerController_Example/Pods-CNLiveImagePickerController_Example-frameworks.sh", | |
| 305 | + "${BUILT_PRODUCTS_DIR}/CNLiveImagePickerController/CNLiveImagePickerController.framework", | |
| 306 | + ); | |
| 307 | + name = "[CP] Embed Pods Frameworks"; | |
| 308 | + outputPaths = ( | |
| 309 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CNLiveImagePickerController.framework", | |
| 310 | + ); | |
| 311 | + runOnlyForDeploymentPostprocessing = 0; | |
| 312 | + shellPath = /bin/sh; | |
| 313 | + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-CNLiveImagePickerController_Example/Pods-CNLiveImagePickerController_Example-frameworks.sh\"\n"; | |
| 314 | + showEnvVarsInLog = 0; | |
| 315 | + }; | |
| 316 | + ADCF8E65BB0A5C262C53995E /* [CP] Check Pods Manifest.lock */ = { | |
| 317 | + isa = PBXShellScriptBuildPhase; | |
| 318 | + buildActionMask = 2147483647; | |
| 319 | + files = ( | |
| 320 | + ); | |
| 321 | + inputFileListPaths = ( | |
| 322 | + ); | |
| 323 | + inputPaths = ( | |
| 324 | + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", | |
| 325 | + "${PODS_ROOT}/Manifest.lock", | |
| 326 | + ); | |
| 327 | + name = "[CP] Check Pods Manifest.lock"; | |
| 328 | + outputFileListPaths = ( | |
| 329 | + ); | |
| 330 | + outputPaths = ( | |
| 331 | + "$(DERIVED_FILE_DIR)/Pods-CNLiveImagePickerController_Tests-checkManifestLockResult.txt", | |
| 332 | + ); | |
| 333 | + runOnlyForDeploymentPostprocessing = 0; | |
| 334 | + shellPath = /bin/sh; | |
| 335 | + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; | |
| 336 | + showEnvVarsInLog = 0; | |
| 337 | + }; | |
| 338 | + FC3031E958514B32A46A8C4B /* [CP] Check Pods Manifest.lock */ = { | |
| 339 | + isa = PBXShellScriptBuildPhase; | |
| 340 | + buildActionMask = 2147483647; | |
| 341 | + files = ( | |
| 342 | + ); | |
| 343 | + inputFileListPaths = ( | |
| 344 | + ); | |
| 345 | + inputPaths = ( | |
| 346 | + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", | |
| 347 | + "${PODS_ROOT}/Manifest.lock", | |
| 348 | + ); | |
| 349 | + name = "[CP] Check Pods Manifest.lock"; | |
| 350 | + outputFileListPaths = ( | |
| 351 | + ); | |
| 352 | + outputPaths = ( | |
| 353 | + "$(DERIVED_FILE_DIR)/Pods-CNLiveImagePickerController_Example-checkManifestLockResult.txt", | |
| 354 | + ); | |
| 355 | + runOnlyForDeploymentPostprocessing = 0; | |
| 356 | + shellPath = /bin/sh; | |
| 357 | + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; | |
| 358 | + showEnvVarsInLog = 0; | |
| 359 | + }; | |
| 360 | +/* End PBXShellScriptBuildPhase section */ | |
| 361 | + | |
| 362 | +/* Begin PBXSourcesBuildPhase section */ | |
| 363 | + 6003F586195388D20070C39A /* Sources */ = { | |
| 364 | + isa = PBXSourcesBuildPhase; | |
| 365 | + buildActionMask = 2147483647; | |
| 366 | + files = ( | |
| 367 | + 6003F59E195388D20070C39A /* CNLiveAppDelegate.m in Sources */, | |
| 368 | + 6003F5A7195388D20070C39A /* CNLiveViewController.m in Sources */, | |
| 369 | + 6003F59A195388D20070C39A /* main.m in Sources */, | |
| 370 | + ); | |
| 371 | + runOnlyForDeploymentPostprocessing = 0; | |
| 372 | + }; | |
| 373 | + 6003F5AA195388D20070C39A /* Sources */ = { | |
| 374 | + isa = PBXSourcesBuildPhase; | |
| 375 | + buildActionMask = 2147483647; | |
| 376 | + files = ( | |
| 377 | + 6003F5BC195388D20070C39A /* Tests.m in Sources */, | |
| 378 | + ); | |
| 379 | + runOnlyForDeploymentPostprocessing = 0; | |
| 380 | + }; | |
| 381 | +/* End PBXSourcesBuildPhase section */ | |
| 382 | + | |
| 383 | +/* Begin PBXTargetDependency section */ | |
| 384 | + 6003F5B4195388D20070C39A /* PBXTargetDependency */ = { | |
| 385 | + isa = PBXTargetDependency; | |
| 386 | + target = 6003F589195388D20070C39A /* CNLiveImagePickerController_Example */; | |
| 387 | + targetProxy = 6003F5B3195388D20070C39A /* PBXContainerItemProxy */; | |
| 388 | + }; | |
| 389 | +/* End PBXTargetDependency section */ | |
| 390 | + | |
| 391 | +/* Begin PBXVariantGroup section */ | |
| 392 | + 6003F596195388D20070C39A /* InfoPlist.strings */ = { | |
| 393 | + isa = PBXVariantGroup; | |
| 394 | + children = ( | |
| 395 | + 6003F597195388D20070C39A /* en */, | |
| 396 | + ); | |
| 397 | + name = InfoPlist.strings; | |
| 398 | + sourceTree = "<group>"; | |
| 399 | + }; | |
| 400 | + 6003F5B8195388D20070C39A /* InfoPlist.strings */ = { | |
| 401 | + isa = PBXVariantGroup; | |
| 402 | + children = ( | |
| 403 | + 6003F5B9195388D20070C39A /* en */, | |
| 404 | + ); | |
| 405 | + name = InfoPlist.strings; | |
| 406 | + sourceTree = "<group>"; | |
| 407 | + }; | |
| 408 | + 71719F9D1E33DC2100824A3D /* LaunchScreen.storyboard */ = { | |
| 409 | + isa = PBXVariantGroup; | |
| 410 | + children = ( | |
| 411 | + 71719F9E1E33DC2100824A3D /* Base */, | |
| 412 | + ); | |
| 413 | + name = LaunchScreen.storyboard; | |
| 414 | + sourceTree = "<group>"; | |
| 415 | + }; | |
| 416 | +/* End PBXVariantGroup section */ | |
| 417 | + | |
| 418 | +/* Begin XCBuildConfiguration section */ | |
| 419 | + 6003F5BD195388D20070C39A /* Debug */ = { | |
| 420 | + isa = XCBuildConfiguration; | |
| 421 | + buildSettings = { | |
| 422 | + ALWAYS_SEARCH_USER_PATHS = NO; | |
| 423 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | |
| 424 | + CLANG_CXX_LIBRARY = "libc++"; | |
| 425 | + CLANG_ENABLE_MODULES = YES; | |
| 426 | + CLANG_ENABLE_OBJC_ARC = YES; | |
| 427 | + CLANG_WARN_BOOL_CONVERSION = YES; | |
| 428 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | |
| 429 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | |
| 430 | + CLANG_WARN_EMPTY_BODY = YES; | |
| 431 | + CLANG_WARN_ENUM_CONVERSION = YES; | |
| 432 | + CLANG_WARN_INT_CONVERSION = YES; | |
| 433 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | |
| 434 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |
| 435 | + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |
| 436 | + COPY_PHASE_STRIP = NO; | |
| 437 | + ENABLE_TESTABILITY = YES; | |
| 438 | + GCC_C_LANGUAGE_STANDARD = gnu99; | |
| 439 | + GCC_DYNAMIC_NO_PIC = NO; | |
| 440 | + GCC_OPTIMIZATION_LEVEL = 0; | |
| 441 | + GCC_PREPROCESSOR_DEFINITIONS = ( | |
| 442 | + "DEBUG=1", | |
| 443 | + "$(inherited)", | |
| 444 | + ); | |
| 445 | + GCC_SYMBOLS_PRIVATE_EXTERN = NO; | |
| 446 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |
| 447 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | |
| 448 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | |
| 449 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | |
| 450 | + GCC_WARN_UNUSED_FUNCTION = YES; | |
| 451 | + GCC_WARN_UNUSED_VARIABLE = YES; | |
| 452 | + IPHONEOS_DEPLOYMENT_TARGET = 9.3; | |
| 453 | + ONLY_ACTIVE_ARCH = YES; | |
| 454 | + SDKROOT = iphoneos; | |
| 455 | + TARGETED_DEVICE_FAMILY = "1,2"; | |
| 456 | + }; | |
| 457 | + name = Debug; | |
| 458 | + }; | |
| 459 | + 6003F5BE195388D20070C39A /* Release */ = { | |
| 460 | + isa = XCBuildConfiguration; | |
| 461 | + buildSettings = { | |
| 462 | + ALWAYS_SEARCH_USER_PATHS = NO; | |
| 463 | + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; | |
| 464 | + CLANG_CXX_LIBRARY = "libc++"; | |
| 465 | + CLANG_ENABLE_MODULES = YES; | |
| 466 | + CLANG_ENABLE_OBJC_ARC = YES; | |
| 467 | + CLANG_WARN_BOOL_CONVERSION = YES; | |
| 468 | + CLANG_WARN_CONSTANT_CONVERSION = YES; | |
| 469 | + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; | |
| 470 | + CLANG_WARN_EMPTY_BODY = YES; | |
| 471 | + CLANG_WARN_ENUM_CONVERSION = YES; | |
| 472 | + CLANG_WARN_INT_CONVERSION = YES; | |
| 473 | + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; | |
| 474 | + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; | |
| 475 | + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; | |
| 476 | + COPY_PHASE_STRIP = YES; | |
| 477 | + ENABLE_NS_ASSERTIONS = NO; | |
| 478 | + GCC_C_LANGUAGE_STANDARD = gnu99; | |
| 479 | + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; | |
| 480 | + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; | |
| 481 | + GCC_WARN_UNDECLARED_SELECTOR = YES; | |
| 482 | + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; | |
| 483 | + GCC_WARN_UNUSED_FUNCTION = YES; | |
| 484 | + GCC_WARN_UNUSED_VARIABLE = YES; | |
| 485 | + IPHONEOS_DEPLOYMENT_TARGET = 9.3; | |
| 486 | + SDKROOT = iphoneos; | |
| 487 | + TARGETED_DEVICE_FAMILY = "1,2"; | |
| 488 | + VALIDATE_PRODUCT = YES; | |
| 489 | + }; | |
| 490 | + name = Release; | |
| 491 | + }; | |
| 492 | + 6003F5C0195388D20070C39A /* Debug */ = { | |
| 493 | + isa = XCBuildConfiguration; | |
| 494 | + baseConfigurationReference = 2EFBCF51E613A31E4CA39B49 /* Pods-CNLiveImagePickerController_Example.debug.xcconfig */; | |
| 495 | + buildSettings = { | |
| 496 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |
| 497 | + GCC_PRECOMPILE_PREFIX_HEADER = YES; | |
| 498 | + GCC_PREFIX_HEADER = "CNLiveImagePickerController/CNLiveImagePickerController-Prefix.pch"; | |
| 499 | + INFOPLIST_FILE = "CNLiveImagePickerController/CNLiveImagePickerController-Info.plist"; | |
| 500 | + MODULE_NAME = ExampleApp; | |
| 501 | + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; | |
| 502 | + PRODUCT_NAME = "$(TARGET_NAME)"; | |
| 503 | + SWIFT_VERSION = 4.0; | |
| 504 | + WRAPPER_EXTENSION = app; | |
| 505 | + }; | |
| 506 | + name = Debug; | |
| 507 | + }; | |
| 508 | + 6003F5C1195388D20070C39A /* Release */ = { | |
| 509 | + isa = XCBuildConfiguration; | |
| 510 | + baseConfigurationReference = C188B280A1A26E9C6D19D5C6 /* Pods-CNLiveImagePickerController_Example.release.xcconfig */; | |
| 511 | + buildSettings = { | |
| 512 | + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | |
| 513 | + GCC_PRECOMPILE_PREFIX_HEADER = YES; | |
| 514 | + GCC_PREFIX_HEADER = "CNLiveImagePickerController/CNLiveImagePickerController-Prefix.pch"; | |
| 515 | + INFOPLIST_FILE = "CNLiveImagePickerController/CNLiveImagePickerController-Info.plist"; | |
| 516 | + MODULE_NAME = ExampleApp; | |
| 517 | + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; | |
| 518 | + PRODUCT_NAME = "$(TARGET_NAME)"; | |
| 519 | + SWIFT_VERSION = 4.0; | |
| 520 | + WRAPPER_EXTENSION = app; | |
| 521 | + }; | |
| 522 | + name = Release; | |
| 523 | + }; | |
| 524 | + 6003F5C3195388D20070C39A /* Debug */ = { | |
| 525 | + isa = XCBuildConfiguration; | |
| 526 | + baseConfigurationReference = F2CA825BC87A414FD6AF3A37 /* Pods-CNLiveImagePickerController_Tests.debug.xcconfig */; | |
| 527 | + buildSettings = { | |
| 528 | + BUNDLE_LOADER = "$(TEST_HOST)"; | |
| 529 | + FRAMEWORK_SEARCH_PATHS = ( | |
| 530 | + "$(PLATFORM_DIR)/Developer/Library/Frameworks", | |
| 531 | + "$(inherited)", | |
| 532 | + "$(DEVELOPER_FRAMEWORKS_DIR)", | |
| 533 | + ); | |
| 534 | + GCC_PRECOMPILE_PREFIX_HEADER = YES; | |
| 535 | + GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; | |
| 536 | + GCC_PREPROCESSOR_DEFINITIONS = ( | |
| 537 | + "DEBUG=1", | |
| 538 | + "$(inherited)", | |
| 539 | + ); | |
| 540 | + INFOPLIST_FILE = "Tests/Tests-Info.plist"; | |
| 541 | + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; | |
| 542 | + PRODUCT_NAME = "$(TARGET_NAME)"; | |
| 543 | + SWIFT_VERSION = 4.0; | |
| 544 | + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CNLiveImagePickerController_Example.app/CNLiveImagePickerController_Example"; | |
| 545 | + WRAPPER_EXTENSION = xctest; | |
| 546 | + }; | |
| 547 | + name = Debug; | |
| 548 | + }; | |
| 549 | + 6003F5C4195388D20070C39A /* Release */ = { | |
| 550 | + isa = XCBuildConfiguration; | |
| 551 | + baseConfigurationReference = 251D01DF472ED3B34CCF79D7 /* Pods-CNLiveImagePickerController_Tests.release.xcconfig */; | |
| 552 | + buildSettings = { | |
| 553 | + BUNDLE_LOADER = "$(TEST_HOST)"; | |
| 554 | + FRAMEWORK_SEARCH_PATHS = ( | |
| 555 | + "$(PLATFORM_DIR)/Developer/Library/Frameworks", | |
| 556 | + "$(inherited)", | |
| 557 | + "$(DEVELOPER_FRAMEWORKS_DIR)", | |
| 558 | + ); | |
| 559 | + GCC_PRECOMPILE_PREFIX_HEADER = YES; | |
| 560 | + GCC_PREFIX_HEADER = "Tests/Tests-Prefix.pch"; | |
| 561 | + INFOPLIST_FILE = "Tests/Tests-Info.plist"; | |
| 562 | + PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.${PRODUCT_NAME:rfc1034identifier}"; | |
| 563 | + PRODUCT_NAME = "$(TARGET_NAME)"; | |
| 564 | + SWIFT_VERSION = 4.0; | |
| 565 | + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CNLiveImagePickerController_Example.app/CNLiveImagePickerController_Example"; | |
| 566 | + WRAPPER_EXTENSION = xctest; | |
| 567 | + }; | |
| 568 | + name = Release; | |
| 569 | + }; | |
| 570 | +/* End XCBuildConfiguration section */ | |
| 571 | + | |
| 572 | +/* Begin XCConfigurationList section */ | |
| 573 | + 6003F585195388D10070C39A /* Build configuration list for PBXProject "CNLiveImagePickerController" */ = { | |
| 574 | + isa = XCConfigurationList; | |
| 575 | + buildConfigurations = ( | |
| 576 | + 6003F5BD195388D20070C39A /* Debug */, | |
| 577 | + 6003F5BE195388D20070C39A /* Release */, | |
| 578 | + ); | |
| 579 | + defaultConfigurationIsVisible = 0; | |
| 580 | + defaultConfigurationName = Release; | |
| 581 | + }; | |
| 582 | + 6003F5BF195388D20070C39A /* Build configuration list for PBXNativeTarget "CNLiveImagePickerController_Example" */ = { | |
| 583 | + isa = XCConfigurationList; | |
| 584 | + buildConfigurations = ( | |
| 585 | + 6003F5C0195388D20070C39A /* Debug */, | |
| 586 | + 6003F5C1195388D20070C39A /* Release */, | |
| 587 | + ); | |
| 588 | + defaultConfigurationIsVisible = 0; | |
| 589 | + defaultConfigurationName = Release; | |
| 590 | + }; | |
| 591 | + 6003F5C2195388D20070C39A /* Build configuration list for PBXNativeTarget "CNLiveImagePickerController_Tests" */ = { | |
| 592 | + isa = XCConfigurationList; | |
| 593 | + buildConfigurations = ( | |
| 594 | + 6003F5C3195388D20070C39A /* Debug */, | |
| 595 | + 6003F5C4195388D20070C39A /* Release */, | |
| 596 | + ); | |
| 597 | + defaultConfigurationIsVisible = 0; | |
| 598 | + defaultConfigurationName = Release; | |
| 599 | + }; | |
| 600 | +/* End XCConfigurationList section */ | |
| 601 | + }; | |
| 602 | + rootObject = 6003F582195388D10070C39A /* Project object */; | |
| 603 | +} | ... | ... |
Example/CNLiveImagePickerController.xcodeproj/xcshareddata/xcschemes/CNLiveImagePickerController-Example.xcscheme
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<Scheme | |
| 3 | + LastUpgradeVersion = "0720" | |
| 4 | + version = "1.3"> | |
| 5 | + <BuildAction | |
| 6 | + parallelizeBuildables = "YES" | |
| 7 | + buildImplicitDependencies = "YES"> | |
| 8 | + <BuildActionEntries> | |
| 9 | + <BuildActionEntry | |
| 10 | + buildForTesting = "YES" | |
| 11 | + buildForRunning = "YES" | |
| 12 | + buildForProfiling = "YES" | |
| 13 | + buildForArchiving = "YES" | |
| 14 | + buildForAnalyzing = "YES"> | |
| 15 | + <BuildableReference | |
| 16 | + BuildableIdentifier = "primary" | |
| 17 | + BlueprintIdentifier = "6003F589195388D20070C39A" | |
| 18 | + BuildableName = "CNLiveImagePickerController_Example.app" | |
| 19 | + BlueprintName = "CNLiveImagePickerController_Example" | |
| 20 | + ReferencedContainer = "container:CNLiveImagePickerController.xcodeproj"> | |
| 21 | + </BuildableReference> | |
| 22 | + </BuildActionEntry> | |
| 23 | + </BuildActionEntries> | |
| 24 | + </BuildAction> | |
| 25 | + <TestAction | |
| 26 | + buildConfiguration = "Debug" | |
| 27 | + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |
| 28 | + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |
| 29 | + shouldUseLaunchSchemeArgsEnv = "YES"> | |
| 30 | + <Testables> | |
| 31 | + <TestableReference | |
| 32 | + skipped = "NO"> | |
| 33 | + <BuildableReference | |
| 34 | + BuildableIdentifier = "primary" | |
| 35 | + BlueprintIdentifier = "6003F5AD195388D20070C39A" | |
| 36 | + BuildableName = "CNLiveImagePickerController_Tests.xctest" | |
| 37 | + BlueprintName = "CNLiveImagePickerController_Tests" | |
| 38 | + ReferencedContainer = "container:CNLiveImagePickerController.xcodeproj"> | |
| 39 | + </BuildableReference> | |
| 40 | + </TestableReference> | |
| 41 | + </Testables> | |
| 42 | + <MacroExpansion> | |
| 43 | + <BuildableReference | |
| 44 | + BuildableIdentifier = "primary" | |
| 45 | + BlueprintIdentifier = "6003F589195388D20070C39A" | |
| 46 | + BuildableName = "CNLiveImagePickerController_Example.app" | |
| 47 | + BlueprintName = "CNLiveImagePickerController_Example" | |
| 48 | + ReferencedContainer = "container:CNLiveImagePickerController.xcodeproj"> | |
| 49 | + </BuildableReference> | |
| 50 | + </MacroExpansion> | |
| 51 | + <AdditionalOptions> | |
| 52 | + </AdditionalOptions> | |
| 53 | + </TestAction> | |
| 54 | + <LaunchAction | |
| 55 | + buildConfiguration = "Debug" | |
| 56 | + selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |
| 57 | + selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |
| 58 | + launchStyle = "0" | |
| 59 | + useCustomWorkingDirectory = "NO" | |
| 60 | + ignoresPersistentStateOnLaunch = "NO" | |
| 61 | + debugDocumentVersioning = "YES" | |
| 62 | + debugServiceExtension = "internal" | |
| 63 | + allowLocationSimulation = "YES"> | |
| 64 | + <BuildableProductRunnable | |
| 65 | + runnableDebuggingMode = "0"> | |
| 66 | + <BuildableReference | |
| 67 | + BuildableIdentifier = "primary" | |
| 68 | + BlueprintIdentifier = "6003F589195388D20070C39A" | |
| 69 | + BuildableName = "CNLiveImagePickerController_Example.app" | |
| 70 | + BlueprintName = "CNLiveImagePickerController_Example" | |
| 71 | + ReferencedContainer = "container:CNLiveImagePickerController.xcodeproj"> | |
| 72 | + </BuildableReference> | |
| 73 | + </BuildableProductRunnable> | |
| 74 | + <AdditionalOptions> | |
| 75 | + </AdditionalOptions> | |
| 76 | + </LaunchAction> | |
| 77 | + <ProfileAction | |
| 78 | + buildConfiguration = "Release" | |
| 79 | + shouldUseLaunchSchemeArgsEnv = "YES" | |
| 80 | + savedToolIdentifier = "" | |
| 81 | + useCustomWorkingDirectory = "NO" | |
| 82 | + debugDocumentVersioning = "YES"> | |
| 83 | + <BuildableProductRunnable | |
| 84 | + runnableDebuggingMode = "0"> | |
| 85 | + <BuildableReference | |
| 86 | + BuildableIdentifier = "primary" | |
| 87 | + BlueprintIdentifier = "6003F589195388D20070C39A" | |
| 88 | + BuildableName = "CNLiveImagePickerController_Example.app" | |
| 89 | + BlueprintName = "CNLiveImagePickerController_Example" | |
| 90 | + ReferencedContainer = "container:CNLiveImagePickerController.xcodeproj"> | |
| 91 | + </BuildableReference> | |
| 92 | + </BuildableProductRunnable> | |
| 93 | + </ProfileAction> | |
| 94 | + <AnalyzeAction | |
| 95 | + buildConfiguration = "Debug"> | |
| 96 | + </AnalyzeAction> | |
| 97 | + <ArchiveAction | |
| 98 | + buildConfiguration = "Release" | |
| 99 | + revealArchiveInOrganizer = "YES"> | |
| 100 | + </ArchiveAction> | |
| 101 | +</Scheme> | ... | ... |
Example/CNLiveImagePickerController/Base.lproj/LaunchScreen.storyboard
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> | |
| 3 | + <device id="retina4_7" orientation="portrait"> | |
| 4 | + <adaptation id="fullscreen"/> | |
| 5 | + </device> | |
| 6 | + <dependencies> | |
| 7 | + <deployment identifier="iOS"/> | |
| 8 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> | |
| 9 | + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | |
| 10 | + </dependencies> | |
| 11 | + <scenes> | |
| 12 | + <!--View Controller--> | |
| 13 | + <scene sceneID="EHf-IW-A2E"> | |
| 14 | + <objects> | |
| 15 | + <viewController id="01J-lp-oVM" sceneMemberID="viewController"> | |
| 16 | + <layoutGuides> | |
| 17 | + <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/> | |
| 18 | + <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/> | |
| 19 | + </layoutGuides> | |
| 20 | + <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> | |
| 21 | + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> | |
| 22 | + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |
| 23 | + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |
| 24 | + </view> | |
| 25 | + </viewController> | |
| 26 | + <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> | |
| 27 | + </objects> | |
| 28 | + <point key="canvasLocation" x="53" y="375"/> | |
| 29 | + </scene> | |
| 30 | + </scenes> | |
| 31 | +</document> | ... | ... |
Example/CNLiveImagePickerController/Base.lproj/Main.storyboard
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="whP-gf-Uak"> | |
| 3 | + <device id="retina4_7" orientation="portrait"> | |
| 4 | + <adaptation id="fullscreen"/> | |
| 5 | + </device> | |
| 6 | + <dependencies> | |
| 7 | + <deployment identifier="iOS"/> | |
| 8 | + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/> | |
| 9 | + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | |
| 10 | + </dependencies> | |
| 11 | + <scenes> | |
| 12 | + <!--View Controller--> | |
| 13 | + <scene sceneID="wQg-tq-qST"> | |
| 14 | + <objects> | |
| 15 | + <viewController id="whP-gf-Uak" customClass="CNLiveViewController" sceneMemberID="viewController"> | |
| 16 | + <layoutGuides> | |
| 17 | + <viewControllerLayoutGuide type="top" id="uEw-UM-LJ8"/> | |
| 18 | + <viewControllerLayoutGuide type="bottom" id="Mvr-aV-6Um"/> | |
| 19 | + </layoutGuides> | |
| 20 | + <view key="view" contentMode="scaleToFill" id="TpU-gO-2f1"> | |
| 21 | + <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> | |
| 22 | + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |
| 23 | + <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |
| 24 | + </view> | |
| 25 | + </viewController> | |
| 26 | + <placeholder placeholderIdentifier="IBFirstResponder" id="tc2-Qw-aMS" userLabel="First Responder" sceneMemberID="firstResponder"/> | |
| 27 | + </objects> | |
| 28 | + <point key="canvasLocation" x="305" y="433"/> | |
| 29 | + </scene> | |
| 30 | + </scenes> | |
| 31 | +</document> | ... | ... |
Example/CNLiveImagePickerController/CNLiveAppDelegate.h
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveAppDelegate.h | |
| 3 | +// CNLiveImagePickerController | |
| 4 | +// | |
| 5 | +// Created by jyyjkt on 08/01/2019. | |
| 6 | +// Copyright (c) 2019 jyyjkt. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +@import UIKit; | |
| 10 | + | |
| 11 | +@interface CNLiveAppDelegate : UIResponder <UIApplicationDelegate> | |
| 12 | + | |
| 13 | +@property (strong, nonatomic) UIWindow *window; | |
| 14 | + | |
| 15 | +@end | ... | ... |
Example/CNLiveImagePickerController/CNLiveAppDelegate.m
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveAppDelegate.m | |
| 3 | +// CNLiveImagePickerController | |
| 4 | +// | |
| 5 | +// Created by jyyjkt on 08/01/2019. | |
| 6 | +// Copyright (c) 2019 jyyjkt. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "CNLiveAppDelegate.h" | |
| 10 | + | |
| 11 | +@implementation CNLiveAppDelegate | |
| 12 | + | |
| 13 | +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | |
| 14 | +{ | |
| 15 | + // Override point for customization after application launch. | |
| 16 | + return YES; | |
| 17 | +} | |
| 18 | + | |
| 19 | +- (void)applicationWillResignActive:(UIApplication *)application | |
| 20 | +{ | |
| 21 | + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. | |
| 22 | + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. | |
| 23 | +} | |
| 24 | + | |
| 25 | +- (void)applicationDidEnterBackground:(UIApplication *)application | |
| 26 | +{ | |
| 27 | + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. | |
| 28 | + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. | |
| 29 | +} | |
| 30 | + | |
| 31 | +- (void)applicationWillEnterForeground:(UIApplication *)application | |
| 32 | +{ | |
| 33 | + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. | |
| 34 | +} | |
| 35 | + | |
| 36 | +- (void)applicationDidBecomeActive:(UIApplication *)application | |
| 37 | +{ | |
| 38 | + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. | |
| 39 | +} | |
| 40 | + | |
| 41 | +- (void)applicationWillTerminate:(UIApplication *)application | |
| 42 | +{ | |
| 43 | + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. | |
| 44 | +} | |
| 45 | + | |
| 46 | +@end | ... | ... |
Example/CNLiveImagePickerController/CNLiveImagePickerController-Info.plist
0 → 100644
| 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>CFBundleDevelopmentRegion</key> | |
| 6 | + <string>en</string> | |
| 7 | + <key>CFBundleDisplayName</key> | |
| 8 | + <string>${PRODUCT_NAME}</string> | |
| 9 | + <key>CFBundleExecutable</key> | |
| 10 | + <string>${EXECUTABLE_NAME}</string> | |
| 11 | + <key>CFBundleIdentifier</key> | |
| 12 | + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | |
| 13 | + <key>CFBundleInfoDictionaryVersion</key> | |
| 14 | + <string>6.0</string> | |
| 15 | + <key>CFBundleName</key> | |
| 16 | + <string>${PRODUCT_NAME}</string> | |
| 17 | + <key>CFBundlePackageType</key> | |
| 18 | + <string>APPL</string> | |
| 19 | + <key>CFBundleShortVersionString</key> | |
| 20 | + <string>1.0</string> | |
| 21 | + <key>CFBundleSignature</key> | |
| 22 | + <string>????</string> | |
| 23 | + <key>CFBundleVersion</key> | |
| 24 | + <string>1.0</string> | |
| 25 | + <key>LSRequiresIPhoneOS</key> | |
| 26 | + <true/> | |
| 27 | + <key>UILaunchStoryboardName</key> | |
| 28 | + <string>LaunchScreen</string> | |
| 29 | + <key>UIMainStoryboardFile</key> | |
| 30 | + <string>Main</string> | |
| 31 | + <key>UIRequiredDeviceCapabilities</key> | |
| 32 | + <array> | |
| 33 | + <string>armv7</string> | |
| 34 | + </array> | |
| 35 | + <key>UISupportedInterfaceOrientations</key> | |
| 36 | + <array> | |
| 37 | + <string>UIInterfaceOrientationPortrait</string> | |
| 38 | + <string>UIInterfaceOrientationLandscapeLeft</string> | |
| 39 | + <string>UIInterfaceOrientationLandscapeRight</string> | |
| 40 | + </array> | |
| 41 | + <key>UISupportedInterfaceOrientations~ipad</key> | |
| 42 | + <array> | |
| 43 | + <string>UIInterfaceOrientationPortrait</string> | |
| 44 | + <string>UIInterfaceOrientationPortraitUpsideDown</string> | |
| 45 | + <string>UIInterfaceOrientationLandscapeLeft</string> | |
| 46 | + <string>UIInterfaceOrientationLandscapeRight</string> | |
| 47 | + </array> | |
| 48 | +</dict> | |
| 49 | +</plist> | ... | ... |
Example/CNLiveImagePickerController/CNLiveImagePickerController-Prefix.pch
0 → 100644
| 1 | +// | |
| 2 | +// Prefix header | |
| 3 | +// | |
| 4 | +// The contents of this file are implicitly included at the beginning of every source file. | |
| 5 | +// | |
| 6 | + | |
| 7 | +#import <Availability.h> | |
| 8 | + | |
| 9 | +#ifndef __IPHONE_5_0 | |
| 10 | +#warning "This project uses features only available in iOS SDK 5.0 and later." | |
| 11 | +#endif | |
| 12 | + | |
| 13 | +#ifdef __OBJC__ | |
| 14 | + @import UIKit; | |
| 15 | + @import Foundation; | |
| 16 | +#endif | ... | ... |
Example/CNLiveImagePickerController/CNLiveViewController.h
0 → 100644
Example/CNLiveImagePickerController/CNLiveViewController.m
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveViewController.m | |
| 3 | +// CNLiveImagePickerController | |
| 4 | +// | |
| 5 | +// Created by jyyjkt on 08/01/2019. | |
| 6 | +// Copyright (c) 2019 jyyjkt. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +#import "CNLiveViewController.h" | |
| 10 | + | |
| 11 | +@interface CNLiveViewController () | |
| 12 | + | |
| 13 | +@end | |
| 14 | + | |
| 15 | +@implementation CNLiveViewController | |
| 16 | + | |
| 17 | +- (void)viewDidLoad | |
| 18 | +{ | |
| 19 | + [super viewDidLoad]; | |
| 20 | + // Do any additional setup after loading the view, typically from a nib. | |
| 21 | +} | |
| 22 | + | |
| 23 | +- (void)didReceiveMemoryWarning | |
| 24 | +{ | |
| 25 | + [super didReceiveMemoryWarning]; | |
| 26 | + // Dispose of any resources that can be recreated. | |
| 27 | +} | |
| 28 | + | |
| 29 | +@end | ... | ... |
Example/CNLiveImagePickerController/Images.xcassets/AppIcon.appiconset/Contents.json
0 → 100644
| 1 | +{ | |
| 2 | + "images" : [ | |
| 3 | + { | |
| 4 | + "idiom" : "iphone", | |
| 5 | + "size" : "20x20", | |
| 6 | + "scale" : "2x" | |
| 7 | + }, | |
| 8 | + { | |
| 9 | + "idiom" : "iphone", | |
| 10 | + "size" : "20x20", | |
| 11 | + "scale" : "3x" | |
| 12 | + }, | |
| 13 | + { | |
| 14 | + "idiom" : "iphone", | |
| 15 | + "size" : "29x29", | |
| 16 | + "scale" : "2x" | |
| 17 | + }, | |
| 18 | + { | |
| 19 | + "idiom" : "iphone", | |
| 20 | + "size" : "29x29", | |
| 21 | + "scale" : "3x" | |
| 22 | + }, | |
| 23 | + { | |
| 24 | + "idiom" : "iphone", | |
| 25 | + "size" : "40x40", | |
| 26 | + "scale" : "2x" | |
| 27 | + }, | |
| 28 | + { | |
| 29 | + "idiom" : "iphone", | |
| 30 | + "size" : "40x40", | |
| 31 | + "scale" : "3x" | |
| 32 | + }, | |
| 33 | + { | |
| 34 | + "idiom" : "iphone", | |
| 35 | + "size" : "60x60", | |
| 36 | + "scale" : "2x" | |
| 37 | + }, | |
| 38 | + { | |
| 39 | + "idiom" : "iphone", | |
| 40 | + "size" : "60x60", | |
| 41 | + "scale" : "3x" | |
| 42 | + }, | |
| 43 | + { | |
| 44 | + "idiom" : "ipad", | |
| 45 | + "size" : "20x20", | |
| 46 | + "scale" : "1x" | |
| 47 | + }, | |
| 48 | + { | |
| 49 | + "idiom" : "ipad", | |
| 50 | + "size" : "20x20", | |
| 51 | + "scale" : "2x" | |
| 52 | + }, | |
| 53 | + { | |
| 54 | + "idiom" : "ipad", | |
| 55 | + "size" : "29x29", | |
| 56 | + "scale" : "1x" | |
| 57 | + }, | |
| 58 | + { | |
| 59 | + "idiom" : "ipad", | |
| 60 | + "size" : "29x29", | |
| 61 | + "scale" : "2x" | |
| 62 | + }, | |
| 63 | + { | |
| 64 | + "idiom" : "ipad", | |
| 65 | + "size" : "40x40", | |
| 66 | + "scale" : "1x" | |
| 67 | + }, | |
| 68 | + { | |
| 69 | + "idiom" : "ipad", | |
| 70 | + "size" : "40x40", | |
| 71 | + "scale" : "2x" | |
| 72 | + }, | |
| 73 | + { | |
| 74 | + "idiom" : "ipad", | |
| 75 | + "size" : "76x76", | |
| 76 | + "scale" : "1x" | |
| 77 | + }, | |
| 78 | + { | |
| 79 | + "idiom" : "ipad", | |
| 80 | + "size" : "76x76", | |
| 81 | + "scale" : "2x" | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + "idiom" : "ipad", | |
| 85 | + "size" : "83.5x83.5", | |
| 86 | + "scale" : "2x" | |
| 87 | + }, | |
| 88 | + { | |
| 89 | + "idiom" : "ios-marketing", | |
| 90 | + "size" : "1024x1024", | |
| 91 | + "scale" : "1x" | |
| 92 | + } | |
| 93 | + ], | |
| 94 | + "info" : { | |
| 95 | + "version" : 1, | |
| 96 | + "author" : "xcode" | |
| 97 | + } | |
| 98 | +} | ... | ... |
Example/CNLiveImagePickerController/en.lproj/InfoPlist.strings
0 → 100644
Example/CNLiveImagePickerController/main.m
0 → 100644
| 1 | +// | |
| 2 | +// main.m | |
| 3 | +// CNLiveImagePickerController | |
| 4 | +// | |
| 5 | +// Created by jyyjkt on 08/01/2019. | |
| 6 | +// Copyright (c) 2019 jyyjkt. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +@import UIKit; | |
| 10 | +#import "CNLiveAppDelegate.h" | |
| 11 | + | |
| 12 | +int main(int argc, char * argv[]) | |
| 13 | +{ | |
| 14 | + @autoreleasepool { | |
| 15 | + return UIApplicationMain(argc, argv, nil, NSStringFromClass([CNLiveAppDelegate class])); | |
| 16 | + } | |
| 17 | +} | ... | ... |
Example/Podfile
0 → 100644
Example/Tests/Tests-Info.plist
0 → 100644
| 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>CFBundleDevelopmentRegion</key> | |
| 6 | + <string>en</string> | |
| 7 | + <key>CFBundleExecutable</key> | |
| 8 | + <string>${EXECUTABLE_NAME}</string> | |
| 9 | + <key>CFBundleIdentifier</key> | |
| 10 | + <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | |
| 11 | + <key>CFBundleInfoDictionaryVersion</key> | |
| 12 | + <string>6.0</string> | |
| 13 | + <key>CFBundlePackageType</key> | |
| 14 | + <string>BNDL</string> | |
| 15 | + <key>CFBundleShortVersionString</key> | |
| 16 | + <string>1.0</string> | |
| 17 | + <key>CFBundleSignature</key> | |
| 18 | + <string>????</string> | |
| 19 | + <key>CFBundleVersion</key> | |
| 20 | + <string>1</string> | |
| 21 | +</dict> | |
| 22 | +</plist> | ... | ... |
Example/Tests/Tests-Prefix.pch
0 → 100644
Example/Tests/Tests.m
0 → 100644
| 1 | +// | |
| 2 | +// CNLiveImagePickerControllerTests.m | |
| 3 | +// CNLiveImagePickerControllerTests | |
| 4 | +// | |
| 5 | +// Created by jyyjkt on 08/01/2019. | |
| 6 | +// Copyright (c) 2019 jyyjkt. All rights reserved. | |
| 7 | +// | |
| 8 | + | |
| 9 | +@import XCTest; | |
| 10 | + | |
| 11 | +@interface Tests : XCTestCase | |
| 12 | + | |
| 13 | +@end | |
| 14 | + | |
| 15 | +@implementation Tests | |
| 16 | + | |
| 17 | +- (void)setUp | |
| 18 | +{ | |
| 19 | + [super setUp]; | |
| 20 | + // Put setup code here. This method is called before the invocation of each test method in the class. | |
| 21 | +} | |
| 22 | + | |
| 23 | +- (void)tearDown | |
| 24 | +{ | |
| 25 | + // Put teardown code here. This method is called after the invocation of each test method in the class. | |
| 26 | + [super tearDown]; | |
| 27 | +} | |
| 28 | + | |
| 29 | +- (void)testExample | |
| 30 | +{ | |
| 31 | + XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); | |
| 32 | +} | |
| 33 | + | |
| 34 | +@end | |
| 35 | + | ... | ... |
Example/Tests/en.lproj/InfoPlist.strings
0 → 100644
LICENSE
| 1 | -MIT License | |
| 2 | - | |
| 3 | -Copyright (c) 2018 cnlive | |
| 1 | +Copyright (c) 2019 jyyjkt <jyyjkt@qq.com> | |
| 4 | 2 | |
| 5 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy |
| 6 | 4 | of this software and associated documentation files (the "Software"), to deal |
| ... | ... | @@ -9,13 +7,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 9 | 7 | copies of the Software, and to permit persons to whom the Software is |
| 10 | 8 | furnished to do so, subject to the following conditions: |
| 11 | 9 | |
| 12 | -The above copyright notice and this permission notice shall be included in all | |
| 13 | -copies or substantial portions of the Software. | |
| 10 | +The above copyright notice and this permission notice shall be included in | |
| 11 | +all copies or substantial portions of the Software. | |
| 14 | 12 | |
| 15 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 18 | 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 20 | -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 21 | -SOFTWARE. | |
| 22 | 18 | \ No newline at end of file |
| 19 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 20 | +THE SOFTWARE. | ... | ... |
README.md
| 1 | +# CNLiveImagePickerController | |
| 2 | + | |
| 3 | +[](https://travis-ci.org/jyyjkt/CNLiveImagePickerController) | |
| 4 | +[](https://cocoapods.org/pods/CNLiveImagePickerController) | |
| 5 | +[](https://cocoapods.org/pods/CNLiveImagePickerController) | |
| 6 | +[](https://cocoapods.org/pods/CNLiveImagePickerController) | |
| 7 | + | |
| 8 | +## Example | |
| 9 | + | |
| 10 | +To run the example project, clone the repo, and run `pod install` from the Example directory first. | |
| 11 | + | |
| 12 | +## Requirements | |
| 13 | + | |
| 14 | +## Installation | |
| 15 | + | |
| 16 | +CNLiveImagePickerController is available through [CocoaPods](https://cocoapods.org). To install | |
| 17 | +it, simply add the following line to your Podfile: | |
| 18 | + | |
| 19 | +```ruby | |
| 20 | +pod 'CNLiveImagePickerController' | |
| 21 | +``` | |
| 22 | + | |
| 23 | +## Author | |
| 24 | + | |
| 25 | +jyyjkt, jyyjkt@qq.com | |
| 26 | + | |
| 27 | +## License | |
| 28 | + | |
| 29 | +CNLiveImagePickerController is available under the MIT license. See the LICENSE file for more info. | ... | ... |
_Pods.xcodeproj
0 → 120000