Commit 8c366ca4 authored by 少言's avatar 少言

0.0.9--新增打开相机

parent c599b972
......@@ -7,7 +7,7 @@
Android 基于 [PictureSelector 2.0](https://github.com/LuckSiege/PictureSelector)
iOS 基于 [TZImagePickerController 1.9.0](https://github.com/banchichen/TZImagePickerController)
iOS 基于 [TZImagePickerController 1.9.5](https://github.com/banchichen/TZImagePickerController)
![](http://oy5rz3rfs.bkt.clouddn.com/github/syan_001.png?imageView/2/w/268)
![](http://oy5rz3rfs.bkt.clouddn.com/github/syan_002.png?imageView/2/w/268)
......@@ -115,7 +115,8 @@ import SYImagePicker from 'react-native-syan-image-picker'
showCropCircle: false, // 是否显示圆形裁剪区域,默认false
circleCropRadius: width/2 // 圆形裁剪半径,默认屏幕宽度一半
showCropFrame: true, // 是否显示裁剪区域,默认true
showCropGrid: false // 是否隐藏裁剪区域网格,默认false
showCropGrid: false, // 是否隐藏裁剪区域网格,默认false
quality: 90 // 压缩质量
};
/**
......@@ -125,7 +126,7 @@ import SYImagePicker from 'react-native-syan-image-picker'
* 1)选择图片成功,err为null,selectedPhotos为选中的图片数组
* 2)取消时,err返回"取消",selectedPhotos将为undefined
* 按需判断各参数值,确保调用正常,示例使用方式:
* showImagePicker(options, (err, selectedPhotos) => {
* SYImagePicker.showImagePicker(options, (err, selectedPhotos) => {
* if (err) {
* // 取消选择
* return;
......@@ -164,6 +165,19 @@ import SYImagePicker from 'react-native-syan-image-picker'
* @return {Promise} 返回一个Promise对象
*/
/**
* 打开相机
* @param options
* @param callback
*/
* SYImagePicker.openCamera(options, (err, selectedPhotos) => {
* if (err) {
* // 取消选择
* return;
* }
* // 选择成功
* })
```
## 帮助
加入React-Native QQ群 397885169
......
......@@ -63,6 +63,14 @@ public class RNSyanImagePickerModule extends ReactContextBaseJavaModule {
this.openImagePicker(options);
}
@ReactMethod
public void openCamera(ReadableMap options, Callback callback) {
this.mPickerPromise = null;
this.mPickerCallback = callback;
this.openCamera(options);
}
/**
* 打开相册选择
*
......@@ -78,6 +86,7 @@ public class RNSyanImagePickerModule extends ReactContextBaseJavaModule {
boolean showCropCircle = options.getBoolean("showCropCircle");
boolean showCropFrame = options.getBoolean("showCropFrame");
boolean showCropGrid = options.getBoolean("showCropGrid");
int quality = options.getInt("quality");
int modeValue;
if (imageCount == 1) {
......@@ -110,15 +119,51 @@ public class RNSyanImagePickerModule extends ReactContextBaseJavaModule {
.showCropFrame(showCropFrame)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
.showCropGrid(showCropGrid)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
.openClickSound(false)// 是否开启点击声音 true or false
.cropCompressQuality(90)// 裁剪压缩质量 默认90 int
.cropCompressQuality(quality)// 裁剪压缩质量 默认90 int
.minimumCompressSize(100)// 小于100kb的图片不压缩
.synOrAsy(true)//同步true或异步false 压缩 默认同步
.rotateEnabled(true) // 裁剪是否可旋转图片 true or false
.scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
//.videoQuality(0)// 视频录制质量 0 or 1 int
//.videoMaxSecond(15)// 显示多少秒以内的视频or音频也可适用 int
//.videoMinSecond(10)// 显示多少秒以内的视频or音频也可适用 int
//.recordVideoSecond(60)//视频秒数录制 默认60s int
.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code
}
/**
* 打开相册选择
*
* @param options 相册参数
*/
private void openCamera(ReadableMap options) {
boolean isCrop = options.getBoolean("isCrop");
int CropW = options.getInt("CropW");
int CropH = options.getInt("CropH");
boolean showCropCircle = options.getBoolean("showCropCircle");
boolean showCropFrame = options.getBoolean("showCropFrame");
boolean showCropGrid = options.getBoolean("showCropGrid");
int quality = options.getInt("quality");
Activity currentActivity = getCurrentActivity();
PictureSelector.create(currentActivity)
.openCamera(PictureMimeType.ofImage())
.imageFormat(PictureMimeType.PNG)// 拍照保存图片格式后缀,默认jpeg
.enableCrop(isCrop)// 是否裁剪 true or false
.compress(true)// 是否压缩 true or false
.glideOverride(160, 160)// int glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
.withAspectRatio(CropW, CropH)// int 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
.hideBottomControls(isCrop)// 是否显示uCrop工具栏,默认不显示 true or false
.freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
.circleDimmedLayer(showCropCircle)// 是否圆形裁剪 true or false
.showCropFrame(showCropFrame)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
.showCropGrid(showCropGrid)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
.openClickSound(false)// 是否开启点击声音 true or false
.cropCompressQuality(quality)// 裁剪压缩质量 默认90 int
.minimumCompressSize(100)// 小于100kb的图片不压缩
.synOrAsy(true)//同步true或异步false 压缩 默认同步
.rotateEnabled(true) // 裁剪是否可旋转图片 true or false
.scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
.videoQuality(0)// 视频录制质量 0 or 1 int
.videoMaxSecond(15)// 显示多少秒以内的视频or音频也可适用 int
.videoMinSecond(10)// 显示多少秒以内的视频or音频也可适用 int
.recordVideoSecond(60)//视频秒数录制 默认60s int
.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code
}
......
......@@ -19,7 +19,8 @@ const defaultOptions = {
showCropCircle: false, // 是否显示圆形裁剪区域,默认false
circleCropRadius: width/2, // 圆形裁剪半径,默认屏幕宽度一半
showCropFrame: true, // 是否显示裁剪区域,默认true
showCropGrid: false // 是否隐藏裁剪区域网格,默认false
showCropGrid: false, // 是否隐藏裁剪区域网格,默认false
quality: 90 // 压缩质量
};
export default {
......@@ -81,5 +82,18 @@ export default {
...options,
};
return RNSyanImagePicker.asyncShowImagePicker(optionObj);
},
/**
* 打开相机支持裁剪参数
* @param options
* @param callback
*/
openCamera(options, callback) {
const optionObj = {
...defaultOptions,
...options
};
RNSyanImagePicker.openCamera(optionObj, callback)
}
};
......@@ -4,8 +4,8 @@
#else
#import <React/RCTBridgeModule.h>
#endif
@interface RNSyanImagePicker : NSObject <RCTBridgeModule>
#import <UIKit/UIKit.h>
@interface RNSyanImagePicker : NSObject <RCTBridgeModule, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIActionSheetDelegate>
@end
#import "RNSyanImagePicker.h"
#import "TZImagePickerController.h"
#import "TZImageManager.h"
#import "NSDictionary+SYSafeConvert.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <React/RCTUtils.h>
@interface RNSyanImagePicker ()
@property (nonatomic, strong) UIImagePickerController *imagePickerVc;
@property (nonatomic, strong) NSDictionary *cameraOptions;
/**
保存Promise的resolve block
*/
......@@ -22,6 +30,14 @@
RCT_EXPORT_MODULE()
- (UIImagePickerController *)imagePickerVc {
if (_imagePickerVc == nil) {
_imagePickerVc = [[UIImagePickerController alloc] init];
_imagePickerVc.delegate = self;
}
return _imagePickerVc;
}
RCT_EXPORT_METHOD(showImagePicker:(NSDictionary *)options
callback:(RCTResponseSenderBlock)callback) {
self.callback = callback;
......@@ -51,6 +67,7 @@ RCT_REMAP_METHOD(asyncShowImagePicker,
NSInteger CropW = [options sy_integerForKey:@"CropW"];
NSInteger CropH = [options sy_integerForKey:@"CropH"];
NSInteger circleCropRadius = [options sy_integerForKey:@"circleCropRadius"];
NSInteger quality = [self.cameraOptions sy_integerForKey:@"quality"];
TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:imageCount delegate:nil];
......@@ -84,37 +101,14 @@ RCT_REMAP_METHOD(asyncShowImagePicker,
[weakPicker showProgressHUD];
if (imageCount == 1 && isCrop) {
NSMutableDictionary *photo = [NSMutableDictionary dictionary];
// 剪切图片并放在tmp中
photo[@"width"] = @(photos[0].size.width);
photo[@"height"] = @(photos[0].size.height);
NSString *fileName = [NSString stringWithFormat:@"%d.jpg", arc4random() % 10000000];
NSString *filePath = [NSString stringWithFormat:@"%@/tmp/%@", NSHomeDirectory(), fileName];
if ([UIImageJPEGRepresentation(photos[0], 0.9) writeToFile:filePath atomically:YES]) {
photo[@"uri"] = filePath;
} else {
NSLog(@"保存压缩图片失败");
}
[selectedPhotos addObject:photo];
[selectedPhotos addObject:[self handleImageData:photos[0] quality:quality]];
} else {
[infos enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSMutableDictionary *photo = [NSMutableDictionary dictionary];
photo[@"width"] = @(photos[idx].size.width);
photo[@"height"] = @(photos[idx].size.height);
photo[@"original_uri"] = [(NSURL *)obj[@"PHImageFileURLKey"] absoluteString];
NSString *fileName = [NSString stringWithFormat:@"%d.jpg", arc4random() % 10000000];
NSString *filePath = [NSString stringWithFormat:@"%@/tmp/%@", NSHomeDirectory(), fileName];
if ([UIImageJPEGRepresentation(photos[idx], 0.9) writeToFile:filePath atomically:YES]) {
photo[@"uri"] = filePath;
} else {
NSLog(@"保存压缩图片失败");
}
[selectedPhotos addObject:[self handleImageData:photos[idx] quality:quality]];
[selectedPhotos addObject:photo];
}];
}
......@@ -130,6 +124,165 @@ RCT_REMAP_METHOD(asyncShowImagePicker,
[[self topViewController] presentViewController:imagePickerVc animated:YES completion:nil];
}
RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options callback:(RCTResponseSenderBlock)callback) {
self.cameraOptions = options;
self.callback = callback;
self.resolveBlock = nil;
self.rejectBlock = nil;
[self takePhoto];
}
#pragma mark - UIImagePickerController
- (void)takePhoto {
AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
if ((authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied) && iOS7Later) {
// 无相机权限 做一个友好的提示
if (iOS8Later) {
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"无法使用相机" message:@"请在iPhone的""设置-隐私-相机""中允许访问相机" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"设置", nil];
[alert show];
} else {
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"无法使用相机" message:@"请在iPhone的""设置-隐私-相机""中允许访问相机" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert show];
}
} else if (authStatus == AVAuthorizationStatusNotDetermined) {
// fix issue 466, 防止用户首次拍照拒绝授权时相机页黑屏
if (iOS7Later) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
if (granted) {
dispatch_sync(dispatch_get_main_queue(), ^{
[self takePhoto];
});
}
}];
} else {
[self takePhoto];
}
// 拍照之前还需要检查相册权限
} else if ([TZImageManager authorizationStatus] == 2) { // 已被拒绝,没有相册权限,将无法保存拍的照片
if (iOS8Later) {
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"无法访问相册" message:@"请在iPhone的""设置-隐私-相册""中允许访问相册" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"设置", nil];
[alert show];
} else {
UIAlertView * alert = [[UIAlertView alloc]initWithTitle:@"无法访问相册" message:@"请在iPhone的""设置-隐私-相册""中允许访问相册" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil];
[alert show];
}
} else if ([TZImageManager authorizationStatus] == 0) { // 未请求过相册权限
[[TZImageManager manager] requestAuthorizationWithCompletion:^{
[self takePhoto];
}];
} else {
[self pushImagePickerController];
}
}
// 调用相机
- (void)pushImagePickerController {
UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]) {
self.imagePickerVc.sourceType = sourceType;
if(iOS8Later) {
self.imagePickerVc.modalPresentationStyle = UIModalPresentationOverCurrentContext;
}
[[self topViewController] presentViewController:self.imagePickerVc animated:YES completion:nil];
} else {
NSLog(@"模拟器中无法打开照相机,请在真机中使用");
}
}
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[picker dismissViewControllerAnimated:YES completion:nil];
NSString *type = [info objectForKey:UIImagePickerControllerMediaType];
if ([type isEqualToString:@"public.image"]) {
TZImagePickerController *tzImagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:1 delegate:nil];
tzImagePickerVc.sortAscendingByModificationDate = NO;
[tzImagePickerVc showProgressHUD];
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// save photo and get asset / 保存图片,获取到asset
[[TZImageManager manager] savePhotoWithImage:image location:NULL completion:^(NSError *error){
if (error) {
[tzImagePickerVc hideProgressHUD];
NSLog(@"图片保存失败 %@",error);
} else {
[[TZImageManager manager] getCameraRollAlbum:NO allowPickingImage:YES completion:^(TZAlbumModel *model) {
[[TZImageManager manager] getAssetsFromFetchResult:model.result allowPickingVideo:NO allowPickingImage:YES completion:^(NSArray<TZAssetModel *> *models) {
[tzImagePickerVc hideProgressHUD];
TZAssetModel *assetModel = [models firstObject];
BOOL isCrop = [self.cameraOptions sy_boolForKey:@"isCrop"];
BOOL showCropCircle = [self.cameraOptions sy_boolForKey:@"showCropCircle"];
NSInteger CropW = [self.cameraOptions sy_integerForKey:@"CropW"];
NSInteger CropH = [self.cameraOptions sy_integerForKey:@"CropH"];
NSInteger circleCropRadius = [self.cameraOptions sy_integerForKey:@"circleCropRadius"];
NSInteger quality = [self.cameraOptions sy_integerForKey:@"quality"];
if (isCrop) {
TZImagePickerController *imagePicker = [[TZImagePickerController alloc] initCropTypeWithAsset:assetModel.asset photo:image completion:^(UIImage *cropImage, id asset) {
[self invokeSuccessWithResult:@[[self handleImageData:cropImage quality:quality]]];
}];
imagePicker.allowCrop = isCrop; // 裁剪
if(showCropCircle) {
imagePicker.needCircleCrop = showCropCircle; //圆形裁剪
imagePicker.circleCropRadius = circleCropRadius; //圆形半径
} else {
CGFloat x = ([[UIScreen mainScreen] bounds].size.width - CropW) / 2;
CGFloat y = ([[UIScreen mainScreen] bounds].size.height - CropH) / 2;
imagePicker.cropRect = CGRectMake(x,y,CropW,CropH);
}
[[self topViewController] presentViewController:imagePicker animated:YES completion:nil];
} else {
[self invokeSuccessWithResult:@[[self handleImageData:image quality:quality]]];
}
}];
}];
}
}];
}
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
[self invokeError];
if ([picker isKindOfClass:[UIImagePickerController class]]) {
[picker dismissViewControllerAnimated:YES completion:nil];
}
}
#pragma mark - UIAlertViewDelegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) { // 去设置界面,开启相机访问权限
if (iOS8Later) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
}
}
}
- (NSDictionary *)handleImageData:(UIImage *) image quality:(NSInteger)quality {
NSMutableDictionary *photo = [NSMutableDictionary dictionary];
// 剪切图片并放在tmp中
photo[@"width"] = @(image.size.width);
photo[@"height"] = @(image.size.height);
NSString *fileName = [NSString stringWithFormat:@"%@.jpg", [[NSUUID UUID] UUIDString]];
NSString *filePath = [NSString stringWithFormat:@"%@/tmp/%@", NSHomeDirectory(), fileName];
if ([UIImageJPEGRepresentation(image, quality/100) writeToFile:filePath atomically:YES]) {
photo[@"uri"] = filePath;
} else {
NSLog(@"保存压缩图片失败");
}
return photo;
}
- (void)invokeSuccessWithResult:(NSArray *)photos {
if (self.callback) {
self.callback(@[[NSNull null], photos]);
......@@ -153,10 +306,8 @@ RCT_REMAP_METHOD(asyncShowImagePicker,
}
- (UIViewController *)topViewController {
UIViewController *rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
if (rootViewController.presentedViewController) {
rootViewController = rootViewController.presentedViewController;
}
// UIViewController *rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];
UIViewController *rootViewController = RCTPresentedViewController();
return rootViewController;
}
......
......@@ -296,7 +296,10 @@
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../../react-native/React\"",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNSyanImagePicker;
......@@ -307,7 +310,10 @@
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = "$(inherited)";
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/../../react-native/React\"",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RNSyanImagePicker;
......
......@@ -28,6 +28,8 @@
NSString *language = [NSLocale preferredLanguages].firstObject;
if ([language rangeOfString:@"zh-Hans"].location != NSNotFound) {
language = @"zh-Hans";
} else if ([language rangeOfString:@"zh-Hant"].location != NSNotFound) {
language = @"zh-Hant";
} else {
language = @"en";
}
......
......@@ -56,7 +56,8 @@
_previewView.model = self.model;
__weak typeof(self) weakSelf = self;
[_previewView setSingleTapGestureBlock:^{
[weakSelf signleTapAction];
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf signleTapAction];
}];
[self.view addSubview:_previewView];
}
......@@ -98,8 +99,9 @@
_previewView.frame = self.view.bounds;
_previewView.scrollView.frame = self.view.bounds;
CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
_toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
_toolBar.frame = CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44);
}
#pragma mark - Click Event
......@@ -107,9 +109,13 @@
- (void)signleTapAction {
_toolBar.hidden = !_toolBar.isHidden;
[self.navigationController setNavigationBarHidden:_toolBar.isHidden];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = _toolBar.isHidden;
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (iOS7Later) {
if (_toolBar.isHidden) {
[UIApplication sharedApplication].statusBarHidden = YES;
} else if (tzImagePickerVc.needShowStatusBar) {
[UIApplication sharedApplication].statusBarHidden = NO;
}
}
}
......
......@@ -47,7 +47,7 @@
/// Return YES if Authorized 返回YES如果得到了授权
- (BOOL)authorizationStatusAuthorized;
+ (NSInteger)authorizationStatus;
- (void)requestAuthorizationWithCompletion:(void (^)())completion;
- (void)requestAuthorizationWithCompletion:(void (^)(void))completion;
/// Get Album 获得相册/相册数组
- (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAlbumModel *model))completion;
......@@ -80,8 +80,11 @@
- (void)getVideoWithAsset:(id)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion;
- (void)getVideoWithAsset:(id)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion;
/// Export video 导出视频
- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion;
/// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480
- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion __attribute__((deprecated("Use -getVideoOutputPathWithAsset:failure:success:")));
/// Get photo bytes 获得一组照片的大小
- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion;
......
......@@ -94,8 +94,8 @@ static dispatch_once_t onceToken;
return NO;
}
- (void)requestAuthorizationWithCompletion:(void (^)())completion {
void (^callCompletionBlock)() = ^(){
- (void)requestAuthorizationWithCompletion:(void (^)(void))completion {
void (^callCompletionBlock)(void) = ^(){
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion();
......@@ -399,6 +399,10 @@ static dispatch_once_t onceToken;
/// Get photo bytes 获得一组照片的大小
- (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion {
if (!photos || !photos.count) {
if (completion) completion(@"0B");
return;
}
__block NSInteger dataLength = 0;
__block NSInteger assetCount = 0;
for (NSInteger i = 0; i < photos.count; i++) {
......@@ -626,9 +630,10 @@ static dispatch_once_t onceToken;
}
- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(NSError *error))completion {
NSData *data = UIImageJPEGRepresentation(image, 0.9);
if (iOS9Later) { // 这里有坑... iOS8系统下这个方法保存图片会失败 原来是因为PHAssetResourceType是iOS9之后的...
if (iOS8Later) {
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
if (iOS9Later) {
NSData *data = UIImageJPEGRepresentation(image, 0.9);
PHAssetResourceCreationOptions *options = [[PHAssetResourceCreationOptions alloc] init];
options.shouldMoveFile = YES;
PHAssetCreationRequest *request = [PHAssetCreationRequest creationRequestForAsset];
......@@ -637,6 +642,13 @@ static dispatch_once_t onceToken;
request.location = location;
}
request.creationDate = [NSDate date];
} else {
PHAssetChangeRequest *request = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
if (location) {
request.location = location;
}
request.creationDate = [NSDate date];
}
} completionHandler:^(BOOL success, NSError *error) {
dispatch_sync(dispatch_get_main_queue(), ^{
if (success && completion) {
......@@ -702,7 +714,11 @@ static dispatch_once_t onceToken;
#pragma mark - Export video
/// Export Video / 导出视频
- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion {
- (void)getVideoOutputPathWithAsset:(id)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
[self getVideoOutputPathWithAsset:asset presetName:AVAssetExportPreset640x480 success:success failure:failure];
}
- (void)getVideoOutputPathWithAsset:(id)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
if ([asset isKindOfClass:[PHAsset class]]) {
PHVideoRequestOptions* options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal;
......@@ -712,16 +728,21 @@ static dispatch_once_t onceToken;
// NSLog(@"Info:\n%@",info);
AVURLAsset *videoAsset = (AVURLAsset*)avasset;
// NSLog(@"AVAsset URL: %@",myAsset.URL);
[self startExportVideoWithVideoAsset:videoAsset completion:completion];
[self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
}];
} else if ([asset isKindOfClass:[ALAsset class]]) {
NSURL *videoURL =[asset valueForProperty:ALAssetPropertyAssetURL]; // ALAssetPropertyURLs
AVURLAsset *videoAsset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
[self startExportVideoWithVideoAsset:videoAsset completion:completion];
[self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
}
}
- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset completion:(void (^)(NSString *outputPath))completion {
/// Deprecated, Use -getVideoOutputPathWithAsset:failure:success:
- (void)getVideoOutputPathWithAsset:(id)asset completion:(void (^)(NSString *outputPath))completion {
[self getVideoOutputPathWithAsset:asset success:completion failure:nil];
}
- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
// Find compatible presets by video asset.
NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:videoAsset];
......@@ -729,13 +750,13 @@ static dispatch_once_t onceToken;
// Now we just compress to low resolution if it supports
// If you need to upload to the server, but server does't support to upload by streaming,
// You can compress the resolution to lower. Or you can support more higher resolution.
if ([presets containsObject:AVAssetExportPreset640x480]) {
AVAssetExportSession *session = [[AVAssetExportSession alloc]initWithAsset:videoAsset presetName:AVAssetExportPreset640x480];
if ([presets containsObject:presetName]) {
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:videoAsset presetName:presetName];
NSDateFormatter *formater = [[NSDateFormatter alloc] init];
[formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss-SSS"];
NSString *outputPath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/output-%@.mp4", [formater stringFromDate:[NSDate date]]];
NSLog(@"video outputPath = %@",outputPath);
// NSLog(@"video outputPath = %@",outputPath);
session.outputURL = [NSURL fileURLWithPath:outputPath];
// Optimize for network use.
......@@ -745,6 +766,9 @@ static dispatch_once_t onceToken;
if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
session.outputFileType = AVFileTypeMPEG4;
} else if (supportedTypeArray.count == 0) {
if (failure) {
failure(@"该视频类型暂不支持导出", nil);
}
NSLog(@"No supported file types 视频类型暂不支持导出");
return;
} else {
......@@ -763,26 +787,44 @@ static dispatch_once_t onceToken;
// Begin to export video to the output path asynchronously.
[session exportAsynchronouslyWithCompletionHandler:^(void) {
dispatch_async(dispatch_get_main_queue(), ^{
switch (session.status) {
case AVAssetExportSessionStatusUnknown:
NSLog(@"AVAssetExportSessionStatusUnknown"); break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"AVAssetExportSessionStatusWaiting"); break;
case AVAssetExportSessionStatusExporting:
NSLog(@"AVAssetExportSessionStatusExporting"); break;
case AVAssetExportSessionStatusUnknown: {
NSLog(@"AVAssetExportSessionStatusUnknown");
} break;
case AVAssetExportSessionStatusWaiting: {
NSLog(@"AVAssetExportSessionStatusWaiting");
} break;
case AVAssetExportSessionStatusExporting: {
NSLog(@"AVAssetExportSessionStatusExporting");
} break;
case AVAssetExportSessionStatusCompleted: {
NSLog(@"AVAssetExportSessionStatusCompleted");
dispatch_async(dispatch_get_main_queue(), ^{
if (completion) {
completion(outputPath);
if (success) {
success(outputPath);
}
} break;
case AVAssetExportSessionStatusFailed: {
NSLog(@"AVAssetExportSessionStatusFailed");
if (failure) {
failure(@"视频导出失败", session.error);
}
} break;
case AVAssetExportSessionStatusCancelled: {
NSLog(@"AVAssetExportSessionStatusCancelled");
if (failure) {
failure(@"导出任务已被取消", nil);
}
});
} break;
case AVAssetExportSessionStatusFailed:
NSLog(@"AVAssetExportSessionStatusFailed"); break;
default: break;
}
});
}];
} else {
if (failure) {
NSString *errorMessage = [NSString stringWithFormat:@"当前设备不支持该预设:%@", presetName];
failure(errorMessage, nil);
}
}
}
......@@ -801,8 +843,20 @@ static dispatch_once_t onceToken;
- (BOOL)isCameraRollAlbum:(id)metadata {
if ([metadata isKindOfClass:[PHAssetCollection class]]) {
NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
if (versionStr.length <= 1) {
versionStr = [versionStr stringByAppendingString:@"00"];
} else if (versionStr.length <= 2) {
versionStr = [versionStr stringByAppendingString:@"0"];
}
CGFloat version = versionStr.floatValue;
// 目前已知8.0.0 ~ 8.0.2系统,拍照后的图片会保存在最近添加中
if (version >= 800 && version <= 802) {
return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded;
} else {
return ((PHAssetCollection *)metadata).assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary;
}
}
if ([metadata isKindOfClass:[ALAssetsGroup class]]) {
ALAssetsGroup *group = metadata;
return ([[group valueForProperty:ALAssetsGroupPropertyType] intValue] == ALAssetsGroupSavedPhotos);
......
......@@ -4,7 +4,7 @@
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
// version 1.9.3 - 2017.09.13
// version 1.9.8 - 2017.12.19
// 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
/*
......@@ -25,8 +25,6 @@
#define iOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
#define iOS9_1Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
#define TZ_isGlobalHideStatusBar [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIStatusBarHidden"] boolValue]
@protocol TZImagePickerControllerDelegate;
@interface TZImagePickerController : UINavigationController
......@@ -126,6 +124,7 @@
- (void)showProgressHUD;
- (void)hideProgressHUD;
@property (nonatomic, assign) BOOL isSelectOriginalPhoto;
@property (assign, nonatomic) BOOL needShowStatusBar;
@property (nonatomic, copy) NSString *takePictureImageName;
@property (nonatomic, copy) NSString *photoSelImageName;
......@@ -166,7 +165,7 @@
// photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它
@property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto);
@property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray<NSDictionary *> *infos);
@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)();
@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(void);
// If user picking a video, this handle will be called.
// If system version > iOS8,asset is kind of PHAsset class, else is ALAsset class.
......@@ -233,5 +232,12 @@
@interface NSString (TzExtension)
- (BOOL)tz_containsString:(NSString *)string;
- (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize;
@end
@interface TZCommonTools : NSObject
+ (BOOL)tz_isIPhoneX;
+ (CGFloat)tz_statusBarHeight;
@end
......@@ -4,7 +4,7 @@
//
// Created by 谭真 on 15/12/24.
// Copyright © 2015年 谭真. All rights reserved.
// version 1.9.3 - 2017.09.13
// version 1.9.8 - 2017.12.19
// 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController
#import "TZImagePickerController.h"
......@@ -14,6 +14,7 @@
#import "TZAssetCell.h"
#import "UIView+Layout.h"
#import "TZImageManager.h"
#import <sys/utsname.h>
@interface TZImagePickerController () {
NSTimer *_timer;
......@@ -36,10 +37,19 @@
@implementation TZImagePickerController
- (instancetype)init {
self = [super init];
if (self) {
self = [self initWithMaxImagesCount:9 delegate:nil];
}
return self;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (void)viewDidLoad {
[super viewDidLoad];
self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden;
self.view.backgroundColor = [UIColor whiteColor];
self.navigationBar.barStyle = UIBarStyleBlack;
self.navigationBar.translucent = YES;
......@@ -54,13 +64,15 @@
self.navigationBar.barTintColor = [UIColor colorWithRed:(34/255.0) green:(34/255.0) blue:(34/255.0) alpha:1.0];
self.navigationBar.tintColor = [UIColor whiteColor];
self.automaticallyAdjustsScrollViewInsets = NO;
if (!TZ_isGlobalHideStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
if (self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
}
}
- (void)setNaviBgColor:(UIColor *)naviBgColor {
_naviBgColor = naviBgColor;
if (iOS7Later) {
self.navigationBar.barTintColor = naviBgColor;
}
}
- (void)setNaviTitleColor:(UIColor *)naviTitleColor {
......@@ -75,8 +87,12 @@
- (void)configNaviTitleAppearance {
NSMutableDictionary *textAttrs = [NSMutableDictionary dictionary];
if (self.naviTitleColor) {
textAttrs[NSForegroundColorAttributeName] = self.naviTitleColor;
}
if (self.naviTitleFont) {
textAttrs[NSFontAttributeName] = self.naviTitleFont;
}
self.navigationBar.titleTextAttributes = textAttrs;
}
......@@ -92,7 +108,7 @@
- (void)configBarButtonItemAppearance {
UIBarButtonItem *barItem;
if (iOS9Later) {
if (@available(iOS 9.0, *)) {
barItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
} else {
barItem = [UIBarButtonItem appearanceWhenContainedIn:[TZImagePickerController class], nil];
......@@ -109,7 +125,7 @@
if (self.isStatusBarDefault) {
[UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque;
}else{
} else {
[UIApplication sharedApplication].statusBarStyle = iOS7Later ? UIStatusBarStyleLightContent : UIStatusBarStyleBlackOpaque;
}
}
......@@ -157,7 +173,7 @@
_tipLabel.font = [UIFont systemFontOfSize:16];
_tipLabel.textColor = [UIColor blackColor];
NSDictionary *infoDict = [NSBundle mainBundle].localizedInfoDictionary;
if (!infoDict) {
if (!infoDict || !infoDict.count) {
infoDict = [NSBundle mainBundle].infoDictionary;
}
NSString *appName = [infoDict valueForKey:@"CFBundleDisplayName"];
......@@ -196,9 +212,11 @@
previewVc.currentIndex = index;
__weak typeof(self) weakSelf = self;
[previewVc setDoneButtonClickBlockWithPreviewType:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL isSelectOriginalPhoto) {
[weakSelf dismissViewControllerAnimated:YES completion:^{
if (weakSelf.didFinishPickingPhotosHandle) {
weakSelf.didFinishPickingPhotosHandle(photos,assets,isSelectOriginalPhoto);
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf dismissViewControllerAnimated:YES completion:^{
if (!strongSelf) return;
if (strongSelf.didFinishPickingPhotosHandle) {
strongSelf.didFinishPickingPhotosHandle(photos,assets,isSelectOriginalPhoto);
}
}];
}];
......@@ -221,7 +239,8 @@
previewVc.currentIndex = 0;
__weak typeof(self) weakSelf = self;
[previewVc setDoneButtonClickBlockCropMode:^(UIImage *cropImage, id asset) {
[weakSelf dismissViewControllerAnimated:YES completion:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf dismissViewControllerAnimated:YES completion:^{
if (completion) {
completion(cropImage,asset);
}
......@@ -350,7 +369,8 @@
// if over time, dismiss HUD automatic
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeout * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf hideProgressHUD];
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf hideProgressHUD];
});
}
......@@ -520,7 +540,7 @@
- (void)willInterfaceOrientionChange {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.02 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (![UIApplication sharedApplication].statusBarHidden) {
if (iOS7Later && !TZ_isGlobalHideStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
if (iOS7Later && self.needShowStatusBar) [UIApplication sharedApplication].statusBarHidden = NO;
}
});
}
......@@ -599,12 +619,11 @@
dispatch_async(dispatch_get_global_queue(0, 0), ^{
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
[[TZImageManager manager] getAllAlbums:imagePickerVc.allowPickingVideo allowPickingImage:imagePickerVc.allowPickingImage completion:^(NSArray<TZAlbumModel *> *models) {
dispatch_async(dispatch_get_main_queue(), ^{
_albumArr = [NSMutableArray arrayWithArray:models];
for (TZAlbumModel *albumModel in _albumArr) {
albumModel.selectedModels = imagePickerVc.selectedModels;
}
dispatch_async(dispatch_get_main_queue(), ^{
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
_tableView.rowHeight = 70;
......@@ -636,7 +655,7 @@
BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
if (self.navigationController.navigationBar.isTranslucent) {
top = naviBarHeight;
if (iOS7Later && !isStatusBarHidden) top += 20;
if (iOS7Later && !isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight];
tableViewHeight = self.view.tz_height - top;
} else {
tableViewHeight = self.view.tz_height;
......@@ -702,4 +721,40 @@
}
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (CGSize)tz_calculateSizeWithAttributes:(NSDictionary *)attributes maxSize:(CGSize)maxSize {
CGSize size;
if (iOS7Later) {
size = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
} else {
size = [self sizeWithFont:attributes[NSFontAttributeName] constrainedToSize:maxSize];
}
return size;
}
#pragma clang diagnostic pop
@end
@implementation TZCommonTools
+ (BOOL)tz_isIPhoneX {
struct utsname systemInfo;
uname(&systemInfo);
NSString *platform = [NSString stringWithCString:systemInfo.machine encoding:NSASCIIStringEncoding];
if ([platform isEqualToString:@"i386"] || [platform isEqualToString:@"x86_64"]) {
// 模拟器下采用屏幕的高度来判断
return (CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(375, 812)) ||
CGSizeEqualToSize([UIScreen mainScreen].bounds.size, CGSizeMake(812, 375)));
}
// iPhone10,6是美版iPhoneX 感谢hegelsu指出:https://github.com/banchichen/TZImagePickerController/issues/635
BOOL isIPhoneX = [platform isEqualToString:@"iPhone10,3"] || [platform isEqualToString:@"iPhone10,6"];
return isIPhoneX;
}
+ (CGFloat)tz_statusBarHeight {
return [self tz_isIPhoneX] ? 44 : 20;
}
@end
......@@ -54,10 +54,12 @@ static CGFloat itemMargin = 5;
_imagePickerVc = [[UIImagePickerController alloc] init];
_imagePickerVc.delegate = self;
// set appearance / 改变相册选择页的导航栏外观
if (iOS7Later) {
_imagePickerVc.navigationBar.barTintColor = self.navigationController.navigationBar.barTintColor;
}
_imagePickerVc.navigationBar.tintColor = self.navigationController.navigationBar.tintColor;
UIBarButtonItem *tzBarItem, *BarItem;
if (iOS9Later) {
if (@available(iOS 9.0, *)) {
tzBarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[TZImagePickerController class]]];
BarItem = [UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UIImagePickerController class]]];
} else {
......@@ -250,8 +252,8 @@ static CGFloat itemMargin = 5;
[_bottomToolBar addSubview:_doneButton];
[_bottomToolBar addSubview:_numberImageView];
[_bottomToolBar addSubview:_numberLabel];
[_bottomToolBar addSubview:_originalPhotoButton];
[self.view addSubview:_bottomToolBar];
[self.view addSubview:_originalPhotoButton];
[_originalPhotoButton addSubview:_originalPhotoLabel];
}
......@@ -266,12 +268,13 @@ static CGFloat itemMargin = 5;
CGFloat collectionViewHeight = 0;
CGFloat naviBarHeight = self.navigationController.navigationBar.tz_height;
BOOL isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 50 + (83 - 49) : 50;
if (self.navigationController.navigationBar.isTranslucent) {
top = naviBarHeight;
if (iOS7Later && !isStatusBarHidden) top += 20;
collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - 50 - top : self.view.tz_height - top;;
if (iOS7Later && !isStatusBarHidden) top += [TZCommonTools tz_statusBarHeight];
collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - toolBarHeight - top : self.view.tz_height - top;;
} else {
collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - 50 : self.view.tz_height;
collectionViewHeight = tzImagePickerVc.showSelectBtn ? self.view.tz_height - toolBarHeight : self.view.tz_height;
}
_collectionView.frame = CGRectMake(0, top, self.view.tz_width, collectionViewHeight);
CGFloat itemWH = (self.view.tz_width - (self.columnNumber + 1) * itemMargin) / self.columnNumber;
......@@ -284,24 +287,24 @@ static CGFloat itemMargin = 5;
[_collectionView setContentOffset:CGPointMake(0, offsetY)];
}
CGFloat yOffset = 0;
CGFloat toolBarTop = 0;
if (!self.navigationController.navigationBar.isHidden) {
yOffset = self.view.tz_height - 50;
toolBarTop = self.view.tz_height - toolBarHeight;
} else {
CGFloat navigationHeight = naviBarHeight;
if (iOS7Later) navigationHeight += 20;
yOffset = self.view.tz_height - 50 - navigationHeight;
if (iOS7Later) navigationHeight += [TZCommonTools tz_statusBarHeight];
toolBarTop = self.view.tz_height - toolBarHeight - navigationHeight;
}
_bottomToolBar.frame = CGRectMake(0, yOffset, self.view.tz_width, 50);
CGFloat previewWidth = [tzImagePickerVc.previewBtnTitleStr boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} context:nil].size.width + 2;
_bottomToolBar.frame = CGRectMake(0, toolBarTop, self.view.tz_width, toolBarHeight);
CGFloat previewWidth = [tzImagePickerVc.previewBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width + 2;
if (!tzImagePickerVc.allowPreview) {
previewWidth = 0.0;
}
_previewButton.frame = CGRectMake(10, 3, previewWidth, 44);
_previewButton.tz_width = !tzImagePickerVc.showSelectBtn ? 0 : previewWidth;
if (tzImagePickerVc.allowPickingOriginalPhoto) {
CGFloat fullImageWidth = [tzImagePickerVc.fullImageBtnTitleStr boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil].size.width;
_originalPhotoButton.frame = CGRectMake(CGRectGetMaxX(_previewButton.frame), self.view.tz_height - 50, fullImageWidth + 56, 50);
CGFloat fullImageWidth = [tzImagePickerVc.fullImageBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width;
_originalPhotoButton.frame = CGRectMake(CGRectGetMaxX(_previewButton.frame), 0, fullImageWidth + 56, 50);
_originalPhotoLabel.frame = CGRectMake(fullImageWidth + 46, 0, 80, 50);
}
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 3, 44, 44);
......@@ -457,10 +460,13 @@ static CGFloat itemMargin = 5;
__weak typeof(self) weakSelf = self;
__weak typeof(_numberImageView.layer) weakLayer = _numberImageView.layer;
cell.didSelectPhotoBlock = ^(BOOL isSelected) {
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)weakSelf.navigationController;
__strong typeof(weakCell) strongCell = weakCell;
__strong typeof(weakSelf) strongSelf = weakSelf;
__strong typeof(weakLayer) strongLayer = weakLayer;
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)strongSelf.navigationController;
// 1. cancel select / 取消选择
if (isSelected) {
weakCell.selectPhotoButton.selected = NO;
strongCell.selectPhotoButton.selected = NO;
model.isSelected = NO;
NSArray *selectedModels = [NSArray arrayWithArray:tzImagePickerVc.selectedModels];
for (TZAssetModel *model_item in selectedModels) {
......@@ -469,20 +475,20 @@ static CGFloat itemMargin = 5;
break;
}
}
[weakSelf refreshBottomToolBarStatus];
[strongSelf refreshBottomToolBarStatus];
} else {
// 2. select:check if over the maxImagesCount / 选择照片,检查是否超过了最大个数的限制
if (tzImagePickerVc.selectedModels.count < tzImagePickerVc.maxImagesCount) {
weakCell.selectPhotoButton.selected = YES;
strongCell.selectPhotoButton.selected = YES;
model.isSelected = YES;
[tzImagePickerVc.selectedModels addObject:model];
[weakSelf refreshBottomToolBarStatus];
[strongSelf refreshBottomToolBarStatus];
} else {
NSString *title = [NSString stringWithFormat:[NSBundle tz_localizedStringForKey:@"Select a maximum of %zd photos"], tzImagePickerVc.maxImagesCount];
[tzImagePickerVc showAlertWithTitle:title];
}
}
[UIView showOscillatoryAnimationWithLayer:weakLayer type:TZOscillatoryAnimationToSmaller];
[UIView showOscillatoryAnimationWithLayer:strongLayer type:TZOscillatoryAnimationToSmaller];
};
return cell;
}
......@@ -573,9 +579,11 @@ static CGFloat itemMargin = 5;
// 提前定位
__weak typeof(self) weakSelf = self;
[[TZLocationManager manager] startLocationWithSuccessBlock:^(CLLocation *location, CLLocation *oldLocation) {
weakSelf.location = location;
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.location = location;
} failureBlock:^(NSError *error) {
weakSelf.location = nil;
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.location = nil;
}];
UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera;
......@@ -610,16 +618,19 @@ static CGFloat itemMargin = 5;
__weak typeof(self) weakSelf = self;
photoPreviewVc.isSelectOriginalPhoto = _isSelectOriginalPhoto;
[photoPreviewVc setBackButtonClickBlock:^(BOOL isSelectOriginalPhoto) {
weakSelf.isSelectOriginalPhoto = isSelectOriginalPhoto;
[weakSelf.collectionView reloadData];
[weakSelf refreshBottomToolBarStatus];
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.isSelectOriginalPhoto = isSelectOriginalPhoto;
[strongSelf.collectionView reloadData];
[strongSelf refreshBottomToolBarStatus];
}];
[photoPreviewVc setDoneButtonClickBlock:^(BOOL isSelectOriginalPhoto) {
weakSelf.isSelectOriginalPhoto = isSelectOriginalPhoto;
[weakSelf doneButtonClick];
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.isSelectOriginalPhoto = isSelectOriginalPhoto;
[strongSelf doneButtonClick];
}];
[photoPreviewVc setDoneButtonClickBlockCropMode:^(UIImage *cropedImage, id asset) {
[weakSelf didGetAllPhotos:@[cropedImage] assets:@[asset] infoArr:nil];
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf didGetAllPhotos:@[cropedImage] assets:@[asset] infoArr:nil];
}];
[self.navigationController pushViewController:photoPreviewVc animated:YES];
}
......
......@@ -11,7 +11,7 @@
@class TZAssetModel;
@interface TZAssetPreviewCell : UICollectionViewCell
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, copy) void (^singleTapGestureBlock)();
@property (nonatomic, copy) void (^singleTapGestureBlock)(void);
- (void)configSubviews;
- (void)photoPreviewCollectionViewDidScroll;
@end
......@@ -43,7 +43,7 @@
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, strong) id asset;
@property (nonatomic, copy) void (^singleTapGestureBlock)();
@property (nonatomic, copy) void (^singleTapGestureBlock)(void);
@property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress);
@property (nonatomic, assign) int32_t imageRequestID;
......
......@@ -50,13 +50,15 @@
self.previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
__weak typeof(self) weakSelf = self;
[self.previewView setSingleTapGestureBlock:^{
if (weakSelf.singleTapGestureBlock) {
weakSelf.singleTapGestureBlock();
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf.singleTapGestureBlock) {
strongSelf.singleTapGestureBlock();
}
}];
[self.previewView setImageProgressUpdateBlock:^(double progress) {
if (weakSelf.imageProgressUpdateBlock) {
weakSelf.imageProgressUpdateBlock(progress);
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf.imageProgressUpdateBlock) {
strongSelf.imageProgressUpdateBlock(progress);
}
}];
[self addSubview:self.previewView];
......@@ -387,9 +389,7 @@
if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
[_player play];
[_playButton setImage:nil forState:UIControlStateNormal];
if (!TZ_isGlobalHideStatusBar && iOS7Later) {
[UIApplication sharedApplication].statusBarHidden = YES;
}
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
if (self.singleTapGestureBlock) {
self.singleTapGestureBlock();
}
......@@ -421,7 +421,8 @@
_previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero];
__weak typeof(self) weakSelf = self;
[_previewView setSingleTapGestureBlock:^{
[weakSelf signleTapAction];
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf signleTapAction];
}];
[self addSubview:_previewView];
}
......
......@@ -51,7 +51,6 @@
if (!self.models.count) {
self.models = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedModels];
_assetsTemp = [NSMutableArray arrayWithArray:_tzImagePickerVc.selectedAssets];
self.isSelectOriginalPhoto = _tzImagePickerVc.isSelectOriginalPhoto;
}
[self configCollectionView];
[self configCustomNaviBar];
......@@ -68,9 +67,7 @@
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:YES];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
}
if (_currentIndex) [_collectionView setContentOffset:CGPointMake((self.view.tz_width + 20) * _currentIndex, 0) animated:NO];
[self refreshNaviBarAndBottomBarState];
}
......@@ -78,8 +75,9 @@
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO;
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc.needShowStatusBar && iOS7Later) {
[UIApplication sharedApplication].statusBarHidden = NO;
}
[TZImageManager manager].shouldFixOrientation = NO;
}
......@@ -183,7 +181,7 @@
- (void)configCropView {
TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (!_tzImagePickerVc.showSelectBtn && _tzImagePickerVc.allowCrop) {
if (_tzImagePickerVc.maxImagesCount <= 1 && _tzImagePickerVc.allowCrop) {
[_cropView removeFromSuperview];
[_cropBgView removeFromSuperview];
......@@ -208,6 +206,9 @@
if (_tzImagePickerVc.cropViewSettingBlock) {
_tzImagePickerVc.cropViewSettingBlock(_cropView);
}
[self.view bringSubviewToFront:_naviBar];
[self.view bringSubviewToFront:_toolBar];
}
}
......@@ -217,9 +218,12 @@
[super viewDidLayoutSubviews];
TZImagePickerController *_tzImagePickerVc = (TZImagePickerController *)self.navigationController;
_naviBar.frame = CGRectMake(0, 0, self.view.tz_width, 64);
_backButton.frame = CGRectMake(10, 10, 44, 44);
_selectButton.frame = CGRectMake(self.view.tz_width - 54, 10, 42, 42);
CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight];
CGFloat statusBarHeightInterval = statusBarHeight - 20;
CGFloat naviBarHeight = statusBarHeight + _tzImagePickerVc.navigationBar.tz_height;
_naviBar.frame = CGRectMake(0, 0, self.view.tz_width, naviBarHeight);
_backButton.frame = CGRectMake(10, 10 + statusBarHeightInterval, 44, 44);
_selectButton.frame = CGRectMake(self.view.tz_width - 54, 10 + statusBarHeightInterval, 42, 42);
_layout.itemSize = CGSizeMake(self.view.tz_width + 20, self.view.tz_height);
_layout.minimumInteritemSpacing = 0;
......@@ -234,9 +238,11 @@
[_collectionView reloadData];
}
_toolBar.frame = CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44);
CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
CGFloat toolBarTop = self.view.tz_height - toolBarHeight;
_toolBar.frame = CGRectMake(0, toolBarTop, self.view.tz_width, toolBarHeight);
if (_tzImagePickerVc.allowPickingOriginalPhoto) {
CGFloat fullImageWidth = [_tzImagePickerVc.fullImageBtnTitleStr boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} context:nil].size.width;
CGFloat fullImageWidth = [_tzImagePickerVc.fullImageBtnTitleStr tz_calculateSizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:13]} maxSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)].width;
_originalPhotoButton.frame = CGRectMake(0, 0, fullImageWidth + 56, 44);
_originalPhotoLabel.frame = CGRectMake(fullImageWidth + 42, 0, 80, 44);
}
......@@ -420,13 +426,17 @@
__weak typeof(_collectionView) weakCollectionView = _collectionView;
__weak typeof(photoPreviewCell) weakCell = photoPreviewCell;
[photoPreviewCell setImageProgressUpdateBlock:^(double progress) {
weakSelf.progress = progress;
__strong typeof(weakSelf) strongSelf = weakSelf;
__strong typeof(weakTzImagePickerVc) strongTzImagePickerVc = weakTzImagePickerVc;
__strong typeof(weakCollectionView) strongCollectionView = weakCollectionView;
__strong typeof(weakCell) strongCell = weakCell;
strongSelf.progress = progress;
if (progress >= 1) {
if (weakSelf.isSelectOriginalPhoto) [weakSelf showPhotoBytes];
if (weakSelf.alertView && [weakCollectionView.visibleCells containsObject:weakCell]) {
[weakTzImagePickerVc hideAlertView:weakSelf.alertView];
weakSelf.alertView = nil;
[weakSelf doneButtonClick];
if (strongSelf.isSelectOriginalPhoto) [strongSelf showPhotoBytes];
if (strongSelf.alertView && [strongCollectionView.visibleCells containsObject:strongCell]) {
[strongTzImagePickerVc hideAlertView:strongSelf.alertView];
strongSelf.alertView = nil;
[strongSelf doneButtonClick];
}
}
}];
......@@ -434,7 +444,8 @@
cell.model = model;
[cell setSingleTapGestureBlock:^{
[weakSelf didTapPreviewCell];
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf didTapPreviewCell];
}];
return cell;
}
......
......@@ -58,6 +58,9 @@
- (void)configMoviePlayer {
[[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
_cover = photo;
if (!isDegraded && photo) {
_doneButton.enabled = YES;
}
}];
[[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
dispatch_async(dispatch_get_main_queue(), ^{
......@@ -101,6 +104,7 @@
_doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
_doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
_doneButton.enabled = NO;
[_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc) {
......@@ -110,6 +114,7 @@
[_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
[_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
}
[_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled];
[_toolBar addSubview:_doneButton];
[self.view addSubview:_toolBar];
}
......@@ -119,10 +124,13 @@
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat statusBarHeight = [TZCommonTools tz_statusBarHeight];
CGFloat statusBarAndNaviBarHeight = statusBarHeight + self.navigationController.navigationBar.tz_height;
_playerLayer.frame = self.view.bounds;
_playButton.frame = CGRectMake(0, 64, self.view.tz_width, self.view.tz_height - 64 - 44);
CGFloat toolBarHeight = [TZCommonTools tz_isIPhoneX] ? 44 + (83 - 49) : 44;
_toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
_toolBar.frame = CGRectMake(0, self.view.tz_height - 44, self.view.tz_width, 44);
_playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight);
}
#pragma mark - Click Event
......@@ -136,9 +144,7 @@
[self.navigationController setNavigationBarHidden:YES];
_toolBar.hidden = YES;
[_playButton setImage:nil forState:UIControlStateNormal];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = YES;
}
} else {
[self pausePlayerAndShowNaviBar];
}
......@@ -179,8 +185,9 @@
[self.navigationController setNavigationBarHidden:NO];
[_playButton setImage:[UIImage imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
if (!TZ_isGlobalHideStatusBar) {
if (iOS7Later) [UIApplication sharedApplication].statusBarHidden = NO;
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc.needShowStatusBar && iOS7Later) {
[UIApplication sharedApplication].statusBarHidden = NO;
}
}
......
{
"name": "react-native-syan-image-picker",
"version": "0.0.8",
"version": "0.0.9",
"description": "",
"main": "index.js",
"scripts": {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment