Commit 89c5d1425d3781882e060e00ccd0927c716127d3

Authored by 梁星国
1 parent f4202c95

提交解决问题

TODO:    1.bundle文件整理
		2.宏定义改为系统方法编写
Showing 62 changed files with 9223 additions and 0 deletions
CNLiveImagePickerController.podspec 0 → 100644
  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.
  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/
  7 +#
  8 +
  9 +Pod::Spec.new do |s|
  10 +
  11 + # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  12 + #
  13 + # These will help people to find your library, and whilst it
  14 + # can feel like a chore to fill in it's definitely to your advantage. The
  15 + # summary should be tweet-length, and the description more in depth.
  16 + #
  17 +
  18 + s.name = "CNLiveImagePickerController" # 项目名称
  19 + s.version = "0.0.1" # 版本号 与 你仓库的 标签号 对应
  20 + s.summary = "相册选择基于TZImagePickerController" # 项目简介
  21 +
  22 + # This description is used to generate tags and improve search results.
  23 + # * Think: What does it do? Why did you write it? What is the focus?
  24 + # * Try to keep it short, snappy and to the point.
  25 + # * Write the description between the DESC delimiters below.
  26 + # * Finally, don't worry about the indent, CocoaPods strips it!
  27 + s.description = <<-DESC
  28 + 1.相册选择图片,视频
  29 + DESC
  30 +
  31 + s.homepage = "http://bj.gitlab.cnlive.com/ios-team/CNLiveImagePickerController"
  32 +
  33 + # s.screenshots = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"
  34 +
  35 +
  36 + # ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  37 + #
  38 + # Licensing your code is important. See http://choosealicense.com for more info.
  39 + # CocoaPods will detect a license file if there is a named LICENSE*
  40 + # Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
  41 + #
  42 +
  43 + s.license = "MIT" # 开源证书
  44 + # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
  45 +
  46 +
  47 + # ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  48 + #
  49 + # Specify the authors of the library, with email addresses. Email addresses
  50 + # of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
  51 + # accepts just a name if you'd rather not provide an email address.
  52 + #
  53 + # Specify a social_media_url where others can refer to, for example a twitter
  54 + # profile URL.
  55 + #
  56 +
  57 + s.author = { "梁星国" => "liangxingguo@cnlive.com" }
  58 + # Or just: s.author = "梁星国"
  59 + # s.authors = { "梁星国" => "jyyjkt@qq.com" }
  60 + # s.social_media_url = "http://twitter.com/梁星国"
  61 +
  62 + # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  63 + #
  64 + # If this Pod runs only on iOS or OS X, then specify the platform and
  65 + # the deployment target. You can optionally include the target after the platform.
  66 + #
  67 +
  68 + # s.platform = :ios
  69 + s.platform = :ios, "9.0"
  70 +
  71 + # When using multiple platforms
  72 + # s.ios.deployment_target = "5.0"
  73 + # s.osx.deployment_target = "10.7"
  74 + # s.watchos.deployment_target = "2.0"
  75 + # s.tvos.deployment_target = "9.0"
  76 +
  77 +
  78 + # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  79 + #
  80 + # Specify the location from where the source should be retrieved.
  81 + # Supports git, hg, bzr, svn and HTTP.
  82 + #
  83 +
  84 + s.source = { :git => "http://bj.gitlab.cnlive.com/ios-team/CNLiveImagePickerController.git", :tag => "#{s.version}" } #你的仓库地址
  85 +
  86 +
  87 + # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  88 + #
  89 + # CocoaPods is smart about how it includes source code. For source files
  90 + # giving a folder will include any swift, h, m, mm, c & cpp files.
  91 + # For header files it will include any header in the folder.
  92 + # Not including the public_header_files will make all headers public.
  93 + #
  94 +
  95 + s.source_files = "CNLiveImagePickerController/*"
  96 + s.exclude_files = "Classes/Exclude"
  97 +
  98 + # s.public_header_files = "Classes/**/*.h"
  99 +
  100 +
  101 + # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  102 + #
  103 + # A list of resources included with the Pod. These are copied into the
  104 + # target bundle with a build phase script. Anything else will be cleaned.
  105 + # You can preserve files from being cleaned, please don't preserve
  106 + # non-essential files like tests, examples and documentation.
  107 + #
  108 +
  109 + # s.resource = "icon.png"
  110 + # s.resources = "Resources/*.png"
  111 +
  112 + # s.preserve_paths = "FilesToSave", "MoreFilesToSave"
  113 +
  114 +
  115 + # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  116 + #
  117 + # Link your library with frameworks, or libraries. Libraries do not include
  118 + # the lib prefix of their name.
  119 + #
  120 +
  121 + # s.framework = "SomeFramework"
  122 + s.frameworks = "UIKit", "Foundation" #支持的框架
  123 +
  124 + # s.library = "iconv"
  125 + # s.libraries = "iconv", "xml2"
  126 +
  127 +
  128 + # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  129 + #
  130 + # If your library depends on compiler flags you can set them in the xcconfig hash
  131 + # where they will only apply to your library. If you depend on other Podspecs
  132 + # you can include multiple dependencies to ensure it works.
  133 +
  134 + s.requires_arc = true
  135 +
  136 + # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
  137 + # s.dependency "JSONKit", "~> 1.4"
  138 +
  139 +end
... ...
CNLiveImagePickerController/AppCommonDefine.h 0 → 100644
  1 +//
  2 +// AppCommonDefine.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 张旭 on 2018/1/2.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#ifndef AppCommonDefine_h
  10 +#define AppCommonDefine_h
  11 +
  12 +#ifndef CNLiveNetAddUrlSchems
  13 +#define CNLiveNetAddUrlSchems @"CNLiveNetAddUrlSchems" //
  14 +#endif
  15 +
  16 +#ifndef CNThirdPayBack
  17 +#define CNThirdPayBack @"CNThirdPayBack" //三方支付返回标识
  18 +#endif
  19 +
  20 +#ifndef CNThirdPayOrderId
  21 +#define CNThirdPayOrderId @"CNThirdPayOrderId" //三方支付订单Id
  22 +#endif
  23 +
  24 +#ifndef CNDarenHomeSelectChangeNotification
  25 +#define CNDarenHomeSelectChangeNotification @"CNDarenHomeSelectChangeNotification" //达人主页选择type 改变
  26 +#define CNAddGroupMemberNotification @"CNAddGroupMemberNotification" //添加群成员
  27 +#define CNDeleteGroupMemberNotification @"CNDeleteGroupMemberNotification" //删除群成功
  28 +#define CNMoviePlaybackStateChangeNotication @"CNMoviePlaybackStateChangeNotication" //播放状态发生改变
  29 +#define CNApplyRefundSuccessNotification @"CNApplyRefundSuccessNotification" //申请退款成功
  30 +#define CNEvaluateSuccessNotioncation @"CNEvaluateSuccessNotioncation" //评论成功
  31 +#define CNUpdateDefultAddressSuccessNotication @"CNUpdateDefultAddressSuccessNotication" //添加或修个收货地址成功
  32 +#define CNDeleteDefultAddressSuccessNotication @"CNDeleteDefultAddressSUccessNotication" //删除默认的收货地址
  33 +#define CNSendImageSuccessNotication @"CNSendImageSuccessNotication" //发送图片成功,更新UI
  34 +#define CNRatatePortraitNotication @"CNRatatePortraitNotication" //全屏点击分享通知播放界面 由全屏变为竖屏
  35 +#endif
  36 +
  37 +//*** Native Classify
  38 +
  39 +//点击推荐页的栏目 跳转到对应栏目详细页
  40 +#define ChangeHomeChannel @"changeHomeChannel"
  41 +
  42 +//首页pagingView News类型的页面从屏幕上消失 news页面上的播放器同时消失
  43 +#define NewsPagingViewDisappear @"NewsPagingViewDisappear"
  44 +
  45 +#define OldChannelVersion @"OldChannelVersion" //首页频道列表版本号
  46 +#define NewChannelVersion @"NewChannelVersion"
  47 +
  48 +#define NormalChannelArray @"NormalChannelArray" //常用频道
  49 +#define OtherChannelArray @"OtherChannelArray" //其他频道
  50 +
  51 +#define AppVersion [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] //CFBundleShortVersionString
  52 +
  53 +//***
  54 +
  55 +// 分类板块h5地址存储
  56 +#ifndef CNLiveNetAddCategoryChannels
  57 +#define CNLiveNetAddCategoryChannels @"CNLiveNetAddCategoryChannels"
  58 +#endif
  59 +// App Store版本号存储
  60 +#ifndef CNLiveNetAddAppStoreVersionNumber
  61 +#define CNLiveNetAddAppStoreVersionNumber @"CNLiveNetAddAppStoreVersionNumber"
  62 +#endif
  63 +////////////////////////////////////////////////////////
  64 +//////////// AppDelegate
  65 +////////////////////////////////////////////////////////
  66 +#ifndef AppKeyWindow
  67 +#define AppKeyWindow ((AppDelegate *)[UIApplication sharedApplication].delegate).window
  68 +#endif
  69 +
  70 +#ifndef CNAppDelegate
  71 +#define CNAppDelegate ((AppDelegate *)[UIApplication sharedApplication].delegate)
  72 +#endif
  73 +
  74 +
  75 +////////////////////////////////////////////////////////
  76 +//////////// function
  77 +////////////////////////////////////////////////////////
  78 +#define isAllowChangeTheme 0
  79 +
  80 +
  81 +////////////////////////////////////////////////////////
  82 +//////////// SCreen
  83 +////////////////////////////////////////////////////////
  84 +#define KScreenWidth ([UIScreen mainScreen].bounds.size.width > [UIScreen mainScreen].bounds.size.height ? [UIScreen mainScreen].bounds.size.height : [UIScreen mainScreen].bounds.size.width)
  85 +#define KScreenHeight ([UIScreen mainScreen].bounds.size.width > [UIScreen mainScreen].bounds.size.height ? [UIScreen mainScreen].bounds.size.width : [UIScreen mainScreen].bounds.size.height)
  86 +
  87 +
  88 +//判断iPHoneXr
  89 +#define Device_Is_iPhoneXS_XR ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(828, 1792), [[UIScreen mainScreen] currentMode].size) : NO)
  90 +
  91 +//判断iPHoneX、iPHoneXs
  92 +#define Device_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
  93 +#define Device_Is_iPhoneXS ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
  94 +
  95 +//判断iPhoneXs Max
  96 +#define Device_Is_iPhoneXS_MAX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2688), [[UIScreen mainScreen] currentMode].size) : NO)
  97 +
  98 +#define 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)))
  99 +
  100 +
  101 +#define kStatusHeight (int)[UIApplication sharedApplication].statusBarFrame.size.height //x44 非x20
  102 +#define kNavigationBarHeight ((int)[UIApplication sharedApplication].statusBarFrame.size.height+44) //x88 非x64
  103 +#define kVerticalNaviBarHeight ((IS_IPhoneX_All > 0) ? 88 : 44)
  104 +#define kVerticalTabBarTotalHeight ((IS_IPhoneX_All > 0) ? 83 : 49)
  105 +#define kVerticalBottomSafeHeight ((IS_IPhoneX_All > 0) ? 34 : 0)
  106 +#define kVerticalStatusHeight ((IS_IPhoneX_All > 0) ? 44 : 20)
  107 +#define kVerticalTopHeight ((IS_IPhoneX_All > 0) ? 24 : 0)
  108 +#define kHorizontalTopNaviBarHeight 32
  109 +#define kHorizontalBottomHeight ((IS_IPhoneX_All > 0) ? 21 : 0)
  110 +#define kHorizontalLeftHeight ((IS_IPhoneX_All > 0) ? 44 : 0)
  111 +#define kHorizontalRightHeight ((IS_IPhoneX_All > 0) ? 44 : 0)
  112 +#define kHorizontalTopHeight ((IS_IPhoneX_All > 0) ? 24 : 0)
  113 +//////////////////////分类中直播点播横屏特用////////////////////////////
  114 +#define kLiveHorizontalTopHeight ((Device_Is_iPhoneX > 0) ? 6 : 0)
  115 +#define kLiveHorizontalBottomHeight ((Device_Is_iPhoneX > 0) ? 11 : 0)
  116 +
  117 +////////////////////////////////////////////////////////
  118 +//////////// Font
  119 +////////////////////////////////////////////////////////
  120 +#define kAppLargeTextFont [UIFont systemFontOfSize:16]
  121 +#define kAppMiddleTextFont [UIFont systemFontOfSize:14]
  122 +#define kAppSmallTextFont [UIFont systemFontOfSize:12]
  123 +
  124 +#define TopToolBarHeight (64.0 + IPhoneXSafeAreaInsets.bottom)
  125 +
  126 +////////////////////////////////////////////////////////
  127 +//////////// 发送图片,视频限制
  128 +////////////////////////////////////////////////////////
  129 +#define kFriendsCircle_limit_photo 20*1024.0*1024.0 //朋友圈限制图片20M
  130 +#define kFirendsCircle_limit_video 30*1024.0*1024.0 //朋友圈限制视频30M
  131 +#define kTarentoComment_limit_photo 10*1024.0*1024.0 //达人评论10M
  132 +#define kSweepCode_limit_phoho 10*1024.0*1024.0 //扫码10M限制
  133 +#define kChat_limit_photo 20*1024.0*1024.0 //聊天限制图片20M
  134 +#define kChat_limit_video 20*1024.0*1024.0 //聊天限制视频20M
  135 +
  136 +#define kChat_limit_video_length 5*60 //聊天限制视频5分钟
  137 +#define kFriendsCircle_limit_video_maxEdit 5*60 //朋友圈限制视频5分钟
  138 +#define kFriendsCircle_limit_video_max 10*60 //朋友圈限制最大视频编辑10分钟
  139 +
  140 +////////////////////////////////////////////////////////
  141 +//////////// Color
  142 +////////////////////////////////////////////////////////
  143 +
  144 +#define RGBOF(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
  145 +green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
  146 +blue:((float)(rgbValue & 0xFF))/255.0 \
  147 +alpha:1.0]
  148 +
  149 +#define RGBA_OF(rgbValue) [UIColor colorWithRed:((float)(((rgbValue) & 0xFF000000) >> 24))/255.0 \
  150 +green:((float)(((rgbValue) & 0x00FF0000) >> 16))/255.0 \
  151 +blue:((float)(rgbValue & 0x0000FF00) >> 8)/255.0 \
  152 +alpha:((float)(rgbValue & 0x000000FF))/255.0]
  153 +
  154 +#define RGBAOF(v, a) [UIColor colorWithRed:((float)(((v) & 0xFF0000) >> 16))/255.0 \
  155 +green:((float)(((v) & 0x00FF00) >> 8))/255.0 \
  156 +blue:((float)(v & 0x0000FF))/255.0 \
  157 +alpha:a]
  158 +
  159 +
  160 +
  161 +#define RGBA(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a]
  162 +#define RGB(r,g,b) RGBA(r,g,b,1.0f)
  163 +#define CommonBgColor [UIColor colorWithHexString:@"eeeeee"];
  164 +
  165 +#define kDarenBgColor [UIColor colorWithRed:0.36 green:0.36 blue:0.36 alpha:1.00]
  166 +
  167 +#define kDarenGradeColor [UIColor colorWithRed:0.85 green:0.36 blue:0.10 alpha:1.00]
  168 +
  169 +#define kDarenYellowColor [UIColor colorWithRed:0.97 green:0.75 blue:0.03 alpha:1.00]
  170 +
  171 +#define kDarenGreenColor [UIColor colorWithRed:0.08 green:0.86 blue:0.52 alpha:1.00]
  172 +
  173 +#define kToolGrayColor [UIColor colorWithRed:0.94 green:0.94 blue:0.94 alpha:1.00]
  174 +
  175 +#define kCameraNextBtnGrayColor [UIColor colorWithRed:0.56 green:0.56 blue:0.56 alpha:1.00]
  176 +
  177 +#define kViewCommonGrayColor [UIColor colorWithRed:0.97 green:0.97 blue:0.97 alpha:1.00]
  178 +
  179 +#define kLineGrayColor [UIColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.00]
  180 +#define kLineBlueColor [UIColor colorWithRed:0.00 green:0.36 blue:1.00 alpha:1.00]
  181 +
  182 +#define kPublishRedColor [UIColor colorWithRed:0.88 green:0.10 blue:0.13 alpha:1.00]
  183 +
  184 +#define kPublishNaviRedColor [UIColor colorWithRed:1.00 green:0.17 blue:0.29 alpha:1.00]
  185 +
  186 +#define kNaviTintColor [UIColor colorWithRed:0.00 green:0.58 blue:1.00 alpha:1.00]
  187 +
  188 +#define kNaviThemeTintColor [UIColor colorWithRed:0.35 green:0.35 blue:0.35 alpha:1.00]
  189 +
  190 +#define kPublishSuccessColor [UIColor colorWithRed:0.21 green:1.00 blue:0.75 alpha:1.00]
  191 +
  192 +#define kPublishFailureColor [UIColor colorWithRed:1.00 green:0.00 blue:0.00 alpha:1.00]
  193 +
  194 +#define kMomentOrgangeColor [UIColor colorWithRed:0.98 green:0.55 blue:0.11 alpha:1.00]
  195 +
  196 +#define kMomentLineColor [UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1.00]
  197 +
  198 +///////正式
  199 +#define kBackGrayColor [UIColor colorWithRed:0.53 green:0.53 blue:0.53 alpha:1.00]
  200 +
  201 +#define kGuangbiaoColor [UIColor colorWithRed:0.20 green:0.35 blue:0.95 alpha:1.00]
  202 +
  203 +////////////////////////////////////////////////////////
  204 +//////////// firendCricle
  205 +////////////////////////////////////////////////////////
  206 +#define contentLabelFontSize 16
  207 +
  208 +
  209 +////////////////////////////////////////////////////////
  210 +//////////// SystemVersion
  211 +////////////////////////////////////////////////////////
  212 +#define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f)
  213 +#define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f)
  214 +#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
  215 +#define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
  216 +#define iOS10Later ([UIDevice currentDevice].systemVersion.floatValue >= 10.0f)
  217 +
  218 +
  219 +////////////////////////////////////////////////////////
  220 +//////////// WeakSelf&StrongSelf
  221 +////////////////////////////////////////////////////////
  222 +/**
  223 + * weakSelf
  224 + */
  225 +#ifndef weakself
  226 +#define weakself __weak typeof(self)weakSelf = self;
  227 +#endif
  228 +/**
  229 + * strongSelf
  230 + */
  231 +#ifndef strongself
  232 +#define strongself __strong typeof(weakSelf)self = weakSelf;
  233 +#endif
  234 +
  235 +////////////////////////////////////////////////////////
  236 +//////////// 输出测试
  237 +////////////////////////////////////////////////////////
  238 +#ifdef DEBUG
  239 +#define NSLog(s, ... ) NSLog( @"[%@ in line %d] ===============>%@", [[NSString stringWithUTF8String:__FILE__] lastPathComponent], __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
  240 +#else
  241 +#define NSLog(s, ... )
  242 +#endif
  243 +
  244 +////////////////////////////////////////////////////////
  245 +//////////// NSUserDefault
  246 +////////////////////////////////////////////////////////
  247 +#ifndef CNUserIsLogin
  248 +#define CNUserIsLogin @"CNUserIsLogin"
  249 +#endif
  250 +
  251 +#ifndef CNUserInfo
  252 +#define CNUserInfo @"CNUserInfo"
  253 +#endif
  254 +
  255 +#ifndef kCNLiveUserDefaultsTingYunUIDKey
  256 +#define kCNLiveUserDefaultsTingYunUIDKey @"kCNLiveUserDefaultsTingYunUIDKey"
  257 +#endif
  258 +
  259 +#ifndef CNGroupListInfo // 某群组成员列表list
  260 +#define CNGroupListInfo @"CNGroupListInfo"
  261 +#endif
  262 +
  263 +#ifndef CNGroupsList // 群组列表list
  264 +#define CNGroupsList @"CNGroupsList"
  265 +#endif
  266 +
  267 +#ifndef CNRefundReason
  268 +#define CNRefundReason @"CNRefundReason"
  269 +#endif
  270 +
  271 +////////////////////////////////////////////////////////
  272 +//////////// Refresh
  273 +////////////////////////////////////////////////////////
  274 +#define TableViewDefaultOffestHeight 64.f
  275 +
  276 +//////////////////////////IM////////////////////////////////
  277 +#pragma mark - IM
  278 +
  279 +#define kSaftyWordsCode 80001
  280 +
  281 +// 是否支持富文本显示
  282 +#define kTestChatAttachment 1
  283 +
  284 +////////////////////////////////////////////////////////
  285 +//////////// 动态跟随系统设置的字体大小改变字体和行高
  286 +////////////////////////////////////////////////////////
  287 +#define RATIO [CNSetUserDefaultTool getScaleCoefficient]
  288 +
  289 +
  290 +//字体大小
  291 +#define Text_FONT(F) [UIFont systemFontOfSize:F]
  292 +
  293 +#define SINGLETON_FOR_HEADER(className) \
  294 +\
  295 ++ (className *)shared##className;
  296 +
  297 +#define SINGLETON_FOR_CLASS(className) \
  298 +\
  299 ++ (className *)shared##className { \
  300 +static className *shared##className = nil; \
  301 +static dispatch_once_t onceToken; \
  302 +dispatch_once(&onceToken, ^{ \
  303 +shared##className = [[self alloc] init]; \
  304 +}); \
  305 +return shared##className; \
  306 +}
  307 +
  308 +#endif /* AppCommonDefine_h */
... ...
CNLiveImagePickerController/CNEditVideoController.h 0 → 100755
  1 +//
  2 +// ZLEditVideoController.h
  3 +// ZLPhotoBrowser
  4 +//
  5 +// Created by long on 2017/9/15.
  6 +// Copyright © 2017年 long. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +
  13 +@interface CNEditVideoController : UIViewController
  14 +
  15 +@property (nonatomic, strong) TZAssetModel *model;
  16 +
  17 +@property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组
  18 +@property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组
  19 +@property (nonatomic, assign) NSInteger currentIndex;
  20 +@property (nonatomic, assign) BOOL isCropImage;
  21 +
  22 +/// Return the new selected photos / 返回最新的选中图片数组
  23 +@property (nonatomic, copy) void (^backButtonEditClickBlock)(BOOL isSelectOriginalPhoto);
  24 +@property (nonatomic, copy) void (^doneButtonEditClickBlock)(BOOL isSelectOriginalPhoto);
  25 +
  26 +
  27 +@end
... ...
CNLiveImagePickerController/CNEditVideoController.m 0 → 100755
  1 +//
  2 +// ZLEditVideoController.m
  3 +// ZLPhotoBrowser
  4 +//
  5 +// Created by long on 2017/9/15.
  6 +// Copyright © 2017年 long. All rights reserved.
  7 +//
  8 +
  9 +#import "CNEditVideoController.h"
  10 +#import <AVFoundation/AVFoundation.h>
  11 +#import "TZAssetModel.h"
  12 +#import <objc/runtime.h>
  13 +#import <AssetsLibrary/AssetsLibrary.h>
  14 +#import "TZImagePickerController.h"
  15 +#import "TZPhotoPreviewCell.h"
  16 +#import "TZImageCropManager.h"
  17 +
  18 +#define kItemWidth kItemHeight * 2/3
  19 +#define kItemHeight 50
  20 +#define kAPPName @"网++"
  21 +
  22 +#pragma mark - 显示帧数的CNEditFrameView
  23 +
  24 +@interface CNEditVideoCell : UICollectionViewCell
  25 +
  26 +@property (nonatomic, strong) UIImageView *imageView;
  27 +
  28 +@end
  29 +
  30 +@implementation CNEditVideoCell
  31 +
  32 +- (UIImageView *)imageView
  33 +{
  34 + if (!_imageView) {
  35 + _imageView = [[UIImageView alloc] init];
  36 + _imageView.frame = self.bounds;
  37 + _imageView.contentMode = UIViewContentModeScaleAspectFill;
  38 + _imageView.clipsToBounds = YES;
  39 + [self.contentView addSubview:_imageView];
  40 + }
  41 + return _imageView;
  42 +}
  43 +
  44 +@end
  45 +
  46 +#pragma mark - 协议编辑帧数协议CNEditFrameViewDelegate
  47 +@protocol CNEditFrameViewDelegate <NSObject>
  48 +
  49 +- (void)editViewValidRectChanged;//有效范围更变
  50 +
  51 +- (void)editViewValidRectEndChanged;//有效范围更变结束
  52 +
  53 +@end
  54 +
  55 +#pragma mark - 编辑时视图CNEditFrameView
  56 +@interface CNEditFrameView : UIView
  57 +{
  58 + UIImageView *_leftView;//左视图
  59 + UIImageView *_rightView;//有视图
  60 +}
  61 +
  62 +@property (nonatomic, assign) CGRect validRect;
  63 +@property (nonatomic, weak) id<CNEditFrameViewDelegate> delegate;
  64 +
  65 +@end
  66 +
  67 +@implementation CNEditFrameView
  68 +
  69 +- (instancetype)init
  70 +{
  71 + self = [super init];
  72 + if (self) {
  73 + [self setupUI];
  74 + }
  75 + return self;
  76 +}
  77 +
  78 +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
  79 +{
  80 + //扩大下有效范围
  81 + CGRect left = _leftView.frame;
  82 + left.origin.x -= kItemWidth/2;
  83 + left.size.width += kItemWidth/2;
  84 + CGRect right = _rightView.frame;
  85 + right.size.width += kItemWidth/2;
  86 +
  87 + if (CGRectContainsPoint(left, point)) {
  88 + return _leftView;
  89 + }
  90 + if (CGRectContainsPoint(right, point)) {
  91 + return _rightView;
  92 + }
  93 + return nil;
  94 +}
  95 +
  96 +- (void)setupUI
  97 +{
  98 + self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5];
  99 + self.layer.borderWidth = 2;
  100 + self.layer.borderColor = [UIColor clearColor].CGColor;
  101 +
  102 + _leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"video_edit_left"]];
  103 + _leftView.userInteractionEnabled = YES;
  104 + _leftView.tag = 0;
  105 + UIPanGestureRecognizer *lg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  106 + [_leftView addGestureRecognizer:lg];
  107 + [self addSubview:_leftView];
  108 +
  109 + _rightView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"video_edit_right"]];
  110 + _rightView.userInteractionEnabled = YES;
  111 + _rightView.tag = 1;
  112 + UIPanGestureRecognizer *rg = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
  113 + [_rightView addGestureRecognizer:rg];
  114 + [self addSubview:_rightView];
  115 +}
  116 +
  117 +- (void)panAction:(UIGestureRecognizer *)pan //滑动收拾实现
  118 +{
  119 + self.layer.borderColor = [[UIColor whiteColor] colorWithAlphaComponent:.4].CGColor;
  120 + CGPoint point = [pan locationInView:self];
  121 +
  122 + CGRect rct = self.validRect;
  123 +
  124 + const CGFloat W = self.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/CNImagePickerController.bundle/Root.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>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/CNImagePickerController.bundle/en.lproj/Root.strings 0 → 100644
1 1 Binary files /dev/null and b/CNLiveImagePickerController/CNImagePickerController.bundle/en.lproj/Root.strings differ
... ...
CNLiveImagePickerController/CNImagePickerController.h 0 → 100644
  1 +//
  2 +// CNTZImagePickerControllerViewController.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/8/22.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImagePickerController.h"
  10 +
  11 +@interface CNImagePickerController : TZImagePickerController
  12 +
  13 +/**
  14 + 配置
  15 + */
  16 +- (void)configTZImagePicker;
  17 +
  18 +@end
... ...
CNLiveImagePickerController/CNImagePickerController.m 0 → 100644
  1 +//
  2 +// CNTZImagePickerControllerViewController.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/8/22.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNImagePickerController.h"
  10 +#import "AppCommonDefine.h"
  11 +
  12 +@interface CNImagePickerController ()
  13 +
  14 +@end
  15 +
  16 +@implementation CNImagePickerController
  17 +
  18 +- (void)viewDidLoad {
  19 + [super viewDidLoad];
  20 +
  21 +}
  22 +
  23 +/**
  24 + 配置
  25 + */
  26 +- (void)configTZImagePicker{
  27 +
  28 + // imagePickerVc.navigationBar.translucent = NO;
  29 +
  30 +#pragma mark - 五类个性化设置,这些参数都可以不传,此时会走默认设置
  31 + // 1.设置目前已经选中的图片数组
  32 + self.allowTakePicture = NO; // 在内部显示拍照按钮
  33 + self.allowTakeVideo = NO;// 在内部拍摄按钮
  34 + self.videoMaximumDuration = 10; // 视频最大拍摄时间
  35 + [self setUiImagePickerControllerSettingBlock:^(UIImagePickerController *imagePickerController) {
  36 + imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;//拍摄分辨率
  37 + }];
  38 + // imagePickerVc.photoWidth = 1000;
  39 +
  40 + // 2. Set the appearance
  41 + // 2. 在这里设置imagePickerVc的外观
  42 + // if (iOS7Later) {
  43 + // imagePickerVc.navigationBar.barTintColor = [UIColor greenColor];
  44 + // }
  45 + // imagePickerVc.oKButtonTitleColorDisabled = [UIColor lightGrayColor];
  46 + // imagePickerVc.oKButtonTitleColorNormal = [UIColor greenColor];
  47 + // imagePickerVc.navigationBar.translucent = NO;
  48 + self.iconThemeColor = RGBOF(0x00BBE06);// 主体颜色
  49 + self.showPhotoCannotSelectLayer = YES;//达到上限是否有浮层
  50 + self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];//设置达到上限的浮层
  51 + self.photoDefImage = [UIImage imageNamed:@"photo_cell_normal"];
  52 +#pragma mark - TODO:RGBOF
  53 +// self.photoSelImage = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06) size:CGSizeMake(22, 22) cornerRadius:11];
  54 + self.photoOriginDefImage = [UIImage imageNamed:@"photo_original_nor"];
  55 +
  56 + // 3. Set allow picking video & photo & originalPhoto or not
  57 + // 3. 设置是否可以选择视频/图片/原图/gif(未开放)
  58 + self.allowPickingVideo = YES;// 显示视频
  59 + self.allowPickingImage = YES;// 显示图片
  60 + self.allowPickingOriginalPhoto = YES; //显示原图
  61 + self.allowPickingGif = NO;// 显示GIF
  62 + self.allowPickingMultipleVideo = YES; // 是否可以多选视频
  63 +
  64 + // 4. 照片排列按修改时间升序
  65 + self.sortAscendingByModificationDate = YES;
  66 +
  67 + // imagePickerVc.minImagesCount = 3;
  68 + // imagePickerVc.alwaysEnableDoneBtn = YES;
  69 +
  70 + // imagePickerVc.minPhotoWidthSelectable = 3000;
  71 + // imagePickerVc.minPhotoHeightSelectable = 2000;
  72 +
  73 + /// 5. Single selection mode, valid when maxImagesCount = 1
  74 + /// 5. 单选模式,maxImagesCount为1时才生效
  75 + self.showSelectBtn = NO;
  76 + self.allowCrop = NO;
  77 + self.needCircleCrop = NO;
  78 + // 设置横屏下的裁剪尺寸
  79 + // imagePickerVc.cropRectLandscape = CGRectMake((self.view.tz_height - widthHeight) / 2, left, widthHeight, widthHeight);
  80 + /*
  81 + [imagePickerVc setCropViewSettingBlock:^(UIView *cropView) {
  82 + cropView.layer.borderColor = [UIColor redColor].CGColor;
  83 + cropView.layer.borderWidth = 2.0;
  84 + }];*/
  85 +
  86 + //imagePickerVc.allowPreview = NO;
  87 + // 自定义导航栏上的返回按钮
  88 + /*
  89 + [imagePickerVc setNavLeftBarButtonSettingBlock:^(UIButton *leftButton){
  90 + [leftButton setImage:[UIImage imageNamed:@"back"] forState:UIControlStateNormal];
  91 + [leftButton setImageEdgeInsets:UIEdgeInsetsMake(0, -10, 0, 20)];
  92 + }];
  93 + imagePickerVc.delegate = self;
  94 + */
  95 +
  96 + self.statusBarStyle = UIStatusBarStyleDefault;//状态栏黑色
  97 +
  98 + self.showSelectedIndex = YES; // 设置是否显示图片序号
  99 +
  100 + self.naviBgColor = RGBOF(0xFFFFFF);//导航栏颜色
  101 + self.naviTitleColor = RGBOF(0x282828);//相册title
  102 + self.naviTitleFont = [UIFont fontWithName:@"PingFangSC-Medium" size:18];//title文字大小
  103 + [self setNavLeftBarButtonSettingBlock:^(UIButton *leftButton) {//设置返回按钮图标
  104 + [leftButton setImage:[UIImage imageNamed:@"photo_back"] forState:UIControlStateNormal];//返回按钮图片
  105 + [leftButton setTitle:@"返回" forState:UIControlStateNormal];//设置文字大小
  106 + [leftButton setTitleColor:RGBOF(0x282828) forState:UIControlStateNormal];//设置文字颜色
  107 + leftButton.titleLabel.font = [UIFont systemFontOfSize:15];//设置文字大小
  108 + leftButton.imageEdgeInsets = UIEdgeInsetsMake(0, -7, 0, +7);//设置图片边缘
  109 + }];
  110 + self.barItemTextColor = RGBOF(0x282828);//设置barItem文字颜色
  111 + self.barItemTextFont = [UIFont systemFontOfSize:15];
  112 +
  113 + // 设置首选语言 / Set preferred language
  114 + // imagePickerVc.preferredLanguage = @"zh-Hans";
  115 +
  116 + // 设置languageBundle以使用其它语言 / Set languageBundle to use other language
  117 + // imagePickerVc.languageBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"tz-ru" ofType:@"lproj"]];
  118 +
  119 + /// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等
  120 + //相册
  121 + [self setPhotoPickerPageUIConfigBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) {
  122 +
  123 + //底部栏
  124 + [bottomToolBar setBackgroundColor:RGBOF(0xFFFFFF)];
  125 +
  126 + //预览
  127 + previewButton.titleLabel.font = [UIFont systemFontOfSize:16];
  128 + [previewButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];//禁用
  129 + [previewButton setTitleColor:RGBOF(0x000000) forState:UIControlStateNormal];//默认
  130 +
  131 + //原图按钮
  132 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用
  133 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateNormal];//默认
  134 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_select"] forState:UIControlStateSelected];//选中
  135 + originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  136 + [originalPhotoButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];
  137 + [originalPhotoButton setTitleColor:RGBOF(0x000000) forState:UIControlStateNormal];
  138 +
  139 + //原图文字提示
  140 + originalPhotoLabel.font = [UIFont fontWithName:@"PingFang-SC-Regular" size:16];
  141 + originalPhotoLabel.textColor = RGBOF(0xB3B3B3);
  142 + originalPhotoLabel.hidden = YES;
  143 +
  144 + //选中提示
  145 + numberImageView = [UIImageView new];
  146 + numberLabel = [UILabel new];
  147 +
  148 + //完成按钮
  149 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  150 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  151 + [doneButton setTitleColor:RGBAOF(0xFFFFFF, 0.5) forState:UIControlStateDisabled];
  152 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  153 +
  154 + //颜色绘制成图片
  155 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  156 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateDisabled];
  157 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  158 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  159 + doneButton.layer.masksToBounds = YES;
  160 + doneButton.layer.cornerRadius = 5;
  161 +
  162 + //分割线
  163 + [divideLine setBackgroundColor:RGBOF(0xDEDEDE)];
  164 +
  165 + }];
  166 +
  167 + //图片预览
  168 + [self setPhotoPreviewPageUIConfigBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) {
  169 +
  170 + //返回按钮
  171 + [backButton setImage:[UIImage imageNamed:@"photo_original_back"] forState:UIControlStateNormal];
  172 + //选择按钮
  173 + [selectButton setImage:[UIImage imageNamed:@"photo_original_nor"] forState:UIControlStateNormal];
  174 +// [selectButton setImage:[UIImage qmui_imageWithColor:RGBOF(0x0BBE06) size:CGSizeMake(28, 28) cornerRadius:14] forState:UIControlStateSelected];
  175 + [selectButton setTitle:@"" forState:UIControlStateDisabled];
  176 +
  177 + //原图按钮
  178 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateDisabled];//禁用
  179 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_normal"] forState:UIControlStateNormal];//默认
  180 + [originalPhotoButton setImage:[UIImage imageNamed:@"photo_original_select"] forState:UIControlStateSelected];//选中
  181 + originalPhotoButton.titleLabel.font = [UIFont systemFontOfSize:16];
  182 + [originalPhotoButton setTitleColor:RGBOF(0xB3B3B3) forState:UIControlStateDisabled];
  183 + [originalPhotoButton setTitleColor:RGBAOF(0xFFFFFF, 0.7) forState:UIControlStateNormal];
  184 + //原图内容隐藏
  185 + originalPhotoLabel.hidden = YES;
  186 +
  187 + //完成按钮
  188 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  189 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  190 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  191 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  192 +
  193 + //颜色绘制成图片
  194 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  195 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  196 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  197 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  198 + doneButton.layer.masksToBounds = YES;
  199 + doneButton.layer.cornerRadius = 5;
  200 + }];
  201 +
  202 + //视频预览
  203 + [self setVideoPreviewPageUIConfigBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) {
  204 +
  205 + //完成按钮
  206 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  207 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  208 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  209 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  210 +
  211 + //颜色绘制成图片
  212 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  213 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  214 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  215 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  216 + doneButton.layer.masksToBounds = YES;
  217 + doneButton.layer.cornerRadius = 5;
  218 +
  219 + }];
  220 +
  221 + //gif预览
  222 + [self setGifPreviewPageUIConfigBlock:^(UIView *toolBar, UIButton *doneButton) {
  223 +
  224 + //完成按钮
  225 + doneButton.titleLabel.font = [UIFont systemFontOfSize:13];
  226 + [doneButton setTitle:@"完成" forState:UIControlStateDisabled];
  227 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateDisabled];
  228 + [doneButton setTitleColor:RGBOF(0xFFFFFF) forState:UIControlStateNormal];
  229 +
  230 + //颜色绘制成图片
  231 +// UIImage *dis_image = [UIImage qmui_imageWithColor:RGBAOF(0x0BBE06, 0.5)];
  232 +// [doneButton setBackgroundImage:dis_image forState:UIControlStateSelected];
  233 +// UIImage *nor_image = [UIImage qmui_imageWithColor:RGBOF(0x0BBE06)];
  234 +// [doneButton setBackgroundImage:nor_image forState:UIControlStateNormal];
  235 + doneButton.layer.masksToBounds = YES;
  236 + doneButton.layer.cornerRadius = 5;
  237 +
  238 + }];
  239 + //相册cell
  240 + [self setAssetCellDidSetModelBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
  241 +
  242 +
  243 + }];
  244 + //相簿
  245 + [self setAlbumCellDidSetModelBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) {
  246 + [posterImageView setBackgroundColor:[UIColor blueColor]];
  247 + [posterImageView setBackgroundColor:[UIColor blueColor]];
  248 +
  249 + }];
  250 +
  251 +
  252 + /// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等
  253 + //相册
  254 + [self setPhotoPickerPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine) {
  255 +
  256 + CGRect frame = bottomToolBar.frame;
  257 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  258 +
  259 + CGRect originalPhotoLabelFrame = originalPhotoLabel.frame;
  260 + CGFloat originalX = (bottomToolBar.frame.size.width - originalPhotoLabelFrame.size.width) /2;
  261 + CGFloat originalY = originalPhotoLabelFrame.origin.y;
  262 + originalPhotoButton.frame = CGRectMake(originalX, originalY, originalPhotoLabelFrame.size.width, originalPhotoLabelFrame.size.height);
  263 +
  264 +
  265 + }];
  266 + //图片预览
  267 + [self setPhotoPreviewPageDidLayoutSubviewsBlock:^(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel) {
  268 +
  269 + CGRect frame = toolBar.frame;
  270 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  271 +
  272 + }];
  273 + //视频预览
  274 + [self setVideoPreviewPageDidLayoutSubviewsBlock:^(UIButton *playButton, UIView *toolBar, UIButton *doneButton) {
  275 +
  276 + CGRect frame = toolBar.frame;
  277 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  278 +
  279 + }];
  280 + //gif预览
  281 + [self setGifPreviewPageDidLayoutSubviewsBlock:^(UIView *toolBar, UIButton *doneButton) {
  282 +
  283 + CGRect frame = toolBar.frame;
  284 + doneButton.frame = CGRectMake(frame.size.width - 60 - 13, frame.size.height /2 - 15, 60, 30);
  285 +
  286 + }];
  287 + //相册cell
  288 +
  289 + [self setAssetCellDidLayoutSubviewsBlock:^(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView) {
  290 + }];
  291 + //相簿
  292 + [self setAlbumCellDidLayoutSubviewsBlock:^(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel) {
  293 +
  294 + }];
  295 +
  296 + //设置图片个数
  297 + self.photoNumberIconImage = [UIImage new];
  298 +
  299 +}
  300 +
  301 +- (void)didReceiveMemoryWarning {
  302 + [super didReceiveMemoryWarning];
  303 + // Dispose of any resources that can be recreated.
  304 +}
  305 +
  306 +
  307 +@end
... ...
CNLiveImagePickerController/CNImagePickerManager.h 0 → 100644
  1 +//
  2 +// CNImagePickerManager.h
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/10/8.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <Foundation/Foundation.h>
  11 +#import "CNImagePickerController.h"
  12 +
  13 +
  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 0 → 100644
  1 +//
  2 +// CNImagePickerManager.m
  3 +// CNLiveNetAdd
  4 +//
  5 +// Created by 梁星国 on 2018/10/8.
  6 +// Copyright © 2018年 cnlive. All rights reserved.
  7 +//
  8 +
  9 +#import "CNImagePickerManager.h"
  10 +#import <AssetsLibrary/AssetsLibrary.h>
  11 +#import "AppCommonDefine.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 +
  41 + break;
  42 + case CNImagePickerEnterTypeWitness:
  43 + imagePickerVc.allowPickingImage = NO;// 显示图片
  44 + imagePickerVc.allowPickingMultipleVideo = NO;
  45 + imagePickerVc.maxEditVideoTime = kFriendsCircle_limit_video_maxEdit;//编辑长度
  46 + imagePickerVc.maxVideoDuration = kFriendsCircle_limit_video_max;//编辑视频最大长度
  47 + break;
  48 + default://其他
  49 + break;
  50 + }
  51 +
  52 + imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;//是否选择原图
  53 + // 1.设置目前已经选中的图片数组
  54 + imagePickerVc.selectedAssets = selectedAssets; // 目前已经选中的图片数组
  55 + /// 5. Single selection mode, valid when maxImagesCount = 1
  56 + /// 5. 单选模式,maxImagesCount为1时才生效
  57 + // 设置竖屏下的裁剪尺寸
  58 + NSInteger left = 30;
  59 + NSInteger widthHeight = vc.view.frame.size.width - 2 * left;
  60 + NSInteger top = (vc.view.frame.size.height - widthHeight) / 2;
  61 + imagePickerVc.cropRect = CGRectMake(left, top, widthHeight, widthHeight);
  62 + // 你可以通过block或者代理,来得到用户选择的照片.
  63 + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  64 + // 回调参数
  65 + !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto);
  66 +
  67 + }];
  68 +
  69 + [vc presentViewController:imagePickerVc animated:YES completion:nil];
  70 +}
  71 +
  72 +/// 预览图片
  73 ++ (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 {
  74 +
  75 + if (![delegate isKindOfClass:[UIViewController class]]) {
  76 + return;
  77 + }
  78 + UIViewController *vc = (UIViewController *)delegate;
  79 +
  80 + CNImagePickerController *imagePickerVc = [[CNImagePickerController alloc] initWithSelectedAssets:selectedAssets selectedPhotos:selectedPhotos index:index];
  81 + [imagePickerVc configTZImagePicker];//基本配置
  82 + //特殊配置
  83 + switch (enterType) {
  84 + case CNImagePickerEnterTypeFriendsCircle:
  85 + imagePickerVc.allowPickingGif = NO;
  86 + imagePickerVc.allowPickingOriginalPhoto = YES;
  87 + imagePickerVc.allowPickingMultipleVideo = NO;
  88 + break;
  89 + case CNImagePickerEnterTypeComment:
  90 +#pragma mark - TODO:根据不同设置
  91 + break;
  92 + case CNImagePickerEnterTypeSweepCode:
  93 +
  94 + break;
  95 + case CNImagePickerEnterTypeChat:
  96 +
  97 + break;
  98 + case CNImagePickerEnterTypeOther:
  99 + break;
  100 + default://其他
  101 + break;
  102 + }
  103 +
  104 + imagePickerVc.maxImagesCount = maxImagesCount;
  105 + imagePickerVc.isSelectOriginalPhoto = isSelectOriginalPhoto;
  106 +
  107 + [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
  108 + // 回调参数
  109 + !pickingPhotosHandle ? : pickingPhotosHandle(photos, assets, isSelectOriginalPhoto);
  110 +
  111 + }];
  112 + [vc presentViewController:imagePickerVc animated:YES completion:nil];
  113 +
  114 +}
  115 +
  116 +/// 预览单个视频
  117 ++ (void)ImagePickerWithSelectedAsset:(id)selectedAsset delegate:(id<TZImagePickerControllerDelegate>)delegate {
  118 +
  119 + if (![delegate isKindOfClass:[UIViewController class]]) {
  120 + return;
  121 + }
  122 + UIViewController *vc = (UIViewController *)delegate;
  123 +
  124 + TZVideoPlayerController *videoVC = [[TZVideoPlayerController alloc] init];
  125 + TZAssetModel *model = [TZAssetModel modelWithAsset:selectedAsset type:TZAssetModelMediaTypeVideo timeLength:@""];
  126 + videoVC.isOther = YES;//(LXG)相册外进入
  127 + videoVC.model = model;
  128 + [vc presentViewController:videoVC animated:YES completion:nil];
  129 +
  130 +}
  131 +
  132 +/// 返回类型
  133 ++ (TZAssetModelMediaType)getAssetType:(id)asset {
  134 +
  135 + TZAssetModelMediaType type = TZAssetModelMediaTypePhoto;
  136 + if ([asset isKindOfClass:[PHAsset class]]) {
  137 + PHAsset *phAsset = (PHAsset *)asset;
  138 + if (phAsset.mediaType == PHAssetMediaTypeVideo) type = TZAssetModelMediaTypeVideo;
  139 + else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = TZAssetModelMediaTypeAudio;
  140 + else if (phAsset.mediaType == PHAssetMediaTypeImage) {
  141 + if (iOS9_1Later) {
  142 + if (@available(iOS 9.1, *)) {
  143 + if (phAsset.mediaSubtypes == PHAssetMediaSubtypePhotoLive)
  144 + {
  145 + type = TZAssetModelMediaTypeLivePhoto;
  146 + }
  147 + } else {
  148 + // Fallback on earlier versions
  149 + }
  150 + }
  151 + // Gif
  152 + if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) {
  153 + type = TZAssetModelMediaTypePhotoGif;
  154 + }
  155 + }
  156 + } else {
  157 + if ([[asset valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) {
  158 + type = TZAssetModelMediaTypeVideo;
  159 + }
  160 + }
  161 + return type;
  162 +}
  163 +
  164 +
  165 ++(void)ImageManagerSavePhotoWithDelegate:(id<TZImagePickerControllerDelegate>)delegate image:(UIImage *)image location:(CLLocation *)location success:(void (^)(TZAssetModel *assetModel))success failure:(void (^)(NSError *error))failure {
  166 +
  167 + TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:delegate];
  168 + tzImagePickerVc.sortAscendingByModificationDate = YES;
  169 +
  170 + [tzImagePickerVc showProgressHUD];
  171 + // save photo and get asset / 保存图片,获取到asset
  172 + [[TZImageManager manager] savePhotoWithImage:image location:location completion:^(NSError *error){
  173 +
  174 + if (error) {
  175 + [tzImagePickerVc hideProgressHUD];
  176 + failure(error);
  177 + NSLog(@"图片保存失败 %@",error);
  178 + } else {
  179 +
  180 + [[TZImageManager manager] getCameraRollAlbum:NO allowPickingImage:YES needFetchAssets:YES completion:^(TZAlbumModel *model) {
  181 + [[TZImageManager manager] getAssetsFromFetchResult:model.result allowPickingVideo:NO allowPickingImage:YES completion:^(NSArray<TZAssetModel *> *models) {
  182 + [tzImagePickerVc hideProgressHUD];
  183 + TZAssetModel *assetModel = [models firstObject];
  184 + if (tzImagePickerVc.sortAscendingByModificationDate) {
  185 + assetModel = [models lastObject];
  186 + }
  187 + success(assetModel);
  188 + }];
  189 +
  190 + }];
  191 + }
  192 + }];
  193 +
  194 +}
  195 +
  196 +
  197 +
  198 +
  199 +
  200 +
  201 +
  202 +
  203 +
  204 +@end
... ...
CNLiveImagePickerController/NSBundle+TZImagePicker.h 0 → 100755
  1 +//
  2 +// NSBundle+TZImagePicker.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/08/18.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface NSBundle (TZImagePicker)
  12 +
  13 ++ (NSBundle *)tz_imagePickerBundle;
  14 +
  15 ++ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value;
  16 ++ (NSString *)tz_localizedStringForKey:(NSString *)key;
  17 +
  18 +@end
  19 +
... ...
CNLiveImagePickerController/NSBundle+TZImagePicker.m 0 → 100755
  1 +//
  2 +// NSBundle+TZImagePicker.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/08/18.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "NSBundle+TZImagePicker.h"
  10 +#import "TZImagePickerController.h"
  11 +
  12 +@implementation NSBundle (TZImagePicker)
  13 +
  14 ++ (NSBundle *)tz_imagePickerBundle {
  15 + NSBundle *bundle = [NSBundle bundleForClass:[TZImagePickerController class]];
  16 + NSURL *url = [bundle URLForResource:@"TZImagePickerController" withExtension:@"bundle"];
  17 + bundle = [NSBundle bundleWithURL:url];
  18 + return bundle;
  19 +}
  20 +
  21 ++ (NSString *)tz_localizedStringForKey:(NSString *)key {
  22 + return [self tz_localizedStringForKey:key value:@""];
  23 +}
  24 +
  25 ++ (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value {
  26 + NSBundle *bundle = [TZImagePickerConfig sharedInstance].languageBundle;
  27 + NSString *value1 = [bundle localizedStringForKey:key value:value table:nil];
  28 + return value1;
  29 +}
  30 +
  31 +@end
... ...
CNLiveImagePickerController/TZAssetCell.h 0 → 100755
  1 +//
  2 +// TZAssetCell.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +#import <Photos/Photos.h>
  11 +
  12 +typedef enum : NSUInteger {
  13 + TZAssetCellTypePhoto = 0,
  14 + TZAssetCellTypeLivePhoto,
  15 + TZAssetCellTypePhotoGif,
  16 + TZAssetCellTypeVideo,
  17 + TZAssetCellTypeAudio,
  18 +} TZAssetCellType;
  19 +
  20 +@class TZAssetModel;
  21 +@interface TZAssetCell : UICollectionViewCell
  22 +@property (weak, nonatomic) UIButton *selectPhotoButton;
  23 +@property (weak, nonatomic) UIButton *cannotSelectLayerButton;
  24 +@property (nonatomic, strong) TZAssetModel *model;
  25 +@property (assign, nonatomic) NSInteger index;
  26 +@property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL);
  27 +@property (nonatomic, assign) TZAssetCellType type;
  28 +@property (nonatomic, assign) BOOL allowPickingGif;
  29 +@property (nonatomic, assign) BOOL allowPickingMultipleVideo;
  30 +@property (nonatomic, copy) NSString *representedAssetIdentifier;
  31 +@property (nonatomic, assign) int32_t imageRequestID;
  32 +
  33 +@property (nonatomic, strong) UIImage *photoSelImage;
  34 +@property (nonatomic, strong) UIImage *photoDefImage;
  35 +
  36 +@property (nonatomic, assign) BOOL showSelectBtn;
  37 +@property (assign, nonatomic) BOOL allowPreview;
  38 +@property (assign, nonatomic) BOOL useCachedImage;
  39 +
  40 +@property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  41 +@property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
  42 +@end
  43 +
  44 +
  45 +@class TZAlbumModel;
  46 +@interface TZAlbumCell : UITableViewCell
  47 +@property (nonatomic, strong) TZAlbumModel *model;
  48 +@property (weak, nonatomic) UIButton *selectedCountButton;
  49 +
  50 +@property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  51 +@property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel);
  52 +@end
  53 +
  54 +
  55 +@interface TZAssetCameraCell : UICollectionViewCell
  56 +@property (nonatomic, strong) UIImageView *imageView;
  57 +@end
... ...
CNLiveImagePickerController/TZAssetCell.m 0 → 100755
  1 +//
  2 +// TZAssetCell.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZAssetCell.h"
  10 +#import "TZAssetModel.h"
  11 +#import "UIView+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 0 → 100755
  1 +//
  2 +// TZAssetModel.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +
  12 +typedef enum : NSUInteger {
  13 + TZAssetModelMediaTypePhoto = 0,
  14 + TZAssetModelMediaTypeLivePhoto,
  15 + TZAssetModelMediaTypePhotoGif,
  16 + TZAssetModelMediaTypeVideo,
  17 + TZAssetModelMediaTypeAudio
  18 +} TZAssetModelMediaType;
  19 +
  20 +@class PHAsset;
  21 +@interface TZAssetModel : NSObject
  22 +
  23 +@property (nonatomic, strong) id asset; ///< PHAsset or ALAsset
  24 +@property (nonatomic, assign) BOOL isSelected; ///< The select status of a photo, default is No
  25 +@property (nonatomic, assign) TZAssetModelMediaType type;
  26 +@property (assign, nonatomic) BOOL needOscillatoryAnimation;
  27 +@property (nonatomic, copy) NSString *timeLength;
  28 +@property (strong, nonatomic) UIImage *cachedImage;
  29 +
  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 0 → 100755
  1 +//
  2 +// TZAssetModel.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZAssetModel.h"
  10 +#import "TZImageManager.h"
  11 +
  12 +@implementation TZAssetModel
  13 +
  14 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type{
  15 + TZAssetModel *model = [[TZAssetModel alloc] init];
  16 + model.asset = asset;
  17 + model.isSelected = NO;
  18 + model.type = type;
  19 + return model;
  20 +}
  21 +
  22 ++ (instancetype)modelWithAsset:(id)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength {
  23 + TZAssetModel *model = [self modelWithAsset:asset type:type];
  24 + model.timeLength = timeLength;
  25 + return model;
  26 +}
  27 +
  28 +@end
  29 +
  30 +
  31 +
  32 +@implementation TZAlbumModel
  33 +
  34 +- (void)setResult:(id)result needFetchAssets:(BOOL)needFetchAssets {
  35 + _result = result;
  36 + if (needFetchAssets) {
  37 + [[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 0 → 100755
  1 +//
  2 +// TZGifPhotoPreviewController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/13.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZGifPhotoPreviewController : UIViewController
  13 +
  14 +@property (nonatomic, strong) TZAssetModel *model;
  15 +
  16 +@end
... ...
CNLiveImagePickerController/TZGifPhotoPreviewController.m 0 → 100755
  1 +//
  2 +// TZGifPhotoPreviewController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/13.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZGifPhotoPreviewController.h"
  10 +#import "TZImagePickerController.h"
  11 +#import "TZAssetModel.h"
  12 +#import "UIView+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 0 → 100755
  1 +//
  2 +// TZImageCropManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2016/12/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +// 图片裁剪管理类
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +
  12 +@interface TZImageCropManager : NSObject
  13 +
  14 +/// 裁剪框背景的处理
  15 ++ (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop;
  16 +
  17 +/*
  18 + 1.7.2 为了解决多位同学对于图片裁剪的需求,我这两天有空便在研究图片裁剪
  19 + 幸好有tuyou的PhotoTweaks库做参考,裁剪的功能实现起来简单许多
  20 + 该方法和其内部引用的方法基本来自于tuyou的PhotoTweaks库,我做了稍许删减和修改
  21 + 感谢tuyou同学在github开源了优秀的裁剪库PhotoTweaks,表示感谢
  22 + PhotoTweaks库的github链接:https://github.com/itouch2/PhotoTweaks
  23 + */
  24 +/// 获得裁剪后的图片
  25 ++ (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView;
  26 +
  27 +/// 获取圆形图片
  28 ++ (UIImage *)circularClipImage:(UIImage *)image;
  29 +
  30 +@end
  31 +
  32 +
  33 +/// 该分类的代码来自SDWebImage:https://github.com/rs/SDWebImage
  34 +/// 为了防止冲突,我将分类名字和方法名字做了修改
  35 +@interface UIImage (TZGif)
  36 +
  37 ++ (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data;
  38 +
  39 +@end
... ...
CNLiveImagePickerController/TZImageCropManager.m 0 → 100755
  1 +//
  2 +// TZImageCropManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2016/12/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImageCropManager.h"
  10 +#import "UIView+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 0 → 100755
  1 +//
  2 +// TZImageManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/4.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +// 图片资源获取管理类
  8 +
  9 +#import <Foundation/Foundation.h>
  10 +#import <UIKit/UIKit.h>
  11 +#import <AVFoundation/AVFoundation.h>
  12 +#import <Photos/Photos.h>
  13 +#import "TZAssetModel.h"
  14 +
  15 +@class TZAlbumModel,TZAssetModel;
  16 +@protocol TZImagePickerControllerDelegate;
  17 +@interface TZImageManager : NSObject
  18 +
  19 +@property (nonatomic, strong) PHCachingImageManager *cachingImageManager;
  20 +
  21 ++ (instancetype)manager NS_SWIFT_NAME(default());
  22 ++ (void)deallocManager;
  23 +
  24 +@property (weak, nonatomic) id<TZImagePickerControllerDelegate> pickerDelegate;
  25 +
  26 +#pragma mark - 添加: 原有逻辑-会话id(LXG)
  27 +//zl__会话Id用于视频导出路径
  28 +@property (nonatomic, strong) NSString *conversationId;
  29 +
  30 +@property (nonatomic, assign) BOOL shouldFixOrientation;
  31 +
  32 +/// Default is 600px / 默认600像素宽
  33 +@property (nonatomic, assign) CGFloat photoPreviewMaxWidth;
  34 +/// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽
  35 +@property (nonatomic, assign) CGFloat photoWidth;
  36 +
  37 +/// Default is 4, Use in photos collectionView in TZPhotoPickerController
  38 +/// 默认4列, TZPhotoPickerController中的照片collectionView
  39 +@property (nonatomic, assign) NSInteger columnNumber;
  40 +
  41 +/// Sort photos ascending by modificationDate,Default is YES
  42 +/// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个
  43 +@property (nonatomic, assign) BOOL sortAscendingByModificationDate;
  44 +
  45 +/// Minimum selectable photo width, Default is 0
  46 +/// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中
  47 +@property (nonatomic, assign) NSInteger minPhotoWidthSelectable;
  48 +@property (nonatomic, assign) NSInteger minPhotoHeightSelectable;
  49 +@property (nonatomic, assign) BOOL hideWhenCanNotSelect;
  50 +
  51 +/// Return YES if Authorized 返回YES如果得到了授权
  52 +- (BOOL)authorizationStatusAuthorized;
  53 ++ (NSInteger)authorizationStatus;
  54 +- (void)requestAuthorizationWithCompletion:(void (^)(void))completion;
  55 +
  56 +/// Get Album 获得相册/相册数组
  57 +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion;
  58 +- (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray<TZAlbumModel *> *models))completion;
  59 +
  60 +/// Get Assets 获得Asset数组
  61 +- (void)getAssetsFromFetchResult:(id)result completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
  62 +- (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray<TZAssetModel *> *models))completion;
  63 +- (void)getAssetFromFetchResult:(id)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion;
  64 +
  65 +/// Get photo 获得照片
  66 +- (void)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion;
  67 +
  68 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  69 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  70 +- (int32_t)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
  71 +- (int32_t)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed;
  72 +- (int32_t)requestImageDataForAsset:(id)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler;
  73 +
  74 +/// Get full Image 获取原图
  75 +/// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。
  76 +- (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion;
  77 +- (void)getOriginalPhotoWithAsset:(id)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion;
  78 +// 该方法中,completion只会走一次
  79 +- (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
  80 +- (void)getOriginalPhotoDataWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
  81 +
  82 +/// Save photo 保存照片
  83 +- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(NSError *error))completion;
  84 +- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
  85 +
  86 +/// Save video 保存视频
  87 +- (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(NSError *error))completion;
  88 +- (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(NSError *error))completion;
  89 +
  90 +/// Get video 获得视频
  91 +- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
  92 +- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion;
  93 +
  94 +/// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480
  95 +- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
  96 +- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
  97 +/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
  98 +- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion __attribute__((deprecated("Use -getVideoOutputPathWithAsset:failure:success:")));
  99 +
  100 +/// Get photo bytes 获得一组照片的大小
  101 +- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
  102 +
  103 +/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
  104 +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset;
  105 +
  106 +- (NSString *)getAssetIdentifier:(id)asset;
  107 +- (BOOL)isCameraRollAlbum:(id)metadata;
  108 +
  109 +/// 检查照片大小是否满足最小要求
  110 +- (BOOL)isPhotoSelectableWithAsset:(id)asset;
  111 +- (CGSize)photoSizeWithAsset:(id)asset;
  112 +
  113 +/// 修正图片转向
  114 +- (UIImage *)fixOrientation:(UIImage *)aImage;
  115 +
  116 +/// 获取asset的资源类型
  117 +- (TZAssetModelMediaType)getAssetType:(id)asset;
  118 +/// 缩放图片至新尺寸
  119 +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size;
  120 +
  121 +/// 判断asset是否是视频
  122 +- (BOOL)isVideo:(id)asset;
  123 +
  124 +@end
  125 +
  126 +//@interface TZSortDescriptor : NSSortDescriptor
  127 +//
  128 +//@end
... ...
CNLiveImagePickerController/TZImageManager.m 0 → 100755
  1 +//
  2 +// TZImageManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/4.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZImageManager.h"
  10 +#import <AssetsLibrary/AssetsLibrary.h>
  11 +#import "TZAssetModel.h"
  12 +#import "TZImagePickerController.h"
  13 +
  14 +@interface TZImageManager ()
  15 +#pragma clang diagnostic push
  16 +#pragma clang diagnostic ignored "-Wdeprecated-declarations"
  17 +@property (nonatomic, strong) ALAssetsLibrary *assetLibrary;
  18 +@end
  19 +
  20 +@implementation TZImageManager
  21 +
  22 +CGSize AssetGridThumbnailSize;
  23 +CGFloat TZScreenWidth;
  24 +CGFloat TZScreenScale;
  25 +
  26 +static TZImageManager *manager;
  27 +static dispatch_once_t onceToken;
  28 +
  29 ++ (instancetype)manager {
  30 + dispatch_once(&onceToken, ^{
  31 + manager = [[self alloc] init];
  32 + if (iOS8Later) {
  33 + // manager.cachingImageManager = [[PHCachingImageManager alloc] init];
  34 + // manager.cachingImageManager.allowsCachingHighQualityImages = YES;
  35 + }
  36 +
  37 + [manager configTZScreenWidth];
  38 + });
  39 + return manager;
  40 +}
  41 +
  42 ++ (void)deallocManager {
  43 + onceToken = 0;
  44 + manager = nil;
  45 +}
  46 +
  47 +- (void)setPhotoWidth:(CGFloat)photoWidth {
  48 + _photoWidth = photoWidth;
  49 + TZScreenWidth = photoWidth / 2;
  50 +}
  51 +
  52 +- (void)setColumnNumber:(NSInteger)columnNumber {
  53 + [self configTZScreenWidth];
  54 +
  55 + _columnNumber = columnNumber;
  56 + CGFloat margin = 4;
  57 + CGFloat itemWH = (TZScreenWidth - 2 * margin - 4) / columnNumber - margin;
  58 + AssetGridThumbnailSize = CGSizeMake(itemWH * TZScreenScale, itemWH * TZScreenScale);
  59 +}
  60 +
  61 +- (void)configTZScreenWidth {
  62 + TZScreenWidth = [UIScreen mainScreen].bounds.size.width;
  63 + // 测试发现,如果scale在plus真机上取到3.0,内存会增大特别多。故这里写死成2.0
  64 + TZScreenScale = 2.0;
  65 + if (TZScreenWidth > 700) {
  66 + TZScreenScale = 1.5;
  67 + }
  68 +}
  69 +
  70 +- (ALAssetsLibrary *)assetLibrary {
  71 + if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init];
  72 + return _assetLibrary;
  73 +}
  74 +
  75 +/// Return YES if Authorized 返回YES如果得到了授权
  76 +- (BOOL)authorizationStatusAuthorized {
  77 + NSInteger status = [self.class authorizationStatus];
  78 + if (status == 0) {
  79 + /**
  80 + * 当某些情况下AuthorizationStatus == AuthorizationStatusNotDetermined时,无法弹出系统首次使用的授权alertView,系统应用设置里亦没有相册的设置,此时将无法使用,故作以下操作,弹出系统首次使用的授权alertView
  81 + */
  82 + [self requestAuthorizationWithCompletion:nil];
  83 + }
  84 +
  85 + return status == 3;
  86 +}
  87 +
  88 ++ (NSInteger)authorizationStatus {
  89 + if (iOS8Later) {
  90 + return [PHPhotoLibrary authorizationStatus];
  91 + } else {
  92 + return [ALAssetsLibrary authorizationStatus];
  93 + }
  94 + return NO;
  95 +}
  96 +
  97 +- (void)requestAuthorizationWithCompletion:(void (^)(void))completion {
  98 + void (^callCompletionBlock)(void) = ^(){
  99 + dispatch_async(dispatch_get_main_queue(), ^{
  100 + if (completion) {
  101 + completion();
  102 + }
  103 + });
  104 + };
  105 +
  106 + if (iOS8Later) {
  107 + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  108 + [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
  109 + callCompletionBlock();
  110 + }];
  111 + });
  112 + } else {
  113 + [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
  114 + callCompletionBlock();
  115 + } failureBlock:^(NSError *error) {
  116 + callCompletionBlock();
  117 + }];
  118 + }
  119 +}
  120 +
  121 +#pragma mark - Get Album
  122 +
  123 +/// Get Album 获得相册/相册数组
  124 +- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion {
  125 + __block TZAlbumModel *model;
  126 + if (iOS8Later) {
  127 + PHFetchOptions *option = [[PHFetchOptions alloc] init];
  128 + if (!allowPickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
  129 + if (!allowPickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld",
  130 + PHAssetMediaTypeVideo];
  131 + // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]];
  132 + if (!self.sortAscendingByModificationDate) {
  133 + option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]];
  134 + }
  135 + PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
  136 + for (PHAssetCollection *collection in smartAlbums) {
  137 + // 有可能是PHCollectionList类的的对象,过滤掉
  138 + if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
  139 + // 过滤空相册
  140 + if (collection.estimatedAssetCount <= 0) continue;
  141 + if ([self isCameraRollAlbum:collection]) {
  142 + PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option];
  143 + model = [self modelWithResult:fetchResult name:collection.localizedTitle isCameraRoll:YES needFetchAssets:needFetchAssets];
  144 + if (completion) completion(model);
  145 + break;
  146 + }
  147 + }
  148 + } else {
  149 + [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 - TODO: 添加: 原有逻辑-根据会话id取得path(LXG)
  868 + NSString *filaName = [NSString stringWithFormat:@"output-%@_fileType=videoType.mp4",[formater stringFromDate:[NSDate date]]];
  869 +// NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]];
  870 + NSString *outputPath = @"";
  871 + if (self.conversationId) {
  872 +// outputPath = [[CNTools newChatFilePathByUserId:self.conversationId] stringByAppendingPathComponent:filaName];//聊天
  873 +//
  874 + }
  875 + else
  876 + {
  877 +
  878 +// outputPath = [[CNTools chatFilePathByUserId:[IMAPlatform sharedInstance].host.userId] stringByAppendingString:filaName];//朋友圈
  879 + }
  880 + NSLog(@"video outputPath = %@",outputPath);
  881 +
  882 + session.outputURL = [NSURL fileURLWithPath:outputPath];
  883 +
  884 + // Optimize for network use.
  885 + session.shouldOptimizeForNetworkUse = true;
  886 +
  887 + NSArray *supportedTypeArray = session.supportedFileTypes;
  888 + if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
  889 + session.outputFileType = AVFileTypeMPEG4;
  890 + } else if (supportedTypeArray.count == 0) {
  891 + if (failure) {
  892 + failure(@"该视频类型暂不支持导出", nil);
  893 + }
  894 + NSLog(@"No supported file types 视频类型暂不支持导出");
  895 + return;
  896 + } else {
  897 + session.outputFileType = [supportedTypeArray objectAtIndex:0];
  898 + }
  899 +
  900 + if (![[NSFileManager defaultManager] fileExistsAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"]]) {
  901 + [[NSFileManager defaultManager] createDirectoryAtPath:[NSHomeDirectory() stringByAppendingFormat:@"/tmp"] withIntermediateDirectories:YES attributes:nil error:nil];
  902 + }
  903 +
  904 + if ([TZImagePickerConfig sharedInstance].needFixComposition) {
  905 + AVMutableVideoComposition *videoComposition = [self fixedCompositionWithAsset:videoAsset];
  906 + if (videoComposition.renderSize.width) {
  907 + // 修正视频转向
  908 + session.videoComposition = videoComposition;
  909 + }
  910 + }
  911 +
  912 + // Begin to export video to the output path asynchronously.
  913 +#pragma mark - 添加: 原有逻辑-会话id置空(LXG)
  914 + self.conversationId = nil;
  915 + [session exportAsynchronouslyWithCompletionHandler:^(void) {
  916 + dispatch_async(dispatch_get_main_queue(), ^{
  917 +
  918 + switch (session.status) {
  919 + case AVAssetExportSessionStatusUnknown: {
  920 + NSLog(@"AVAssetExportSessionStatusUnknown");
  921 + } break;
  922 + case AVAssetExportSessionStatusWaiting: {
  923 + NSLog(@"AVAssetExportSessionStatusWaiting");
  924 + } break;
  925 + case AVAssetExportSessionStatusExporting: {
  926 + NSLog(@"AVAssetExportSessionStatusExporting");
  927 + } break;
  928 + case AVAssetExportSessionStatusCompleted: {
  929 + NSLog(@"AVAssetExportSessionStatusCompleted");
  930 + if (success) {
  931 + success(outputPath);
  932 + }
  933 + } break;
  934 + case AVAssetExportSessionStatusFailed: {
  935 + NSLog(@"AVAssetExportSessionStatusFailed");
  936 + if (failure) {
  937 + failure(@"视频导出失败", session.error);
  938 + }
  939 + } break;
  940 + case AVAssetExportSessionStatusCancelled: {
  941 + NSLog(@"AVAssetExportSessionStatusCancelled");
  942 + if (failure) {
  943 + failure(@"导出任务已被取消", nil);
  944 + }
  945 + } break;
  946 + default:
  947 + NSLog(@"未知错误");
  948 + break;
  949 + }
  950 + });
  951 + }];
  952 + } else {
  953 + if (failure) {
  954 + NSString *errorMessage = [NSString stringWithFormat:@"当前设备不支持该预设:%@", presetName];
  955 + failure(errorMessage, nil);
  956 + }
  957 + }
  958 +}
  959 +
  960 +/// Judge is a assets array contain the asset 判断一个assets数组是否包含这个asset
  961 +- (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset {
  962 + if (iOS8Later) {
  963 + return [assets containsObject:asset];
  964 + } else {
  965 + NSMutableArray *selectedAssetUrls = [NSMutableArray array];
  966 + for (ALAsset *asset_item in assets) {
  967 + [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]];
  968 + }
  969 + return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]];
  970 + }
  971 +}
  972 +
  973 +- (BOOL)isCameraRollAlbum:(id)metadata {
  974 + if ([metadata isKindOfClass:[PHAssetCollection class]]) {
  975 + NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
  976 + if (versionStr.length <= 1) {
  977 + versionStr = [versionStr stringByAppendingString:@"00"];
  978 + } else if (versionStr.length <= 2) {
  979 + versionStr = [versionStr stringByAppendingString:@"0"];
  980 + }
  981 + CGFloat version = versionStr.floatValue;
  982 + // 目前已知8.0.0 ~ 8.0.2系统,拍照后的图片会保存在最近添加中
  983 + if (version >= 800 && version <= 802) {
  984 + return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded;
  985 + } else {
  986 + return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary;
  987 + }
  988 + }
  989 + if ([metadata isKindOfClass:[ALAssetsGroup class]]) {
  990 + ALAssetsGroup *group = metadata;
  991 + return ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupSavedPhotos);
  992 + }
  993 +
  994 + return NO;
  995 +}
  996 +
  997 +- (NSString *)getAssetIdentifier:(id)asset {
  998 + if (iOS8Later) {
  999 + PHAsset *phAsset = (PHAsset *)asset;
  1000 + return phAsset.localIdentifier;
  1001 + } else {
  1002 + ALAsset *alAsset = (ALAsset *)asset;
  1003 + NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL];
  1004 + return assetUrl.absoluteString;
  1005 + }
  1006 +}
  1007 +
  1008 +/// 检查照片大小是否满足最小要求
  1009 +- (BOOL)isPhotoSelectableWithAsset:(id)asset {
  1010 + CGSize photoSize = [self photoSizeWithAsset:asset];
  1011 + if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) {
  1012 + return NO;
  1013 + }
  1014 + return YES;
  1015 +}
  1016 +
  1017 +- (CGSize)photoSizeWithAsset:(id)asset {
  1018 + if (iOS8Later) {
  1019 + PHAsset *phAsset = (PHAsset *)asset;
  1020 + return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight);
  1021 + } else {
  1022 + ALAsset *alAsset = (ALAsset *)asset;
  1023 + return alAsset.defaultRepresentation.dimensions;
  1024 + }
  1025 +}
  1026 +
  1027 +#pragma mark - Private Method
  1028 +
  1029 +- (TZAlbumModel *)modelWithResult:(id)result name:(NSString *)name isCameraRoll:(BOOL)isCameraRoll needFetchAssets:(BOOL)needFetchAssets {
  1030 + TZAlbumModel *model = [[TZAlbumModel alloc] init];
  1031 + [model setResult:result needFetchAssets:needFetchAssets];
  1032 + model.name = name;
  1033 + model.isCameraRoll = isCameraRoll;
  1034 + if ([result isKindOfClass:[PHFetchResult class]]) {
  1035 + PHFetchResult *fetchResult = (PHFetchResult *)result;
  1036 + model.count = fetchResult.count;
  1037 + } else if ([result isKindOfClass:[ALAssetsGroup class]]) {
  1038 + ALAssetsGroup *group = (ALAssetsGroup *)result;
  1039 + model.count = [group numberOfAssets];
  1040 + }
  1041 + return model;
  1042 +}
  1043 +
  1044 +/// 缩放图片至新尺寸
  1045 +- (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size {
  1046 + if (image.size.width > size.width) {
  1047 + UIGraphicsBeginImageContext(size);
  1048 + [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
  1049 + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
  1050 + UIGraphicsEndImageContext();
  1051 + return newImage;
  1052 +
  1053 + /* 好像不怎么管用:https://mp.weixin.qq.com/s/CiqMlEIp1Ir2EJSDGgMooQ
  1054 + CGFloat maxPixelSize = MAX(size.width, size.height);
  1055 + CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)UIImageJPEGRepresentation(image, 0.9), nil);
  1056 + NSDictionary *options = @{(__bridge id)kCGImageSourceCreateThumbnailFromImageAlways:(__bridge id)kCFBooleanTrue,
  1057 + (__bridge id)kCGImageSourceThumbnailMaxPixelSize:[NSNumber numberWithFloat:maxPixelSize]
  1058 + };
  1059 + CGImageRef imageRef = CGImageSourceCreateImageAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
  1060 + UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:2 orientation:image.imageOrientation];
  1061 + CGImageRelease(imageRef);
  1062 + CFRelease(sourceRef);
  1063 + return newImage;
  1064 + */
  1065 + } else {
  1066 + return image;
  1067 + }
  1068 +}
  1069 +
  1070 +/// 判断asset是否是视频
  1071 +- (BOOL)isVideo:(id)asset {
  1072 + if (iOS8Later) {
  1073 + PHAsset *phAsset = asset;
  1074 + return phAsset.mediaType == PHAssetMediaTypeVideo;
  1075 + } else {
  1076 + ALAsset *alAsset = asset;
  1077 + NSString *alAssetType = [[alAsset valueForProperty:ALAssetPropertyType] stringValue];
  1078 + return [alAssetType isEqualToString:ALAssetTypeVideo];
  1079 + }
  1080 +}
  1081 +
  1082 +- (ALAssetOrientation)orientationFromImage:(UIImage *)image {
  1083 + NSInteger orientation = image.imageOrientation;
  1084 + return orientation;
  1085 +}
  1086 +
  1087 +/// 获取优化后的视频转向信息
  1088 +- (AVMutableVideoComposition *)fixedCompositionWithAsset:(AVAsset *)videoAsset {
  1089 + AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
  1090 + // 视频转向
  1091 + int degrees = [self degressFromVideoFileWithAsset:videoAsset];
  1092 + if (degrees != 0) {
  1093 + CGAffineTransform translateToCenter;
  1094 + CGAffineTransform mixedTransform;
  1095 + videoComposition.frameDuration = CMTimeMake(1, 30);
  1096 +
  1097 + NSArray *tracks = [videoAsset tracksWithMediaType:AVMediaTypeVideo];
  1098 + AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  1099 +
  1100 + AVMutableVideoCompositionInstruction *roateInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  1101 + roateInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]);
  1102 + AVMutableVideoCompositionLayerInstruction *roateLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
  1103 +
  1104 + if (degrees == 90) {
  1105 + // 顺时针旋转90°
  1106 + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.height, 0.0);
  1107 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2);
  1108 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
  1109 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1110 + } else if(degrees == 180){
  1111 + // 顺时针旋转180°
  1112 + translateToCenter = CGAffineTransformMakeTranslation(videoTrack.naturalSize.width, videoTrack.naturalSize.height);
  1113 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI);
  1114 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height);
  1115 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1116 + } else if(degrees == 270){
  1117 + // 顺时针旋转270°
  1118 + translateToCenter = CGAffineTransformMakeTranslation(0.0, videoTrack.naturalSize.width);
  1119 + mixedTransform = CGAffineTransformRotate(translateToCenter,M_PI_2*3.0);
  1120 + videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.height,videoTrack.naturalSize.width);
  1121 + [roateLayerInstruction setTransform:mixedTransform atTime:kCMTimeZero];
  1122 + }
  1123 +
  1124 + roateInstruction.layerInstructions = @[roateLayerInstruction];
  1125 + // 加入视频方向信息
  1126 + videoComposition.instructions = @[roateInstruction];
  1127 + }
  1128 + return videoComposition;
  1129 +}
  1130 +
  1131 +/// 获取视频角度
  1132 +- (int)degressFromVideoFileWithAsset:(AVAsset *)asset {
  1133 + int degress = 0;
  1134 + NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
  1135 + if([tracks count] > 0) {
  1136 + AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
  1137 + CGAffineTransform t = videoTrack.preferredTransform;
  1138 + if(t.a == 0 && t.b == 1.0 && t.c == -1.0 && t.d == 0){
  1139 + // Portrait
  1140 + degress = 90;
  1141 + } else if(t.a == 0 && t.b == -1.0 && t.c == 1.0 && t.d == 0){
  1142 + // PortraitUpsideDown
  1143 + degress = 270;
  1144 + } else if(t.a == 1.0 && t.b == 0 && t.c == 0 && t.d == 1.0){
  1145 + // LandscapeRight
  1146 + degress = 0;
  1147 + } else if(t.a == -1.0 && t.b == 0 && t.c == 0 && t.d == -1.0){
  1148 + // LandscapeLeft
  1149 + degress = 180;
  1150 + }
  1151 + }
  1152 + return degress;
  1153 +}
  1154 +
  1155 +/// 修正图片转向
  1156 +- (UIImage *)fixOrientation:(UIImage *)aImage {
  1157 + if (!self.shouldFixOrientation) return aImage;
  1158 +
  1159 + // No-op if the orientation is already correct
  1160 + if (aImage.imageOrientation == UIImageOrientationUp)
  1161 + return aImage;
  1162 +
  1163 + // We need to calculate the proper transformation to make the image upright.
  1164 + // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
  1165 + CGAffineTransform transform = CGAffineTransformIdentity;
  1166 +
  1167 + switch (aImage.imageOrientation) {
  1168 + case UIImageOrientationDown:
  1169 + case UIImageOrientationDownMirrored:
  1170 + transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
  1171 + transform = CGAffineTransformRotate(transform, M_PI);
  1172 + break;
  1173 +
  1174 + case UIImageOrientationLeft:
  1175 + case UIImageOrientationLeftMirrored:
  1176 + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  1177 + transform = CGAffineTransformRotate(transform, M_PI_2);
  1178 + break;
  1179 +
  1180 + case UIImageOrientationRight:
  1181 + case UIImageOrientationRightMirrored:
  1182 + transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
  1183 + transform = CGAffineTransformRotate(transform, -M_PI_2);
  1184 + break;
  1185 + default:
  1186 + break;
  1187 + }
  1188 +
  1189 + switch (aImage.imageOrientation) {
  1190 + case UIImageOrientationUpMirrored:
  1191 + case UIImageOrientationDownMirrored:
  1192 + transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
  1193 + transform = CGAffineTransformScale(transform, -1, 1);
  1194 + break;
  1195 +
  1196 + case UIImageOrientationLeftMirrored:
  1197 + case UIImageOrientationRightMirrored:
  1198 + transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
  1199 + transform = CGAffineTransformScale(transform, -1, 1);
  1200 + break;
  1201 + default:
  1202 + break;
  1203 + }
  1204 +
  1205 + // Now we draw the underlying CGImage into a new context, applying the transform
  1206 + // calculated above.
  1207 + CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
  1208 + CGImageGetBitsPerComponent(aImage.CGImage), 0,
  1209 + CGImageGetColorSpace(aImage.CGImage),
  1210 + CGImageGetBitmapInfo(aImage.CGImage));
  1211 + CGContextConcatCTM(ctx, transform);
  1212 + switch (aImage.imageOrientation) {
  1213 + case UIImageOrientationLeft:
  1214 + case UIImageOrientationLeftMirrored:
  1215 + case UIImageOrientationRight:
  1216 + case UIImageOrientationRightMirrored:
  1217 + // Grr...
  1218 + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
  1219 + break;
  1220 +
  1221 + default:
  1222 + CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
  1223 + break;
  1224 + }
  1225 +
  1226 + // And now we just create a new UIImage from the drawing context
  1227 + CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
  1228 + UIImage *img = [UIImage imageWithCGImage:cgimg];
  1229 + CGContextRelease(ctx);
  1230 + CGImageRelease(cgimg);
  1231 + return img;
  1232 +}
  1233 +
  1234 +#pragma clang diagnostic pop
  1235 +
  1236 +@end
  1237 +
  1238 +
  1239 +//@implementation TZSortDescriptor
  1240 +//
  1241 +//- (id)reversedSortDescriptor {
  1242 +// return [NSNumber numberWithBool:![TZImageManager manager].sortAscendingByModificationDate];
  1243 +//}
  1244 +//
  1245 +//@end
... ...
CNLiveImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png 0 → 100755

3.56 KB

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

3.56 KB

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

223 Bytes

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

1.16 KB

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

116 Bytes

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

1.31 KB

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

902 Bytes

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

1.13 KB

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

1.13 KB

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

501 Bytes

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

1.56 KB

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

620 Bytes

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

1006 Bytes

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

1.16 KB

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

501 Bytes

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

392 Bytes

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

1.25 KB

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

2.98 KB

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

1.35 KB

CNLiveImagePickerController/TZImagePickerController.bundle/vi.lproj/Localizable.strings 0 → 100755
  1 +"OK" = "Xác nhận";
  2 +"Back" = "Quay lại";
  3 +"Done" = "Hoàn thành";
  4 +"Sorry" = "Xin lỗi";
  5 +"Cancel" = "Hủy";
  6 +"Setting" = "Cài đặt";
  7 +"Photos" = "Hình";
  8 +"Videos" = "Clip";
  9 +"Preview" = "Xem trước";
  10 +"Full image" = "Hình gốc";
  11 +"Processing..." = "Đang xử lý...";
  12 +"Can not use camera" = "Máy chụp hình không khả dụng";
  13 +"Synchronizing photos from iCloud" = "Đang đồng bộ hình ảnh từ ICloud";
  14 +"Can not choose both video and photo" = "Trong lúc chọn hình ảnh không cùng lúc chọn video";
  15 +"Can not choose both photo and GIF" = "Trong lúc chọn hình ảnh không cùng lúc chọn hình GIF";
  16 +"Select the video when in multi state, we will handle the video as a photo" = "Chọn hình ảnh cùng video, video sẽ bị mặc nhận thành hình ảnh và gửi đi.";
  17 +"Can not jump to the privacy settings page, please go to the settings page by self, thank you" = "Không thể chuyển tự động qua trang cài đặt riêng tư, bạn hãy thoát ra cà điều chỉnh lại, cám ơn bạn.";
  18 +
  19 +"Select a maximum of %zd photos" = "Bạn chỉ được chọn nhiều nhất %zd tấm hình";
  20 +"Select a minimum of %zd photos" = "Chọn ít nhất %zd tấm hình";
  21 +"Allow %@ to access your album in \"Settings -> Privacy -> Photos\"" = "Vui lòng tại mục iPhone \" Cài đặt – quyền riêng tư - Ảnh\" mở quyền cho phép %@ truy cập ảnh.";
  22 +"Please allow %@ to access your camera in \"Settings -> Privacy -> Camera\"" = "Vui lòng tại mục iPhone \" Cài đặt – quyền riêng tư - Ảnh\" mở quyền cho phép %@ truy cập máy ảnh";
... ...
CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings 0 → 100755
1 1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings differ
... ...
CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings 0 → 100755
1 1 Binary files /dev/null and b/CNLiveImagePickerController/TZImagePickerController.bundle/zh-Hant.lproj/Localizable.strings differ
... ...
CNLiveImagePickerController/TZImagePickerController.h 0 → 100755
  1 +//
  2 +// TZImagePickerController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +// version 2.2.6 - 2018.08.21
  8 +// 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
  9 +
  10 +/*
  11 + 经过测试,比起xib的方式,把TZAssetCell改用纯代码的方式来写,滑动帧数明显提高了(约提高10帧左右)
  12 +
  13 + 最初发现这个问题并修复的是@小鱼周凌宇同学,她的博客地址: http://zhoulingyu.com/
  14 + 表示感谢~
  15 +
  16 + 原来xib确实会导致性能问题啊...大家也要注意了...
  17 + */
  18 +
  19 +#import <UIKit/UIKit.h>
  20 +#import "TZAssetModel.h"
  21 +#import "NSBundle+TZImagePicker.h"
  22 +#import "TZImageManager.h"
  23 +#import "TZVideoPlayerController.h"
  24 +#import "TZGifPhotoPreviewController.h"
  25 +#import "TZLocationManager.h"
  26 +#import "TZPhotoPreviewController.h"
  27 +
  28 +#define iOS7Later ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f)
  29 +#define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f)
  30 +///
  31 +#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
  32 +#define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
  33 +
  34 +@class TZAlbumCell, TZAssetCell;
  35 +@protocol TZImagePickerControllerDelegate;
  36 +@interface TZImagePickerController : UINavigationController
  37 +
  38 +#pragma mark -
  39 +/// Use this init method / 用这个初始化方法
  40 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id<TZImagePickerControllerDelegate>)delegate;
  41 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate;
  42 +- (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id<TZImagePickerControllerDelegate>)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc;
  43 +/// This init method just for previewing photos / 用这个初始化方法以预览图片
  44 +- (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index;
  45 +/// This init method for crop photo / 用这个初始化方法以裁剪图片
  46 +- (instancetype)initCropTypeWithAsset:(id)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,id asset))completion;
  47 +
  48 +#pragma mark -
  49 +
  50 +#pragma mark - 添加:视频编辑(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 0 → 100755
  1 +//
  2 +// TZImagePickerController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +// version 2.2.6 - 2018.08.21
  8 +// 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
  9 +
  10 +#import "TZImagePickerController.h"
  11 +#import "TZPhotoPickerController.h"
  12 +#import "TZPhotoPreviewController.h"
  13 +#import "TZAssetModel.h"
  14 +#import "TZAssetCell.h"
  15 +#import "UIView+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 - 添加:视频编辑(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 + struct utsname systemInfo;
  896 + uname(&systemInfo);
  897 + NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];
  898 + if ([platform isEqualToString:@"i386"] || [platform isEqualToString:@"x86_64"]) {
  899 + // 模拟器下采用屏幕的高度来判断
  900 + return (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||
  901 + CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)));
  902 + }
  903 + // iPhone10,6是美版iPhoneX 感谢hegelsu指出:https://github.com/banchichen/TZImagePickerController/issues/635
  904 + BOOL isIPhoneX = [platform isEqualToString:@"iPhone10,3"] || [platform isEqualToString:@"iPhone10,6"];
  905 + return isIPhoneX;
  906 +}
  907 +
  908 ++ (CGFloat)tz_statusBarHeight {
  909 + return [self tz_isIPhoneX] ? 44 : 20;
  910 +}
  911 +
  912 +// 获得Info.plist数据字典
  913 ++ (NSDictionary *)tz_getInfoDictionary {
  914 + NSDictionary *infoDict = [NSBundle mainBundle].localizedInfoDictionary;
  915 + if (!infoDict || !infoDict.count) {
  916 + infoDict = [NSBundle mainBundle].infoDictionary;
  917 + }
  918 + if (!infoDict || !infoDict.count) {
  919 + NSString *path = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"];
  920 + infoDict = [NSDictionary dictionaryWithContentsOfFile:path];
  921 + }
  922 + return infoDict ? infoDict : @{};
  923 +}
  924 +@end
  925 +
  926 +
  927 +@implementation TZImagePickerConfig
  928 +
  929 ++ (instancetype)sharedInstance {
  930 + static dispatch_once_t onceToken;
  931 + static TZImagePickerConfig *config = nil;
  932 + dispatch_once(&onceToken, ^{
  933 + if (config == nil) {
  934 + config = [[TZImagePickerConfig alloc] init];
  935 + config.preferredLanguage = nil;
  936 + config.gifPreviewMaxImagesCount = 200;
  937 + }
  938 + });
  939 + return config;
  940 +}
  941 +
  942 +- (void)setPreferredLanguage:(NSString *)preferredLanguage {
  943 + _preferredLanguage = preferredLanguage;
  944 +
  945 + if (!preferredLanguage || !preferredLanguage.length) {
  946 + preferredLanguage = [NSLocale preferredLanguages].firstObject;
  947 + }
  948 + if ([preferredLanguage rangeOfString:@"zh-Hans"].location != NSNotFound) {
  949 + preferredLanguage = @"zh-Hans";
  950 + } else if ([preferredLanguage rangeOfString:@"zh-Hant"].location != NSNotFound) {
  951 + preferredLanguage = @"zh-Hant";
  952 + } else if ([preferredLanguage rangeOfString:@"vi"].location != NSNotFound) {
  953 + preferredLanguage = @"vi";
  954 + } else {
  955 + preferredLanguage = @"en";
  956 + }
  957 + _languageBundle = [NSBundle bundleWithPath:[[NSBundle tz_imagePickerBundle] pathForResource:preferredLanguage ofType:@"lproj"]];
  958 +}
  959 +
  960 +@end
... ...
CNLiveImagePickerController/TZLocationManager.h 0 → 100755
  1 +//
  2 +// TZLocationManager.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2017/06/03.
  6 +// Copyright © 2017年 谭真. All rights reserved.
  7 +// 定位管理类
  8 +
  9 +
  10 +#import <Foundation/Foundation.h>
  11 +#import <CoreLocation/CoreLocation.h>
  12 +
  13 +@interface TZLocationManager : NSObject
  14 +
  15 ++ (instancetype)manager;
  16 +
  17 +/// 开始定位
  18 +- (void)startLocation;
  19 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock;
  20 +- (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
  21 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock;
  22 +
  23 +@end
  24 +
... ...
CNLiveImagePickerController/TZLocationManager.m 0 → 100755
  1 +//
  2 +// TZLocationManager.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 2017/06/03.
  6 +// Copyright © 2017年 谭真. All rights reserved.
  7 +// 定位管理类
  8 +
  9 +#import "TZLocationManager.h"
  10 +#import "TZImagePickerController.h"
  11 +
  12 +@interface TZLocationManager ()<CLLocationManagerDelegate>
  13 +@property (nonatomic, strong) CLLocationManager *locationManager;
  14 +/// 定位成功的回调block
  15 +@property (nonatomic, copy) void (^successBlock)(NSArray<CLLocation *> *);
  16 +/// 编码成功的回调block
  17 +@property (nonatomic, copy) void (^geocodeBlock)(NSArray *geocodeArray);
  18 +/// 定位失败的回调block
  19 +@property (nonatomic, copy) void (^failureBlock)(NSError *error);
  20 +@end
  21 +
  22 +@implementation TZLocationManager
  23 +
  24 ++ (instancetype)manager {
  25 + static TZLocationManager *manager;
  26 + static dispatch_once_t onceToken;
  27 + dispatch_once(&onceToken, ^{
  28 + manager = [[self alloc] init];
  29 + manager.locationManager = [[CLLocationManager alloc] init];
  30 + manager.locationManager.delegate = manager;
  31 + if (iOS8Later) {
  32 + [manager.locationManager requestWhenInUseAuthorization];
  33 + }
  34 + });
  35 + return manager;
  36 +}
  37 +
  38 +- (void)startLocation {
  39 + [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:nil];
  40 +}
  41 +
  42 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock {
  43 + [self startLocationWithSuccessBlock:successBlock failureBlock:failureBlock geocoderBlock:nil];
  44 +}
  45 +
  46 +- (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
  47 + [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:geocoderBlock];
  48 +}
  49 +
  50 +- (void)startLocationWithSuccessBlock:(void (^)(NSArray<CLLocation *> *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock {
  51 + [self.locationManager startUpdatingLocation];
  52 + _successBlock = successBlock;
  53 + _geocodeBlock = geocoderBlock;
  54 + _failureBlock = failureBlock;
  55 +}
  56 +
  57 +#pragma mark - CLLocationManagerDelegate
  58 +
  59 +/// 地理位置发生改变时触发
  60 +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
  61 + [manager stopUpdatingLocation];
  62 +
  63 + if (_successBlock) {
  64 + _successBlock(locations);
  65 + }
  66 +
  67 + if (_geocodeBlock && locations.count) {
  68 + CLGeocoder *geocoder = [[CLGeocoder alloc] init];
  69 + [geocoder reverseGeocodeLocation:[locations firstObject] completionHandler:^(NSArray *array, NSError *error) {
  70 + self->_geocodeBlock(array);
  71 + }];
  72 + }
  73 +}
  74 +
  75 +/// 定位失败回调方法
  76 +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
  77 + NSLog(@"定位失败, 错误: %@",error);
  78 + switch([error code]) {
  79 + case kCLErrorDenied: { // 用户禁止了定位权限
  80 +
  81 + } break;
  82 + default: break;
  83 + }
  84 + if (_failureBlock) {
  85 + _failureBlock(error);
  86 + }
  87 +}
  88 +
  89 +@end
... ...
CNLiveImagePickerController/TZPhotoPickerController.h 0 → 100755
  1 +//
  2 +// TZPhotoPickerController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAlbumModel;
  12 +@interface TZPhotoPickerController : UIViewController
  13 +
  14 +@property (nonatomic, assign) BOOL isFirstAppear;
  15 +@property (nonatomic, assign) NSInteger columnNumber;
  16 +@property (nonatomic, strong) TZAlbumModel *model;
  17 +@end
  18 +
  19 +
  20 +@interface TZCollectionView : UICollectionView
  21 +
  22 +@end
... ...
CNLiveImagePickerController/TZPhotoPickerController.m 0 → 100755
  1 +//
  2 +// TZPhotoPickerController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZPhotoPickerController.h"
  10 +#import "TZImagePickerController.h"
  11 +#import "TZPhotoPreviewController.h"
  12 +#import "TZAssetCell.h"
  13 +#import "TZAssetModel.h"
  14 +#import "UIView+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 - 添加: 选择图片个数显示(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 - 添加: 选择图片个数显示(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 0 → 100755
  1 +//
  2 +// TZPhotoPreviewCell.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZAssetPreviewCell : UICollectionViewCell
  13 +@property (nonatomic, strong) TZAssetModel *model;
  14 +@property (nonatomic, copy) void (^singleTapGestureBlock)(void);
  15 +- (void)configSubviews;
  16 +- (void)photoPreviewCollectionViewDidScroll;
  17 +@end
  18 +
  19 +
  20 +@class TZAssetModel,TZProgressView,TZPhotoPreviewView;
  21 +@interface TZPhotoPreviewCell : TZAssetPreviewCell
  22 +
  23 +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
  24 +
  25 +@property (nonatomic, strong) TZPhotoPreviewView *previewView;
  26 +
  27 +@property (nonatomic, assign) BOOL allowCrop;
  28 +@property (nonatomic, assign) CGRect cropRect;
  29 +
  30 +- (void)recoverSubviews;
  31 +
  32 +@end
  33 +
  34 +
  35 +@interface TZPhotoPreviewView : UIView
  36 +@property (nonatomic, strong) UIImageView *imageView;
  37 +@property (nonatomic, strong) UIScrollView *scrollView;
  38 +@property (nonatomic, strong) UIView *imageContainerView;
  39 +@property (nonatomic, strong) TZProgressView *progressView;
  40 +
  41 +@property (nonatomic, assign) BOOL allowCrop;
  42 +@property (nonatomic, assign) CGRect cropRect;
  43 +
  44 +@property (nonatomic, strong) TZAssetModel *model;
  45 +@property (nonatomic, strong) id asset;
  46 +@property (nonatomic, copy) void (^singleTapGestureBlock)(void);
  47 +@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
  48 +
  49 +@property (nonatomic, assign) int32_t imageRequestID;
  50 +
  51 +- (void)recoverSubviews;
  52 +@end
  53 +
  54 +
  55 +@class AVPlayer, AVPlayerLayer;
  56 +@interface TZVideoPreviewCell : TZAssetPreviewCell
  57 +@property (strong, nonatomic) AVPlayer *player;
  58 +@property (strong, nonatomic) AVPlayerLayer *playerLayer;
  59 +@property (strong, nonatomic) UIButton *playButton;
  60 +@property (strong, nonatomic) UIImage *cover;
  61 +- (void)pausePlayerAndShowNaviBar;
  62 +@end
  63 +
  64 +
  65 +@interface TZGifPreviewCell : TZAssetPreviewCell
  66 +@property (strong, nonatomic) TZPhotoPreviewView *previewView;
  67 +@end
... ...
CNLiveImagePickerController/TZPhotoPreviewCell.m 0 → 100755
  1 +//
  2 +// TZPhotoPreviewCell.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZPhotoPreviewCell.h"
  10 +#import "TZAssetModel.h"
  11 +#import "UIView+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 0 → 100755
  1 +//
  2 +// TZPhotoPreviewController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@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 0 → 100755
  1 +//
  2 +// TZPhotoPreviewController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 15/12/24.
  6 +// Copyright © 2015年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZPhotoPreviewController.h"
  10 +#import "TZPhotoPreviewCell.h"
  11 +#import "TZAssetModel.h"
  12 +#import "UIView+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 - 添加: 选择图片个数显示(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 - 添加: 选择图片个数显示(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 - 添加: 视频显示操作(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 0 → 100755
  1 +//
  2 +// TZProgressView.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/6.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@interface TZProgressView : UIView
  12 +
  13 +@property (nonatomic, assign) double progress;
  14 +
  15 +@end
... ...
CNLiveImagePickerController/TZProgressView.m 0 → 100755
  1 +//
  2 +// TZProgressView.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by ttouch on 2016/12/6.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZProgressView.h"
  10 +
  11 +@interface TZProgressView ()
  12 +@property (nonatomic, strong) CAShapeLayer *progressLayer;
  13 +@end
  14 +
  15 +@implementation TZProgressView
  16 +
  17 +- (instancetype)init {
  18 + self = [super init];
  19 + if (self) {
  20 + self.backgroundColor = [UIColor clearColor];
  21 +
  22 + _progressLayer = [CAShapeLayer layer];
  23 + _progressLayer.fillColor = [[UIColor clearColor] CGColor];
  24 + _progressLayer.strokeColor = [[UIColor whiteColor] CGColor];
  25 + _progressLayer.opacity = 1;
  26 + _progressLayer.lineCap = kCALineCapRound;
  27 + _progressLayer.lineWidth = 5;
  28 +
  29 + [_progressLayer setShadowColor:[UIColor blackColor].CGColor];
  30 + [_progressLayer setShadowOffset:CGSizeMake(1, 1)];
  31 + [_progressLayer setShadowOpacity:0.5];
  32 + [_progressLayer setShadowRadius:2];
  33 + }
  34 + return self;
  35 +}
  36 +
  37 +- (void)drawRect:(CGRect)rect {
  38 + CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2);
  39 + CGFloat radius = rect.size.width / 2;
  40 + CGFloat startA = - M_PI_2;
  41 + CGFloat endA = - M_PI_2 + M_PI * 2 * _progress;
  42 + _progressLayer.frame = self.bounds;
  43 + UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
  44 + _progressLayer.path =[path CGPath];
  45 +
  46 + [_progressLayer removeFromSuperlayer];
  47 + [self.layer addSublayer:_progressLayer];
  48 +}
  49 +
  50 +- (void)setProgress:(double)progress {
  51 + _progress = progress;
  52 + [self setNeedsDisplay];
  53 +}
  54 +
  55 +@end
... ...
CNLiveImagePickerController/TZVideoPlayerController.h 0 → 100755
  1 +//
  2 +// TZVideoPlayerController.h
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import <UIKit/UIKit.h>
  10 +
  11 +@class TZAssetModel;
  12 +@interface TZVideoPlayerController : UIViewController
  13 +
  14 +@property (nonatomic, strong) TZAssetModel *model;
  15 +///其他进入和相册进入(lxg)
  16 +@property (nonatomic, assign) BOOL isOther;
  17 +
  18 +@end
... ...
CNLiveImagePickerController/TZVideoPlayerController.m 0 → 100755
  1 +//
  2 +// TZVideoPlayerController.m
  3 +// TZImagePickerController
  4 +//
  5 +// Created by 谭真 on 16/1/5.
  6 +// Copyright © 2016年 谭真. All rights reserved.
  7 +//
  8 +
  9 +#import "TZVideoPlayerController.h"
  10 +#import <MediaPlayer/MediaPlayer.h>
  11 +#import "UIView+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 - 添加: 导航栏(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/UIView+Layout.h 0 → 100755
  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 0 → 100755
  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
... ...