海报分享
This commit is contained in:
parent
a02eb85c53
commit
6d4694dfab
|
@ -30,7 +30,12 @@ pod 'YYText'
|
|||
#pod 'AMapLocation'
|
||||
#pod 'AMapSearch'
|
||||
|
||||
pod 'HXPhotoPicker'
|
||||
|
||||
#pod 'HXPhotoPicker-Lite'
|
||||
#pod 'HXPhotoPicker-Lite/Picker'
|
||||
#pod 'HXPhotoPicker-Lite/Editor'
|
||||
#pod 'HXPhotoPicker-Lite/Camera'
|
||||
|
||||
|
||||
post_install do |installer|
|
||||
|
|
|
@ -15,6 +15,9 @@ PODS:
|
|||
- AFNetworking/UIKit (4.0.1):
|
||||
- AFNetworking/NSURLSession
|
||||
- DZNEmptyDataSet (1.8.1)
|
||||
- HXPhotoPicker (3.3.2):
|
||||
- HXPhotoPicker/Default (= 3.3.2)
|
||||
- HXPhotoPicker/Default (3.3.2)
|
||||
- IQKeyboardManager (6.5.10)
|
||||
- LSTTimer (0.2.10)
|
||||
- Masonry (1.1.0)
|
||||
|
@ -37,6 +40,7 @@ PODS:
|
|||
DEPENDENCIES:
|
||||
- AFNetworking
|
||||
- DZNEmptyDataSet
|
||||
- HXPhotoPicker
|
||||
- IQKeyboardManager
|
||||
- LSTTimer
|
||||
- Masonry
|
||||
|
@ -57,6 +61,7 @@ SPEC REPOS:
|
|||
trunk:
|
||||
- AFNetworking
|
||||
- DZNEmptyDataSet
|
||||
- HXPhotoPicker
|
||||
- IQKeyboardManager
|
||||
- LSTTimer
|
||||
- Masonry
|
||||
|
@ -76,6 +81,7 @@ SPEC REPOS:
|
|||
SPEC CHECKSUMS:
|
||||
AFNetworking: 3bd23d814e976cd148d7d44c3ab78017b744cd58
|
||||
DZNEmptyDataSet: 9525833b9e68ac21c30253e1d3d7076cc828eaa7
|
||||
HXPhotoPicker: 3d0526bc46cd2a4510a777d5f57dfad8e683fcfd
|
||||
IQKeyboardManager: 45a1fa55c1a5b02c61ac0fd7fd5b62bb4ad20d97
|
||||
LSTTimer: caf8f02ff366ca175cf4c1778d26c166183c1b6f
|
||||
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
|
||||
|
@ -92,6 +98,6 @@ SPEC CHECKSUMS:
|
|||
YYModel: 2a7fdd96aaa4b86a824e26d0c517de8928c04b30
|
||||
YYText: 5c461d709e24d55a182d1441c41dc639a18a4849
|
||||
|
||||
PODFILE CHECKSUM: 3a3f16ff03dd509a5468a270e3ff3de69a081d1e
|
||||
PODFILE CHECKSUM: b0cff93312a33561a9d76a35193aedc3fc970c7f
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// NSArray+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/7.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AVAsset, HXPhotoModel;
|
||||
|
||||
@interface NSArray (HXExtension)
|
||||
|
||||
/// 获取image,同时获取
|
||||
/// 如果model是视频的话,获取的则是视频封面
|
||||
/// @param original 是否原图
|
||||
/// @param completion imageArray 获取成功的image数组, errorArray 获取失败的model数组
|
||||
- (void)hx_requestImageWithOriginal:(BOOL)original completion:(void (^)(NSArray<UIImage *> * _Nullable imageArray, NSArray<HXPhotoModel *> * _Nullable errorArray))completion;
|
||||
|
||||
/// 分别获取image,前面一个获取完了再去获取第二个
|
||||
/// @param original 是否原图
|
||||
/// @param completion imageArray 获取成功的image数组, errorArray 获取失败的model数组
|
||||
- (void)hx_requestImageSeparatelyWithOriginal:(BOOL)original completion:(void (^)(NSArray<UIImage *> * _Nullable imageArray, NSArray<HXPhotoModel *> * _Nullable errorArray))completion;
|
||||
|
||||
/// 获取imageData
|
||||
/// @param completion 获取失败的不会添加到数组中
|
||||
- (void)hx_requestImageDataWithCompletion:(void (^)(NSArray<NSData *> * _Nullable imageDataArray))completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
369
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSArray+HXExtension.m
generated
Normal file
369
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSArray+HXExtension.m
generated
Normal file
|
@ -0,0 +1,369 @@
|
|||
//
|
||||
// NSArray+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/7.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSArray+HXExtension.h"
|
||||
#import "HXPhotoModel.h"
|
||||
#import "HXPhotoEdit.h"
|
||||
#import "HXPhotoManager.h"
|
||||
|
||||
@implementation NSArray (HXExtension)
|
||||
|
||||
- (BOOL)hx_detection {
|
||||
if (!self.count) {
|
||||
return NO;
|
||||
}
|
||||
for (id obj in self) {
|
||||
if (![obj respondsToSelector:@selector(isKindOfClass:)]) {
|
||||
return NO;
|
||||
}
|
||||
if (![obj isKindOfClass:[HXPhotoModel class]]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
+ (NSArray *)hx_dictHandler:(NSDictionary *)dict {
|
||||
NSMutableArray *dataArray = [NSMutableArray array];
|
||||
NSArray *keys = [dict.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSString * obj1, NSString * obj2) {
|
||||
if (obj1.integerValue > obj2.integerValue) {
|
||||
return NSOrderedDescending;
|
||||
}else if (obj1.integerValue < obj2.integerValue) {
|
||||
return NSOrderedAscending;
|
||||
}else {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
}];
|
||||
for (NSString *key in keys) {
|
||||
if ([dict[key] isKindOfClass:[NSError class]]) {
|
||||
continue;
|
||||
}
|
||||
if ([dict[key] isKindOfClass:[NSString class]]) {
|
||||
NSString *path = dict[key];
|
||||
UIImage *image = [self hx_disposeHEICWithPath:path];
|
||||
if (image) {
|
||||
if (image.imageOrientation != UIImageOrientationUp) {
|
||||
image = [image hx_normalizedImage];
|
||||
}
|
||||
[dataArray addObject:image];
|
||||
}
|
||||
}else {
|
||||
[dataArray addObject:dict[key]];
|
||||
}
|
||||
}
|
||||
return dataArray.copy;
|
||||
}
|
||||
+ (UIImage *)hx_disposeHEICWithPath:(NSString *)path {
|
||||
if ([path.pathExtension isEqualToString:@"HEIC"]) {
|
||||
// 处理一下 HEIC 格式图片
|
||||
CIImage *ciImage = [CIImage imageWithContentsOfURL:[NSURL fileURLWithPath:path]];
|
||||
CIContext *context = [CIContext context];
|
||||
NSString *key = (__bridge NSString *)kCGImageDestinationLossyCompressionQuality;
|
||||
NSData *jpgData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{key : @1}];
|
||||
UIImage *image = [UIImage imageWithData:jpgData];
|
||||
if (image.imageOrientation != UIImageOrientationUp) {
|
||||
image = [image hx_normalizedImage];
|
||||
}
|
||||
return image;
|
||||
}else {
|
||||
NSData *imageData = [NSData dataWithContentsOfFile:path];
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
if (!image) {
|
||||
if (image.imageOrientation != UIImageOrientationUp) {
|
||||
image = [image hx_normalizedImage];
|
||||
}
|
||||
image = [UIImage imageWithContentsOfFile:path];
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
- (void)hx_requestImageWithOriginal:(BOOL)original completion:(nonnull void (^)(NSArray<UIImage *> * _Nullable, NSArray<HXPhotoModel *> * _Nullable))completion {
|
||||
if (![self hx_detection] || !self.count) {
|
||||
if (completion) {
|
||||
completion(nil, self);
|
||||
}
|
||||
if (HXShowLog) NSSLog(@"数组里装的不是HXPhotoModel对象或者为空");
|
||||
return;
|
||||
}
|
||||
NSInteger count = self.count;
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
for (int i = 0 ; i < self.count; i++) {
|
||||
HXPhotoModel *model = self[i];
|
||||
[dict setValue:[NSError errorWithDomain:@"获取失败" code:99999 userInfo:nil] forKey:model.selectIndexStr];
|
||||
}
|
||||
__block NSInteger index = 0;
|
||||
NSMutableArray *errorArray = [NSMutableArray array];
|
||||
for (HXPhotoModel *model in self) {
|
||||
[self requestImageWithOriginal:original photoModel:model successful:^(UIImage * _Nullable image, NSURL * _Nullable imagePath, HXPhotoModel *photoModel) {
|
||||
if (image) {
|
||||
// 如果photoModel 为nil可能是数组里的模型被移除了
|
||||
[dict setObject:image forKey:photoModel.selectIndexStr];
|
||||
}else if (imagePath) {
|
||||
UIImage *hImage = [NSArray hx_disposeHEICWithPath:imagePath.relativePath];
|
||||
if (hImage) {
|
||||
photoModel.thumbPhoto = hImage;
|
||||
photoModel.previewPhoto = hImage;
|
||||
[dict setObject:hImage forKey:photoModel.selectIndexStr];
|
||||
}else {
|
||||
[errorArray addObject:photoModel];
|
||||
}
|
||||
}else {
|
||||
[errorArray addObject:photoModel];
|
||||
}
|
||||
index++;
|
||||
if (index == count) {
|
||||
if (completion) {
|
||||
completion([NSArray hx_dictHandler:dict], errorArray);
|
||||
}
|
||||
}
|
||||
} failure:^(HXPhotoModel *photoModel) {
|
||||
[errorArray addObject:photoModel];
|
||||
index++;
|
||||
if (index == count) {
|
||||
if (completion) {
|
||||
completion([NSArray hx_dictHandler:dict], errorArray);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
- (void)hx_requestImageSeparatelyWithOriginal:(BOOL)original completion:(void (^)(NSArray<UIImage *> * _Nullable, NSArray<HXPhotoModel *> * _Nullable))completion {
|
||||
if (![self hx_detection] || !self.count) {
|
||||
if (completion) {
|
||||
completion(nil, self);
|
||||
}
|
||||
if (HXShowLog) NSSLog(@"数组里装的不是HXPhotoModel对象或者为空");
|
||||
return;
|
||||
}
|
||||
[self requestImageSeparatelyWithOriginal:original imageList:@[].mutableCopy photoModels:self.mutableCopy errorPhotoModels:@[].mutableCopy completion:completion];
|
||||
}
|
||||
- (void)requestImageSeparatelyWithOriginal:(BOOL)original
|
||||
imageList:(NSMutableArray *)imageList
|
||||
photoModels:(NSMutableArray *)photoModels
|
||||
errorPhotoModels:(NSMutableArray *)errorPhotoModels
|
||||
completion:(void (^)(NSArray<UIImage *> * _Nullable imageArray, NSArray<HXPhotoModel *> * _Nullable errorArray))completion {
|
||||
if (!photoModels.count) {
|
||||
if (completion) {
|
||||
completion(imageList, errorPhotoModels);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!imageList) imageList = [NSMutableArray array];
|
||||
if (!errorPhotoModels) errorPhotoModels = [NSMutableArray array];
|
||||
HXPhotoModel *model = photoModels.firstObject;
|
||||
HXWeakSelf
|
||||
[self requestImageWithOriginal:original photoModel:model successful:^(UIImage * _Nullable image, NSURL * _Nullable imagePath, HXPhotoModel *photoModel) {
|
||||
if (image) {
|
||||
photoModel.thumbPhoto = image;
|
||||
photoModel.previewPhoto = image;
|
||||
[imageList addObject:image];
|
||||
}else if (imagePath) {
|
||||
UIImage *hImage = [NSArray hx_disposeHEICWithPath:imagePath.relativePath];
|
||||
if (hImage) {
|
||||
photoModel.thumbPhoto = hImage;
|
||||
photoModel.previewPhoto = hImage;
|
||||
[imageList addObject:hImage];
|
||||
}else {
|
||||
//已知在iPhone 8,iOS 10.0.2系统上,通过requestImageDataStartRequestICloud能获取到图片的URL,但通过此URL并不能获取到image。故调用requestPreviewImageWithSize方法获取image,并存到沙盒tmp下
|
||||
[model requestPreviewImageWithSize:PHImageManagerMaximumSize startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel * _Nullable model) {
|
||||
} progressHandler:^(double progress, HXPhotoModel * _Nullable model) {
|
||||
} success:^(UIImage * _Nullable imageValue, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
|
||||
NSString *photoPathStr = [NSTemporaryDirectory() stringByAppendingString:@"HXPhotoPickerSave/"];
|
||||
BOOL isDir;
|
||||
BOOL isDirExit = [[NSFileManager defaultManager] fileExistsAtPath:photoPathStr isDirectory:&isDir];
|
||||
NSError *error;
|
||||
if (isDirExit == NO) {
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:photoPathStr withIntermediateDirectories:YES attributes:nil error:&error];
|
||||
}
|
||||
if (error) {
|
||||
[errorPhotoModels addObject:photoModel];
|
||||
}
|
||||
else {
|
||||
NSInteger timeStamp = [[NSDate new] timeIntervalSince1970];
|
||||
NSString *imgPath = [NSString stringWithFormat:@"%@%zd_%zd.jpg",photoPathStr, timeStamp, photoModels.count];
|
||||
[UIImageJPEGRepresentation(imageValue, 1.0) writeToFile:imgPath atomically:YES];
|
||||
photoModel.imageURL = [NSURL fileURLWithPath:imgPath];
|
||||
photoModel.thumbPhoto = imageValue;
|
||||
photoModel.previewPhoto = imageValue;
|
||||
[imageList addObject:imageValue];
|
||||
}
|
||||
|
||||
[photoModels removeObjectAtIndex:0];
|
||||
if (!photoModels.count) {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList.copy photoModels:photoModels errorPhotoModels:errorPhotoModels.copy completion:completion];
|
||||
}else {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList photoModels:photoModels errorPhotoModels:errorPhotoModels completion:completion];
|
||||
}
|
||||
} failed:^(NSDictionary * _Nullable info, HXPhotoModel * _Nullable model) {
|
||||
[errorPhotoModels addObject:photoModel];
|
||||
[photoModels removeObjectAtIndex:0];
|
||||
if (!photoModels.count) {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList.copy photoModels:photoModels errorPhotoModels:errorPhotoModels.copy completion:completion];
|
||||
}else {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList photoModels:photoModels errorPhotoModels:errorPhotoModels completion:completion];
|
||||
}
|
||||
}];
|
||||
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
[errorPhotoModels addObject:photoModel];
|
||||
}
|
||||
[photoModels removeObjectAtIndex:0];
|
||||
if (!photoModels.count) {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList.copy photoModels:photoModels errorPhotoModels:errorPhotoModels.copy completion:completion];
|
||||
}else {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList photoModels:photoModels errorPhotoModels:errorPhotoModels completion:completion];
|
||||
}
|
||||
} failure:^(HXPhotoModel *photoModel) {
|
||||
[errorPhotoModels addObject:photoModel];
|
||||
[photoModels removeObjectAtIndex:0];
|
||||
if (!photoModels.count) {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList.copy photoModels:photoModels errorPhotoModels:errorPhotoModels.copy completion:completion];
|
||||
}else {
|
||||
[weakSelf requestImageSeparatelyWithOriginal:original imageList:imageList photoModels:photoModels errorPhotoModels:errorPhotoModels completion:completion];
|
||||
}
|
||||
}];
|
||||
}
|
||||
- (void)requestImageWithOriginal:(BOOL)original photoModel:(HXPhotoModel *)photoModel successful:(void (^)(UIImage * _Nullable image, NSURL * _Nullable imagePath, HXPhotoModel *photoModel))successful failure:(void (^)(HXPhotoModel *photoModel))failure {
|
||||
if (photoModel.photoEdit) {
|
||||
UIImage *image = photoModel.photoEdit.editPreviewImage;
|
||||
if (successful) {
|
||||
successful(image, nil, photoModel);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (photoModel.type == HXPhotoModelMediaTypeCameraPhoto) {
|
||||
if (photoModel.networkPhotoUrl) {
|
||||
if ([HXPhotoCommon photoCommon].requestNetworkAfter) {
|
||||
// 需要下载网络图片就将 [HXPhotoCommon photoCommon].requestNetworkAfter = YES
|
||||
[HXPhotoModel requestImageWithURL:photoModel.networkPhotoUrl progress:nil completion:^(UIImage * _Nullable image, NSURL * _Nullable url, NSError * _Nullable error) {
|
||||
if (image) {
|
||||
photoModel.thumbPhoto = image;
|
||||
photoModel.previewPhoto = image;
|
||||
if (successful) {
|
||||
successful(image, nil, photoModel);
|
||||
}
|
||||
}else {
|
||||
if (failure) {
|
||||
failure(photoModel);
|
||||
}
|
||||
if (HXShowLog) NSSLog(@"网络图片获取失败!");
|
||||
}
|
||||
}];
|
||||
}else {
|
||||
if (successful) {
|
||||
successful(photoModel.thumbPhoto, nil, photoModel);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
// 本地图片
|
||||
if (successful) {
|
||||
successful(photoModel.thumbPhoto, nil, photoModel);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}else {
|
||||
if (!photoModel.asset) {
|
||||
if (photoModel.thumbPhoto) {
|
||||
if (successful) {
|
||||
successful(photoModel.thumbPhoto, nil, photoModel);
|
||||
}
|
||||
}else {
|
||||
if (failure) {
|
||||
failure(photoModel);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if ((original && photoModel.type != HXPhotoModelMediaTypeVideo) ||
|
||||
photoModel.type == HXPhotoModelMediaTypePhotoGif) {
|
||||
// 如果选择了原图,就换一种获取方式
|
||||
[photoModel getAssetURLWithSuccess:^(NSURL * _Nullable imageURL, HXPhotoModelMediaSubType mediaType, BOOL isNetwork, HXPhotoModel * _Nullable model) {
|
||||
if (successful) {
|
||||
successful(nil, imageURL, model);
|
||||
}
|
||||
} failed:^(NSDictionary * _Nullable info, HXPhotoModel * _Nullable model) {
|
||||
if (failure) {
|
||||
failure(model);
|
||||
}
|
||||
}];
|
||||
}else {
|
||||
[photoModel requestImageDataStartRequestICloud:nil progressHandler:nil success:^(NSData * _Nullable imageData, UIImageOrientation orientation, HXPhotoModel * _Nullable model, NSDictionary * _Nullable info) {
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
if (image.imageOrientation != UIImageOrientationUp) {
|
||||
image = [image hx_normalizedImage];
|
||||
}
|
||||
// 不是原图那就压缩
|
||||
if (!original) {
|
||||
image = [image hx_scaleImagetoScale:0.5f];
|
||||
}
|
||||
if (successful) {
|
||||
successful(image, nil, model);
|
||||
}
|
||||
} failed:^(NSDictionary * _Nullable info, HXPhotoModel * _Nullable model) {
|
||||
if (model.previewPhoto) {
|
||||
if (successful) {
|
||||
successful(model.previewPhoto, nil, model);
|
||||
}
|
||||
}else {
|
||||
if (failure) {
|
||||
failure(model);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hx_requestImageDataWithCompletion:(void (^)(NSArray<NSData *> * _Nullable imageDataArray))completion {
|
||||
if (![self hx_detection] || !self.count) {
|
||||
if (completion) {
|
||||
completion(nil);
|
||||
}
|
||||
if (HXShowLog) NSSLog(@"数组里装的不是HXPhotoModel对象或者为空");
|
||||
return;
|
||||
}
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
||||
for (int i = 0 ; i < self.count; i++) {
|
||||
HXPhotoModel *model = self[i];
|
||||
[dict setValue:[NSError errorWithDomain:@"获取失败" code:99999 userInfo:nil] forKey:model.selectIndexStr];
|
||||
}
|
||||
__block NSInteger index = 0;
|
||||
NSInteger count = self.count;
|
||||
for (HXPhotoModel *model in self) {
|
||||
if (model.subType != HXPhotoModelMediaSubTypePhoto) {
|
||||
continue;
|
||||
}
|
||||
[model requestImageDataStartRequestICloud:nil progressHandler:nil success:^(NSData *imageData, UIImageOrientation orientation, HXPhotoModel *model, NSDictionary *info) {
|
||||
if (model.asset && [HXPhotoTools assetIsHEIF:model.asset]) {
|
||||
CIImage *ciImage = [CIImage imageWithData:imageData];
|
||||
CIContext *context = [CIContext context];
|
||||
NSData *jpgData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{}];
|
||||
[dict setObject:jpgData forKey:model.selectIndexStr];
|
||||
}else {
|
||||
[dict setObject:imageData forKey:model.selectIndexStr];
|
||||
}
|
||||
index++;
|
||||
if (index == count) {
|
||||
if (completion) {
|
||||
completion([NSArray hx_dictHandler:dict]);
|
||||
}
|
||||
}
|
||||
} failed:^(NSDictionary *info, HXPhotoModel *model) {
|
||||
index++;
|
||||
if (HXShowLog) NSSLog(@"一个获取失败!");
|
||||
if (index == count) {
|
||||
if (completion) {
|
||||
completion([NSArray hx_dictHandler:dict]);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
15
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSBundle+HXPhotoPicker.h
generated
Normal file
15
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSBundle+HXPhotoPicker.h
generated
Normal file
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// NSBundle+HXPhotoPicker.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/7/25.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSBundle (HXPhotoPicker)
|
||||
+ (instancetype)hx_photoPickerBundle;
|
||||
+ (NSString *)hx_localizedStringForKey:(NSString *)key value:(NSString *)value;
|
||||
+ (NSString *)hx_localizedStringForKey:(NSString *)key;
|
||||
@end
|
43
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSBundle+HXPhotoPicker.m
generated
Normal file
43
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSBundle+HXPhotoPicker.m
generated
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// NSBundle+HXPhotopicker.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/7/25.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
#import "HXPhotoCommon.h"
|
||||
|
||||
@implementation NSBundle (HXPhotoPicker)
|
||||
+ (instancetype)hx_photoPickerBundle {
|
||||
static NSBundle *hxBundle = nil;
|
||||
if (hxBundle == nil) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(@"HXPhotoPicker")];
|
||||
NSString *path = [bundle pathForResource:@"HXPhotoPicker" ofType:@"bundle"];
|
||||
//使用framework形式
|
||||
if (!path) {
|
||||
NSURL *associateBundleURL = [[NSBundle mainBundle] URLForResource:@"Frameworks" withExtension:nil];
|
||||
if (associateBundleURL) {
|
||||
associateBundleURL = [associateBundleURL URLByAppendingPathComponent:@"HXPhotoPicker"];
|
||||
associateBundleURL = [associateBundleURL URLByAppendingPathExtension:@"framework"];
|
||||
NSBundle *associateBunle = [NSBundle bundleWithURL:associateBundleURL];
|
||||
path = [associateBunle pathForResource:@"HXPhotoPicker" ofType:@"bundle"];
|
||||
}
|
||||
}
|
||||
hxBundle = path ? [NSBundle bundleWithPath:path]: [NSBundle mainBundle];
|
||||
}
|
||||
return hxBundle;
|
||||
}
|
||||
+ (NSString *)hx_localizedStringForKey:(NSString *)key {
|
||||
return [self hx_localizedStringForKey:key value:nil];
|
||||
}
|
||||
+ (NSString *)hx_localizedStringForKey:(NSString *)key value:(NSString *)value {
|
||||
NSBundle *bundle = [HXPhotoCommon photoCommon].languageBundle;
|
||||
value = [bundle localizedStringForKey:key value:value table:nil];
|
||||
if (!value) {
|
||||
value = key;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// NSDate+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSDate (HXExtension)
|
||||
|
||||
/**
|
||||
是否今天
|
||||
|
||||
@return yes or no
|
||||
*/
|
||||
- (BOOL)hx_isToday;
|
||||
|
||||
/**
|
||||
是否昨天
|
||||
|
||||
@return yes or no
|
||||
*/
|
||||
- (BOOL)hx_isYesterday;
|
||||
|
||||
/**
|
||||
是否今年
|
||||
|
||||
@return yes or no
|
||||
*/
|
||||
- (BOOL)hx_isThisYear;
|
||||
|
||||
/**
|
||||
和今天是否在同一周
|
||||
|
||||
@return yes or no
|
||||
*/
|
||||
- (BOOL)hx_isSameWeek;
|
||||
|
||||
- (NSString *)hx_getNowWeekday;
|
||||
|
||||
/**
|
||||
按指定格式获取当前的时间
|
||||
|
||||
@param format 格式
|
||||
@return 日期字符串
|
||||
*/
|
||||
- (NSString *)hx_dateStringWithFormat:(NSString *)format;
|
||||
|
||||
@end
|
|
@ -0,0 +1,199 @@
|
|||
//
|
||||
// NSDate+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSDate+HXExtension.h"
|
||||
#import "HXPhotoCommon.h"
|
||||
|
||||
@implementation NSDate (HXExtension)
|
||||
/**
|
||||
* 是否为今天
|
||||
*/
|
||||
- (BOOL)hx_isToday {
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
int unit = NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear;
|
||||
|
||||
// 1.获得当前时间的年月日
|
||||
NSDateComponents *nowCmps = [calendar components:unit fromDate:[NSDate date]];
|
||||
|
||||
// 2.获得self的年月日
|
||||
NSDateComponents *selfCmps = [calendar components:unit fromDate:self];
|
||||
return
|
||||
(selfCmps.year == nowCmps.year) &&
|
||||
(selfCmps.month == nowCmps.month) &&
|
||||
(selfCmps.day == nowCmps.day);
|
||||
}
|
||||
/**
|
||||
* 是否为昨天
|
||||
*/
|
||||
- (BOOL)hx_isYesterday {
|
||||
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
|
||||
fmt.dateFormat = @"yyyyMMdd";
|
||||
|
||||
// 生成只有年月日的字符串对象
|
||||
NSString *selfString = [fmt stringFromDate:self];
|
||||
NSString *nowString = [fmt stringFromDate:[NSDate date]];
|
||||
|
||||
// 生成只有年月日的日期对象
|
||||
NSDate *selfDate = [fmt dateFromString:selfString];
|
||||
NSDate *nowDate = [fmt dateFromString:nowString];
|
||||
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
|
||||
NSDateComponents *cmps = [calendar components:unit fromDate:selfDate toDate:nowDate options:0];
|
||||
return cmps.year == 0
|
||||
&& cmps.month == 0
|
||||
&& cmps.day == 1;
|
||||
}
|
||||
/**
|
||||
* 是否为今年
|
||||
*/
|
||||
- (BOOL)hx_isThisYear {
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
int unit = NSCalendarUnitYear;
|
||||
|
||||
// 1.获得当前时间的年月日
|
||||
NSDateComponents *nowCmps = [calendar components:unit fromDate:[NSDate date]];
|
||||
|
||||
// 2.获得self的年月日
|
||||
NSDateComponents *selfCmps = [calendar components:unit fromDate:self];
|
||||
|
||||
return nowCmps.year == selfCmps.year;
|
||||
}
|
||||
|
||||
/**
|
||||
是否为同一周内
|
||||
*/
|
||||
- (BOOL)hx_isSameWeek {
|
||||
NSCalendar *calendar = [NSCalendar currentCalendar];
|
||||
int unit = NSCalendarUnitWeekday | NSCalendarUnitMonth | NSCalendarUnitYear | kCFCalendarUnitDay | kCFCalendarUnitHour | kCFCalendarUnitMinute ;
|
||||
|
||||
//1.获得当前时间的 年月日
|
||||
NSDateComponents *nowCmps = [calendar components:unit fromDate:[NSDate date]];
|
||||
NSDateComponents *sourceCmps = [calendar components:unit fromDate:self];
|
||||
|
||||
// 对比时间差
|
||||
NSDateComponents *dateCom = [calendar components:unit fromDate:[NSDate date] toDate:self options:0];
|
||||
NSInteger subDay = labs(dateCom.day);
|
||||
NSInteger subMonth = labs(dateCom.month);
|
||||
NSInteger subYear = labs(dateCom.year);
|
||||
|
||||
if (subYear == 0 && subMonth == 0) { //当相关的差值等于零的时候说明在一个年、月、日的时间范围内,不是按照零点到零点的时间算的
|
||||
if (subDay > 6) { //相差天数大于6肯定不在一周内
|
||||
return NO;
|
||||
} else { //相差的天数大于或等于后面的时间所对应的weekday则不在一周内
|
||||
if (dateCom.day >= 0 && dateCom.hour >=0 && dateCom.minute >= 0) { //比较的时间大于当前时间
|
||||
//西方一周的开始是从周日开始算的,周日是1,周一是2,而我们是从周一开始算新的一周
|
||||
NSInteger chinaWeekday = sourceCmps.weekday == 1 ? 7 : sourceCmps.weekday - 1;
|
||||
if (subDay >= chinaWeekday) {
|
||||
return NO;
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
} else {
|
||||
NSInteger chinaWeekday = sourceCmps.weekday == 1 ? 7 : nowCmps.weekday - 1;
|
||||
if (subDay >= chinaWeekday) { //比较的时间比当前时间小,已经过去的时间
|
||||
return NO;
|
||||
} else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { //时间范围差值超过了一年或一个月的时间范围肯定就不在一个周内了
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
- (NSString *)hx_getNowWeekday {
|
||||
NSDateFormatter *dateday = [[NSDateFormatter alloc] init];
|
||||
|
||||
HXPhotoLanguageType type = [HXPhotoCommon photoCommon].languageType;
|
||||
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-Hans"];
|
||||
if (type == HXPhotoLanguageTypeSc) {
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-Hans"];
|
||||
}else if (type == HXPhotoLanguageTypeTc) {
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-Hant"];
|
||||
}else if (type == HXPhotoLanguageTypeJa) {
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"ja"];
|
||||
}else if (type == HXPhotoLanguageTypeKo) {
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"ko"];
|
||||
}else if (type == HXPhotoLanguageTypeEn) {
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en"];
|
||||
}
|
||||
if (locale) {
|
||||
[dateday setLocale:locale];
|
||||
}
|
||||
[dateday setDateFormat:@"MMM dd"];
|
||||
[dateday setDateFormat:@"EEE"];
|
||||
// switch (type) {
|
||||
// case HXPhotoLanguageTypeSc :
|
||||
// case HXPhotoLanguageTypeTc :
|
||||
// case HXPhotoLanguageTypeJa : {
|
||||
// // 中 / 日 / 繁
|
||||
// [dateday setDateFormat:@"MM月dd日"];
|
||||
// [dateday setDateFormat:@"EEEE"];
|
||||
// } break;
|
||||
// case HXPhotoLanguageTypeKo : {
|
||||
// // 韩语
|
||||
// [dateday setDateFormat:@"MM월dd일"];
|
||||
// [dateday setDateFormat:@"EEEE"];
|
||||
// } break;
|
||||
// case HXPhotoLanguageTypeEn : {
|
||||
// // 英文
|
||||
// [dateday setDateFormat:@"MMM dd"];
|
||||
// [dateday setDateFormat:@"EEE"];
|
||||
// } break;
|
||||
// default : {
|
||||
// NSString *language = [NSLocale preferredLanguages].firstObject;
|
||||
// if ([language hasPrefix:@"zh"] ||
|
||||
// [language hasPrefix:@"ja"]) {
|
||||
// // 中 / 日 / 繁
|
||||
// [dateday setDateFormat:@"MM月dd日"];
|
||||
// [dateday setDateFormat:@"EEEE"];
|
||||
// }else if ([language hasPrefix:@"ko"]) {
|
||||
// // 韩语
|
||||
// [dateday setDateFormat:@"MM월dd일"];
|
||||
// [dateday setDateFormat:@"EEEE"];
|
||||
// } else {
|
||||
// // 英文
|
||||
// [dateday setDateFormat:@"MMM dd"];
|
||||
// [dateday setDateFormat:@"EEE"];
|
||||
// }
|
||||
// }break;
|
||||
// }
|
||||
return [dateday stringFromDate:self];
|
||||
}
|
||||
|
||||
- (NSString *)hx_dateStringWithFormat:(NSString *)format {
|
||||
NSDateFormatter *formater = [[NSDateFormatter alloc] init];
|
||||
formater.dateFormat = format;
|
||||
HXPhotoLanguageType type = [HXPhotoCommon photoCommon].languageType;
|
||||
NSLocale *locale;
|
||||
switch (type) {
|
||||
case HXPhotoLanguageTypeEn:
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en"];
|
||||
break;
|
||||
case HXPhotoLanguageTypeSc:
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-Hans"];
|
||||
break;
|
||||
case HXPhotoLanguageTypeTc:
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh-Hant"];
|
||||
break;
|
||||
case HXPhotoLanguageTypeJa:
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"ja"];
|
||||
break;
|
||||
case HXPhotoLanguageTypeKo:
|
||||
locale = [[NSLocale alloc] initWithLocaleIdentifier:@"ko"];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (locale) {
|
||||
[formater setLocale:locale];
|
||||
}
|
||||
return [formater stringFromDate:self];
|
||||
}
|
||||
@end
|
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSString+HXExtension.h
generated
Normal file
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSString+HXExtension.h
generated
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// NSString+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/10.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (HXExtension)
|
||||
- (NSString *)hx_countStrBecomeComma;
|
||||
+ (NSString *)hx_fileName;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
53
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSString+HXExtension.m
generated
Normal file
53
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/NSString+HXExtension.m
generated
Normal file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// NSString+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/10.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+HXExtension.h"
|
||||
|
||||
@implementation NSString (HXExtension)
|
||||
|
||||
- (NSString *)hx_countStrBecomeComma {
|
||||
if (self.length < 3) {
|
||||
return self;
|
||||
}
|
||||
int count = 0;
|
||||
long long int a = self.longLongValue;
|
||||
while (a != 0) {
|
||||
count++;
|
||||
a /= 10;
|
||||
}
|
||||
NSMutableString *string = [NSMutableString stringWithString:self];
|
||||
NSMutableString *newstring = [NSMutableString string];
|
||||
while (count > 3) {
|
||||
count -= 3;
|
||||
NSRange rang = NSMakeRange(string.length - 3, 3);
|
||||
NSString *str = [string substringWithRange:rang];
|
||||
[newstring insertString:str atIndex:0];
|
||||
[newstring insertString:@"," atIndex:0];
|
||||
[string deleteCharactersInRange:rang];
|
||||
}
|
||||
[newstring insertString:string atIndex:0];
|
||||
return newstring;
|
||||
}
|
||||
+ (NSString *)hx_fileName {
|
||||
CFUUIDRef uuid = CFUUIDCreate(nil);
|
||||
NSString *uuidString = (__bridge_transfer NSString*)CFUUIDCreateString(nil, uuid);
|
||||
CFRelease(uuid);
|
||||
NSString *uuidStr = [[uuidString stringByReplacingOccurrencesOfString:@"-" withString:@""] lowercaseString];
|
||||
NSString *name = [NSString stringWithFormat:@"%@",uuidStr];
|
||||
|
||||
NSString *fileName = @"";
|
||||
NSDate *nowDate = [NSDate date];
|
||||
NSString *dateStr = [NSString stringWithFormat:@"%ld", (long)[nowDate timeIntervalSince1970]];
|
||||
NSString *numStr = [NSString stringWithFormat:@"%d",arc4random()%10000];
|
||||
fileName = [fileName stringByAppendingString:@"hx"];
|
||||
fileName = [fileName stringByAppendingString:dateStr];
|
||||
fileName = [fileName stringByAppendingString:numStr];
|
||||
|
||||
return [NSString stringWithFormat:@"%@%@",name,fileName];
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// NSTimer+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/3.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSTimer (HXExtension)
|
||||
+ (id)hx_scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(void))inBlock repeats:(BOOL)inRepeats;
|
||||
+ (id)hx_timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(void))inBlock repeats:(BOOL)inRepeats;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// NSTimer+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/3.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSTimer+HXExtension.h"
|
||||
|
||||
@implementation NSTimer (HXExtension)
|
||||
+ (id)hx_scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(void))inBlock repeats:(BOOL)inRepeats
|
||||
{
|
||||
void (^block)(void) = [inBlock copy];
|
||||
id ret = [self scheduledTimerWithTimeInterval:inTimeInterval target:self selector:@selector(hx_executeSimpleBlock:) userInfo:block repeats:inRepeats];
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (id)hx_timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)(void))inBlock repeats:(BOOL)inRepeats
|
||||
{
|
||||
void (^block)(void) = [inBlock copy];
|
||||
id ret = [self timerWithTimeInterval:inTimeInterval target:self selector:@selector(hx_executeSimpleBlock:) userInfo:block repeats:inRepeats];
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (void)hx_executeSimpleBlock:(NSTimer *)inTimer;
|
||||
{
|
||||
if([inTimer userInfo])
|
||||
{
|
||||
void (^block)(void) = (void (^)(void))[inTimer userInfo];
|
||||
block();
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// PHAsset+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Slience on 2021/6/8.
|
||||
// Copyright © 2021 洪欣. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Photos/Photos.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface PHAsset (HXExtension)
|
||||
|
||||
- (void)hx_checkForModificationsWithAssetPathMethodCompletion:(void (^)(BOOL))completion;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// PHAsset+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Slience on 2021/6/8.
|
||||
// Copyright © 2021 洪欣. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "PHAsset+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
|
||||
@implementation PHAsset (HXExtension)
|
||||
|
||||
- (void)hx_checkForModificationsWithAssetPathMethodCompletion:(void (^)(BOOL))completion {
|
||||
[self requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
|
||||
AVAsset *avAsset;
|
||||
if HX_IOS9Later {
|
||||
avAsset = contentEditingInput.audiovisualAsset;
|
||||
}else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
avAsset = contentEditingInput.avAsset;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
NSString *path = avAsset ? [avAsset description] : contentEditingInput.fullSizeImageURL.path;
|
||||
completion([path containsString:@"/Mutations/"]);
|
||||
}];
|
||||
}
|
||||
@end
|
14
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIButton+HXExtension.h
generated
Normal file
14
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIButton+HXExtension.h
generated
Normal file
|
@ -0,0 +1,14 @@
|
|||
//
|
||||
// UIButton+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 17/2/16.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIButton (HXExtension)
|
||||
/** 扩大buuton点击范围 */
|
||||
- (void)hx_setEnlargeEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left;
|
||||
@end
|
53
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIButton+HXExtension.m
generated
Normal file
53
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIButton+HXExtension.m
generated
Normal file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// UIButton+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 17/2/16.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIButton+HXExtension.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation UIButton (HXExtension)
|
||||
|
||||
static char topNameKey;
|
||||
static char rightNameKey;
|
||||
static char bottomNameKey;
|
||||
static char leftNameKey;
|
||||
|
||||
- (void)hx_setEnlargeEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left
|
||||
{
|
||||
objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
|
||||
- (CGRect)enlargedRect{
|
||||
NSNumber* topEdge = objc_getAssociatedObject(self, &topNameKey);
|
||||
NSNumber* rightEdge = objc_getAssociatedObject(self, &rightNameKey);
|
||||
NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomNameKey);
|
||||
NSNumber* leftEdge = objc_getAssociatedObject(self, &leftNameKey);
|
||||
|
||||
if (topEdge && rightEdge && bottomEdge && leftEdge){
|
||||
return CGRectMake(self.bounds.origin.x - leftEdge.floatValue,
|
||||
self.bounds.origin.y - topEdge.floatValue,
|
||||
self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue,
|
||||
self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue);
|
||||
} else{
|
||||
return self.bounds;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
|
||||
CGRect rect = [self enlargedRect];
|
||||
|
||||
if (CGRectEqualToRect(rect, self.bounds)){
|
||||
return [super pointInside:point withEvent:event];
|
||||
}else{
|
||||
return CGRectContainsPoint(rect, point);
|
||||
}
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// UIColor+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/12/3.
|
||||
// Copyright © 2019 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIColor (HXExtension)
|
||||
+ (UIColor *)hx_colorWithHexStr:(NSString *)string;
|
||||
+ (UIColor *)hx_colorWithHexStr:(NSString *)string alpha:(CGFloat)alpha;
|
||||
+ (UIColor *)hx_colorWithR:(CGFloat)red g:(CGFloat)green b:(CGFloat)blue a:(CGFloat)alpha;
|
||||
+ (NSString *)hx_hexStringWithColor:(UIColor *)color;
|
||||
- (BOOL)hx_colorIsWhite;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// UIColor+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/12/3.
|
||||
// Copyright © 2019 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIColor+HXExtension.h"
|
||||
|
||||
@implementation UIColor (HXExtension)
|
||||
|
||||
+ (UIColor *)hx_colorWithHexStr:(NSString *)string {
|
||||
return [UIColor hx_colorWithHexStr:string alpha:1.0];
|
||||
}
|
||||
|
||||
+ (UIColor *)hx_colorWithHexStr:(NSString *)string alpha:(CGFloat)alpha {
|
||||
NSString *str;
|
||||
if ([string containsString:@"#"]) {
|
||||
str = [string substringFromIndex:1];
|
||||
} else {
|
||||
str = string;
|
||||
}
|
||||
|
||||
NSScanner *scanner = [[NSScanner alloc] initWithString:str];
|
||||
UInt32 hexNum = 0;
|
||||
if ([scanner scanHexInt:&hexNum] == NO) {
|
||||
NSLog(@"16进制转UIColor, hexString为空");
|
||||
}
|
||||
|
||||
return [UIColor hx_colorWithR:(hexNum & 0xFF0000) >> 16 g:(hexNum & 0x00FF00) >> 8 b:hexNum & 0x0000FF a:alpha];
|
||||
}
|
||||
|
||||
+ (UIColor *)hx_colorWithR:(CGFloat)red g:(CGFloat)green b:(CGFloat)blue a:(CGFloat)alpha {
|
||||
return [UIColor colorWithRed:red / 255.0 green:green / 255.0 blue:blue / 255.0 alpha:alpha];
|
||||
}
|
||||
|
||||
+ (NSString *)hx_hexStringWithColor:(UIColor *)color {
|
||||
CGFloat r, g, b, a;
|
||||
BOOL bo = [color getRed:&r green:&g blue:&b alpha:&a];
|
||||
if (bo) {
|
||||
int rgb = (int) (r * 255.0f)<<16 | (int) (g * 255.0f)<<8 | (int) (b * 255.0f)<<0;
|
||||
return [NSString stringWithFormat:@"#%06x", rgb].uppercaseString;
|
||||
} else {
|
||||
return @"";
|
||||
}
|
||||
}
|
||||
- (BOOL)hx_colorIsWhite {
|
||||
CGFloat red = 0;
|
||||
CGFloat green = 0;
|
||||
CGFloat blue = 0;
|
||||
[self getRed:&red green:&green blue:&blue alpha:NULL];
|
||||
if (red >= 0.99 && green >= 0.99 & blue >= 0.99) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// UIFont+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIFont (HXExtension)
|
||||
+ (instancetype)hx_pingFangFontOfSize:(CGFloat)size;
|
||||
+ (instancetype)hx_regularPingFangOfSize:(CGFloat)size;
|
||||
+ (instancetype)hx_mediumPingFangOfSize:(CGFloat)size;
|
||||
+ (instancetype)hx_boldPingFangOfSize:(CGFloat)size;
|
||||
+ (instancetype)hx_helveticaNeueOfSize:(CGFloat)size;
|
||||
+ (instancetype)hx_mediumHelveticaNeueOfSize:(CGFloat)size;
|
||||
+ (instancetype)hx_mediumSFUITextOfSize:(CGFloat)size;
|
||||
@end
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// UIFont+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIFont+HXExtension.h"
|
||||
|
||||
@implementation UIFont (HXExtension)
|
||||
+ (instancetype)hx_pingFangFontOfSize:(CGFloat)size {
|
||||
UIFont *font = [self fontWithName:@"PingFangSC-Regular" size:size];
|
||||
return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
+ (instancetype)hx_regularPingFangOfSize:(CGFloat)size {
|
||||
UIFont *font = [self fontWithName:@"PingFangSC-Regular" size:size];
|
||||
return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
+ (instancetype)hx_mediumPingFangOfSize:(CGFloat)size {
|
||||
UIFont *font = [self fontWithName:@"PingFangSC-Medium" size:size];
|
||||
return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
+ (instancetype)hx_boldPingFangOfSize:(CGFloat)size {
|
||||
UIFont *font = [self fontWithName:@"PingFangSC-Semibold" size:size];
|
||||
return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
+ (instancetype)hx_helveticaNeueOfSize:(CGFloat)size {
|
||||
UIFont *font = [self fontWithName:@"HelveticaNeue" size:size];
|
||||
return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
+ (instancetype)hx_mediumHelveticaNeueOfSize:(CGFloat)size {
|
||||
UIFont *font = [self fontWithName:@"HelveticaNeue-Medium" size:size];
|
||||
return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
+ (instancetype)hx_mediumSFUITextOfSize:(CGFloat)size {
|
||||
return [self hx_mediumPingFangOfSize:size];
|
||||
// UIFont *font = [self fontWithName:@".SFUIText-Medium" size:size];
|
||||
// return font ? font : [UIFont systemFontOfSize:size];
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// UIImage+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 17/2/15.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreMedia/CoreMedia.h>
|
||||
|
||||
@interface UIImage (HXExtension)
|
||||
+ (UIImage *)hx_imageNamed:(NSString *)imageName;
|
||||
+ (UIImage *)hx_imageContentsOfFile:(NSString *)imageName;
|
||||
+ (UIImage *)hx_thumbnailImageForVideo:(NSURL *)videoURL
|
||||
atTime:(NSTimeInterval)time;
|
||||
+ (UIImage *)hx_animatedGIFWithData:(NSData *)data;
|
||||
+ (UIImage *)hx_animatedGIFWithURL:(NSURL *)URL;
|
||||
- (UIImage *)hx_normalizedImage;
|
||||
|
||||
- (UIImage *)hx_scaleImagetoScale:(float)scaleSize;
|
||||
- (UIImage *)hx_rotationImage:(UIImageOrientation)orient;
|
||||
|
||||
+ (UIImage *)hx_imageWithColor:(UIColor *)color havingSize:(CGSize)size;
|
||||
|
||||
|
||||
- (UIImage *)hx_cropInRect:(CGRect)rect;
|
||||
- (UIImage *)hx_roundClipingImage;
|
||||
- (UIImage *)hx_scaleToFillSize:(CGSize)size;
|
||||
- (UIImage *)hx_mergeimages:(NSArray <UIImage *>*)images;
|
||||
+ (UIImage *)hx_mergeimages:(NSArray <UIImage *>*)images;
|
||||
+ (CGSize)hx_scaleImageSizeBySize:(CGSize)imageSize targetSize:(CGSize)size isBoth:(BOOL)isBoth ;
|
||||
- (UIImage *)hx_scaleToFitSize:(CGSize)size;
|
||||
|
||||
@end
|
445
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIImage+HXExtension.m
generated
Normal file
445
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIImage+HXExtension.m
generated
Normal file
|
@ -0,0 +1,445 @@
|
|||
//
|
||||
// UIImage+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 17/2/15.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "HXPhotoTools.h"
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <Accelerate/Accelerate.h>
|
||||
|
||||
@implementation UIImage (HXExtension)
|
||||
+ (UIImage *)hx_imageNamed:(NSString *)imageName {
|
||||
if (!imageName) {
|
||||
return nil;
|
||||
}
|
||||
UIImage *image;
|
||||
NSBundle *bundle = [NSBundle hx_photoPickerBundle];
|
||||
if (bundle) {
|
||||
NSString *path = [bundle pathForResource:@"images" ofType:nil];
|
||||
path = [path stringByAppendingPathComponent:imageName];
|
||||
image = [UIImage imageNamed:path];
|
||||
}
|
||||
if (!image) {
|
||||
image = [self imageNamed:imageName];
|
||||
}
|
||||
return image;
|
||||
}
|
||||
+ (UIImage *)hx_imageContentsOfFile:(NSString *)imageName {
|
||||
if (!imageName) {
|
||||
return nil;
|
||||
}
|
||||
UIImage *image;
|
||||
NSBundle *bundle = [NSBundle hx_photoPickerBundle];
|
||||
if (bundle) {
|
||||
NSString *path = [bundle pathForResource:@"images" ofType:nil];
|
||||
path = [path stringByAppendingPathComponent:imageName];
|
||||
image = [UIImage imageWithContentsOfFile:path];
|
||||
}
|
||||
if (!image) {
|
||||
image = [self imageNamed:imageName];
|
||||
}
|
||||
return image;
|
||||
}
|
||||
+ (UIImage *)hx_thumbnailImageForVideo:(NSURL *)videoURL atTime:(NSTimeInterval)time {
|
||||
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
|
||||
if (!asset) {
|
||||
return nil;
|
||||
}
|
||||
AVAssetImageGenerator *assetImageGenerator =[[AVAssetImageGenerator alloc] initWithAsset:asset];
|
||||
assetImageGenerator.appliesPreferredTrackTransform = YES;
|
||||
assetImageGenerator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
|
||||
CGImageRef thumbnailImageRef = NULL;
|
||||
CFTimeInterval thumbnailImageTime = time;
|
||||
NSError *thumbnailImageGenerationError = nil;
|
||||
thumbnailImageRef = [assetImageGenerator copyCGImageAtTime:CMTimeMake(thumbnailImageTime, 60)actualTime:NULL error:&thumbnailImageGenerationError];
|
||||
UIImage*thumbnailImage = thumbnailImageRef ? [[UIImage alloc]initWithCGImage: thumbnailImageRef] : nil;
|
||||
CGImageRelease(thumbnailImageRef);
|
||||
return thumbnailImage;
|
||||
}
|
||||
+ (UIImage *)hx_animatedGIFWithImageSourceRef:(CGImageSourceRef)source {
|
||||
//获取gif文件的帧数
|
||||
size_t count = CGImageSourceGetCount(source);
|
||||
UIImage *animatedImage;
|
||||
if (count > 1) { //大于一张图片时
|
||||
NSMutableArray *images = [NSMutableArray array];
|
||||
//设置gif播放的时间
|
||||
NSTimeInterval duration = 0.0f;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
//获取gif指定帧的像素位图
|
||||
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
|
||||
if (!image) {
|
||||
continue;
|
||||
}
|
||||
//获取每张图的播放时间
|
||||
duration += [self frameDurationAtIndex:i source:source];
|
||||
[images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
|
||||
CGImageRelease(image);
|
||||
}
|
||||
if (!duration) {//如果播放时间为空
|
||||
duration = (1.0f / 10.0f) * count;
|
||||
}
|
||||
animatedImage = [UIImage animatedImageWithImages:images duration:duration];
|
||||
}
|
||||
|
||||
return animatedImage;
|
||||
}
|
||||
+ (UIImage *)hx_animatedGIFWithURL:(NSURL *)URL {
|
||||
if (!URL) {
|
||||
return nil;
|
||||
}
|
||||
CGImageSourceRef source = CGImageSourceCreateWithURL((__bridge CFURLRef)URL, NULL);
|
||||
|
||||
UIImage *animatedImage = [self hx_animatedGIFWithImageSourceRef:source];
|
||||
if (!animatedImage) {
|
||||
animatedImage = [UIImage imageWithContentsOfFile:URL.relativePath];
|
||||
}
|
||||
CFRelease(source);
|
||||
return animatedImage;
|
||||
}
|
||||
+ (UIImage *)hx_animatedGIFWithData:(NSData *)data {
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
//通过CFData读取gif文件的数据
|
||||
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
|
||||
|
||||
UIImage *animatedImage = [self hx_animatedGIFWithImageSourceRef:source];
|
||||
if (!animatedImage) {
|
||||
animatedImage = [UIImage imageWithData:data];
|
||||
}
|
||||
|
||||
CFRelease(source);
|
||||
return animatedImage;
|
||||
}
|
||||
|
||||
+ (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
|
||||
float frameDuration = 0.1f;
|
||||
//获取这一帧图片的属性字典
|
||||
CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
|
||||
NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
|
||||
//获取gif属性字典
|
||||
NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
|
||||
//获取这一帧持续的时间
|
||||
NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
|
||||
if (delayTimeUnclampedProp) {
|
||||
frameDuration = [delayTimeUnclampedProp floatValue];
|
||||
}
|
||||
else {
|
||||
NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
|
||||
if (delayTimeProp) {
|
||||
frameDuration = [delayTimeProp floatValue];
|
||||
}
|
||||
}
|
||||
//如果帧数小于0.1,则指定为0.1
|
||||
if (frameDuration < 0.011f) {
|
||||
frameDuration = 0.100f;
|
||||
}
|
||||
CFRelease(cfFrameProperties);
|
||||
return frameDuration;
|
||||
}
|
||||
|
||||
- (UIImage *)hx_normalizedImage {
|
||||
if (self.imageOrientation == UIImageOrientationUp) return self;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
|
||||
[self drawInRect:(CGRect){0, 0, self.size}];
|
||||
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return normalizedImage;
|
||||
}
|
||||
|
||||
- (UIImage *)hx_scaleImagetoScale:(float)scaleSize {
|
||||
|
||||
UIGraphicsBeginImageContext(CGSizeMake(self.size.width * scaleSize, self.size.height * scaleSize));
|
||||
|
||||
[self drawInRect:CGRectMake(0, 0, self.size.width * scaleSize, self.size.height * scaleSize)];
|
||||
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return scaledImage;
|
||||
}
|
||||
|
||||
- (UIImage *)hx_rotationImage:(UIImageOrientation)orient {
|
||||
CGRect bnds = CGRectZero;
|
||||
UIImage* copy = nil;
|
||||
CGContextRef ctxt = nil;
|
||||
CGImageRef imag = self.CGImage;
|
||||
CGRect rect = CGRectZero;
|
||||
CGAffineTransform tran = CGAffineTransformIdentity;
|
||||
|
||||
rect.size.width = CGImageGetWidth(imag) * self.scale;
|
||||
rect.size.height = CGImageGetHeight(imag) * self.scale;
|
||||
|
||||
while (rect.size.width * rect.size.height > 3 * 1000 * 1000) {
|
||||
rect.size.width /= 2;
|
||||
rect.size.height /= 2;
|
||||
}
|
||||
|
||||
bnds = rect;
|
||||
|
||||
switch (orient)
|
||||
{
|
||||
case UIImageOrientationUp:
|
||||
return self;
|
||||
|
||||
case UIImageOrientationUpMirrored:
|
||||
tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
|
||||
tran = CGAffineTransformScale(tran, -1.0, 1.0);
|
||||
break;
|
||||
|
||||
case UIImageOrientationDown:
|
||||
tran = CGAffineTransformMakeTranslation(rect.size.width,
|
||||
rect.size.height);
|
||||
tran = CGAffineTransformRotate(tran, M_PI);
|
||||
break;
|
||||
|
||||
case UIImageOrientationDownMirrored:
|
||||
tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
|
||||
tran = CGAffineTransformScale(tran, 1.0, -1.0);
|
||||
break;
|
||||
|
||||
case UIImageOrientationLeft:
|
||||
bnds = swapWidthAndHeight(bnds);
|
||||
tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
|
||||
tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
|
||||
break;
|
||||
|
||||
case UIImageOrientationLeftMirrored:
|
||||
bnds = swapWidthAndHeight(bnds);
|
||||
tran = CGAffineTransformMakeTranslation(rect.size.height,
|
||||
rect.size.width);
|
||||
tran = CGAffineTransformScale(tran, -1.0, 1.0);
|
||||
tran = CGAffineTransformRotate(tran, 3.0 * M_PI / 2.0);
|
||||
break;
|
||||
|
||||
case UIImageOrientationRight:
|
||||
bnds = swapWidthAndHeight(bnds);
|
||||
tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
|
||||
tran = CGAffineTransformRotate(tran, M_PI / 2.0);
|
||||
break;
|
||||
|
||||
case UIImageOrientationRightMirrored:
|
||||
bnds = swapWidthAndHeight(bnds);
|
||||
tran = CGAffineTransformMakeScale(-1.0, 1.0);
|
||||
tran = CGAffineTransformRotate(tran, M_PI / 2.0);
|
||||
break;
|
||||
|
||||
default:
|
||||
return self;
|
||||
}
|
||||
|
||||
UIGraphicsBeginImageContext(bnds.size);
|
||||
ctxt = UIGraphicsGetCurrentContext();
|
||||
|
||||
switch (orient)
|
||||
{
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
CGContextScaleCTM(ctxt, -1.0, 1.0);
|
||||
CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
|
||||
break;
|
||||
|
||||
default:
|
||||
CGContextScaleCTM(ctxt, 1.0, -1.0);
|
||||
CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
|
||||
break;
|
||||
}
|
||||
|
||||
CGContextConcatCTM(ctxt, tran);
|
||||
CGContextDrawImage(UIGraphicsGetCurrentContext(), rect, imag);
|
||||
|
||||
copy = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return copy;
|
||||
}
|
||||
/** 交换宽和高 */
|
||||
static CGRect swapWidthAndHeight(CGRect rect) {
|
||||
CGFloat swap = rect.size.width;
|
||||
|
||||
rect.size.width = rect.size.height;
|
||||
rect.size.height = swap;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
+ (UIImage *)hx_imageWithColor:(UIColor *)color havingSize:(CGSize)size {
|
||||
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
|
||||
UIGraphicsBeginImageContext(rect.size);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextSetFillColorWithColor(context, [color CGColor]);
|
||||
CGContextFillRect(context, rect);
|
||||
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return image;
|
||||
}
|
||||
- (UIImage *)hx_cropInRect:(CGRect)rect {
|
||||
if (CGPointEqualToPoint(CGPointZero, rect.origin) && CGSizeEqualToSize(self.size, rect.size)) {
|
||||
return self;
|
||||
}
|
||||
UIImage *smallImage = nil;
|
||||
CGImageRef sourceImageRef = [self CGImage];
|
||||
CGImageRef newImageRef = CGImageCreateWithImageInRect(sourceImageRef, rect);
|
||||
if (newImageRef) {
|
||||
smallImage = [UIImage imageWithCGImage:newImageRef scale:self.scale orientation:self.imageOrientation];
|
||||
CGImageRelease(newImageRef);
|
||||
}
|
||||
|
||||
return smallImage;
|
||||
}
|
||||
- (UIImage *)hx_roundClipingImage {
|
||||
UIGraphicsBeginImageContext(self.size);
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
|
||||
[path addClip];
|
||||
[self drawAtPoint:CGPointZero];
|
||||
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return newImage;
|
||||
}
|
||||
- (UIImage *)hx_scaleToFillSize:(CGSize)size {
|
||||
if (CGSizeEqualToSize(self.size, size)) {
|
||||
return self;
|
||||
}
|
||||
|
||||
// 创建一个context
|
||||
// 并把它设置成为当前正在使用的context
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
|
||||
|
||||
// 绘制改变大小的图片
|
||||
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
|
||||
|
||||
// 从当前context中创建一个改变大小后的图片
|
||||
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
// 使当前的context出堆栈
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
// 返回新的改变大小后的图片
|
||||
return scaledImage;
|
||||
}
|
||||
/** 合并图片(图片大小一致) */
|
||||
- (UIImage *)hx_mergeimages:(NSArray <UIImage *>*)images {
|
||||
CGSize size = self.size;
|
||||
while (size.width * size.height > 3 * 1000 * 1000) {
|
||||
size.width /= 2;
|
||||
size.height /= 2;
|
||||
}
|
||||
UIGraphicsBeginImageContextWithOptions(size ,NO, 0);
|
||||
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
|
||||
for (UIImage *image in images) {
|
||||
size = image.size;
|
||||
while (size.width * size.height > 3 * 1000 * 1000) {
|
||||
size.width /= 2;
|
||||
size.height /= 2;
|
||||
}
|
||||
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
|
||||
}
|
||||
UIImage *mergeImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return mergeImage;
|
||||
}
|
||||
/** 合并图片(图片大小以第一张为准) */
|
||||
+ (UIImage *)hx_mergeimages:(NSArray <UIImage *>*)images {
|
||||
UIGraphicsBeginImageContextWithOptions(images.firstObject.size ,NO, 0);
|
||||
for (UIImage *image in images) {
|
||||
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
|
||||
}
|
||||
UIImage *mergeImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return mergeImage;
|
||||
}
|
||||
+ (CGSize)hx_scaleImageSizeBySize:(CGSize)imageSize targetSize:(CGSize)size isBoth:(BOOL)isBoth {
|
||||
|
||||
/** 原图片大小为0 不再往后处理 */
|
||||
if (CGSizeEqualToSize(imageSize, CGSizeZero)) {
|
||||
return imageSize;
|
||||
}
|
||||
|
||||
CGFloat width = imageSize.width;
|
||||
CGFloat height = imageSize.height;
|
||||
CGFloat targetWidth = size.width;
|
||||
CGFloat targetHeight = size.height;
|
||||
CGFloat scaleFactor = 0.0;
|
||||
CGFloat scaledWidth = targetWidth;
|
||||
CGFloat scaledHeight = targetHeight;
|
||||
CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
|
||||
if(CGSizeEqualToSize(imageSize, size) == NO){
|
||||
CGFloat widthFactor = targetWidth / width;
|
||||
CGFloat heightFactor = targetHeight / height;
|
||||
if (isBoth) {
|
||||
if(widthFactor > heightFactor){
|
||||
scaleFactor = widthFactor;
|
||||
}
|
||||
else{
|
||||
scaleFactor = heightFactor;
|
||||
}
|
||||
} else {
|
||||
if(widthFactor > heightFactor){
|
||||
scaleFactor = heightFactor;
|
||||
}
|
||||
else{
|
||||
scaleFactor = widthFactor;
|
||||
}
|
||||
}
|
||||
scaledWidth = width * scaleFactor;
|
||||
scaledHeight = height * scaleFactor;
|
||||
if(widthFactor > heightFactor){
|
||||
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
|
||||
}else if(widthFactor < heightFactor){
|
||||
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
|
||||
}
|
||||
}
|
||||
return CGSizeMake(ceilf(scaledWidth), ceilf(scaledHeight));
|
||||
}
|
||||
- (UIImage*)hx_scaleToFitSize:(CGSize)size {
|
||||
if (CGSizeEqualToSize(self.size, size)) {
|
||||
return self;
|
||||
}
|
||||
CGFloat width = CGImageGetWidth(self.CGImage);
|
||||
CGFloat height = CGImageGetHeight(self.CGImage);
|
||||
|
||||
float verticalRadio = size.height*1.0/height;
|
||||
float horizontalRadio = size.width*1.0/width;
|
||||
|
||||
float radio = 1;
|
||||
if(verticalRadio>1 && horizontalRadio>1)
|
||||
{
|
||||
radio = verticalRadio > horizontalRadio ? horizontalRadio : verticalRadio;
|
||||
}
|
||||
else
|
||||
{
|
||||
radio = verticalRadio < horizontalRadio ? verticalRadio : horizontalRadio;
|
||||
}
|
||||
|
||||
width = roundf(width*radio);
|
||||
height = roundf(height*radio);
|
||||
|
||||
int xPos = (size.width - width)/2;
|
||||
int yPos = (size.height-height)/2;
|
||||
|
||||
// 创建一个context
|
||||
// 并把它设置成为当前正在使用的context
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
|
||||
|
||||
// 绘制改变大小的图片
|
||||
[self drawInRect:CGRectMake(xPos, yPos, width, height)];
|
||||
|
||||
// 从当前context中创建一个改变大小后的图片
|
||||
UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
// 使当前的context出堆栈
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
// 返回新的改变大小后的图片
|
||||
return scaledImage;
|
||||
}
|
||||
@end
|
19
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIImageView+HXExtension.h
generated
Normal file
19
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIImageView+HXExtension.h
generated
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// UIImageView+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2018/2/14.
|
||||
// Copyright © 2018年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class HXPhotoModel;
|
||||
@interface UIImageView (HXExtension)
|
||||
- (void)hx_setImageWithModel:(HXPhotoModel *)model progress:(void (^)(CGFloat progress, HXPhotoModel *model))progressBlock completed:(void (^)(UIImage * image, NSError * error, HXPhotoModel * model))completedBlock;
|
||||
|
||||
- (void)hx_setImageWithModel:(HXPhotoModel *)model original:(BOOL)original progress:(void (^)(CGFloat progress, HXPhotoModel *model))progressBlock completed:(void (^)(UIImage * image, NSError * error, HXPhotoModel * model))completedBlock;
|
||||
- (void)hx_setImageWithURL:(NSURL *)url
|
||||
progress:(void (^)(CGFloat progress))progressBlock
|
||||
completed:(void (^)(UIImage * image, NSError * error))completedBlock;
|
||||
@end
|
196
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIImageView+HXExtension.m
generated
Normal file
196
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIImageView+HXExtension.m
generated
Normal file
|
@ -0,0 +1,196 @@
|
|||
//
|
||||
// UIImageView+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2018/2/14.
|
||||
// Copyright © 2018年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIImageView+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
#import "HXPhotoModel.h"
|
||||
|
||||
#if __has_include(<SDWebImage/UIImageView+WebCache.h>)
|
||||
#import <SDWebImage/UIImageView+WebCache.h>
|
||||
#import <SDWebImage/SDWebImageManager.h>
|
||||
#elif __has_include("UIImageView+WebCache.h")
|
||||
#import "UIImageView+WebCache.h"
|
||||
#import "SDWebImageManager.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if __has_include(<YYWebImage/YYWebImage.h>)
|
||||
#import <YYWebImage/YYWebImage.h>
|
||||
#elif __has_include("YYWebImage.h")
|
||||
#import "YYWebImage.h"
|
||||
#elif __has_include(<YYKit/YYKit.h>)
|
||||
#import <YYKit/YYKit.h>
|
||||
#elif __has_include("YYKit.h")
|
||||
#import "YYKit.h"
|
||||
#endif
|
||||
#import "HXPhotoEdit.h"
|
||||
|
||||
@implementation UIImageView (HXExtension)
|
||||
|
||||
- (void)hx_setImageWithModel:(HXPhotoModel *)model progress:(void (^)(CGFloat progress, HXPhotoModel *model))progressBlock completed:(void (^)(UIImage * image, NSError * error, HXPhotoModel * model))completedBlock {
|
||||
[self hx_setImageWithModel:model original:YES progress:progressBlock completed:completedBlock];
|
||||
}
|
||||
|
||||
- (void)hx_setImageWithModel:(HXPhotoModel *)model original:(BOOL)original progress:(void (^)(CGFloat progress, HXPhotoModel *model))progressBlock completed:(void (^)(UIImage * image, NSError * error, HXPhotoModel * model))completedBlock {
|
||||
if (model.photoEdit) {
|
||||
UIImage *image = model.photoEdit.editPreviewImage;
|
||||
self.image = image;
|
||||
model.imageSize = image.size;
|
||||
model.thumbPhoto = image;
|
||||
model.previewPhoto = image;
|
||||
model.downloadComplete = YES;
|
||||
model.downloadError = NO;
|
||||
if (completedBlock) {
|
||||
completedBlock(image, nil, model);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!model.networkThumbURL) model.networkThumbURL = model.networkPhotoUrl;
|
||||
#if HasSDWebImage
|
||||
HXWeakSelf
|
||||
NSString *cacheKey = [[SDWebImageManager sharedManager] cacheKeyForURL:model.networkPhotoUrl];
|
||||
[[SDWebImageManager sharedManager].imageCache queryImageForKey:cacheKey options:SDWebImageQueryMemoryData context:nil completion:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) {
|
||||
if (image) {
|
||||
weakSelf.image = image;
|
||||
model.imageSize = image.size;
|
||||
model.thumbPhoto = image;
|
||||
model.previewPhoto = image;
|
||||
model.downloadComplete = YES;
|
||||
model.downloadError = NO;
|
||||
if (completedBlock) {
|
||||
completedBlock(image, nil, model);
|
||||
}
|
||||
}else {
|
||||
NSURL *url = (original || image) ? model.networkPhotoUrl : model.networkThumbURL;
|
||||
[weakSelf sd_setImageWithURL:url placeholderImage:model.thumbPhoto options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
||||
model.receivedSize = receivedSize;
|
||||
model.expectedSize = expectedSize;
|
||||
CGFloat progress = (CGFloat)receivedSize / expectedSize;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (progressBlock) {
|
||||
progressBlock(progress, model);
|
||||
}
|
||||
});
|
||||
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
model.downloadComplete = YES;
|
||||
if (error != nil) {
|
||||
model.downloadError = YES;
|
||||
}else {
|
||||
if (image) {
|
||||
weakSelf.image = image;
|
||||
model.imageSize = image.size;
|
||||
model.thumbPhoto = image;
|
||||
model.previewPhoto = image;
|
||||
model.downloadError = NO;
|
||||
}
|
||||
}
|
||||
if (completedBlock) {
|
||||
completedBlock(image,error,model);
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
#elif HasYYKitOrWebImage
|
||||
HXWeakSelf
|
||||
YYWebImageManager *manager = [YYWebImageManager sharedManager];
|
||||
[manager.cache getImageForKey:[manager cacheKeyForURL:model.networkPhotoUrl] withType:YYImageCacheTypeAll withBlock:^(UIImage * _Nullable image, YYImageCacheType type) {
|
||||
if (image) {
|
||||
weakSelf.image = image;
|
||||
model.imageSize = weakSelf.image.size;
|
||||
model.thumbPhoto = weakSelf.image;
|
||||
model.previewPhoto = weakSelf.image;
|
||||
model.downloadComplete = YES;
|
||||
model.downloadError = NO;
|
||||
if (completedBlock) {
|
||||
completedBlock(weakSelf.image, nil, model);
|
||||
}
|
||||
}else {
|
||||
NSURL *url = original ? model.networkPhotoUrl : model.networkThumbURL;
|
||||
[weakSelf yy_setImageWithURL:url placeholder:model.thumbPhoto options:YYWebImageOptionShowNetworkActivity progress:^(NSInteger receivedSize, NSInteger expectedSize) {
|
||||
model.receivedSize = receivedSize;
|
||||
model.expectedSize = expectedSize;
|
||||
CGFloat progress = (CGFloat)receivedSize / expectedSize;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (progressBlock) {
|
||||
progressBlock(progress, model);
|
||||
}
|
||||
});
|
||||
} transform:^UIImage * _Nullable(UIImage * _Nonnull image, NSURL * _Nonnull url) {
|
||||
return image;
|
||||
} completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
|
||||
if (error != nil) {
|
||||
model.downloadError = YES;
|
||||
model.downloadComplete = YES;
|
||||
}else {
|
||||
if (image) {
|
||||
weakSelf.image = image;
|
||||
model.imageSize = image.size;
|
||||
model.thumbPhoto = image;
|
||||
model.previewPhoto = image;
|
||||
model.downloadComplete = YES;
|
||||
model.downloadError = NO;
|
||||
}
|
||||
}
|
||||
if (completedBlock) {
|
||||
completedBlock(image,error,model);
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
#else
|
||||
/// 如果都是pod导入的提示找不到话,先将SD或YY 和 HX 的pod全部移除,再 pod install
|
||||
/// 然后再 pod HXPhotoPicker/SDWebImage 或者 HXPhotoPicker/YYWebImage
|
||||
NSSLog(@"请导入YYWebImage/SDWebImage后再使用网络图片功能");
|
||||
// NSAssert(NO, @"请导入YYWebImage/SDWebImage后再使用网络图片功能,HXPhotoPicker为pod导入的那么YY或者SD也必须是pod导入的否则会找不到");
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)hx_setImageWithURL:(NSURL *)url
|
||||
progress:(void (^)(CGFloat progress))progressBlock
|
||||
completed:(void (^)(UIImage * image, NSError * error))completedBlock {
|
||||
|
||||
#if HasSDWebImage
|
||||
HXWeakSelf
|
||||
[self sd_setImageWithURL:url placeholderImage:nil options:0 context:nil progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
||||
CGFloat progress = (CGFloat)receivedSize / expectedSize;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (progressBlock) {
|
||||
progressBlock(progress);
|
||||
}
|
||||
});
|
||||
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
weakSelf.image = image;
|
||||
if (completedBlock) {
|
||||
completedBlock(image, error);
|
||||
}
|
||||
}];
|
||||
#elif HasYYKitOrWebImage
|
||||
HXWeakSelf
|
||||
[self yy_setImageWithURL:url placeholder:nil options:YYWebImageOptionShowNetworkActivity progress:^(NSInteger receivedSize, NSInteger expectedSize) {
|
||||
CGFloat progress = (CGFloat)receivedSize / expectedSize;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (progressBlock) {
|
||||
progressBlock(progress);
|
||||
}
|
||||
});
|
||||
} transform:^UIImage * _Nullable(UIImage * _Nonnull image, NSURL * _Nonnull url) {
|
||||
return image;
|
||||
} completion:^(UIImage * _Nullable image, NSURL * _Nonnull url, YYWebImageFromType from, YYWebImageStage stage, NSError * _Nullable error) {
|
||||
weakSelf.image = image;
|
||||
if (completedBlock) {
|
||||
completedBlock(image, error);
|
||||
}
|
||||
}];
|
||||
#else
|
||||
/// 如果都是pod导入的提示找不到话,先将SD或YY 和 HX 的pod全部移除,再 pod install
|
||||
/// 然后再 pod HXPhotoPicker/SDWebImage 或者 HXPhotoPicker/YYWebImage
|
||||
NSSLog(@"请导入YYWebImage/SDWebImage后再使用网络图片功能");
|
||||
// NSAssert(NO, @"请导入YYWebImage/SDWebImage后再使用网络图片功能,HXPhotoPicker为pod导入的那么YY或者SD也必须是pod导入的否则会找不到");
|
||||
#endif
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// UILabel+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2018/12/28.
|
||||
// Copyright © 2018年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UILabel (HXExtension)
|
||||
|
||||
/**
|
||||
获取文本内容的宽度,获取宽度前先给label高度
|
||||
|
||||
@return 宽度
|
||||
*/
|
||||
- (CGFloat)hx_getTextWidth;
|
||||
|
||||
/**
|
||||
获取文本内容的高度,获取高度前先给label宽度
|
||||
|
||||
@return 高度
|
||||
*/
|
||||
- (CGFloat)hx_getTextHeight;
|
||||
|
||||
+ (CGFloat)hx_getTextWidthWithText:(NSString *)text height:(CGFloat)height font:(UIFont *)font;
|
||||
+ (CGFloat)hx_getTextWidthWithText:(NSString *)text height:(CGFloat)height fontSize:(CGFloat)fontSize;
|
||||
+ (CGFloat)hx_getTextHeightWithText:(NSString *)text width:(CGFloat)width font:(UIFont *)font;
|
||||
+ (CGFloat)hx_getTextHeightWithText:(NSString *)text width:(CGFloat)width fontSize:(CGFloat)fontSize;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,34 @@
|
|||
//
|
||||
// UILabel+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2018/12/28.
|
||||
// Copyright © 2018年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UILabel+HXExtension.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
|
||||
@implementation UILabel (HXExtension)
|
||||
- (CGFloat)hx_getTextWidth {
|
||||
return [UILabel hx_getTextWidthWithText:self.text height:self.hx_h font:self.font];
|
||||
}
|
||||
- (CGFloat)hx_getTextHeight {
|
||||
return [UILabel hx_getTextHeightWithText:self.text width:self.hx_w font:self.font];
|
||||
}
|
||||
+ (CGFloat)hx_getTextWidthWithText:(NSString *)text height:(CGFloat)height font:(UIFont *)font {
|
||||
CGSize newSize = [text boundingRectWithSize:CGSizeMake(MAXFLOAT, height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil].size;
|
||||
return newSize.width;
|
||||
}
|
||||
+ (CGFloat)hx_getTextWidthWithText:(NSString *)text height:(CGFloat)height fontSize:(CGFloat)fontSize {
|
||||
return [UILabel hx_getTextWidthWithText:text height:height font:[UIFont systemFontOfSize:fontSize]];
|
||||
}
|
||||
|
||||
+ (CGFloat)hx_getTextHeightWithText:(NSString *)text width:(CGFloat)width font:(UIFont *)font {
|
||||
CGSize newSize = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil].size;
|
||||
return newSize.height;
|
||||
}
|
||||
+ (CGFloat)hx_getTextHeightWithText:(NSString *)text width:(CGFloat)width fontSize:(CGFloat)fontSize {
|
||||
return [UILabel hx_getTextHeightWithText:text width:width font:[UIFont systemFontOfSize:fontSize]];
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// UIView+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 17/2/16.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class HXPhotoManager;
|
||||
@interface UIView (HXExtension)
|
||||
|
||||
@property (assign, nonatomic) CGFloat hx_x;
|
||||
@property (assign, nonatomic) CGFloat hx_y;
|
||||
@property (assign, nonatomic) CGFloat hx_w;
|
||||
@property (assign, nonatomic) CGFloat hx_h;
|
||||
@property (assign, nonatomic) CGFloat hx_centerX;
|
||||
@property (assign, nonatomic) CGFloat hx_centerY;
|
||||
@property (assign, nonatomic) CGSize hx_size;
|
||||
@property (assign, nonatomic) CGPoint hx_origin;
|
||||
|
||||
/**
|
||||
获取当前视图的控制器
|
||||
|
||||
@return 控制器
|
||||
*/
|
||||
- (UIViewController *)hx_viewController;
|
||||
|
||||
- (void)hx_showImageHUDText:(NSString *)text;
|
||||
- (void)hx_showLoadingHUDText:(NSString *)text;
|
||||
- (void)hx_showLoadingHUDText:(NSString *)text delay:(NSTimeInterval)delay;
|
||||
- (void)hx_immediatelyShowLoadingHudWithText:(NSString *)text;
|
||||
- (void)hx_handleLoading;
|
||||
- (void)hx_handleLoading:(BOOL)animation;
|
||||
- (void)hx_handleLoading:(BOOL)animation duration:(NSTimeInterval)duration;
|
||||
- (void)hx_handleImageWithDelay:(NSTimeInterval)delay;
|
||||
- (void)hx_handleImageWithAnimation:(BOOL)animation;
|
||||
- (void)hx_handleGraceTimer;
|
||||
|
||||
/* <HXAlbumListViewControllerDelegate> */
|
||||
- (void)hx_presentAlbumListViewControllerWithManager:(HXPhotoManager *)manager delegate:(id)delegate DEPRECATED_MSG_ATTRIBUTE("Use UIViewController+HXEXtension 'hx_presentSelectPhotoControllerWithManager:' instead");
|
||||
|
||||
/* <HXCustomCameraViewControllerDelegate> */
|
||||
- (void)hx_presentCustomCameraViewControllerWithManager:(HXPhotoManager *)manager delegate:(id)delegate DEPRECATED_MSG_ATTRIBUTE("Use UIViewController+HXEXtension 'hx_presentCustomCameraViewControllerWithManager:' instead");
|
||||
|
||||
/// 设置圆角。使用自动布局,需要在layoutsubviews 中使用
|
||||
/// @param radius 圆角尺寸
|
||||
/// @param corner 圆角位置
|
||||
- (void)hx_radiusWithRadius:(CGFloat)radius corner:(UIRectCorner)corner;
|
||||
- (UIImage *)hx_captureImageAtFrame:(CGRect)rect;
|
||||
- (UIColor *)hx_colorOfPoint:(CGPoint)point;
|
||||
@end
|
||||
|
||||
|
||||
@interface HXHUD : UIView
|
||||
@property (assign, nonatomic) BOOL isImage;
|
||||
@property (copy, nonatomic) NSString *text;
|
||||
- (instancetype)initWithFrame:(CGRect)frame imageName:(NSString *)imageName text:(NSString *)text;
|
||||
- (void)showloading;
|
||||
@end
|
|
@ -0,0 +1,482 @@
|
|||
//
|
||||
// UIView+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 17/2/16.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPhotoPicker.h"
|
||||
|
||||
@implementation UIView (HXExtension)
|
||||
- (void)setHx_x:(CGFloat)hx_x
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.x = hx_x;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)hx_x
|
||||
{
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
|
||||
- (void)setHx_y:(CGFloat)hx_y
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.origin.y = hx_y;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)hx_y
|
||||
{
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
|
||||
- (void)setHx_w:(CGFloat)hx_w
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.size.width = hx_w;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)hx_w
|
||||
{
|
||||
return self.frame.size.width;
|
||||
}
|
||||
|
||||
- (void)setHx_h:(CGFloat)hx_h
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.size.height = hx_h;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGFloat)hx_h
|
||||
{
|
||||
return self.frame.size.height;
|
||||
}
|
||||
|
||||
- (CGFloat)hx_centerX
|
||||
{
|
||||
return self.center.x;
|
||||
}
|
||||
|
||||
- (void)setHx_centerX:(CGFloat)hx_centerX {
|
||||
CGPoint center = self.center;
|
||||
center.x = hx_centerX;
|
||||
self.center = center;
|
||||
}
|
||||
|
||||
- (CGFloat)hx_centerY
|
||||
{
|
||||
return self.center.y;
|
||||
}
|
||||
|
||||
- (void)setHx_centerY:(CGFloat)hx_centerY {
|
||||
CGPoint center = self.center;
|
||||
center.y = hx_centerY;
|
||||
self.center = center;
|
||||
}
|
||||
|
||||
- (void)setHx_size:(CGSize)hx_size
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.size = hx_size;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGSize)hx_size
|
||||
{
|
||||
return self.frame.size;
|
||||
}
|
||||
|
||||
- (void)setHx_origin:(CGPoint)hx_origin
|
||||
{
|
||||
CGRect frame = self.frame;
|
||||
frame.origin = hx_origin;
|
||||
self.frame = frame;
|
||||
}
|
||||
|
||||
- (CGPoint)hx_origin
|
||||
{
|
||||
return self.frame.origin;
|
||||
}
|
||||
|
||||
/**
|
||||
获取当前视图的控制器
|
||||
|
||||
@return 控制器
|
||||
*/
|
||||
- (UIViewController*)hx_viewController {
|
||||
for (UIView* next = [self superview]; next; next = next.superview) {
|
||||
UIResponder* nextResponder = [next nextResponder];
|
||||
if ([nextResponder isKindOfClass:[UINavigationController class]] || [nextResponder isKindOfClass:[UIViewController class]]) {
|
||||
return (UIViewController*)nextResponder;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)hx_presentAlbumListViewControllerWithManager:(HXPhotoManager *)manager delegate:(id)delegate {
|
||||
HXAlbumListViewController *vc = [[HXAlbumListViewController alloc] initWithManager:manager];
|
||||
vc.delegate = delegate ? delegate : (id)self;
|
||||
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithRootViewController:vc];
|
||||
nav.supportRotation = manager.configuration.supportRotation;
|
||||
nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
nav.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[self.hx_viewController presentViewController:nav animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentCustomCameraViewControllerWithManager:(HXPhotoManager *)manager delegate:(id)delegate {
|
||||
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[self.hx_viewController.view hx_showImageHUDText:[NSBundle hx_localizedStringForKey:@"无法使用相机!"]];
|
||||
return;
|
||||
}
|
||||
HXWeakSelf
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (granted) {
|
||||
HXCustomCameraViewController *vc = [[HXCustomCameraViewController alloc] init];
|
||||
vc.delegate = delegate ? delegate : (id)weakSelf;
|
||||
vc.manager = manager;
|
||||
vc.isOutside = YES;
|
||||
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithRootViewController:vc];
|
||||
nav.isCamera = YES;
|
||||
nav.supportRotation = manager.configuration.supportRotation;
|
||||
nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
nav.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[weakSelf.hx_viewController presentViewController:nav animated:YES completion:nil];
|
||||
}else {
|
||||
[HXPhotoTools showUnusableCameraAlert:weakSelf.hx_viewController];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)hx_showImageHUDText:(NSString *)text {
|
||||
CGFloat hudW = [UILabel hx_getTextWidthWithText:text height:15 fontSize:14];
|
||||
if (hudW > self.frame.size.width - 60) {
|
||||
hudW = self.frame.size.width - 60;
|
||||
}
|
||||
|
||||
CGFloat hudH = [UILabel hx_getTextHeightWithText:text width:hudW fontSize:14];
|
||||
if (hudW < 100) {
|
||||
hudW = 100;
|
||||
}
|
||||
HXHUD *hud = [[HXHUD alloc] initWithFrame:CGRectMake(0, 0, hudW + 20, 110 + hudH - 15) imageName:@"hx_alert_failed" text:text];
|
||||
hud.alpha = 0;
|
||||
[self addSubview:hud];
|
||||
hud.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
|
||||
hud.transform = CGAffineTransformMakeScale(0.4, 0.4);
|
||||
[UIView animateWithDuration:0.25 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:1.0 options:0 animations:^{
|
||||
hud.alpha = 1;
|
||||
hud.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
[UIView cancelPreviousPerformRequestsWithTarget:self];
|
||||
[self performSelector:@selector(hx_handleGraceTimer) withObject:nil afterDelay:1.75f inModes:@[NSRunLoopCommonModes]];
|
||||
}
|
||||
|
||||
- (void)hx_immediatelyShowLoadingHudWithText:(NSString *)text {
|
||||
[self hx_showLoadingHudWithText:text delay:0 immediately:YES];
|
||||
}
|
||||
|
||||
- (void)hx_showLoadingHUDText:(NSString *)text {
|
||||
[self hx_showLoadingHUDText:text delay:0.f];
|
||||
}
|
||||
|
||||
- (void)hx_showLoadingHUDText:(NSString *)text delay:(NSTimeInterval)delay {
|
||||
[self hx_showLoadingHudWithText:text delay:delay immediately:NO];
|
||||
}
|
||||
|
||||
- (void)hx_showLoadingHudWithText:(NSString *)text delay:(NSTimeInterval)delay immediately:(BOOL)immediately {
|
||||
CGFloat hudW = [UILabel hx_getTextWidthWithText:text height:15 fontSize:14];
|
||||
if (hudW > self.frame.size.width - 60) {
|
||||
hudW = self.frame.size.width - 60;
|
||||
}
|
||||
|
||||
CGFloat hudH = [UILabel hx_getTextHeightWithText:text width:hudW fontSize:14];
|
||||
CGFloat width = 110;
|
||||
CGFloat height = width + hudH - 15;
|
||||
if (!text) {
|
||||
width = 95;
|
||||
height = 95;
|
||||
}
|
||||
HXHUD *hud = [[HXHUD alloc] initWithFrame:CGRectMake(0, 0, width, height) imageName:nil text:text];
|
||||
[hud showloading];
|
||||
hud.alpha = 0;
|
||||
[self addSubview:hud];
|
||||
hud.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
|
||||
if (immediately) {
|
||||
hud.alpha = 1;
|
||||
}else {
|
||||
hud.transform = CGAffineTransformMakeScale(0.4, 0.4);
|
||||
[UIView animateWithDuration:0.25 delay:delay usingSpringWithDamping:0.5 initialSpringVelocity:1 options:0 animations:^{
|
||||
hud.alpha = 1;
|
||||
hud.transform = CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hx_handleLoading {
|
||||
[self hx_handleLoading:YES];
|
||||
}
|
||||
- (void)hx_handleLoading:(BOOL)animation {
|
||||
[self hx_handleLoading:animation duration:0.2f];
|
||||
}
|
||||
- (void)hx_handleLoading:(BOOL)animation duration:(NSTimeInterval)duration {
|
||||
[UIView cancelPreviousPerformRequestsWithTarget:self];
|
||||
for (UIView *view in self.subviews) {
|
||||
if ([view isKindOfClass:[HXHUD class]] && ![(HXHUD *)view isImage]) {
|
||||
if (animation) {
|
||||
[UIView animateWithDuration:duration animations:^{
|
||||
view.alpha = 0;
|
||||
view.transform = CGAffineTransformMakeScale(0.5, 0.5);
|
||||
} completion:^(BOOL finished) {
|
||||
[view removeFromSuperview];
|
||||
}];
|
||||
}else {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)hx_handleImageWithAnimation:(BOOL)animation {
|
||||
[UIView cancelPreviousPerformRequestsWithTarget:self];
|
||||
for (UIView *view in self.subviews) {
|
||||
if ([view isKindOfClass:[HXHUD class]] && [(HXHUD *)view isImage]) {
|
||||
if (animation) {
|
||||
[UIView animateWithDuration:0.25f animations:^{
|
||||
view.alpha = 0;
|
||||
view.transform = CGAffineTransformMakeScale(0.5, 0.5);
|
||||
} completion:^(BOOL finished) {
|
||||
[view removeFromSuperview];
|
||||
}];
|
||||
}else {
|
||||
[view removeFromSuperview];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)hx_handleImageWithDelay:(NSTimeInterval)delay {
|
||||
if (delay) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self hx_handleGraceTimer];
|
||||
});
|
||||
}else {
|
||||
[self hx_handleGraceTimer];
|
||||
}
|
||||
}
|
||||
- (void)hx_handleGraceTimer {
|
||||
[self hx_handleImageWithAnimation:YES];
|
||||
}
|
||||
/**
|
||||
圆角
|
||||
使用自动布局,需要在layoutsubviews 中使用
|
||||
@param radius 圆角尺寸
|
||||
@param corner 圆角位置
|
||||
*/
|
||||
- (void)hx_radiusWithRadius:(CGFloat)radius corner:(UIRectCorner)corner {
|
||||
#ifdef __IPHONE_11_0
|
||||
if (@available(iOS 11.0, *)) {
|
||||
self.layer.cornerRadius = radius;
|
||||
self.layer.maskedCorners = (CACornerMask)corner;
|
||||
#else
|
||||
if ((NO)) {
|
||||
#endif
|
||||
} else {
|
||||
UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:corner cornerRadii:CGSizeMake(radius, radius)];
|
||||
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
|
||||
maskLayer.frame = self.bounds;
|
||||
maskLayer.path = path.CGPath;
|
||||
self.layer.mask = maskLayer;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)hx_captureImageAtFrame:(CGRect)rect {
|
||||
|
||||
UIImage* image = nil;
|
||||
|
||||
if (/* DISABLES CODE */ (YES)) {
|
||||
CGSize size = self.bounds.size;
|
||||
CGPoint point = self.bounds.origin;
|
||||
if (!CGRectEqualToRect(CGRectZero, rect)) {
|
||||
size = rect.size;
|
||||
point = CGPointMake(-rect.origin.x, -rect.origin.y);
|
||||
}
|
||||
@autoreleasepool {
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
||||
[self drawViewHierarchyInRect:(CGRect){point, self.bounds.size} afterScreenUpdates:YES];
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
BOOL translateCTM = !CGRectEqualToRect(CGRectZero, rect);
|
||||
|
||||
if (!translateCTM) {
|
||||
rect = self.frame;
|
||||
}
|
||||
|
||||
/** 参数取整,否则可能会出现1像素偏差 */
|
||||
/** 有小数部分才调整差值 */
|
||||
#define lfme_fixDecimal(d) ((fmod(d, (int)d)) > 0.59f ? ((int)(d+0.5)*1.f) : (((fmod(d, (int)d)) < 0.59f && (fmod(d, (int)d)) > 0.1f) ? ((int)(d)*1.f+0.5f) : (int)(d)*1.f))
|
||||
rect.origin.x = lfme_fixDecimal(rect.origin.x);
|
||||
rect.origin.y = lfme_fixDecimal(rect.origin.y);
|
||||
rect.size.width = lfme_fixDecimal(rect.size.width);
|
||||
rect.size.height = lfme_fixDecimal(rect.size.height);
|
||||
#undef lfme_fixDecimal
|
||||
CGSize size = rect.size;
|
||||
|
||||
@autoreleasepool {
|
||||
//1.开启上下文
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
if (translateCTM) {
|
||||
/** 移动上下文 */
|
||||
CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);
|
||||
}
|
||||
//2.绘制图层
|
||||
[self.layer renderInContext: context];
|
||||
|
||||
//3.从上下文中获取新图片
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
//4.关闭图形上下文
|
||||
UIGraphicsEndImageContext();
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
- (UIColor *)hx_colorOfPoint:(CGPoint)point {
|
||||
unsigned char pixel[4] = {0};
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast);
|
||||
|
||||
CGContextTranslateCTM(context, -point.x, -point.y);
|
||||
|
||||
[self.layer renderInContext:context];
|
||||
|
||||
CGContextRelease(context);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
UIColor *color = [UIColor colorWithRed:pixel[0]/255.0 green:pixel[1]/255.0 blue:pixel[2]/255.0 alpha:pixel[3]/255.0];
|
||||
|
||||
return color;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface HXHUD ()
|
||||
@property (copy, nonatomic) NSString *imageName;
|
||||
@property (strong, nonatomic) UIImageView *imageView;
|
||||
@property (strong, nonatomic) UIVisualEffectView *visualEffectView;
|
||||
@property (strong, nonatomic) UILabel *titleLb;
|
||||
@property (strong, nonatomic) UIActivityIndicatorView *loading;
|
||||
@end
|
||||
|
||||
@implementation HXHUD
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame imageName:(NSString *)imageName text:(NSString *)text {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
_text = text;
|
||||
self.imageName = imageName;
|
||||
self.layer.masksToBounds = YES;
|
||||
self.layer.cornerRadius = 5;
|
||||
[self addSubview:self.visualEffectView];
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
UIImage *image = self.imageName.length ? [UIImage hx_imageNamed:self.imageName] : nil;
|
||||
self.isImage = image != nil;
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
}
|
||||
self.imageView = [[UIImageView alloc] initWithImage:image];
|
||||
[self addSubview:self.imageView];
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
self.imageView.tintColor = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
}
|
||||
|
||||
self.titleLb = [[UILabel alloc] init];
|
||||
self.titleLb.text = self.text;
|
||||
self.titleLb.textColor = [HXPhotoCommon photoCommon].isDark ? [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1] : [UIColor whiteColor];
|
||||
self.titleLb.textAlignment = NSTextAlignmentCenter;
|
||||
self.titleLb.font = [UIFont systemFontOfSize:14];
|
||||
self.titleLb.numberOfLines = 0;
|
||||
[self addSubview:self.titleLb];
|
||||
}
|
||||
- (void)setText:(NSString *)text {
|
||||
_text = text;
|
||||
self.titleLb.text = text;
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
CGFloat imgW = self.imageView.image.size.width;
|
||||
if (imgW <= 0) imgW = 37;
|
||||
CGFloat imgH = self.imageView.image.size.height;
|
||||
if (imgH <= 0) imgH = 37;
|
||||
CGFloat imgCenterX = self.frame.size.width / 2;
|
||||
self.imageView.frame = CGRectMake(0, 20, imgW, imgH);
|
||||
self.imageView.center = CGPointMake(imgCenterX, self.imageView.center.y);
|
||||
|
||||
self.titleLb.hx_x = 10;
|
||||
self.titleLb.hx_y = CGRectGetMaxY(self.imageView.frame) + 10;
|
||||
self.titleLb.hx_w = self.frame.size.width - 20;
|
||||
self.titleLb.hx_h = [self.titleLb hx_getTextHeight];
|
||||
if (self.text.length) {
|
||||
self.hx_h = CGRectGetMaxY(self.titleLb.frame) + 20;
|
||||
}
|
||||
if (_loading) {
|
||||
if (self.text) {
|
||||
self.loading.frame = self.imageView.frame;
|
||||
}else {
|
||||
self.loading.frame = self.bounds;
|
||||
}
|
||||
}
|
||||
}
|
||||
- (UIActivityIndicatorView *)loading {
|
||||
if (!_loading) {
|
||||
_loading = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
#ifdef __IPHONE_13_0
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
_loading.activityIndicatorViewStyle = UIActivityIndicatorViewStyleLarge;
|
||||
} else {
|
||||
_loading.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
|
||||
}
|
||||
_loading.color = [UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1];
|
||||
}
|
||||
#endif
|
||||
[_loading startAnimating];
|
||||
}
|
||||
return _loading;
|
||||
}
|
||||
- (void)showloading {
|
||||
[self addSubview:self.loading];
|
||||
self.imageView.hidden = YES;
|
||||
}
|
||||
|
||||
- (UIVisualEffectView *)visualEffectView {
|
||||
if (!_visualEffectView) {
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
UIBlurEffect *blurEffrct =[UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
|
||||
_visualEffectView = [[UIVisualEffectView alloc]initWithEffect:blurEffrct];
|
||||
}else {
|
||||
UIBlurEffect *blurEffrct =[UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
_visualEffectView = [[UIVisualEffectView alloc]initWithEffect:blurEffrct];
|
||||
}
|
||||
_visualEffectView.frame = self.bounds;
|
||||
}
|
||||
return _visualEffectView;
|
||||
}
|
||||
@end
|
161
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIViewController+HXExtension.h
generated
Normal file
161
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIViewController+HXExtension.h
generated
Normal file
|
@ -0,0 +1,161 @@
|
|||
//
|
||||
// UIViewController+HXExtension.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/11/24.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "HXCustomCameraViewController.h"
|
||||
#import "HXPhotoEditViewController.h"
|
||||
#import "HX_PhotoEditViewController.h"
|
||||
#import "HXVideoEditViewController.h"
|
||||
#import "HXPhotoView.h"
|
||||
#import "HXCustomNavigationController.h"
|
||||
|
||||
@class HXPhotoView;
|
||||
@interface UIViewController (HXExtension)
|
||||
|
||||
/// 跳转相册列表
|
||||
/// @param manager 照片管理者
|
||||
/// @param models NSArray<HXPhotoModel *> *allList - 所选的所有模型数组
|
||||
/// NSArray<HXPhotoModel *> *videoList - 所选的视频模型数组
|
||||
/// NSArray<HXPhotoModel *> *photoList - 所选的照片模型数组
|
||||
/// BOOL original - 是否原图
|
||||
/// UIViewController *viewController 相册列表控制器
|
||||
/// @param cancel 取消选择
|
||||
- (void)hx_presentSelectPhotoControllerWithManager:(HXPhotoManager *_Nullable)manager
|
||||
didDone:(void (^_Nullable)
|
||||
(NSArray<HXPhotoModel *> * _Nullable allList,
|
||||
NSArray<HXPhotoModel *> * _Nullable photoList,
|
||||
NSArray<HXPhotoModel *> * _Nullable videoList,
|
||||
BOOL isOriginal,
|
||||
UIViewController * _Nullable viewController,
|
||||
HXPhotoManager * _Nullable manager))models
|
||||
cancel:(void (^_Nullable)
|
||||
(UIViewController * _Nullable viewController,
|
||||
HXPhotoManager * _Nullable manager))cancel;
|
||||
|
||||
/// 跳转相册列表
|
||||
/// @param delegate HXCustomNavigationControllerDelegate
|
||||
- (void)hx_presentSelectPhotoControllerWithManager:(HXPhotoManager * _Nullable)manager
|
||||
delegate:(id _Nullable )delegate;
|
||||
|
||||
/// 跳转预览照片界面
|
||||
/// @param manager 照片管理者
|
||||
/// @param previewStyle 预览样式
|
||||
/// @param currentIndex 当前预览的下标
|
||||
/// @param photoView 照片展示视图 - 没有就不传
|
||||
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager * _Nullable)manager
|
||||
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
|
||||
currentIndex:(NSUInteger)currentIndex
|
||||
photoView:(HXPhotoView * _Nullable)photoView;
|
||||
|
||||
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager * _Nullable)manager
|
||||
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
|
||||
showBottomPageControl:(BOOL)showBottomPageControl
|
||||
currentIndex:(NSUInteger)currentIndex;
|
||||
|
||||
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager * _Nullable)manager
|
||||
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
|
||||
showBottomPageControl:(BOOL)showBottomPageControl
|
||||
currentIndex:(NSUInteger)currentIndex
|
||||
photoView:(HXPhotoView * _Nullable)photoView;
|
||||
|
||||
/// 跳转相机界面
|
||||
/// @param manager 照片管理者
|
||||
/// @param delegate 代理
|
||||
- (void)hx_presentCustomCameraViewControllerWithManager:(HXPhotoManager * _Nullable)manager
|
||||
delegate:(id _Nullable )delegate;
|
||||
|
||||
/// 跳转相机界面
|
||||
/// @param manager 照片管理者
|
||||
/// @param done 完成回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentCustomCameraViewControllerWithManager:(HXPhotoManager * _Nullable)manager
|
||||
done:(HXCustomCameraViewControllerDidDoneBlock _Nullable )done
|
||||
cancel:(HXCustomCameraViewControllerDidCancelBlock _Nullable )cancel;
|
||||
|
||||
/// 跳转照片编辑界面
|
||||
/// @param manager 照片管理者,主要设置编辑参数
|
||||
/// @param photomodel 需要编辑的照片模型
|
||||
/// @param delegate 代理
|
||||
/// @param done 完成回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentPhotoEditViewControllerWithManager:(HXPhotoManager * _Nonnull)manager
|
||||
photoModel:(HXPhotoModel * _Nonnull)photomodel
|
||||
delegate:(id _Nullable )delegate
|
||||
done:(HXPhotoEditViewControllerDidDoneBlock _Nullable)done
|
||||
cancel:(HXPhotoEditViewControllerDidCancelBlock _Nullable)cancel;
|
||||
|
||||
/// 跳转照片编辑界面
|
||||
/// @param manager 照片管理者,主要设置编辑参数
|
||||
/// @param editPhoto 需要编辑的照片
|
||||
/// @param done 完成回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentPhotoEditViewControllerWithManager:(HXPhotoManager * _Nonnull)manager
|
||||
editPhoto:(UIImage * _Nonnull)editPhoto
|
||||
done:(HXPhotoEditViewControllerDidDoneBlock _Nullable)done
|
||||
cancel:(HXPhotoEditViewControllerDidCancelBlock _Nullable)cancel;
|
||||
|
||||
/// 跳转视频编辑界面
|
||||
/// @param manager 照片管理者,主要设置编辑参数
|
||||
/// @param videoModel 需要编辑的视频模型
|
||||
/// @param delegate 代理
|
||||
/// @param done 完成后的回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentVideoEditViewControllerWithManager:(HXPhotoManager * _Nonnull)manager
|
||||
videoModel:(HXPhotoModel * _Nonnull)videoModel
|
||||
delegate:(id _Nullable )delegate
|
||||
done:(HXVideoEditViewControllerDidDoneBlock _Nullable)done
|
||||
cancel:(HXVideoEditViewControllerDidCancelBlock _Nullable)cancel;
|
||||
|
||||
/// 跳转视频编辑界面
|
||||
/// @param manager 照片管理者,主要设置编辑参数
|
||||
/// @param videoURL 需要编辑的视频本地地址
|
||||
/// @param done 完成后的回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentVideoEditViewControllerWithManager:(HXPhotoManager * _Nonnull)manager
|
||||
videoURL:(NSURL * _Nonnull)videoURL
|
||||
done:(HXVideoEditViewControllerDidDoneBlock _Nullable)done
|
||||
cancel:(HXVideoEditViewControllerDidCancelBlock _Nullable)cancel;
|
||||
|
||||
/// 跳转仿微信照片编辑界面
|
||||
/// @param configuration 配置
|
||||
/// @param photomodel 需要编辑的照片模型
|
||||
/// 如果需要在原有编辑的基础上进行编辑,直接将之前编辑model传入即可
|
||||
/// 如果不需要在原有基础上编辑,请将 model.photoEdit 置为nil
|
||||
/// @param delegate 代理
|
||||
/// @param finish 完成后的回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentWxPhotoEditViewControllerWithConfiguration:(HXPhotoEditConfiguration * _Nonnull)configuration
|
||||
photoModel:(HXPhotoModel * _Nonnull)photomodel
|
||||
delegate:(id _Nullable)delegate
|
||||
finish:(HX_PhotoEditViewControllerDidFinishBlock _Nullable)finish
|
||||
cancel:(HX_PhotoEditViewControllerDidCancelBlock _Nullable)cancel;
|
||||
|
||||
/// 跳转仿微信照片编辑界面
|
||||
/// @param configuration 配置
|
||||
/// @param editImage 需要编辑的图片
|
||||
/// @param photoEdit 之前编辑的数据,为nil则重新开始编辑
|
||||
/// @param finish 完成后的回调
|
||||
/// @param cancel 取消回调
|
||||
- (void)hx_presentWxPhotoEditViewControllerWithConfiguration:(HXPhotoEditConfiguration * _Nonnull)configuration
|
||||
editImage:(UIImage * _Nonnull)editImage
|
||||
photoEdit:(HXPhotoEdit * _Nullable)photoEdit
|
||||
finish:(HX_PhotoEditViewControllerDidFinishBlock _Nullable)finish
|
||||
cancel:(HX_PhotoEditViewControllerDidCancelBlock _Nullable)cancel;
|
||||
|
||||
- (BOOL)hx_navigationBarWhetherSetupBackground;
|
||||
|
||||
- (HXCustomNavigationController *_Nullable)hx_customNavigationController;
|
||||
|
||||
#pragma mark - < obsoleting >
|
||||
/* <HXAlbumListViewControllerDelegate>
|
||||
* delegate 不传则代表自己
|
||||
*/
|
||||
- (void)hx_presentAlbumListViewControllerWithManager:(HXPhotoManager *_Nullable)manager
|
||||
delegate:(id _Nullable )delegate DEPRECATED_MSG_ATTRIBUTE("Use 'hx_presentSelectPhotoControllerWithManager:' instead");
|
||||
@end
|
252
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIViewController+HXExtension.m
generated
Normal file
252
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Category/UIViewController+HXExtension.m
generated
Normal file
|
@ -0,0 +1,252 @@
|
|||
//
|
||||
// UIViewController+HXExtension.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/11/24.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "UIViewController+HXExtension.h"
|
||||
#import "HXPhotoPicker.h"
|
||||
|
||||
@implementation UIViewController (HXExtension)
|
||||
- (void)hx_presentAlbumListViewControllerWithManager:(HXPhotoManager *)manager
|
||||
delegate:(id)delegate {
|
||||
NSSLog(@"Use 'hx_presentSelectPhotoControllerWithManager:'");
|
||||
// HXAlbumListViewController *vc = [[HXAlbumListViewController alloc] initWithManager:manager];
|
||||
// vc.delegate = delegate ? delegate : (id)self;
|
||||
// HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithRootViewController:vc];
|
||||
// nav.supportRotation = manager.configuration.supportRotation;
|
||||
// nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
// nav.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
// [self presentViewController:nav animated:YES completion:nil];
|
||||
}
|
||||
- (void)hx_presentSelectPhotoControllerWithManager:(HXPhotoManager *)manager
|
||||
didDone:(void (^)(NSArray<HXPhotoModel *> *, NSArray<HXPhotoModel *> *, NSArray<HXPhotoModel *> *, BOOL, UIViewController *, HXPhotoManager *))models
|
||||
cancel:(void (^)(UIViewController *, HXPhotoManager *))cancel {
|
||||
|
||||
viewControllerDidDoneBlock modelBlock = ^(NSArray<HXPhotoModel *> *allList, NSArray<HXPhotoModel *> *photoList, NSArray<HXPhotoModel *> *videoList, BOOL original, UIViewController *viewController, HXPhotoManager *manager) {
|
||||
if (models) {
|
||||
models(allList, photoList, videoList, original, viewController, manager);
|
||||
}
|
||||
};
|
||||
viewControllerDidCancelBlock cancelBlock = ^(UIViewController *viewController, HXPhotoManager *manager) {
|
||||
if (cancel) {
|
||||
cancel(viewController, manager);
|
||||
}
|
||||
};
|
||||
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithManager:manager doneBlock:modelBlock cancelBlock:cancelBlock];
|
||||
[self presentViewController:nav animated:YES completion:nil];
|
||||
}
|
||||
- (void)hx_presentSelectPhotoControllerWithManager:(HXPhotoManager *_Nullable)manager
|
||||
delegate:(id _Nullable )delegate {
|
||||
|
||||
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithManager:manager delegate:delegate];
|
||||
[self presentViewController:nav animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentCustomCameraViewControllerWithManager:(HXPhotoManager *)manager
|
||||
delegate:(id)delegate {
|
||||
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[self.view hx_showImageHUDText:[NSBundle hx_localizedStringForKey:@"无法使用相机!"]];
|
||||
return;
|
||||
}
|
||||
HXWeakSelf
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (granted) {
|
||||
HXCustomCameraViewController *vc = [[HXCustomCameraViewController alloc] init];
|
||||
vc.delegate = delegate ? delegate : (id)weakSelf;
|
||||
vc.manager = manager;
|
||||
vc.isOutside = YES;
|
||||
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithRootViewController:vc];
|
||||
nav.isCamera = YES;
|
||||
nav.supportRotation = manager.configuration.supportRotation;
|
||||
nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
nav.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[weakSelf presentViewController:nav animated:YES completion:nil];
|
||||
}else {
|
||||
[HXPhotoTools showUnusableCameraAlert:weakSelf];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)hx_presentCustomCameraViewControllerWithManager:(HXPhotoManager *)manager
|
||||
done:(HXCustomCameraViewControllerDidDoneBlock)done
|
||||
cancel:(HXCustomCameraViewControllerDidCancelBlock)cancel {
|
||||
if(![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
|
||||
[self.view hx_showImageHUDText:[NSBundle hx_localizedStringForKey:@"无法使用相机!"]];
|
||||
return;
|
||||
}
|
||||
HXWeakSelf
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (granted) {
|
||||
HXCustomCameraViewController *vc = [[HXCustomCameraViewController alloc] init];
|
||||
vc.doneBlock = done;
|
||||
vc.cancelBlock = cancel;
|
||||
vc.manager = manager;
|
||||
vc.isOutside = YES;
|
||||
HXCustomNavigationController *nav = [[HXCustomNavigationController alloc] initWithRootViewController:vc];
|
||||
nav.isCamera = YES;
|
||||
nav.supportRotation = manager.configuration.supportRotation;
|
||||
nav.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
nav.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[weakSelf presentViewController:nav animated:YES completion:nil];
|
||||
}else {
|
||||
[HXPhotoTools showUnusableCameraAlert:weakSelf];
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager *)manager
|
||||
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
|
||||
showBottomPageControl:(BOOL)showBottomPageControl
|
||||
currentIndex:(NSUInteger)currentIndex {
|
||||
[self hx_presentPreviewPhotoControllerWithManager:manager previewStyle:previewStyle showBottomPageControl:showBottomPageControl currentIndex:currentIndex photoView:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager *)manager
|
||||
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
|
||||
currentIndex:(NSUInteger)currentIndex
|
||||
photoView:(HXPhotoView * _Nullable)photoView {
|
||||
[self hx_presentPreviewPhotoControllerWithManager:manager previewStyle:previewStyle showBottomPageControl:YES currentIndex:currentIndex photoView:photoView];
|
||||
}
|
||||
|
||||
- (void)hx_presentPreviewPhotoControllerWithManager:(HXPhotoManager *)manager
|
||||
previewStyle:(HXPhotoViewPreViewShowStyle)previewStyle
|
||||
showBottomPageControl:(BOOL)showBottomPageControl
|
||||
currentIndex:(NSUInteger)currentIndex
|
||||
photoView:(HXPhotoView * _Nullable)photoView {
|
||||
|
||||
HXPhotoPreviewViewController *vc = [[HXPhotoPreviewViewController alloc] init];
|
||||
vc.disableaPersentInteractiveTransition = photoView.disableaInteractiveTransition;
|
||||
vc.outside = YES;
|
||||
vc.manager = manager ?: photoView.manager;
|
||||
vc.exteriorPreviewStyle = photoView ? photoView.previewStyle : previewStyle;
|
||||
vc.delegate = (id)self;
|
||||
if (manager.afterSelectedArray) {
|
||||
vc.modelArray = [NSMutableArray arrayWithArray:manager.afterSelectedArray];
|
||||
}
|
||||
if (currentIndex >= vc.modelArray.count) {
|
||||
vc.currentModelIndex = vc.modelArray.count - 1;
|
||||
}else if (currentIndex < 0) {
|
||||
vc.currentModelIndex = 0;
|
||||
}else {
|
||||
vc.currentModelIndex = currentIndex;
|
||||
}
|
||||
if (photoView) {
|
||||
vc.showBottomPageControl = photoView.previewShowDeleteButton;
|
||||
}else {
|
||||
vc.showBottomPageControl = showBottomPageControl;
|
||||
}
|
||||
vc.previewShowDeleteButton = photoView.previewShowDeleteButton;
|
||||
vc.photoView = photoView;
|
||||
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
vc.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentWxPhotoEditViewControllerWithConfiguration:(HXPhotoEditConfiguration * _Nonnull)configuration
|
||||
photoModel:(HXPhotoModel * _Nonnull)photomodel
|
||||
delegate:(id _Nullable)delegate
|
||||
finish:(HX_PhotoEditViewControllerDidFinishBlock _Nullable)finish
|
||||
cancel:(HX_PhotoEditViewControllerDidCancelBlock _Nullable)cancel {
|
||||
HX_PhotoEditViewController *vc = [[HX_PhotoEditViewController alloc] initWithConfiguration:configuration];
|
||||
vc.delegate = delegate ?: self;
|
||||
vc.photoModel = photomodel;
|
||||
vc.finishBlock = finish;
|
||||
vc.cancelBlock = cancel;
|
||||
vc.supportRotation = YES;
|
||||
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
vc.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentWxPhotoEditViewControllerWithConfiguration:(HXPhotoEditConfiguration * _Nonnull)configuration
|
||||
editImage:(UIImage * _Nonnull)editImage
|
||||
photoEdit:(HXPhotoEdit * _Nullable)photoEdit
|
||||
finish:(HX_PhotoEditViewControllerDidFinishBlock _Nullable)finish
|
||||
cancel:(HX_PhotoEditViewControllerDidCancelBlock _Nullable)cancel {
|
||||
HXPhotoModel *photoModel = [HXPhotoModel photoModelWithImage:editImage];
|
||||
photoModel.photoEdit = photoEdit;
|
||||
[self hx_presentWxPhotoEditViewControllerWithConfiguration:configuration
|
||||
photoModel:photoModel
|
||||
delegate:nil
|
||||
finish:finish
|
||||
cancel:cancel];
|
||||
}
|
||||
- (void)hx_presentPhotoEditViewControllerWithManager:(HXPhotoManager *)manager
|
||||
photoModel:(HXPhotoModel *)photomodel
|
||||
delegate:(id)delegate
|
||||
done:(HXPhotoEditViewControllerDidDoneBlock)done
|
||||
cancel:(HXPhotoEditViewControllerDidCancelBlock)cancel {
|
||||
HXPhotoEditViewController *vc = [[HXPhotoEditViewController alloc] init];
|
||||
vc.isInside = YES;
|
||||
vc.delegate = delegate ?: self;
|
||||
vc.manager = manager;
|
||||
vc.model = photomodel;
|
||||
vc.doneBlock = done;
|
||||
vc.cancelBlock = cancel;
|
||||
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
vc.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentPhotoEditViewControllerWithManager:(HXPhotoManager * _Nonnull)manager
|
||||
editPhoto:(UIImage * _Nonnull)editPhoto
|
||||
done:(HXPhotoEditViewControllerDidDoneBlock _Nullable)done
|
||||
cancel:(HXPhotoEditViewControllerDidCancelBlock _Nullable)cancel {
|
||||
HXPhotoModel *photoModel = [HXPhotoModel photoModelWithImage:editPhoto];
|
||||
[self hx_presentPhotoEditViewControllerWithManager:manager photoModel:photoModel delegate:nil done:done cancel:cancel];
|
||||
}
|
||||
|
||||
- (void)hx_presentVideoEditViewControllerWithManager:(HXPhotoManager *)manager
|
||||
videoModel:(HXPhotoModel *)videoModel
|
||||
delegate:(id)delegate
|
||||
done:(HXVideoEditViewControllerDidDoneBlock)done
|
||||
cancel:(HXVideoEditViewControllerDidCancelBlock)cancel {
|
||||
HXVideoEditViewController *vc = [[HXVideoEditViewController alloc] init];
|
||||
vc.model = videoModel;
|
||||
vc.delegate = delegate ?: self;
|
||||
vc.manager = manager;
|
||||
vc.isInside = YES;
|
||||
vc.doneBlock = done;
|
||||
vc.cancelBlock = cancel;
|
||||
vc.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
vc.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
[self presentViewController:vc animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)hx_presentVideoEditViewControllerWithManager:(HXPhotoManager * _Nonnull)manager
|
||||
videoURL:(NSURL * _Nonnull)videoURL
|
||||
done:(HXVideoEditViewControllerDidDoneBlock _Nullable)done
|
||||
cancel:(HXVideoEditViewControllerDidCancelBlock _Nullable)cancel {
|
||||
HXPhotoModel *videoModel = [HXPhotoModel photoModelWithVideoURL:videoURL];
|
||||
[self hx_presentVideoEditViewControllerWithManager:manager videoModel:videoModel delegate:nil done:done cancel:cancel];
|
||||
}
|
||||
|
||||
- (BOOL)hx_navigationBarWhetherSetupBackground {
|
||||
if ([self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]) {
|
||||
return YES;
|
||||
}else if ([self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsCompact]) {
|
||||
return YES;
|
||||
}else if ([self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefaultPrompt]) {
|
||||
return YES;
|
||||
}else if ([self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsCompactPrompt]) {
|
||||
return YES;
|
||||
}else if (self.navigationController.navigationBar.backgroundColor) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (HXCustomNavigationController *)hx_customNavigationController {
|
||||
if ([NSStringFromClass([self.navigationController class]) isEqualToString:@"HXCustomNavigationController"]) {
|
||||
return (HXCustomNavigationController *)self.navigationController;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@end
|
65
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXAlbumListViewController.h
generated
Normal file
65
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXAlbumListViewController.h
generated
Normal file
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// HXDateAlbumViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXAlbumModel.h"
|
||||
#import "HXPhotoManager.h"
|
||||
#import "HXPickerResult.h"
|
||||
|
||||
@class HXAlbumListViewController;
|
||||
|
||||
@protocol HXAlbumListViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
点击取消
|
||||
|
||||
@param albumListViewController self
|
||||
*/
|
||||
- (void)albumListViewControllerDidCancel:(HXAlbumListViewController *)albumListViewController;
|
||||
|
||||
/**
|
||||
点击完成
|
||||
|
||||
@param albumListViewController self
|
||||
@param allList 已选的所有列表(包含照片、视频)
|
||||
@param photoList 已选的照片列表
|
||||
@param videoList 已选的视频列表
|
||||
@param original 是否原图
|
||||
*/
|
||||
- (void)albumListViewController:(HXAlbumListViewController *)albumListViewController
|
||||
didDoneAllList:(NSArray<HXPhotoModel *> *)allList
|
||||
photos:(NSArray<HXPhotoModel *> *)photoList
|
||||
videos:(NSArray<HXPhotoModel *> *)videoList
|
||||
original:(BOOL)original;
|
||||
|
||||
- (void)albumListViewController:(HXAlbumListViewController *)albumListViewController
|
||||
didDoneWithResult:(HXPickerResult *)result;
|
||||
|
||||
- (void)albumListViewControllerFinishDismissCompletion:(HXAlbumListViewController *)albumListViewController;
|
||||
- (void)albumListViewControllerCancelDismissCompletion:(HXAlbumListViewController *)albumListViewController;
|
||||
@end
|
||||
|
||||
@interface HXAlbumListViewController : UIViewController
|
||||
@property (weak, nonatomic) id<HXAlbumListViewControllerDelegate> delegate;
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
@property (copy, nonatomic) viewControllerDidDoneBlock doneBlock;
|
||||
@property (copy, nonatomic) viewControllerDidCancelBlock cancelBlock;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager;
|
||||
@end
|
||||
|
||||
@interface HXAlbumListSingleViewCell : UITableViewCell
|
||||
@property (strong, nonatomic) UIColor *bgColor;
|
||||
@property (strong, nonatomic) UIColor *textColor;
|
||||
@property (strong, nonatomic) UIColor *selectedBgColor;
|
||||
@property (strong, nonatomic) UIColor *lineViewColor;
|
||||
|
||||
@property (strong, nonatomic) HXAlbumModel *model;
|
||||
@property (copy, nonatomic) void (^getResultCompleteBlock)(NSInteger count, HXAlbumListSingleViewCell *myCell);
|
||||
- (void)cancelRequest ;
|
||||
@end
|
632
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXAlbumListViewController.m
generated
Normal file
632
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXAlbumListViewController.m
generated
Normal file
|
@ -0,0 +1,632 @@
|
|||
//
|
||||
// HXDateAlbumViewController.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXAlbumListViewController.h"
|
||||
#import "HXPhotoViewController.h"
|
||||
#import "UIViewController+HXExtension.h"
|
||||
#import "HXAssetManager.h"
|
||||
|
||||
@interface HXAlbumListViewController ()
|
||||
<
|
||||
HXPhotoViewControllerDelegate,
|
||||
UITableViewDataSource,
|
||||
UITableViewDelegate
|
||||
>
|
||||
@property (strong, nonatomic) UITableView *tableView;
|
||||
@property (strong, nonatomic) NSMutableArray *albumModelArray;
|
||||
@property (strong, nonatomic) UILabel *authorizationLb;
|
||||
@property (assign, nonatomic) BOOL orientationDidChange;
|
||||
@property (strong, nonatomic) NSIndexPath *beforeOrientationIndexPath;
|
||||
@end
|
||||
|
||||
@implementation HXAlbumListViewController
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.manager = manager;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)requestData {
|
||||
// 获取当前应用对照片的访问授权状态
|
||||
HXWeakSelf
|
||||
self.hx_customNavigationController.reloadAsset = ^(BOOL initialAuthorization){
|
||||
if (initialAuthorization) {
|
||||
[weakSelf authorizationHandler];
|
||||
}
|
||||
};
|
||||
[self authorizationHandler];
|
||||
}
|
||||
|
||||
- (void)authorizationHandler {
|
||||
PHAuthorizationStatus status = [HXPhotoTools authorizationStatus];
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
[self getAlbumModelList:YES];
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
else if (@available(iOS 14, *)) {
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
[self getAlbumModelList:YES];
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
else if (status == PHAuthorizationStatusDenied ||
|
||||
status == PHAuthorizationStatusRestricted){
|
||||
[self.hx_customNavigationController.view hx_handleLoading];
|
||||
[self.view addSubview:self.authorizationLb];
|
||||
[HXPhotoTools showNoAuthorizedAlertWithViewController:self status:status];
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
}else if (status == PHAuthorizationStatusDenied ||
|
||||
status == PHAuthorizationStatusRestricted){
|
||||
[self.hx_customNavigationController.view hx_handleLoading];
|
||||
[self.view addSubview:self.authorizationLb];
|
||||
[HXPhotoTools showNoAuthorizedAlertWithViewController:self status:status];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
return UIStatusBarStyleLightContent;
|
||||
}
|
||||
return self.manager.configuration.statusBarStyle;
|
||||
}
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
#ifdef __IPHONE_13_0
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
|
||||
[self changeColor];
|
||||
[self changeStatusBarStyle];
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
UIColor *authorizationColor = self.manager.configuration.authorizationTipColor;
|
||||
_authorizationLb.textColor = [HXPhotoCommon photoCommon].isDark ? [UIColor whiteColor] : authorizationColor;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
self.extendedLayoutIncludesOpaqueBars = YES;
|
||||
self.edgesForExtendedLayout = UIRectEdgeAll;
|
||||
self.navigationController.popoverPresentationController.delegate = (id)self;
|
||||
[self requestData];
|
||||
[self setupUI];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(customCameraViewControllerDidDoneClick) name:@"CustomCameraViewControllerDidDoneNotification" object:nil];
|
||||
}
|
||||
- (void)customCameraViewControllerDidDoneClick {
|
||||
NSInteger i = 0;
|
||||
for (HXAlbumModel *albumMd in self.albumModelArray) {
|
||||
albumMd.cameraCount = [self.manager cameraCount];
|
||||
if (i == 0 && !albumMd.localIdentifier) {
|
||||
albumMd.tempImage = [self.manager firstCameraModel].thumbPhoto;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
- (void)viewDidLayoutSubviews {
|
||||
[super viewDidLayoutSubviews];
|
||||
if (self.orientationDidChange) {
|
||||
[self changeSubviewFrame];
|
||||
self.orientationDidChange = NO;
|
||||
}
|
||||
}
|
||||
- (void)deviceOrientationChanged:(NSNotification *)notify {
|
||||
self.orientationDidChange = YES;
|
||||
}
|
||||
- (void)changeSubviewFrame {
|
||||
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
CGFloat navBarHeight = hxNavigationBarHeight;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown || HX_UI_IS_IPAD) {
|
||||
navBarHeight = hxNavigationBarHeight;
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
|
||||
}else if (orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft){
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
|
||||
if ([UIApplication sharedApplication].statusBarHidden) {
|
||||
navBarHeight = self.navigationController.navigationBar.hx_h;
|
||||
}else {
|
||||
navBarHeight = self.navigationController.navigationBar.hx_h + 20;
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
CGFloat leftMargin = 0;
|
||||
CGFloat rightMargin = 0;
|
||||
CGFloat bottomMargin = hxBottomMargin;
|
||||
if (HX_IS_IPhoneX_All && (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)) {
|
||||
leftMargin = 35;
|
||||
rightMargin = 35;
|
||||
bottomMargin = 0;
|
||||
}
|
||||
|
||||
self.tableView.contentInset = UIEdgeInsetsMake(navBarHeight, leftMargin, bottomMargin, rightMargin);
|
||||
|
||||
#ifdef __IPHONE_13_0
|
||||
if (@available(iOS 13.0, *)) {
|
||||
}else {
|
||||
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(navBarHeight, leftMargin, bottomMargin, rightMargin);
|
||||
}
|
||||
#else
|
||||
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(navBarHeight, leftMargin, bottomMargin, rightMargin);
|
||||
#endif
|
||||
self.tableView.frame = self.view.bounds;
|
||||
if (self.manager.configuration.albumListTableView) {
|
||||
self.manager.configuration.albumListTableView(self.tableView);
|
||||
}
|
||||
|
||||
self.navigationController.navigationBar.translucent = self.manager.configuration.navBarTranslucent;
|
||||
if (self.manager.configuration.navigationBar) {
|
||||
self.manager.configuration.navigationBar(self.navigationController.navigationBar, self);
|
||||
}
|
||||
}
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
[self changeStatusBarStyle];
|
||||
if (self.manager.viewWillAppear) {
|
||||
self.manager.viewWillAppear(self);
|
||||
}
|
||||
}
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
if (self.manager.viewWillDisappear) {
|
||||
self.manager.viewWillDisappear(self);
|
||||
}
|
||||
}
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
if (self.manager.viewDidDisappear) {
|
||||
self.manager.viewDidDisappear(self);
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
- (void)changeStatusBarStyle {
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
|
||||
return;
|
||||
}
|
||||
[[UIApplication sharedApplication] setStatusBarStyle:self.manager.configuration.statusBarStyle animated:YES];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
if (!self.albumModelArray.count) {
|
||||
PHAuthorizationStatus status = [HXPhotoTools authorizationStatus];
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
[self getAlbumModelList:NO];
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
else if (@available(iOS 14, *)) {
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
[self getAlbumModelList:NO];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (self.manager.viewDidAppear) {
|
||||
self.manager.viewDidAppear(self);
|
||||
}
|
||||
}
|
||||
- (void)setupUI {
|
||||
self.title = [NSBundle hx_localizedStringForKey:@"相册"];
|
||||
[self changeColor];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[NSBundle hx_localizedStringForKey:@"取消"] style:UIBarButtonItemStyleDone target:self action:@selector(cancelClick)];
|
||||
if (self.manager.configuration.navigationBar) {
|
||||
self.manager.configuration.navigationBar(self.navigationController.navigationBar, self);
|
||||
}
|
||||
}
|
||||
- (void)changeColor {
|
||||
UIColor *backgroudColor;
|
||||
UIColor *themeColor;
|
||||
UIColor *navBarBackgroudColor;
|
||||
UIColor *navigationTitleColor;
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
backgroudColor = [UIColor colorWithRed:0.075 green:0.075 blue:0.075 alpha:1];
|
||||
themeColor = [UIColor whiteColor];
|
||||
navBarBackgroudColor = [UIColor blackColor];
|
||||
navigationTitleColor = [UIColor whiteColor];
|
||||
}else {
|
||||
backgroudColor = self.manager.configuration.albumListViewBgColor;
|
||||
themeColor = self.manager.configuration.themeColor;
|
||||
navBarBackgroudColor = self.manager.configuration.navBarBackgroudColor;
|
||||
navigationTitleColor = self.manager.configuration.navigationTitleColor;
|
||||
}
|
||||
self.view.backgroundColor = backgroudColor;
|
||||
self.tableView.backgroundColor = backgroudColor;
|
||||
[self.navigationController.navigationBar setTintColor:themeColor];
|
||||
self.navigationController.navigationBar.barTintColor = navBarBackgroudColor;
|
||||
self.navigationController.navigationBar.barStyle = self.manager.configuration.navBarStyle;
|
||||
|
||||
if (self.manager.configuration.navBarBackgroundImage) {
|
||||
[self.navigationController.navigationBar setBackgroundImage:self.manager.configuration.navBarBackgroundImage forBarMetrics:UIBarMetricsDefault];
|
||||
}
|
||||
// if (navBarBackgroudColor) {
|
||||
// [self.navigationController.navigationBar setBackgroundColor:navBarBackgroudColor];
|
||||
// [self.navigationController.navigationBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
|
||||
// }
|
||||
|
||||
if (self.manager.configuration.navigationTitleSynchColor) {
|
||||
self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : themeColor};
|
||||
}else {
|
||||
if (navigationTitleColor) {
|
||||
self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : navigationTitleColor};
|
||||
}else {
|
||||
self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName : [UIColor blackColor]};
|
||||
}
|
||||
}
|
||||
if (@available(iOS 15.0, *)) {
|
||||
UINavigationBarAppearance *appearance = [[UINavigationBarAppearance alloc] init];
|
||||
appearance.titleTextAttributes = self.navigationController.navigationBar.titleTextAttributes;
|
||||
switch (self.manager.configuration.navBarStyle) {
|
||||
case UIBarStyleDefault:
|
||||
appearance.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
|
||||
break;
|
||||
default:
|
||||
appearance.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
break;
|
||||
}
|
||||
self.navigationController.navigationBar.standardAppearance = appearance;
|
||||
self.navigationController.navigationBar.scrollEdgeAppearance = appearance;
|
||||
}
|
||||
}
|
||||
- (void)configTableView {
|
||||
[self.view addSubview:self.tableView];
|
||||
|
||||
[self changeSubviewFrame];
|
||||
}
|
||||
- (void)cancelClick {
|
||||
[self.manager cancelBeforeSelectedList];
|
||||
if ([self.delegate respondsToSelector:@selector(albumListViewControllerDidCancel:)]) {
|
||||
[self.delegate albumListViewControllerDidCancel:self];
|
||||
}
|
||||
if (self.cancelBlock) {
|
||||
self.cancelBlock(self, self.manager);
|
||||
}
|
||||
self.manager.selectPhotoing = NO;
|
||||
|
||||
BOOL selectPhotoCancelDismissAnimated = self.manager.selectPhotoCancelDismissAnimated;
|
||||
[self dismissViewControllerAnimated:selectPhotoCancelDismissAnimated completion:^{
|
||||
if ([self.delegate respondsToSelector:@selector(albumListViewControllerCancelDismissCompletion:)]) {
|
||||
[self.delegate albumListViewControllerCancelDismissCompletion:self];
|
||||
}
|
||||
}];
|
||||
}
|
||||
#pragma mark - < HXPhotoViewControllerDelegate >
|
||||
- (void)photoViewController:(HXPhotoViewController *)photoViewController didDoneAllList:(NSArray<HXPhotoModel *> *)allList photos:(NSArray<HXPhotoModel *> *)photoList videos:(NSArray<HXPhotoModel *> *)videoList original:(BOOL)original {
|
||||
if ([self.delegate respondsToSelector:@selector(albumListViewController:didDoneAllList:photos:videos:original:)]) {
|
||||
[self.delegate albumListViewController:self didDoneAllList:allList photos:photoList videos:videoList original:original];
|
||||
}
|
||||
if (self.doneBlock) {
|
||||
self.doneBlock(allList, photoList, videoList, original, self, self.manager);
|
||||
}
|
||||
}
|
||||
- (void)photoViewController:(HXPhotoViewController *)photoViewController didDoneWithResult:(HXPickerResult *)result {
|
||||
if ([self.delegate respondsToSelector:@selector(albumListViewController:didDoneWithResult:)]) {
|
||||
[self.delegate albumListViewController:self
|
||||
didDoneWithResult:result];
|
||||
}
|
||||
}
|
||||
- (void)photoViewControllerDidCancel:(HXPhotoViewController *)photoViewController {
|
||||
[self cancelClick];
|
||||
}
|
||||
- (void)photoViewControllerDidChangeSelect:(HXPhotoModel *)model selected:(BOOL)selected {
|
||||
if (self.albumModelArray.count > 0) {
|
||||
// HXAlbumModel *albumModel = self.albumModelArray[model.currentAlbumIndex];
|
||||
// if (selected) {
|
||||
// albumModel.selectedCount++;
|
||||
// }else {
|
||||
// albumModel.selectedCount--;
|
||||
// }
|
||||
// [self.collectionView reloadItemsAtIndexPaths:@[[NSIndexPath indexPathForItem:model.currentAlbumIndex inSection:0]]];
|
||||
}
|
||||
}
|
||||
- (void)pushPhotoListViewControllerWithAlbumModel:(HXAlbumModel *)albumModel animated:(BOOL) animated {
|
||||
if (self.navigationController.topViewController != self) {
|
||||
[self.navigationController popToViewController:self animated:NO];
|
||||
}
|
||||
HXPhotoViewController *vc = [[HXPhotoViewController alloc] init];
|
||||
vc.manager = self.manager;
|
||||
vc.title = albumModel.albumName;
|
||||
vc.albumModel = albumModel;
|
||||
vc.delegate = self;
|
||||
[self.navigationController pushViewController:vc animated:animated];
|
||||
}
|
||||
- (void)getAlbumModelList:(BOOL)isFirst {
|
||||
HXWeakSelf
|
||||
if (isFirst) {
|
||||
if (self.hx_customNavigationController.cameraRollAlbumModel) {
|
||||
[self.view hx_handleLoading];
|
||||
[self pushPhotoListViewControllerWithAlbumModel:self.hx_customNavigationController.cameraRollAlbumModel animated:NO];
|
||||
}else {
|
||||
self.hx_customNavigationController.requestCameraRollCompletion = ^{
|
||||
[weakSelf.view hx_handleLoading];
|
||||
[weakSelf pushPhotoListViewControllerWithAlbumModel:weakSelf.hx_customNavigationController.cameraRollAlbumModel animated:NO];
|
||||
};
|
||||
}
|
||||
}else {
|
||||
[self configTableView];
|
||||
[self.view hx_showLoadingHUDText:nil];
|
||||
if (self.hx_customNavigationController.albums) {
|
||||
self.albumModelArray = self.hx_customNavigationController.albums;
|
||||
[self.tableView reloadData];
|
||||
[self.view hx_handleLoading:YES];
|
||||
}else {
|
||||
self.hx_customNavigationController.requestAllAlbumCompletion = ^{
|
||||
weakSelf.albumModelArray = weakSelf.hx_customNavigationController.albums;
|
||||
[weakSelf.tableView reloadData];
|
||||
[weakSelf.view hx_handleLoading:YES];
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - < UITableViewDataSource >
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.albumModelArray.count;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HXAlbumListSingleViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"tableViewCellId"];
|
||||
cell.bgColor = self.manager.configuration.albumListViewCellBgColor;
|
||||
cell.textColor = self.manager.configuration.albumListViewCellTextColor;
|
||||
cell.selectedBgColor = self.manager.configuration.albumListViewCellSelectBgColor;
|
||||
cell.lineViewColor = self.manager.configuration.albumListViewCellLineColor;
|
||||
cell.model = self.albumModelArray[indexPath.row];
|
||||
|
||||
HXWeakSelf
|
||||
cell.getResultCompleteBlock = ^(NSInteger count, HXAlbumListSingleViewCell *myCell) {
|
||||
if (count <= 0) {
|
||||
if ([weakSelf.albumModelArray containsObject:myCell.model]) {
|
||||
NSIndexPath *myIndexPath = [weakSelf.tableView indexPathForCell:myCell];
|
||||
if (myIndexPath) {
|
||||
[weakSelf.albumModelArray removeObject:myCell.model];
|
||||
[weakSelf.tableView deleteRowsAtIndexPaths:@[myIndexPath] withRowAnimation:UITableViewRowAnimationFade];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - < UITableViewDelegate >
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
if (self.navigationController.topViewController != self) {
|
||||
return;
|
||||
}
|
||||
[self.hx_customNavigationController clearAssetCache];
|
||||
HXAlbumModel *model = self.albumModelArray[indexPath.row];
|
||||
[self pushPhotoListViewControllerWithAlbumModel:model animated:YES];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return 100;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[(HXAlbumListSingleViewCell *)cell cancelRequest];
|
||||
}
|
||||
|
||||
#pragma mark - < 懒加载 >
|
||||
- (UITableView *)tableView {
|
||||
if (!_tableView) {
|
||||
_tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.hx_w, self.view.hx_h) style:UITableViewStylePlain];
|
||||
_tableView.dataSource = self;
|
||||
_tableView.delegate = self;
|
||||
_tableView.estimatedRowHeight = 0;
|
||||
_tableView.estimatedSectionFooterHeight = 0;
|
||||
_tableView.estimatedSectionHeaderHeight = 0;
|
||||
_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
[_tableView registerClass:[HXAlbumListSingleViewCell class] forCellReuseIdentifier:@"tableViewCellId"];
|
||||
#ifdef __IPHONE_11_0
|
||||
if (@available(iOS 11.0, *)) {
|
||||
// if ([self hx_navigationBarWhetherSetupBackground]) {
|
||||
// self.navigationController.navigationBar.translucent = NO;
|
||||
// }else {
|
||||
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
// }
|
||||
#else
|
||||
if ((NO)) {
|
||||
#endif
|
||||
} else {
|
||||
// if ([self hx_navigationBarWhetherSetupBackground]) {
|
||||
// self.navigationController.navigationBar.translucent = NO;
|
||||
// }else {
|
||||
self.automaticallyAdjustsScrollViewInsets = NO;
|
||||
// }
|
||||
}
|
||||
}
|
||||
return _tableView;
|
||||
}
|
||||
- (UILabel *)authorizationLb {
|
||||
if (!_authorizationLb) {
|
||||
_authorizationLb = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, self.view.frame.size.width, 100)];
|
||||
_authorizationLb.text = [NSBundle hx_localizedStringForKey:@"无法访问照片\n请点击这里前往设置中允许访问照片"];
|
||||
_authorizationLb.textAlignment = NSTextAlignmentCenter;
|
||||
_authorizationLb.numberOfLines = 0;
|
||||
UIColor *authorizationColor = self.manager.configuration.authorizationTipColor;
|
||||
_authorizationLb.textColor = [HXPhotoCommon photoCommon].isDark ? [UIColor whiteColor] : authorizationColor;
|
||||
_authorizationLb.font = [UIFont systemFontOfSize:15];
|
||||
_authorizationLb.userInteractionEnabled = YES;
|
||||
[_authorizationLb addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(goSetup)]];
|
||||
}
|
||||
return _authorizationLb;
|
||||
}
|
||||
- (void)dealloc {
|
||||
self.manager.selectPhotoing = NO;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"CustomCameraViewControllerDidDoneNotification" object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
|
||||
}
|
||||
- (void)goSetup {
|
||||
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
|
||||
if (@available(iOS 10.0, *)) {
|
||||
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
|
||||
}else {
|
||||
[[UIApplication sharedApplication] openURL:url];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@interface HXAlbumListSingleViewCell ()
|
||||
@property (strong, nonatomic) UIImageView *coverView1;
|
||||
@property (strong, nonatomic) UILabel *albumNameLb;
|
||||
@property (strong, nonatomic) UILabel *photoNumberLb;
|
||||
@property (assign, nonatomic) PHImageRequestID requestId1;
|
||||
@property (assign, nonatomic) PHImageRequestID requestId2;
|
||||
@property (assign, nonatomic) PHImageRequestID requestId3;
|
||||
@property (strong, nonatomic) UIView *lineView;
|
||||
@property (strong, nonatomic) UIView *selectBgView;
|
||||
@end
|
||||
|
||||
@implementation HXAlbumListSingleViewCell
|
||||
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
|
||||
if (self) {
|
||||
self.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
[self setupUI];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)setupUI {
|
||||
[self.contentView addSubview:self.coverView1];
|
||||
[self.contentView addSubview:self.albumNameLb];
|
||||
[self.contentView addSubview:self.photoNumberLb];
|
||||
[self.contentView addSubview:self.lineView];
|
||||
}
|
||||
- (void)cancelRequest {
|
||||
if (self.requestId1) {
|
||||
[[PHImageManager defaultManager] cancelImageRequest:self.requestId1];
|
||||
self.requestId1 = -1;
|
||||
}
|
||||
}
|
||||
- (void)setModel:(HXAlbumModel *)model {
|
||||
_model = model;
|
||||
[self changeColor];
|
||||
self.albumNameLb.text = self.model.albumName;
|
||||
if (!model.assetResult && model.localIdentifier) {
|
||||
HXWeakSelf
|
||||
[model getResultWithCompletion:^(HXAlbumModel *albumModel) {
|
||||
if (albumModel == weakSelf.model) {
|
||||
[weakSelf setAlbumImage];
|
||||
}
|
||||
}];
|
||||
}else {
|
||||
[self setAlbumImage];
|
||||
}
|
||||
if (!model.assetResult || !model.count) {
|
||||
self.coverView1.image = model.tempImage ?: [UIImage hx_imageNamed:@"hx_yundian_tupian"];
|
||||
}
|
||||
}
|
||||
- (void)setAlbumImage {
|
||||
NSInteger photoCount = self.model.count;
|
||||
HXWeakSelf
|
||||
PHAsset *asset = self.model.assetResult.lastObject;
|
||||
if (asset) {
|
||||
self.requestId1 = [HXAssetManager requestThumbnailImageForAsset:asset targetWidth:300 completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
if (weakSelf.model.assetResult.lastObject == asset && result) {
|
||||
weakSelf.coverView1.image = result;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
self.photoNumberLb.text = [@(photoCount + self.model.cameraCount).stringValue hx_countStrBecomeComma];
|
||||
if (self.getResultCompleteBlock) {
|
||||
self.getResultCompleteBlock(photoCount + self.model.cameraCount, self);
|
||||
}
|
||||
}
|
||||
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
|
||||
[super setHighlighted:highlighted animated:animated];
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
self.coverView1.frame = CGRectMake(10, 5, self.hx_h - 10, self.hx_h - 10);
|
||||
CGFloat albumNameLbX = CGRectGetMaxX(self.coverView1.frame) + 12;
|
||||
CGFloat albumNameLbY = self.hx_h / 2 - 16;
|
||||
self.albumNameLb.frame = CGRectMake(albumNameLbX, albumNameLbY, self.hx_w - albumNameLbX - 40, 14);
|
||||
self.photoNumberLb.frame = CGRectMake(albumNameLbX, self.hx_h / 2 + 4, self.hx_w, 13);
|
||||
self.lineView.frame = CGRectMake(10, self.hx_h - 0.5f, self.hx_w - 22, 0.5f);
|
||||
|
||||
self.selectBgView.frame = self.bounds;
|
||||
}
|
||||
- (void)dealloc {
|
||||
// [self cancelRequest];
|
||||
}
|
||||
#pragma mark - < cell懒加载 >
|
||||
- (UIView *)lineView {
|
||||
if (!_lineView) {
|
||||
_lineView = [[UIView alloc] init];
|
||||
}
|
||||
return _lineView;
|
||||
}
|
||||
- (UIImageView *)coverView1 {
|
||||
if (!_coverView1) {
|
||||
_coverView1 = [[UIImageView alloc] init];
|
||||
_coverView1.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_coverView1.clipsToBounds = YES;
|
||||
_coverView1.layer.borderColor = [UIColor whiteColor].CGColor;
|
||||
_coverView1.layer.borderWidth = 0.5f;
|
||||
}
|
||||
return _coverView1;
|
||||
}
|
||||
- (UILabel *)albumNameLb {
|
||||
if (!_albumNameLb) {
|
||||
_albumNameLb = [[UILabel alloc] init];
|
||||
_albumNameLb.font = [UIFont hx_mediumSFUITextOfSize:13];
|
||||
}
|
||||
return _albumNameLb;
|
||||
}
|
||||
- (UILabel *)photoNumberLb {
|
||||
if (!_photoNumberLb) {
|
||||
_photoNumberLb = [[UILabel alloc] init];
|
||||
_photoNumberLb.textColor = [UIColor lightGrayColor];
|
||||
_photoNumberLb.font = [UIFont systemFontOfSize:12];
|
||||
}
|
||||
return _photoNumberLb;
|
||||
}
|
||||
- (UIView *)selectBgView {
|
||||
if (!_selectBgView) {
|
||||
_selectBgView = [[UIView alloc] init];
|
||||
_selectBgView.backgroundColor = [UIColor colorWithRed:0.125 green:0.125 blue:0.125 alpha:1];
|
||||
}
|
||||
return _selectBgView;
|
||||
}
|
||||
- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
|
||||
[super traitCollectionDidChange:previousTraitCollection];
|
||||
#ifdef __IPHONE_13_0
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) {
|
||||
[self changeColor];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
- (void)changeAlbumNameTextColor {
|
||||
if ([HXPhotoCommon photoCommon].isDark) {
|
||||
self.albumNameLb.textColor = [UIColor whiteColor];
|
||||
}else {
|
||||
self.albumNameLb.textColor = self.textColor;
|
||||
}
|
||||
}
|
||||
- (void)changeColor {
|
||||
self.backgroundColor = [HXPhotoCommon photoCommon].isDark ? [UIColor colorWithRed:0.075 green:0.075 blue:0.075 alpha:1] : self.bgColor;
|
||||
if (self.selectedBgColor) {
|
||||
self.selectBgView.backgroundColor = self.selectedBgColor;
|
||||
self.selectedBackgroundView = self.selectBgView;
|
||||
}else {
|
||||
self.selectedBackgroundView = [HXPhotoCommon photoCommon].isDark ? self.selectBgView : nil;
|
||||
}
|
||||
self.lineView.backgroundColor = [HXPhotoCommon photoCommon].isDark ? [[UIColor colorWithRed:0.1 green:0.1 blue:0.1 alpha:1] colorWithAlphaComponent:1] : self.lineViewColor;
|
||||
[self changeAlbumNameTextColor];
|
||||
}
|
||||
|
||||
@end
|
82
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraController.h
generated
Normal file
82
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraController.h
generated
Normal file
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// HXCustomCameraController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/31.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class HXPhotoManager;
|
||||
@protocol HXCustomCameraControllerDelegate <NSObject>
|
||||
@optional;
|
||||
- (void)deviceConfigurationFailedWithError:(NSError *)error;
|
||||
- (void)mediaCaptureFailedWithError:(NSError *)error;
|
||||
- (void)assetLibraryWriteFailedWithError:(NSError *)error;
|
||||
- (void)videoStartRecording;
|
||||
- (void)videoFinishRecording:(NSURL *)videoURL;
|
||||
- (void)takePicturesComplete:(UIImage *)image;
|
||||
- (void)takePicturesFailed;
|
||||
- (void)handleDeviceMotion:(UIDeviceOrientation)deviceOrientation;
|
||||
//- (void)rampedZoomToValue:(CGFloat)value;
|
||||
@end
|
||||
|
||||
@interface HXCustomCameraController : NSObject
|
||||
@property (weak, nonatomic) id<HXCustomCameraControllerDelegate> delegate;
|
||||
@property (strong, nonatomic, readonly) AVCaptureSession *captureSession;
|
||||
|
||||
/// 相机界面默认前置摄像头
|
||||
@property (assign, nonatomic) BOOL defaultFrontCamera;
|
||||
@property (assign, nonatomic) NSTimeInterval videoMaximumDuration;
|
||||
- (void)initSeesion;
|
||||
- (void)setupPreviewLayer:(AVCaptureVideoPreviewLayer *)previewLayer startSessionCompletion:(void (^)(BOOL success))completion;
|
||||
|
||||
- (void)startSession;
|
||||
- (void)stopSession;
|
||||
|
||||
- (void)initImageOutput;
|
||||
- (void)initMovieOutput;
|
||||
- (void)removeMovieOutput;
|
||||
|
||||
- (BOOL)addAudioInput;
|
||||
|
||||
- (BOOL)switchCameras;
|
||||
- (BOOL)canSwitchCameras;
|
||||
@property (nonatomic, readonly) NSUInteger cameraCount;
|
||||
@property (nonatomic, readonly) BOOL cameraHasTorch;
|
||||
@property (nonatomic, readonly) BOOL cameraHasFlash;
|
||||
@property (nonatomic, readonly) BOOL cameraSupportsTapToFocus;
|
||||
@property (nonatomic, readonly) BOOL cameraSupportsTapToExpose;
|
||||
@property (nonatomic) AVCaptureTorchMode torchMode;
|
||||
@property (nonatomic) AVCaptureFlashMode flashMode;
|
||||
|
||||
|
||||
@property (copy, nonatomic) NSString *videoCodecKey;
|
||||
@property (copy, nonatomic) NSString *sessionPreset;
|
||||
|
||||
- (void)focusAtPoint:(CGPoint)point;
|
||||
- (void)exposeAtPoint:(CGPoint)point;
|
||||
- (void)resetFocusAndExposureModes;
|
||||
|
||||
- (void)captureStillImage;
|
||||
|
||||
- (void)startRecording;
|
||||
- (void)stopRecording;
|
||||
- (BOOL)isRecording;
|
||||
- (CMTime)recordedDuration;
|
||||
|
||||
- (void)startMontionUpdate;
|
||||
- (void)stopMontionUpdate;
|
||||
|
||||
- (BOOL)cameraSupportsZoom;
|
||||
|
||||
- (CGFloat)maxZoomFactor;
|
||||
- (CGFloat)currentZoomFacto;
|
||||
|
||||
- (void)setZoomValue:(CGFloat)zoomValue;
|
||||
- (void)rampZoomToValue:(CGFloat)zoomValue;
|
||||
- (void)cancelZoom;
|
||||
|
||||
@end
|
599
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraController.m
generated
Normal file
599
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraController.m
generated
Normal file
|
@ -0,0 +1,599 @@
|
|||
//
|
||||
// HXCustomCameraController.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/31.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXCustomCameraController.h"
|
||||
#import <CoreMotion/CoreMotion.h>
|
||||
#import "HXPhotoTools.h"
|
||||
#import "HXCustomPreviewView.h"
|
||||
|
||||
const CGFloat HXZoomRate = 1.0f;
|
||||
|
||||
@interface HXCustomCameraController ()<AVCaptureFileOutputRecordingDelegate>
|
||||
@property (strong, nonatomic) dispatch_queue_t videoQueue;
|
||||
@property (strong, nonatomic) AVCaptureSession *captureSession;
|
||||
@property (weak, nonatomic) AVCaptureDeviceInput *activeVideoInput;
|
||||
|
||||
@property (strong, nonatomic) AVCaptureStillImageOutput *imageOutput;
|
||||
@property (strong, nonatomic) AVCaptureMovieFileOutput *movieOutput;
|
||||
@property (strong, nonatomic) NSURL *outputURL;
|
||||
@property (strong, nonatomic) CMMotionManager *motionManager;
|
||||
@property (nonatomic, assign) UIDeviceOrientation deviceOrientation;
|
||||
@property (nonatomic, assign) UIDeviceOrientation imageOrientation;
|
||||
@end
|
||||
|
||||
@implementation HXCustomCameraController
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.motionManager = [[CMMotionManager alloc] init];
|
||||
self.motionManager.deviceMotionUpdateInterval = 1/15.0;
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)startMontionUpdate {
|
||||
if (self.motionManager.deviceMotionAvailable) {
|
||||
HXWeakSelf
|
||||
[self.motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) {
|
||||
[weakSelf performSelectorOnMainThread:@selector(handleDeviceMotion:) withObject:motion waitUntilDone:YES];
|
||||
}];
|
||||
}
|
||||
}
|
||||
- (void)stopMontionUpdate {
|
||||
[self.motionManager stopDeviceMotionUpdates];
|
||||
}
|
||||
- (void)dealloc {
|
||||
}
|
||||
/// 重力感应回调
|
||||
- (void)handleDeviceMotion:(CMDeviceMotion *)deviceMotion {
|
||||
double x = deviceMotion.gravity.x;
|
||||
double y = deviceMotion.gravity.y;
|
||||
|
||||
if (fabs(y) >= fabs(x)) {
|
||||
if (y >= 0) {
|
||||
_imageOrientation = UIDeviceOrientationPortraitUpsideDown;
|
||||
_deviceOrientation = UIDeviceOrientationPortraitUpsideDown;
|
||||
if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
|
||||
[self.delegate handleDeviceMotion:UIDeviceOrientationPortraitUpsideDown];
|
||||
}
|
||||
} else {
|
||||
_imageOrientation = UIDeviceOrientationPortrait;
|
||||
_deviceOrientation = UIDeviceOrientationPortrait;
|
||||
if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
|
||||
[self.delegate handleDeviceMotion:UIDeviceOrientationPortrait];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (x >= 0) { // Home键左侧水平拍摄
|
||||
_imageOrientation = UIDeviceOrientationLandscapeRight;
|
||||
_deviceOrientation = UIDeviceOrientationLandscapeRight;
|
||||
if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
|
||||
[self.delegate handleDeviceMotion:UIDeviceOrientationLandscapeRight];
|
||||
}
|
||||
} else {
|
||||
_imageOrientation = UIDeviceOrientationLandscapeLeft;
|
||||
_deviceOrientation = UIDeviceOrientationLandscapeLeft; // Home键右侧水平拍摄
|
||||
if ([self.delegate respondsToSelector:@selector(handleDeviceMotion:)]) {
|
||||
[self.delegate handleDeviceMotion:UIDeviceOrientationLandscapeLeft];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)initSeesion {
|
||||
self.captureSession = [[AVCaptureSession alloc] init];
|
||||
}
|
||||
|
||||
- (void)setupPreviewLayer:(AVCaptureVideoPreviewLayer *)previewLayer startSessionCompletion:(void (^)(BOOL success))completion {
|
||||
if ([self.captureSession canSetSessionPreset:self.sessionPreset]) {
|
||||
self.captureSession.sessionPreset = self.sessionPreset;
|
||||
}else {
|
||||
if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) {
|
||||
self.captureSession.sessionPreset = AVCaptureSessionPreset1280x720;
|
||||
}else if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {
|
||||
self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;
|
||||
}else {
|
||||
self.captureSession.sessionPreset = AVCaptureSessionPreset640x480;
|
||||
}
|
||||
}
|
||||
AVCaptureDevice *videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
|
||||
if (self.defaultFrontCamera) {
|
||||
videoDevice = [self cameraWithPosition:AVCaptureDevicePositionFront];
|
||||
}
|
||||
|
||||
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
|
||||
if (videoInput) {
|
||||
if ([self.captureSession canAddInput:videoInput]) {
|
||||
[self.captureSession addInput:videoInput];
|
||||
self.activeVideoInput = videoInput;
|
||||
}
|
||||
}else {
|
||||
if (completion) {
|
||||
completion(NO);
|
||||
}
|
||||
return;
|
||||
}
|
||||
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
if (completion) {
|
||||
completion(YES);
|
||||
}
|
||||
}
|
||||
- (AVCaptureMovieFileOutput *)movieOutput {
|
||||
if (!_movieOutput) {
|
||||
_movieOutput = [[AVCaptureMovieFileOutput alloc] init];
|
||||
CMTime maxDuration = CMTimeMakeWithSeconds(MAX(1, self.videoMaximumDuration), 30);
|
||||
_movieOutput.maxRecordedDuration = maxDuration;
|
||||
}
|
||||
return _movieOutput;
|
||||
}
|
||||
- (AVCaptureStillImageOutput *)imageOutput {
|
||||
if (!_imageOutput) {
|
||||
_imageOutput = [[AVCaptureStillImageOutput alloc] init];
|
||||
_imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG};
|
||||
_imageOutput.highResolutionStillImageOutputEnabled = YES;
|
||||
}
|
||||
return _imageOutput;
|
||||
}
|
||||
- (void)initImageOutput {
|
||||
if ([self.captureSession canAddOutput:self.imageOutput]) {
|
||||
[self.captureSession addOutput:self.imageOutput];
|
||||
}
|
||||
}
|
||||
- (void)initMovieOutput {
|
||||
if ([self.captureSession canAddOutput:self.movieOutput]) {
|
||||
[self.captureSession addOutput:self.movieOutput];
|
||||
AVCaptureConnection *videoConnection = [self.movieOutput connectionWithMediaType:AVMediaTypeVideo];
|
||||
if ([videoConnection isVideoStabilizationSupported]) {
|
||||
videoConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)removeMovieOutput {
|
||||
[self.captureSession removeOutput:self.movieOutput];
|
||||
}
|
||||
- (BOOL)addAudioInput {
|
||||
NSError *error;
|
||||
AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
|
||||
AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
|
||||
if (audioDevice) {
|
||||
if ([self.captureSession canAddInput:audioInput]) {
|
||||
[self.captureSession addInput:audioInput];
|
||||
}
|
||||
}else {
|
||||
return NO;
|
||||
}
|
||||
if (error) {
|
||||
return NO;
|
||||
}else {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
- (void)startSession {
|
||||
AVCaptureSession *session = self.captureSession;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if (![session isRunning]) {
|
||||
[session startRunning];
|
||||
}
|
||||
});
|
||||
// if (![self.captureSession isRunning]) {
|
||||
// dispatch_async(self.videoQueue, ^{
|
||||
// [self.captureSession startRunning];
|
||||
// });
|
||||
// }
|
||||
}
|
||||
- (void)stopSession {
|
||||
AVCaptureSession *session = self.captureSession;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if (session.running) {
|
||||
[session stopRunning];
|
||||
}
|
||||
});
|
||||
|
||||
// if ([self.captureSession isRunning]) {
|
||||
// dispatch_async(self.videoQueue, ^{
|
||||
// [self.captureSession stopRunning];
|
||||
// });
|
||||
// }
|
||||
}
|
||||
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition)position {
|
||||
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
|
||||
for (AVCaptureDevice *device in devices) {
|
||||
if (device.position == position) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
- (AVCaptureDevice *)activeCamera {
|
||||
return self.activeVideoInput.device;
|
||||
}
|
||||
- (AVCaptureDevice *)inactiveCamer {
|
||||
AVCaptureDevice *device = nil;
|
||||
if (self.cameraCount > 1) {
|
||||
if ([self activeCamera].position == AVCaptureDevicePositionBack) {
|
||||
device = [self cameraWithPosition:AVCaptureDevicePositionFront];
|
||||
}else {
|
||||
device = [self cameraWithPosition:AVCaptureDevicePositionBack];
|
||||
}
|
||||
}
|
||||
return device;
|
||||
}
|
||||
- (BOOL)canSwitchCameras {
|
||||
return self.cameraCount > 1;
|
||||
}
|
||||
- (NSUInteger)cameraCount {
|
||||
return [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count];
|
||||
}
|
||||
- (BOOL)switchCameras {
|
||||
if (![self canSwitchCameras]) {
|
||||
return NO;
|
||||
}
|
||||
NSError *error;
|
||||
AVCaptureDevice *videoDevice = [self inactiveCamer];
|
||||
AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
|
||||
if (videoInput) {
|
||||
|
||||
[self.captureSession beginConfiguration];
|
||||
[self.captureSession removeInput:self.activeVideoInput];
|
||||
if ([self.captureSession canAddInput:videoInput]) {
|
||||
[self.captureSession addInput:videoInput];
|
||||
self.activeVideoInput = videoInput;
|
||||
}else {
|
||||
[self.captureSession addInput:self.activeVideoInput];
|
||||
}
|
||||
[self.captureSession commitConfiguration];
|
||||
}else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
- (BOOL)cameraSupportsTapToFocus {
|
||||
return [[self activeCamera] isFocusPointOfInterestSupported];
|
||||
}
|
||||
- (void)focusAtPoint:(CGPoint)point {
|
||||
AVCaptureDevice *device = [self activeCamera];
|
||||
if (device.isFocusPointOfInterestSupported && [device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {
|
||||
NSError *error;
|
||||
if ([device lockForConfiguration:&error]) {
|
||||
if (device.smoothAutoFocusSupported) {
|
||||
device.smoothAutoFocusEnabled = YES;
|
||||
}
|
||||
device.focusPointOfInterest = point;
|
||||
device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
|
||||
[device unlockForConfiguration];
|
||||
}else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (BOOL)cameraSupportsTapToExpose {
|
||||
return [[self activeCamera] isExposurePointOfInterestSupported];
|
||||
}
|
||||
static const NSString *HXCustomCameraAdjustingExposureContext;
|
||||
|
||||
- (void)exposeAtPoint:(CGPoint)point {
|
||||
AVCaptureDevice *device = [self activeCamera];
|
||||
AVCaptureExposureMode exposureMode = AVCaptureExposureModeContinuousAutoExposure;
|
||||
if (device.isExposurePointOfInterestSupported && [device isExposureModeSupported:exposureMode]) {
|
||||
NSError *error;
|
||||
if ([device lockForConfiguration:&error]) {
|
||||
device.exposurePointOfInterest = point;
|
||||
device.exposureMode = exposureMode;
|
||||
// if ([device isExposureModeSupported:AVCaptureExposureModeLocked]) {
|
||||
// [device addObserver:self forKeyPath:@"adjustingExposure" options:NSKeyValueObservingOptionNew context:&HXCustomCameraAdjustingExposureContext];
|
||||
// }
|
||||
[device unlockForConfiguration];
|
||||
}else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)resetFocusAndExposureModes {
|
||||
AVCaptureDevice *device = [self activeCamera];
|
||||
|
||||
AVCaptureExposureMode exposureMode =
|
||||
AVCaptureExposureModeContinuousAutoExposure;
|
||||
|
||||
AVCaptureFocusMode focusMode = AVCaptureFocusModeContinuousAutoFocus;
|
||||
|
||||
BOOL canResetFocus = [device isFocusPointOfInterestSupported] &&
|
||||
[device isFocusModeSupported:focusMode];
|
||||
|
||||
BOOL canResetExposure = [device isExposurePointOfInterestSupported] &&
|
||||
[device isExposureModeSupported:exposureMode];
|
||||
|
||||
CGPoint centerPoint = CGPointMake(0.5f, 0.5f);
|
||||
|
||||
NSError *error;
|
||||
if ([device lockForConfiguration:&error]) {
|
||||
if (device.smoothAutoFocusSupported) {
|
||||
device.smoothAutoFocusEnabled = YES;
|
||||
}
|
||||
|
||||
if (canResetFocus) {
|
||||
device.focusMode = focusMode;
|
||||
device.focusPointOfInterest = centerPoint;
|
||||
}
|
||||
|
||||
if (canResetExposure) {
|
||||
device.exposureMode = exposureMode;
|
||||
device.exposurePointOfInterest = centerPoint;
|
||||
}
|
||||
|
||||
[device unlockForConfiguration];
|
||||
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
// 闪光灯
|
||||
- (BOOL)cameraHasFlash {
|
||||
return [[self activeCamera] hasFlash];
|
||||
}
|
||||
- (AVCaptureFlashMode)flashMode {
|
||||
return [[self activeCamera] flashMode];
|
||||
}
|
||||
- (void)setFlashMode:(AVCaptureFlashMode)flashMode {
|
||||
AVCaptureDevice *device = [self activeCamera];
|
||||
|
||||
if (device.flashMode != flashMode &&
|
||||
[device isFlashModeSupported:flashMode]) {
|
||||
|
||||
NSError *error;
|
||||
if ([device lockForConfiguration:&error]) {
|
||||
device.flashMode = flashMode;
|
||||
[device unlockForConfiguration];
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 手电筒
|
||||
- (BOOL)cameraHasTorch {
|
||||
return [[self activeCamera] hasTorch];
|
||||
}
|
||||
|
||||
- (AVCaptureTorchMode)torchMode {
|
||||
return [[self activeCamera] torchMode];
|
||||
}
|
||||
|
||||
- (void)setTorchMode:(AVCaptureTorchMode)torchMode {
|
||||
|
||||
AVCaptureDevice *device = [self activeCamera];
|
||||
|
||||
if (device.torchMode != torchMode &&
|
||||
[device isTorchModeSupported:torchMode]) {
|
||||
|
||||
NSError *error;
|
||||
if ([device lockForConfiguration:&error]) {
|
||||
device.torchMode = torchMode;
|
||||
[device unlockForConfiguration];
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)captureStillImage {
|
||||
|
||||
AVCaptureConnection *connection =
|
||||
[self.imageOutput connectionWithMediaType:AVMediaTypeVideo];
|
||||
|
||||
if (connection.isVideoOrientationSupported) {
|
||||
connection.videoOrientation = [self currentVideoOrientation];
|
||||
}
|
||||
|
||||
AVCaptureDevicePosition position = [[self activeCamera] position];
|
||||
if (position == AVCaptureDevicePositionUnspecified ||
|
||||
position == AVCaptureDevicePositionFront) {
|
||||
connection.videoMirrored = YES;
|
||||
}else {
|
||||
connection.videoMirrored = NO;
|
||||
}
|
||||
HXWeakSelf
|
||||
id handler = ^(CMSampleBufferRef sampleBuffer, NSError *error) {
|
||||
if (sampleBuffer != NULL) {
|
||||
|
||||
NSData *imageData =
|
||||
[AVCaptureStillImageOutput
|
||||
jpegStillImageNSDataRepresentation:sampleBuffer];
|
||||
|
||||
UIImage *image = [[UIImage alloc] initWithData:imageData];
|
||||
if ([weakSelf.delegate respondsToSelector:@selector(takePicturesComplete:)]) {
|
||||
[weakSelf.delegate takePicturesComplete:image];
|
||||
}
|
||||
} else {
|
||||
if ([weakSelf.delegate respondsToSelector:@selector(takePicturesFailed)]) {
|
||||
[weakSelf.delegate takePicturesFailed];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[self.imageOutput captureStillImageAsynchronouslyFromConnection:connection
|
||||
completionHandler:handler];
|
||||
}
|
||||
- (AVCaptureVideoOrientation)currentVideoOrientation {
|
||||
|
||||
AVCaptureVideoOrientation orientation;
|
||||
switch (self.imageOrientation) {
|
||||
case UIDeviceOrientationPortrait:
|
||||
orientation = AVCaptureVideoOrientationPortrait;
|
||||
break;
|
||||
case UIDeviceOrientationLandscapeRight:
|
||||
orientation = AVCaptureVideoOrientationLandscapeLeft;
|
||||
break;
|
||||
case UIDeviceOrientationPortraitUpsideDown:
|
||||
orientation = AVCaptureVideoOrientationPortraitUpsideDown;
|
||||
break;
|
||||
default:
|
||||
orientation = AVCaptureVideoOrientationLandscapeRight;
|
||||
break;
|
||||
}
|
||||
return orientation;
|
||||
}
|
||||
- (BOOL)isRecording {
|
||||
return self.movieOutput.isRecording;
|
||||
}
|
||||
- (void)startRecording {
|
||||
if (![self isRecording]) {
|
||||
AVCaptureConnection *videoConnection =
|
||||
[self.movieOutput connectionWithMediaType:AVMediaTypeVideo];
|
||||
|
||||
// 设置编码格式
|
||||
if (HX_IOS11_Later && self.videoCodecKey) {
|
||||
NSMutableDictionary* outputSettings = [NSMutableDictionary dictionary];
|
||||
outputSettings[AVVideoCodecKey] = self.videoCodecKey;
|
||||
[self.movieOutput setOutputSettings:outputSettings forConnection:videoConnection];
|
||||
}
|
||||
|
||||
if ([videoConnection isVideoOrientationSupported]) {
|
||||
videoConnection.videoOrientation = (AVCaptureVideoOrientation)_deviceOrientation;
|
||||
}
|
||||
|
||||
AVCaptureDevice *device = [self activeCamera];
|
||||
if (device.isSmoothAutoFocusSupported) {
|
||||
NSError *error;
|
||||
if ([device lockForConfiguration:&error]) {
|
||||
device.smoothAutoFocusEnabled = NO;
|
||||
[device unlockForConfiguration];
|
||||
}
|
||||
}
|
||||
self.outputURL = [self uniqueURL];
|
||||
[self.movieOutput startRecordingToOutputFileURL:self.outputURL
|
||||
recordingDelegate:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (CMTime)recordedDuration {
|
||||
return self.movieOutput.recordedDuration;
|
||||
}
|
||||
|
||||
- (NSURL *)uniqueURL {
|
||||
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), [NSString stringWithFormat:@"hx%@.mov",[self videoOutFutFileName]]]];
|
||||
}
|
||||
- (NSString *)videoOutFutFileName {
|
||||
return [NSString hx_fileName];
|
||||
}
|
||||
- (void)stopRecording {
|
||||
if ([self isRecording]) {
|
||||
[self.movieOutput stopRecording];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - AVCaptureFileOutputRecordingDelegate
|
||||
// 开始录制
|
||||
- (void)captureOutput:(AVCaptureFileOutput *)output didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray<AVCaptureConnection *> *)connections {
|
||||
if ([self.delegate respondsToSelector:@selector(videoStartRecording)]) {
|
||||
[self.delegate videoStartRecording];
|
||||
}
|
||||
}
|
||||
// 录制完成
|
||||
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL
|
||||
fromConnections:(NSArray *)connections
|
||||
error:(NSError *)error {
|
||||
if ([error.userInfo[AVErrorRecordingSuccessfullyFinishedKey] boolValue]) {
|
||||
if ([self.delegate respondsToSelector:@selector(videoFinishRecording:)]) {
|
||||
[self.delegate videoFinishRecording:[self.outputURL copy]];
|
||||
}
|
||||
self.outputURL = nil;
|
||||
return;
|
||||
}
|
||||
if (error) {
|
||||
if ([self.delegate respondsToSelector:@selector(mediaCaptureFailedWithError:)]) {
|
||||
[self.delegate mediaCaptureFailedWithError:error];
|
||||
}
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(videoFinishRecording:)]) {
|
||||
[self.delegate videoFinishRecording:[self.outputURL copy]];
|
||||
}
|
||||
}
|
||||
self.outputURL = nil;
|
||||
}
|
||||
|
||||
- (void)updateZoomingDelegate {
|
||||
// CGFloat curZoomFactor = self.activeCamera.videoZoomFactor;
|
||||
// CGFloat maxZoomFactor = [self maxZoomFactor];
|
||||
// CGFloat value = log(curZoomFactor) / log(maxZoomFactor);
|
||||
// if ([self.delegate respondsToSelector:@selector(rampedZoomToValue:)]) {
|
||||
// [self.delegate rampedZoomToValue:value];
|
||||
// }
|
||||
}
|
||||
|
||||
- (BOOL)cameraSupportsZoom {
|
||||
return self.activeCamera.activeFormat.videoMaxZoomFactor > 1.0f;
|
||||
}
|
||||
|
||||
- (CGFloat)maxZoomFactor {
|
||||
return MIN(self.activeCamera.activeFormat.videoMaxZoomFactor, 5.0f);
|
||||
}
|
||||
|
||||
- (CGFloat)currentZoomFacto {
|
||||
return self.activeCamera.videoZoomFactor;
|
||||
}
|
||||
- (void)setZoomValue:(CGFloat)zoomValue {
|
||||
if (zoomValue > self.maxZoomFactor) {
|
||||
zoomValue = self.maxZoomFactor;
|
||||
}
|
||||
if (!self.activeCamera.isRampingVideoZoom) {
|
||||
|
||||
NSError *error;
|
||||
if ([self.activeCamera lockForConfiguration:&error]) {
|
||||
|
||||
// Provide linear feel to zoom slider
|
||||
// CGFloat zoomFactor = pow([self maxZoomFactor], zoomValue);
|
||||
self.activeCamera.videoZoomFactor = zoomValue;
|
||||
|
||||
[self.activeCamera unlockForConfiguration];
|
||||
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)rampZoomToValue:(CGFloat)zoomValue {
|
||||
// CGFloat zoomFactor = pow([self maxZoomFactor], zoomValue);
|
||||
NSError *error;
|
||||
if ([self.activeCamera lockForConfiguration:&error]) {
|
||||
[self.activeCamera rampToVideoZoomFactor:zoomValue
|
||||
withRate:HXZoomRate];
|
||||
[self.activeCamera unlockForConfiguration];
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelZoom {
|
||||
NSError *error;
|
||||
if ([self.activeCamera lockForConfiguration:&error]) {
|
||||
[self.activeCamera cancelVideoZoomRamp];
|
||||
[self.activeCamera unlockForConfiguration];
|
||||
} else {
|
||||
if ([self.delegate respondsToSelector:@selector(deviceConfigurationFailedWithError:)]) {
|
||||
[self.delegate deviceConfigurationFailedWithError:error];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
59
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraViewController.h
generated
Normal file
59
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraViewController.h
generated
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// HXCustomCameraViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/9/30.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXCustomCameraBottomViewMode) {
|
||||
HXCustomCameraBottomViewModePhoto, //!< 拍照
|
||||
HXCustomCameraBottomViewModeVideo = 1, //!< 录制
|
||||
};
|
||||
|
||||
@class HXPhotoManager,HXCustomCameraViewController,HXPhotoModel;
|
||||
|
||||
typedef void (^ HXCustomCameraViewControllerDidDoneBlock)(HXPhotoModel *model, HXCustomCameraViewController *viewController);
|
||||
typedef void (^ HXCustomCameraViewControllerDidCancelBlock)(HXCustomCameraViewController *viewController);
|
||||
|
||||
@protocol HXCustomCameraViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/// 拍照/录制完成
|
||||
/// @param viewController self
|
||||
/// @param model 资源模型
|
||||
- (void)customCameraViewController:(HXCustomCameraViewController *)viewController
|
||||
didDone:(HXPhotoModel *)model;
|
||||
|
||||
/// 取消
|
||||
/// @param viewController self
|
||||
- (void)customCameraViewControllerDidCancel:(HXCustomCameraViewController *)viewController;
|
||||
|
||||
- (void)customCameraViewControllerFinishDismissCompletion:(HXCustomCameraViewController *)viewController;
|
||||
- (void)customCameraViewControllerCancelDismissCompletion:(HXCustomCameraViewController *)viewController;
|
||||
@end
|
||||
|
||||
@interface HXCustomCameraViewController : UIViewController
|
||||
@property (weak, nonatomic) id<HXCustomCameraViewControllerDelegate> delegate;
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
@property (assign, nonatomic) BOOL isOutside;
|
||||
@property (copy, nonatomic) HXCustomCameraViewControllerDidDoneBlock doneBlock;
|
||||
@property (copy, nonatomic) HXCustomCameraViewControllerDidCancelBlock cancelBlock;
|
||||
|
||||
#pragma mark - < other >
|
||||
- (UIImage *)jumpImage;
|
||||
- (CGRect)jumpRect;
|
||||
- (void)hidePlayerView;
|
||||
- (void)showPlayerView;
|
||||
- (void)hiddenTopBottomView;
|
||||
- (void)showTopBottomView;
|
||||
@end
|
||||
|
||||
@interface HXCustomCameraPlayVideoView : UIView
|
||||
@property (strong, nonatomic) NSURL *videoURL;
|
||||
@property (strong, nonatomic) AVPlayerLayer *playerLayer;
|
||||
- (void)stopPlay;
|
||||
@end
|
1010
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraViewController.m
generated
Normal file
1010
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomCameraViewController.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
76
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomNavigationController.h
generated
Normal file
76
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomNavigationController.h
generated
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// HXCustomNavigationController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/31.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoManager.h"
|
||||
#import "HXPickerResult.h"
|
||||
@class HXPhotoModel, HXCustomNavigationController;
|
||||
|
||||
@protocol HXCustomNavigationControllerDelegate <NSObject>
|
||||
@optional
|
||||
/**
|
||||
点击完成按钮
|
||||
|
||||
@param photoNavigationViewController self
|
||||
@param allList 已选的所有列表(包含照片、视频)
|
||||
@param photoList 已选的照片列表
|
||||
@param videoList 已选的视频列表
|
||||
@param original 是否原图
|
||||
*/
|
||||
- (void)photoNavigationViewController:(HXCustomNavigationController *)photoNavigationViewController
|
||||
didDoneAllList:(NSArray<HXPhotoModel *> *)allList
|
||||
photos:(NSArray<HXPhotoModel *> *)photoList
|
||||
videos:(NSArray<HXPhotoModel *> *)videoList
|
||||
original:(BOOL)original;
|
||||
|
||||
- (void)photoNavigationViewController:(HXCustomNavigationController *)photoNavigationViewController
|
||||
didDoneWithResult:(HXPickerResult *)result;
|
||||
|
||||
/**
|
||||
点击取消
|
||||
|
||||
@param photoNavigationViewController self
|
||||
*/
|
||||
- (void)photoNavigationViewControllerDidCancel:(HXCustomNavigationController *)photoNavigationViewController;
|
||||
|
||||
- (void)photoNavigationViewControllerFinishDismissCompletion:(HXCustomNavigationController *)photoNavigationViewController;
|
||||
- (void)photoNavigationViewControllerCancelDismissCompletion:(HXCustomNavigationController *)photoNavigationViewController;
|
||||
@end
|
||||
|
||||
@interface HXCustomNavigationController : UINavigationController
|
||||
@property (strong, nonatomic) NSMutableArray *albums;
|
||||
@property (strong, nonatomic) HXAlbumModel *cameraRollAlbumModel;
|
||||
|
||||
@property (copy, nonatomic) void (^requestCameraRollPhotoListCompletion)(void);
|
||||
|
||||
@property (copy, nonatomic) void (^requestCameraRollCompletion)(void);
|
||||
@property (copy, nonatomic) void (^requestAllAlbumCompletion)(void);
|
||||
|
||||
@property (copy, nonatomic) void (^ reloadAsset)(BOOL initialAuthorization);
|
||||
|
||||
//@property (copy, nonatomic) void (^ photoLibraryDidChange)(HXAlbumModel *albumModel);
|
||||
|
||||
@property (assign ,nonatomic) BOOL isCamera;
|
||||
@property (weak, nonatomic) id<HXCustomNavigationControllerDelegate> hx_delegate;
|
||||
@property (assign, nonatomic) BOOL supportRotation;
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
@property (copy, nonatomic) viewControllerDidDoneBlock doneBlock;
|
||||
@property (copy, nonatomic) viewControllerDidCancelBlock cancelBlock;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager
|
||||
delegate:(id<HXCustomNavigationControllerDelegate>)delegate;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager
|
||||
doneBlock:(viewControllerDidDoneBlock)doneBlock
|
||||
cancelBlock:(viewControllerDidCancelBlock)cancelBlock;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager
|
||||
delegate:(id<HXCustomNavigationControllerDelegate>)delegate
|
||||
doneBlock:(viewControllerDidDoneBlock)doneBlock
|
||||
cancelBlock:(viewControllerDidCancelBlock)cancelBlock;
|
||||
|
||||
- (void)clearAssetCache;
|
||||
@end
|
385
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomNavigationController.m
generated
Normal file
385
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXCustomNavigationController.m
generated
Normal file
|
@ -0,0 +1,385 @@
|
|||
//
|
||||
// HXCustomNavigationController.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/31.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXCustomNavigationController.h"
|
||||
#import "HXAlbumListViewController.h"
|
||||
#import "HXPhotoViewController.h"
|
||||
#import "HXPhotoTools.h"
|
||||
#import "HXAssetManager.h"
|
||||
|
||||
@interface HXCustomNavigationController ()<HXAlbumListViewControllerDelegate, HXPhotoViewControllerDelegate>
|
||||
@property (assign, nonatomic) BOOL didPresentImagePicker;
|
||||
@property (assign, nonatomic) BOOL initialAuthorization;
|
||||
@property (strong, nonatomic) NSTimer *timer;
|
||||
@property (weak, nonatomic) UIImageView *imageView;
|
||||
@property (assign, nonatomic) PHImageRequestID requestID;
|
||||
@end
|
||||
|
||||
@implementation HXCustomNavigationController
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager {
|
||||
return [self initWithManager:manager delegate:nil doneBlock:nil cancelBlock:nil];
|
||||
}
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager
|
||||
delegate:(id<HXCustomNavigationControllerDelegate>)delegate {
|
||||
return [self initWithManager:manager delegate:delegate doneBlock:nil cancelBlock:nil];
|
||||
}
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager
|
||||
doneBlock:(viewControllerDidDoneBlock)doneBlock
|
||||
cancelBlock:(viewControllerDidCancelBlock)cancelBlock {
|
||||
return [self initWithManager:manager delegate:nil doneBlock:doneBlock cancelBlock:cancelBlock];
|
||||
}
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager
|
||||
delegate:(id<HXCustomNavigationControllerDelegate>)delegate
|
||||
doneBlock:(viewControllerDidDoneBlock)doneBlock
|
||||
cancelBlock:(viewControllerDidCancelBlock)cancelBlock {
|
||||
[manager selectedListTransformBefore];
|
||||
manager.selectPhotoing = YES;
|
||||
|
||||
if (manager.configuration.albumShowMode == HXPhotoAlbumShowModeDefault) {
|
||||
HXAlbumListViewController *vc = [[HXAlbumListViewController alloc] initWithManager:manager];
|
||||
self = [super initWithRootViewController:vc];
|
||||
self.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
self.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
if (self) {
|
||||
self.hx_delegate = delegate;
|
||||
self.manager = manager;
|
||||
[self requestAuthorization];
|
||||
self.doneBlock = doneBlock;
|
||||
self.cancelBlock = cancelBlock;
|
||||
vc.doneBlock = self.doneBlock;
|
||||
vc.cancelBlock = self.cancelBlock;
|
||||
vc.delegate = self;
|
||||
}
|
||||
}else if (manager.configuration.albumShowMode == HXPhotoAlbumShowModePopup) {
|
||||
HXPhotoViewController *vc = [[HXPhotoViewController alloc] init];
|
||||
vc.manager = manager;
|
||||
self = [super initWithRootViewController:vc];
|
||||
self.modalPresentationStyle = UIModalPresentationOverFullScreen;
|
||||
self.modalPresentationCapturesStatusBarAppearance = YES;
|
||||
if (self) {
|
||||
self.hx_delegate = delegate;
|
||||
self.manager = manager;
|
||||
[self requestAuthorization];
|
||||
self.doneBlock = doneBlock;
|
||||
self.cancelBlock = cancelBlock;
|
||||
vc.doneBlock = self.doneBlock;
|
||||
vc.cancelBlock = self.cancelBlock;
|
||||
vc.delegate = self;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)requestAuthorization {
|
||||
self.initialAuthorization = NO;
|
||||
HXWeakSelf
|
||||
#ifdef __IPHONE_14_0
|
||||
if (@available(iOS 14, *)) {
|
||||
[HXPhotoCommon photoCommon].photoLibraryDidChange = ^{
|
||||
if (!weakSelf.initialAuthorization) {
|
||||
if (weakSelf.timer) {
|
||||
[weakSelf.timer invalidate];
|
||||
weakSelf.timer = nil;
|
||||
}
|
||||
[weakSelf imagePickerDidFinish];
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
||||
PHAuthorizationStatus status = [HXPhotoTools authorizationStatus];
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
[self requestModel];
|
||||
return;
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
else if (@available(iOS 14, *)) {
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
[self requestModel];
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (status == PHAuthorizationStatusNotDetermined) {
|
||||
self.initialAuthorization = YES;
|
||||
}
|
||||
[HXPhotoTools requestAuthorization:nil handler:^(PHAuthorizationStatus status) {
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
[self requestModel];
|
||||
if (self.reloadAsset) {
|
||||
self.reloadAsset(self.initialAuthorization);
|
||||
}
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
else if (@available(iOS 14, *)) {
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
self.didPresentImagePicker = YES;
|
||||
}
|
||||
#endif
|
||||
else if (status == PHAuthorizationStatusRestricted ||
|
||||
status == PHAuthorizationStatusDenied) {
|
||||
if (self.reloadAsset) {
|
||||
self.reloadAsset(weakSelf.initialAuthorization);
|
||||
}
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
}else if (status == PHAuthorizationStatusRestricted ||
|
||||
status == PHAuthorizationStatusDenied) {
|
||||
if (self.reloadAsset) {
|
||||
self.reloadAsset(self.initialAuthorization);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}];
|
||||
}
|
||||
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
|
||||
if (!self.initialAuthorization) {
|
||||
[super presentViewController:viewControllerToPresent animated:flag completion:completion];
|
||||
return;
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
if (@available(iOS 14, *)) {
|
||||
if ([viewControllerToPresent isKindOfClass:[UIImagePickerController class]]) {
|
||||
UIImagePickerController *imagePickerController = (UIImagePickerController *)viewControllerToPresent;
|
||||
if (imagePickerController.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
|
||||
HXWeakSelf
|
||||
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
|
||||
if ([weakSelf.presentedViewController isKindOfClass:[UIImagePickerController class]]) {
|
||||
weakSelf.didPresentImagePicker = YES;
|
||||
}else {
|
||||
if (weakSelf.didPresentImagePicker) {
|
||||
weakSelf.didPresentImagePicker = NO;
|
||||
[timer invalidate];
|
||||
weakSelf.timer = nil;
|
||||
[weakSelf imagePickerDidFinish];
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
[super presentViewController:viewControllerToPresent animated:flag completion:completion];
|
||||
}
|
||||
- (void)imagePickerDidFinish {
|
||||
[HXPhotoCommon photoCommon].cameraRollLocalIdentifier = nil;
|
||||
[HXPhotoCommon photoCommon].cameraRollResult = nil;
|
||||
self.cameraRollAlbumModel = nil;
|
||||
self.albums = nil;
|
||||
[self requestModel];
|
||||
if (self.reloadAsset) {
|
||||
self.reloadAsset(self.initialAuthorization);
|
||||
}
|
||||
if (self.initialAuthorization) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"HXPhotoRequestAuthorizationCompletion" object:nil];
|
||||
self.initialAuthorization = NO;
|
||||
}
|
||||
}
|
||||
- (void)requestModel {
|
||||
[self.view hx_showLoadingHUDText:nil];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HXWeakSelf
|
||||
[self.manager getCameraRollAlbumCompletion:^(HXAlbumModel *albumModel) {
|
||||
weakSelf.cameraRollAlbumModel = albumModel;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (weakSelf.requestCameraRollCompletion) {
|
||||
weakSelf.requestCameraRollCompletion();
|
||||
}
|
||||
});
|
||||
}];
|
||||
[self.manager getAllAlbumModelWithCompletion:^(NSMutableArray<HXAlbumModel *> *albums) {
|
||||
weakSelf.albums = albums.mutableCopy;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (weakSelf.requestAllAlbumCompletion) {
|
||||
weakSelf.requestAllAlbumCompletion();
|
||||
}
|
||||
});
|
||||
}];
|
||||
});
|
||||
}
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
if (self.manager.viewWillAppear) {
|
||||
self.manager.viewWillAppear(self);
|
||||
}
|
||||
}
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
if (self.manager.viewDidAppear) {
|
||||
self.manager.viewDidAppear(self);
|
||||
}
|
||||
}
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
if (_timer) {
|
||||
self.didPresentImagePicker = NO;
|
||||
[self.timer invalidate];
|
||||
self.timer = nil;
|
||||
}
|
||||
if (self.manager.viewWillDisappear) {
|
||||
self.manager.viewWillDisappear(self);
|
||||
}
|
||||
}
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
if (self.manager.viewDidDisappear) {
|
||||
self.manager.viewDidDisappear(self);
|
||||
}
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
if ([HXPhotoCommon photoCommon].clearAssetRequestID) {
|
||||
[[PHImageManager defaultManager] cancelImageRequest:[HXPhotoCommon photoCommon].clearAssetRequestID];
|
||||
[HXPhotoCommon photoCommon].clearAssetRequestID = -1;
|
||||
}
|
||||
}
|
||||
#pragma mark - < HXAlbumListViewControllerDelegate >
|
||||
- (void)albumListViewControllerCancelDismissCompletion:(HXAlbumListViewController *)albumListViewController {
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewControllerCancelDismissCompletion:)]) {
|
||||
[self.hx_delegate photoNavigationViewControllerCancelDismissCompletion:self];
|
||||
}
|
||||
}
|
||||
- (void)albumListViewControllerDidCancel:(HXAlbumListViewController *)albumListViewController {
|
||||
[self clearAssetCacheWithAddOnWindow:!self.manager.selectPhotoCancelDismissAnimated];
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewControllerDidCancel:)]) {
|
||||
[self.hx_delegate photoNavigationViewControllerDidCancel:self];
|
||||
}
|
||||
}
|
||||
- (void)albumListViewController:(HXAlbumListViewController *)albumListViewController didDoneAllList:(NSArray<HXPhotoModel *> *)allList photos:(NSArray<HXPhotoModel *> *)photoList videos:(NSArray<HXPhotoModel *> *)videoList original:(BOOL)original {
|
||||
if (!self.manager.configuration.requestImageAfterFinishingSelection) {
|
||||
[self clearAssetCacheWithAddOnWindow:!self.manager.selectPhotoFinishDismissAnimated];
|
||||
}
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewController:didDoneAllList:photos:videos:original:)]) {
|
||||
[self.hx_delegate photoNavigationViewController:self didDoneAllList:allList photos:photoList videos:videoList original:original];
|
||||
}
|
||||
}
|
||||
- (void)albumListViewController:(HXAlbumListViewController *)albumListViewController didDoneWithResult:(HXPickerResult *)result {
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewController:didDoneWithResult:)]) {
|
||||
[self.hx_delegate photoNavigationViewController:self didDoneWithResult:result];
|
||||
}
|
||||
}
|
||||
#pragma mark - < HXPhotoViewControllerDelegate >
|
||||
- (void)photoViewControllerFinishDismissCompletion:(HXPhotoViewController *)photoViewController {
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewControllerFinishDismissCompletion:)]) {
|
||||
[self.hx_delegate photoNavigationViewControllerFinishDismissCompletion:self];
|
||||
}
|
||||
}
|
||||
- (void)photoViewController:(HXPhotoViewController *)photoViewController didDoneWithResult:(HXPickerResult *)result {
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewController:didDoneWithResult:)]) {
|
||||
[self.hx_delegate photoNavigationViewController:self didDoneWithResult:result];
|
||||
}
|
||||
}
|
||||
- (void)photoViewControllerCancelDismissCompletion:(HXPhotoViewController *)photoViewController {
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewControllerCancelDismissCompletion:)]) {
|
||||
[self.hx_delegate photoNavigationViewControllerCancelDismissCompletion:self];
|
||||
}
|
||||
}
|
||||
- (void)photoViewControllerDidCancel:(HXPhotoViewController *)photoViewController {
|
||||
[self clearAssetCacheWithAddOnWindow:!self.manager.selectPhotoCancelDismissAnimated];
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewControllerDidCancel:)]) {
|
||||
[self.hx_delegate photoNavigationViewControllerDidCancel:self];
|
||||
}
|
||||
}
|
||||
- (void)photoViewController:(HXPhotoViewController *)photoViewController didDoneAllList:(NSArray<HXPhotoModel *> *)allList photos:(NSArray<HXPhotoModel *> *)photoList videos:(NSArray<HXPhotoModel *> *)videoList original:(BOOL)original {
|
||||
if (!self.manager.configuration.requestImageAfterFinishingSelection) {
|
||||
[self clearAssetCacheWithAddOnWindow:!self.manager.selectPhotoFinishDismissAnimated];
|
||||
}
|
||||
if ([self.hx_delegate respondsToSelector:@selector(photoNavigationViewController:didDoneAllList:photos:videos:original:)]) {
|
||||
[self.hx_delegate photoNavigationViewController:self didDoneAllList:allList photos:photoList videos:videoList original:original];
|
||||
}
|
||||
}
|
||||
- (BOOL)shouldAutorotate{
|
||||
if (self.isCamera) {
|
||||
return NO;
|
||||
}
|
||||
if (self.manager.configuration.supportRotation) {
|
||||
return YES;
|
||||
}else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
return [self.topViewController preferredStatusBarStyle];
|
||||
}
|
||||
- (BOOL)prefersStatusBarHidden {
|
||||
return [self.topViewController prefersStatusBarHidden];
|
||||
}
|
||||
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
|
||||
return UIStatusBarAnimationFade;
|
||||
}
|
||||
//支持的方向
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
if (self.isCamera) {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
if (self.manager.configuration.supportRotation) {
|
||||
return UIInterfaceOrientationMaskAll;
|
||||
}else {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
}
|
||||
- (void)clearAssetCache {
|
||||
[self clearAssetCacheWithAddOnWindow:NO];
|
||||
}
|
||||
- (void)clearAssetCacheWithAddOnWindow:(BOOL)addOnWindow {
|
||||
PHAsset *asset = self.cameraRollAlbumModel.assetResult.firstObject;
|
||||
if (asset) {
|
||||
[[PHImageManager defaultManager] cancelImageRequest:self.requestID];
|
||||
[HXPhotoCommon photoCommon].clearAssetRequestID = -1;
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat;
|
||||
options.resizeMode = PHImageRequestOptionsResizeModeFast;
|
||||
options.synchronous = NO;
|
||||
options.networkAccessAllowed = NO;
|
||||
HXWeakSelf
|
||||
self.requestID = [HXAssetManager requestImageDataForAsset:asset options:options completion:^(NSData * _Nonnull imageData, UIImageOrientation orientation, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
[HXPhotoCommon photoCommon].clearAssetRequestID = -1;
|
||||
if (imageData) {
|
||||
if (addOnWindow || !weakSelf) {
|
||||
[HXCustomNavigationController addImageViewOnWindowWithImageData:imageData];
|
||||
}else {
|
||||
[weakSelf addImageViewWithImageData:imageData addOnWindow:addOnWindow];
|
||||
}
|
||||
}
|
||||
}];
|
||||
[HXPhotoCommon photoCommon].clearAssetRequestID = self.requestID;
|
||||
}
|
||||
}
|
||||
+ (void)addImageViewOnWindowWithImageData:(NSData *)imageData {
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
|
||||
imageView.alpha = 0;
|
||||
imageView.userInteractionEnabled = NO;
|
||||
imageView.frame = [UIScreen mainScreen].bounds;
|
||||
[[UIApplication sharedApplication].keyWindow addSubview:imageView];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[imageView removeFromSuperview];
|
||||
});
|
||||
}
|
||||
- (void)addImageViewWithImageData:(NSData *)imageData addOnWindow:(BOOL)addOnWindow {
|
||||
[self.imageView removeFromSuperview];
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
|
||||
imageView.alpha = 0;
|
||||
imageView.userInteractionEnabled = NO;
|
||||
imageView.frame = self.view.bounds;
|
||||
[self.view addSubview:imageView];
|
||||
self.imageView = imageView;
|
||||
}
|
||||
- (void)dealloc {
|
||||
if (_manager) {
|
||||
self.manager.selectPhotoing = NO;
|
||||
}
|
||||
if (_timer) {
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
}
|
||||
if (HXShowLog) NSSLog(@"%@ dealloc", self);
|
||||
}
|
||||
|
||||
@end
|
49
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhoto3DTouchViewController.h
generated
Normal file
49
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhoto3DTouchViewController.h
generated
Normal file
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// HXPhoto3DTouchViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/9/25.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoTools.h"
|
||||
|
||||
|
||||
#if __has_include(<SDWebImage/UIImageView+WebCache.h>)
|
||||
#import <SDWebImage/UIImageView+WebCache.h>
|
||||
#import <SDWebImage/SDAnimatedImageView.h>
|
||||
#import <SDWebImage/SDAnimatedImageView+WebCache.h>
|
||||
#import <SDWebImage/UIImage+GIF.h>
|
||||
#elif __has_include("UIImageView+WebCache.h")
|
||||
#import "UIImageView+WebCache.h"
|
||||
#import "UIImage+GIF.h"
|
||||
#import "SDAnimatedImageView.h"
|
||||
#import "SDAnimatedImageView+WebCache.h"
|
||||
#endif
|
||||
|
||||
#if __has_include(<YYWebImage/YYWebImage.h>)
|
||||
#import <YYWebImage/YYWebImage.h>
|
||||
#elif __has_include("YYWebImage.h")
|
||||
#import "YYWebImage.h"
|
||||
#elif __has_include(<YYKit/YYKit.h>)
|
||||
#import <YYKit/YYKit.h>
|
||||
#elif __has_include("YYKit.h")
|
||||
#import "YYKit.h"
|
||||
#endif
|
||||
|
||||
@interface HXPhoto3DTouchViewController : UIViewController
|
||||
@property (strong, nonatomic) HXPhotoModel *model;
|
||||
@property (strong, nonatomic) UIImage *image;
|
||||
@property (strong, nonatomic) UIImageView *imageView;
|
||||
#if HasSDWebImage
|
||||
@property (strong, nonatomic) SDAnimatedImageView *sdImageView;
|
||||
#elif HasYYKitOrWebImage
|
||||
@property (strong, nonatomic) YYAnimatedImageView *animatedImageView;
|
||||
#endif
|
||||
@property (strong, nonatomic) NSIndexPath *indexPath;
|
||||
|
||||
@property (copy, nonatomic) NSArray<id<UIPreviewActionItem>> *(^ previewActionItemsBlock)(void);
|
||||
@property (copy, nonatomic) void (^downloadImageComplete)(HXPhoto3DTouchViewController *vc, HXPhotoModel *model);
|
||||
@end
|
||||
|
399
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhoto3DTouchViewController.m
generated
Normal file
399
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhoto3DTouchViewController.m
generated
Normal file
|
@ -0,0 +1,399 @@
|
|||
//
|
||||
// HXPhoto3DTouchViewController.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/9/25.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhoto3DTouchViewController.h"
|
||||
#import <PhotosUI/PhotosUI.h>
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "HXCircleProgressView.h"
|
||||
#import "UIImageView+HXExtension.h"
|
||||
|
||||
@interface HXPhoto3DTouchViewController ()<PHLivePhotoViewDelegate>
|
||||
@property (strong, nonatomic) PHLivePhotoView *livePhotoView;
|
||||
@property (strong, nonatomic) AVPlayer *player;
|
||||
@property (strong, nonatomic) AVPlayerLayer *playerLayer;
|
||||
@property (strong, nonatomic) HXCircleProgressView *progressView;
|
||||
@property (strong, nonatomic) UIActivityIndicatorView *loadingView;
|
||||
@property (assign, nonatomic) PHImageRequestID requestId;
|
||||
@end
|
||||
|
||||
@implementation HXPhoto3DTouchViewController
|
||||
|
||||
- (NSArray<id<UIPreviewActionItem>> *)previewActionItems {
|
||||
NSArray *items = @[];
|
||||
if (self.previewActionItemsBlock) items = self.previewActionItemsBlock();
|
||||
return items;
|
||||
}
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
#if HasSDWebImage
|
||||
self.sdImageView.hx_size = self.model.previewViewSize;
|
||||
self.sdImageView.image = self.image;
|
||||
[self.view addSubview:self.sdImageView];
|
||||
self.progressView.center = CGPointMake(self.sdImageView.hx_size.width / 2, self.sdImageView.hx_size.height / 2);
|
||||
#elif HasYYKitOrWebImage
|
||||
self.animatedImageView.hx_size = self.model.previewViewSize;
|
||||
self.animatedImageView.image = self.image;
|
||||
[self.view addSubview:self.animatedImageView];
|
||||
self.progressView.center = CGPointMake(self.animatedImageView.hx_size.width / 2, self.animatedImageView.hx_size.height / 2);
|
||||
#else
|
||||
self.imageView.hx_size = self.model.previewViewSize;
|
||||
self.imageView.image = self.image;
|
||||
[self.view addSubview:self.imageView];
|
||||
self.progressView.center = CGPointMake(self.imageView.hx_size.width / 2, self.imageView.hx_size.height / 2);
|
||||
#endif
|
||||
[self.view addSubview:self.progressView];
|
||||
[self.view addSubview:self.loadingView];
|
||||
self.loadingView.center = self.progressView.center;
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
switch (self.model.type) {
|
||||
case HXPhotoModelMediaTypeVideo:
|
||||
[self loadVideo];
|
||||
break;
|
||||
case HXPhotoModelMediaTypeCameraVideo:
|
||||
[self loadVideo];
|
||||
break;
|
||||
case HXPhotoModelMediaTypePhotoGif:
|
||||
[self loadGifPhoto];
|
||||
break;
|
||||
case HXPhotoModelMediaTypeLivePhoto:
|
||||
[self loadLivePhoto];
|
||||
break;
|
||||
default:
|
||||
[self loadPhoto];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
if (self.requestId) {
|
||||
[[PHImageManager defaultManager] cancelImageRequest:self.requestId];
|
||||
}
|
||||
if (_livePhotoView) {
|
||||
self.livePhotoView.delegate = nil;
|
||||
[self.livePhotoView stopPlayback];
|
||||
[self.livePhotoView removeFromSuperview];
|
||||
self.livePhotoView.livePhoto = nil;
|
||||
self.livePhotoView = nil;
|
||||
}
|
||||
if (_progressView) {
|
||||
[self.progressView removeFromSuperview];
|
||||
}
|
||||
if (_loadingView) {
|
||||
[self.loadingView stopAnimating];
|
||||
}
|
||||
#if HasSDWebImage
|
||||
if (_sdImageView) {
|
||||
[self.view addSubview:self.sdImageView];
|
||||
}
|
||||
#elif HasYYKitOrWebImage
|
||||
if (_animatedImageView) {
|
||||
[self.view addSubview:self.animatedImageView];
|
||||
}
|
||||
#else
|
||||
if (_imageView) {
|
||||
[self.view addSubview:self.imageView];
|
||||
}
|
||||
#endif
|
||||
if (_player) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem];
|
||||
[self.player pause];
|
||||
[self.player seekToTime:kCMTimeZero];
|
||||
self.player = nil;
|
||||
}
|
||||
if (_playerLayer) {
|
||||
self.playerLayer.player = nil;
|
||||
[self.playerLayer removeFromSuperlayer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadPhoto {
|
||||
HXWeakSelf
|
||||
if (self.model.type == HXPhotoModelMediaTypeCameraPhoto) {
|
||||
if (self.model.networkPhotoUrl) {
|
||||
self.progressView.hidden = self.model.downloadComplete;
|
||||
CGFloat progress = (CGFloat)self.model.receivedSize / self.model.expectedSize;
|
||||
self.progressView.progress = progress;
|
||||
#if HasSDWebImage
|
||||
[self.sdImageView sd_setImageWithURL:self.model.networkPhotoUrl placeholderImage:self.model.thumbPhoto options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
|
||||
weakSelf.model.receivedSize = receivedSize;
|
||||
weakSelf.model.expectedSize = expectedSize;
|
||||
CGFloat progress = (CGFloat)receivedSize / expectedSize;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
weakSelf.progressView.progress = progress;
|
||||
});
|
||||
} completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
|
||||
if (error != nil) {
|
||||
weakSelf.model.downloadError = YES;
|
||||
weakSelf.model.downloadComplete = YES;
|
||||
[weakSelf.progressView showError];
|
||||
}else {
|
||||
if (image) {
|
||||
if (weakSelf.downloadImageComplete) {
|
||||
weakSelf.downloadImageComplete(weakSelf, weakSelf.model);
|
||||
}
|
||||
weakSelf.model.imageSize = image.size;
|
||||
weakSelf.model.thumbPhoto = image;
|
||||
weakSelf.model.previewPhoto = image;
|
||||
weakSelf.model.downloadComplete = YES;
|
||||
weakSelf.model.downloadError = NO;
|
||||
weakSelf.model.imageSize = image.size;
|
||||
weakSelf.progressView.progress = 1;
|
||||
weakSelf.progressView.hidden = YES;
|
||||
weakSelf.sdImageView.image = image;
|
||||
}
|
||||
}
|
||||
}];
|
||||
#elif HasYYKitOrWebImage
|
||||
[self.animatedImageView hx_setImageWithModel:self.model progress:^(CGFloat progress, HXPhotoModel *model) {
|
||||
if (weakSelf.model == model) {
|
||||
weakSelf.progressView.progress = progress;
|
||||
}
|
||||
} completed:^(UIImage *image, NSError *error, HXPhotoModel *model) {
|
||||
if (weakSelf.model == model) {
|
||||
if (error != nil) {
|
||||
[weakSelf.progressView showError];
|
||||
}else {
|
||||
if (image) {
|
||||
if (weakSelf.downloadImageComplete) {
|
||||
weakSelf.downloadImageComplete(weakSelf, weakSelf.model);
|
||||
}
|
||||
weakSelf.progressView.progress = 1;
|
||||
weakSelf.progressView.hidden = YES;
|
||||
weakSelf.animatedImageView.image = image;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
#else
|
||||
[self.imageView hx_setImageWithModel:self.model progress:^(CGFloat progress, HXPhotoModel *model) {
|
||||
if (weakSelf.model == model) {
|
||||
weakSelf.progressView.progress = progress;
|
||||
}
|
||||
} completed:^(UIImage *image, NSError *error, HXPhotoModel *model) {
|
||||
if (weakSelf.model == model) {
|
||||
if (error != nil) {
|
||||
[weakSelf.progressView showError];
|
||||
}else {
|
||||
if (image) {
|
||||
if (weakSelf.downloadImageComplete) {
|
||||
weakSelf.downloadImageComplete(weakSelf, weakSelf.model);
|
||||
}
|
||||
weakSelf.progressView.progress = 1;
|
||||
weakSelf.progressView.hidden = YES;
|
||||
weakSelf.imageView.image = image;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
#endif
|
||||
}else {
|
||||
#if HasSDWebImage
|
||||
self.sdImageView.image = self.model.thumbPhoto;
|
||||
#elif HasYYKitOrWebImage
|
||||
self.animatedImageView.image = self.model.thumbPhoto;
|
||||
#else
|
||||
self.imageView.image = self.model.thumbPhoto;
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
}
|
||||
[self loadImageDataWithCompletion:^(NSData *imageData) {
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
#if HasSDWebImage
|
||||
weakSelf.sdImageView.image = image;
|
||||
#elif HasYYKitOrWebImage
|
||||
weakSelf.animatedImageView.image = image;
|
||||
#else
|
||||
weakSelf.imageView.image = image;
|
||||
#endif
|
||||
}];
|
||||
}
|
||||
- (void)loadImageDataWithCompletion:(void (^)(NSData *imageData))completion {
|
||||
HXWeakSelf
|
||||
self.requestId = [self.model requestImageDataStartRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
|
||||
weakSelf.requestId = iCloudRequestId;
|
||||
if (weakSelf.model.isICloud) {
|
||||
weakSelf.progressView.hidden = NO;
|
||||
}
|
||||
} progressHandler:^(double progress, HXPhotoModel *model) {
|
||||
if (weakSelf.model.isICloud) {
|
||||
weakSelf.progressView.hidden = NO;
|
||||
}
|
||||
weakSelf.progressView.progress = progress;
|
||||
} success:^(NSData *imageData, UIImageOrientation orientation, HXPhotoModel *model, NSDictionary *info) {
|
||||
weakSelf.progressView.hidden = YES;
|
||||
if (completion) {
|
||||
completion(imageData);
|
||||
}
|
||||
} failed:^(NSDictionary *info, HXPhotoModel *model) {
|
||||
// [weakSelf.progressView showError];
|
||||
}];
|
||||
}
|
||||
- (void)loadGifPhoto {
|
||||
HXWeakSelf
|
||||
[self loadImageDataWithCompletion:^(NSData *imageData) {
|
||||
#if HasSDWebImage
|
||||
UIImage *gifImage = [UIImage sd_imageWithGIFData:imageData];
|
||||
if (gifImage.images.count > 0) {
|
||||
weakSelf.sdImageView.image = nil;
|
||||
weakSelf.sdImageView.image = gifImage;
|
||||
}
|
||||
#elif HasYYKitOrWebImage
|
||||
YYImage *gifImage = [YYImage imageWithData:imageData];
|
||||
weakSelf.animatedImageView.image = nil;
|
||||
weakSelf.animatedImageView.image = gifImage;
|
||||
#else
|
||||
UIImage *gifImage = [UIImage hx_animatedGIFWithData:imageData];
|
||||
if (gifImage.images.count > 0) {
|
||||
weakSelf.imageView.image = nil;
|
||||
weakSelf.imageView.image = gifImage;
|
||||
}
|
||||
#endif
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)loadLivePhoto {
|
||||
self.livePhotoView = [[PHLivePhotoView alloc] initWithFrame:CGRectMake(0, 0, self.model.previewViewSize.width, self.model.previewViewSize.height)];
|
||||
self.livePhotoView.delegate = self;
|
||||
self.livePhotoView.clipsToBounds = YES;
|
||||
self.livePhotoView.hidden = YES;
|
||||
self.livePhotoView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
[self.view addSubview:self.livePhotoView];
|
||||
HXWeakSelf
|
||||
self.requestId = [self.model requestLivePhotoWithSize:CGSizeMake(self.model.previewViewSize.width * 1.5, self.model.previewViewSize.height * 1.5) startRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
|
||||
weakSelf.requestId = iCloudRequestId;
|
||||
if (weakSelf.model.isICloud) {
|
||||
weakSelf.progressView.hidden = NO;
|
||||
}
|
||||
} progressHandler:^(double progress, HXPhotoModel *model) {
|
||||
if (weakSelf.model.isICloud) {
|
||||
weakSelf.progressView.hidden = NO;
|
||||
}
|
||||
weakSelf.progressView.progress = progress;
|
||||
} success:^(PHLivePhoto *livePhoto, HXPhotoModel *model, NSDictionary *info) {
|
||||
weakSelf.progressView.hidden = YES;
|
||||
weakSelf.livePhotoView.hidden = NO;
|
||||
weakSelf.livePhotoView.livePhoto = livePhoto;
|
||||
[weakSelf.livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleFull];
|
||||
#if HasSDWebImage
|
||||
[weakSelf.sdImageView removeFromSuperview];
|
||||
#elif HasYYKitOrWebImage
|
||||
[weakSelf.animatedImageView removeFromSuperview];
|
||||
#else
|
||||
[weakSelf.imageView removeFromSuperview];
|
||||
#endif
|
||||
|
||||
} failed:^(NSDictionary *info, HXPhotoModel *model) {
|
||||
|
||||
}];
|
||||
}
|
||||
- (void)livePhotoView:(PHLivePhotoView *)livePhotoView didEndPlaybackWithStyle:(PHLivePhotoViewPlaybackStyle)playbackStyle {
|
||||
[self.livePhotoView startPlaybackWithStyle:PHLivePhotoViewPlaybackStyleFull];
|
||||
}
|
||||
- (void)loadVideo {
|
||||
HXWeakSelf
|
||||
self.requestId = [self.model requestAVAssetStartRequestICloud:^(PHImageRequestID iCloudRequestId, HXPhotoModel *model) {
|
||||
weakSelf.requestId = iCloudRequestId;
|
||||
[weakSelf.loadingView startAnimating];
|
||||
} progressHandler:^(double progress, HXPhotoModel *model) {
|
||||
if (weakSelf.model.isICloud) {
|
||||
weakSelf.progressView.hidden = NO;
|
||||
}
|
||||
weakSelf.progressView.progress = progress;
|
||||
} success:^(AVAsset *avAsset, AVAudioMix *audioMix, HXPhotoModel *model, NSDictionary *info) {
|
||||
weakSelf.progressView.hidden = YES;
|
||||
weakSelf.player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithAsset:avAsset]];
|
||||
[weakSelf playVideo];
|
||||
[weakSelf.loadingView stopAnimating];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:weakSelf selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:weakSelf.player.currentItem];
|
||||
} failed:^(NSDictionary *info, HXPhotoModel *model) {
|
||||
[weakSelf.loadingView stopAnimating];
|
||||
}];
|
||||
}
|
||||
- (void)pausePlayerAndShowNaviBar {
|
||||
[self.player.currentItem seekToTime:CMTimeMake(0, 1)];
|
||||
[self.player play];
|
||||
}
|
||||
- (void)playVideo {
|
||||
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
|
||||
self.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
self.playerLayer.frame = CGRectMake(0, 0, self.model.previewViewSize.width, self.model.previewViewSize.height);
|
||||
[self.view.layer insertSublayer:self.playerLayer atIndex:0];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self.player play];
|
||||
#if HasSDWebImage
|
||||
[self.sdImageView removeFromSuperview];
|
||||
#elif HasYYKitOrWebImage
|
||||
[self.animatedImageView removeFromSuperview];
|
||||
#else
|
||||
[self.imageView removeFromSuperview];
|
||||
#endif
|
||||
});
|
||||
}
|
||||
#if HasSDWebImage
|
||||
- (SDAnimatedImageView *)sdImageView {
|
||||
if (!_sdImageView) {
|
||||
_sdImageView = [[SDAnimatedImageView alloc] init];
|
||||
_sdImageView.clipsToBounds = YES;
|
||||
_sdImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_sdImageView.hx_x = 0;
|
||||
_sdImageView.hx_y = 0;
|
||||
}
|
||||
return _sdImageView;
|
||||
}
|
||||
#elif HasYYKitOrWebImage
|
||||
- (YYAnimatedImageView *)animatedImageView {
|
||||
if (!_animatedImageView) {
|
||||
_animatedImageView = [[YYAnimatedImageView alloc] init];
|
||||
_animatedImageView.clipsToBounds = YES;
|
||||
_animatedImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_animatedImageView.hx_x = 0;
|
||||
_animatedImageView.hx_y = 0;
|
||||
}
|
||||
return _animatedImageView;
|
||||
}
|
||||
#endif
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
_imageView.clipsToBounds = YES;
|
||||
_imageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_imageView.hx_x = 0;
|
||||
_imageView.hx_y = 0;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
- (HXCircleProgressView *)progressView {
|
||||
if (!_progressView) {
|
||||
_progressView = [[HXCircleProgressView alloc] init];
|
||||
_progressView.hidden = YES;
|
||||
}
|
||||
return _progressView;
|
||||
}
|
||||
- (UIActivityIndicatorView *)loadingView {
|
||||
if (!_loadingView) {
|
||||
_loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
//- (PHLivePhotoView *)livePhotoView {
|
||||
// if (!_livePhotoView) {
|
||||
// _livePhotoView = [[PHLivePhotoView alloc] init];
|
||||
// _livePhotoView.clipsToBounds = YES;
|
||||
// _livePhotoView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
// }
|
||||
// return _livePhotoView;
|
||||
//}
|
||||
@end
|
||||
|
85
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoEditViewController.h
generated
Normal file
85
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoEditViewController.h
generated
Normal file
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// HXPhotoEditViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/27.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoManager.h"
|
||||
|
||||
@class HXPhotoEditViewController;
|
||||
|
||||
typedef void (^ HXPhotoEditViewControllerDidDoneBlock)(HXPhotoModel *beforeModel, HXPhotoModel *afterModel, HXPhotoEditViewController *viewController);
|
||||
typedef void (^ HXPhotoEditViewControllerDidCancelBlock)(HXPhotoEditViewController *viewController);
|
||||
|
||||
@protocol HXPhotoEditViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/// 编辑完成
|
||||
/// @param photoEditViewController 照片编辑控制器
|
||||
/// @param beforeModel 编辑之前的模型
|
||||
/// @param afterModel 编辑之后的模型
|
||||
- (void)photoEditViewControllerDidClipClick:(HXPhotoEditViewController *)photoEditViewController beforeModel:(HXPhotoModel *)beforeModel afterModel:(HXPhotoModel *)afterModel;
|
||||
|
||||
/// 取消编辑
|
||||
/// @param photoEditViewController 照片编辑控制器
|
||||
- (void)photoEditViewControllerDidCancel:(HXPhotoEditViewController *)photoEditViewController;
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditViewController : UIViewController<UIViewControllerTransitioningDelegate>
|
||||
@property (weak, nonatomic) id<HXPhotoEditViewControllerDelegate> delegate;
|
||||
/// 需要编辑的照片模型
|
||||
@property (strong, nonatomic) HXPhotoModel *model;
|
||||
/// 照片管理类
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
|
||||
@property (copy, nonatomic) HXPhotoEditViewControllerDidDoneBlock doneBlock;
|
||||
@property (copy, nonatomic) HXPhotoEditViewControllerDidCancelBlock cancelBlock;
|
||||
|
||||
@property (assign, nonatomic) BOOL outside;
|
||||
@property (assign, nonatomic) BOOL isInside;
|
||||
@property (assign, nonatomic) BOOL imageRequestComplete;
|
||||
@property (assign, nonatomic) BOOL transitionCompletion;
|
||||
@property (assign, nonatomic) BOOL isCancel;
|
||||
@property (strong, nonatomic, readonly) UIImage *originalImage;
|
||||
- (void)completeTransition:(UIImage *)image;
|
||||
- (void)showBottomView;
|
||||
- (void)hideImageView;
|
||||
- (UIImage *)getCurrentImage;
|
||||
- (CGRect)getImageFrame;
|
||||
@end
|
||||
|
||||
@class HXEditRatio;
|
||||
@protocol HXPhotoEditBottomViewDelegate <NSObject>
|
||||
@optional
|
||||
- (void)bottomViewDidCancelClick;
|
||||
- (void)bottomViewDidRestoreClick;
|
||||
- (void)bottomViewDidRotateClick;
|
||||
- (void)bottomViewDidClipClick;
|
||||
- (void)bottomViewDidSelectRatioClick:(HXEditRatio *)ratio;
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditBottomView : UIView
|
||||
@property (weak, nonatomic) id<HXPhotoEditBottomViewDelegate> delegate;
|
||||
@property (assign, nonatomic) BOOL enabled;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager;
|
||||
@end
|
||||
|
||||
@interface HXEditGridLayer : UIView
|
||||
@property (nonatomic, assign) CGRect clippingRect;
|
||||
@property (nonatomic, strong) UIColor *bgColor;
|
||||
@property (nonatomic, strong) UIColor *gridColor;
|
||||
@end
|
||||
|
||||
@interface HXEditCornerView : UIView
|
||||
@property (nonatomic, strong) UIColor *bgColor;
|
||||
@end
|
||||
|
||||
@interface HXEditRatio : NSObject
|
||||
@property (nonatomic, assign) BOOL isLandscape;
|
||||
@property (nonatomic, readonly) CGFloat ratio;
|
||||
@property (nonatomic, strong) NSString *titleFormat;
|
||||
- (id)initWithValue1:(CGFloat)value1 value2:(CGFloat)value2;
|
||||
@end
|
1226
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoEditViewController.m
generated
Normal file
1226
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoEditViewController.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
119
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoPreviewViewController.h
generated
Normal file
119
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoPreviewViewController.h
generated
Normal file
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// HXPhotoPreviewViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <PhotosUI/PhotosUI.h>
|
||||
#import "HXPhotoManager.h"
|
||||
#import "HXPhotoView.h"
|
||||
#import "HXPhotoPreviewImageViewCell.h"
|
||||
#import "HXPhotoPreviewVideoViewCell.h"
|
||||
#import "HXPhotoPreviewLivePhotoCell.h"
|
||||
|
||||
@class
|
||||
HXPhotoPreviewViewController,
|
||||
HXPhotoPreviewBottomView,
|
||||
HXPhotoPreviewViewCell;
|
||||
@protocol HXPhotoPreviewViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/// 选择某个model
|
||||
/// 根据 model.selected 来判断是否选中
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param model 当前选择的模型
|
||||
- (void)photoPreviewControllerDidSelect:(HXPhotoPreviewViewController *)previewController
|
||||
model:(HXPhotoModel *)model;
|
||||
|
||||
/// 点击
|
||||
/// @param previewController 照片预览控制器
|
||||
- (void)photoPreviewControllerDidDone:(HXPhotoPreviewViewController *)previewController;
|
||||
|
||||
/// 预览界面编辑完成之后的回调
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param model 编辑之后的模型
|
||||
/// @param beforeModel 编辑之前的模型
|
||||
- (void)photoPreviewDidEditClick:(HXPhotoPreviewViewController *)previewController
|
||||
model:(HXPhotoModel *)model
|
||||
beforeModel:(HXPhotoModel *)beforeModel;
|
||||
|
||||
/// 单选模式下选择了某个model
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param model 当前选择的model
|
||||
- (void)photoPreviewSingleSelectedClick:(HXPhotoPreviewViewController *)previewController
|
||||
model:(HXPhotoModel *)model;
|
||||
|
||||
/// 预览界面加载iCloud上的照片完成后的回调
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param model 当前model
|
||||
- (void)photoPreviewDownLoadICloudAssetComplete:(HXPhotoPreviewViewController *)previewController
|
||||
model:(HXPhotoModel *)model;
|
||||
|
||||
/// 在HXPhotoView上预览时编辑model完成之后的回调
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param beforeModel 编辑之前的model
|
||||
/// @param afterModel 编辑之后的model
|
||||
- (void)photoPreviewSelectLaterDidEditClick:(HXPhotoPreviewViewController *)previewController
|
||||
beforeModel:(HXPhotoModel *)beforeModel
|
||||
afterModel:(HXPhotoModel *)afterModel;
|
||||
|
||||
/// 在HXPhotoView上预览时删除model的回调
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param model 被删除的model
|
||||
/// @param index model下标
|
||||
- (void)photoPreviewDidDeleteClick:(HXPhotoPreviewViewController *)previewController
|
||||
deleteModel:(HXPhotoModel *)model
|
||||
deleteIndex:(NSInteger)index;
|
||||
|
||||
/// 预览时网络图片下载完成的回调,用于刷新前一个界面的展示
|
||||
/// @param previewController 照片预览控制器
|
||||
/// @param model 当前预览的model
|
||||
- (void)photoPreviewCellDownloadImageComplete:(HXPhotoPreviewViewController *)previewController
|
||||
model:(HXPhotoModel *)model;
|
||||
|
||||
/// 取消预览
|
||||
/// @param previewController self
|
||||
/// @param model 取消时展示的model
|
||||
- (void)photoPreviewControllerDidCancel:(HXPhotoPreviewViewController *)previewController
|
||||
model:(HXPhotoModel *)model;
|
||||
|
||||
|
||||
- (void)photoPreviewControllerFinishDismissCompletion:(HXPhotoPreviewViewController *)previewController;
|
||||
- (void)photoPreviewControllerCancelDismissCompletion:(HXPhotoPreviewViewController *)previewController;
|
||||
@end
|
||||
|
||||
/// 单独使用 HXPhotoPreviewViewController 来预览图片
|
||||
/// 请使用 <UIViewController+HXExtension> 中的方法
|
||||
@interface HXPhotoPreviewViewController : UIViewController<UIViewControllerTransitioningDelegate,UINavigationControllerDelegate>
|
||||
@property (weak, nonatomic) id<HXPhotoPreviewViewControllerDelegate> delegate;
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
@property (strong, nonatomic) NSMutableArray *modelArray;
|
||||
@property (assign, nonatomic) NSInteger currentModelIndex;
|
||||
@property (assign, nonatomic) BOOL outside;
|
||||
@property (assign, nonatomic) BOOL selectPreview;
|
||||
@property (strong, nonatomic) UICollectionView *collectionView;
|
||||
@property (strong, nonatomic) HXPhotoPreviewBottomView *bottomView;
|
||||
@property (strong, nonatomic) HXPhotoView *photoView;
|
||||
/// 停止取消
|
||||
@property (assign, nonatomic) BOOL stopCancel;
|
||||
/// 预览时显示删除按钮
|
||||
@property (assign, nonatomic) BOOL previewShowDeleteButton;
|
||||
/// 预览大图时是否禁用手势返回
|
||||
@property (assign, nonatomic) BOOL disableaPersentInteractiveTransition;
|
||||
/// 使用HXPhotoView预览大图时的风格样式
|
||||
@property (assign, nonatomic) HXPhotoViewPreViewShowStyle exteriorPreviewStyle;
|
||||
/// 预览时是否显示底部pageControl
|
||||
@property (assign, nonatomic) BOOL showBottomPageControl;
|
||||
/// 处理ios8 导航栏转场动画崩溃问题
|
||||
@property (strong, nonatomic) UIViewController *photoViewController;
|
||||
|
||||
- (HXPhotoPreviewViewCell *)currentPreviewCell:(HXPhotoModel *)model;
|
||||
- (HXPhotoPreviewViewCell *)currentPreviewCell;
|
||||
- (void)changeStatusBarWithHidden:(BOOL)hidden;
|
||||
- (void)setSubviewAlphaAnimate:(BOOL)animete duration:(NSTimeInterval)duration;
|
||||
- (void)setupDarkBtnAlpha:(CGFloat)alpha;
|
||||
- (void)setCellImage:(UIImage *)image;
|
||||
@end
|
1658
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoPreviewViewController.m
generated
Normal file
1658
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoPreviewViewController.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
153
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoViewController.h
generated
Normal file
153
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoViewController.h
generated
Normal file
|
@ -0,0 +1,153 @@
|
|||
//
|
||||
// HXPhotoViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/10/14.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoManager.h"
|
||||
#import "HXCustomCollectionReusableView.h"
|
||||
#import "HXPhotoLimitView.h"
|
||||
#import "HXPickerResult.h"
|
||||
|
||||
@class
|
||||
HXPhotoViewController ,
|
||||
HXPhotoViewCell ,
|
||||
HXPhotoBottomView ,
|
||||
HXCustomPreviewView ,
|
||||
HXAlbumListViewController,
|
||||
HXCustomCameraController;
|
||||
@protocol HXPhotoViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/**
|
||||
点击取消
|
||||
|
||||
@param photoViewController self
|
||||
*/
|
||||
- (void)photoViewControllerDidCancel:(HXPhotoViewController *)photoViewController;
|
||||
|
||||
/**
|
||||
点击完成按钮
|
||||
|
||||
@param photoViewController self
|
||||
@param allList 已选的所有列表(包含照片、视频)
|
||||
@param photoList 已选的照片列表
|
||||
@param videoList 已选的视频列表
|
||||
@param original 是否原图
|
||||
*/
|
||||
- (void)photoViewController:(HXPhotoViewController *)photoViewController
|
||||
didDoneAllList:(NSArray<HXPhotoModel *> *)allList
|
||||
photos:(NSArray<HXPhotoModel *> *)photoList
|
||||
videos:(NSArray<HXPhotoModel *> *)videoList
|
||||
original:(BOOL)original;
|
||||
|
||||
- (void)photoViewController:(HXPhotoViewController *)photoViewController
|
||||
didDoneWithResult:(HXPickerResult *)result;
|
||||
|
||||
/**
|
||||
改变了选择
|
||||
|
||||
@param model 改的模型
|
||||
@param selected 是否选中
|
||||
*/
|
||||
- (void)photoViewControllerDidChangeSelect:(HXPhotoModel *)model
|
||||
selected:(BOOL)selected;
|
||||
|
||||
- (void)photoViewControllerFinishDismissCompletion:(HXPhotoViewController *)photoViewController;
|
||||
- (void)photoViewControllerCancelDismissCompletion:(HXPhotoViewController *)photoViewController;
|
||||
@end
|
||||
|
||||
@interface HXPhotoViewController : UIViewController
|
||||
@property (copy, nonatomic) viewControllerDidDoneBlock doneBlock;
|
||||
@property (copy, nonatomic) viewControllerDidCancelBlock cancelBlock;
|
||||
@property (weak, nonatomic) id<HXPhotoViewControllerDelegate> delegate;
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
@property (strong, nonatomic) HXAlbumModel *albumModel;
|
||||
@property (strong, nonatomic) HXPhotoBottomView *bottomView;
|
||||
@property (strong, nonatomic) HXPhotoLimitView *limitView;
|
||||
- (HXPhotoViewCell *)currentPreviewCell:(HXPhotoModel *)model;
|
||||
- (BOOL)scrollToModel:(HXPhotoModel *)model;
|
||||
- (void)scrollToPoint:(HXPhotoViewCell *)cell rect:(CGRect)rect;
|
||||
- (void)startGetAllPhotoModel;
|
||||
@end
|
||||
|
||||
@protocol HXPhotoViewCellDelegate <NSObject>
|
||||
@optional
|
||||
- (void)photoViewCell:(HXPhotoViewCell *)cell didSelectBtn:(UIButton *)selectBtn;
|
||||
- (void)photoViewCellRequestICloudAssetComplete:(HXPhotoViewCell *)cell;
|
||||
@end
|
||||
|
||||
@interface HXPhotoViewCell : UICollectionViewCell
|
||||
@property (weak, nonatomic) id<HXPhotoViewCellDelegate> delegate;
|
||||
@property (assign, nonatomic) NSInteger section;
|
||||
@property (assign, nonatomic) NSInteger item;
|
||||
@property (assign, nonatomic) BOOL canSelect;
|
||||
@property (strong, nonatomic, readonly) UIImageView *imageView;
|
||||
@property (strong, nonatomic) CALayer *selectMaskLayer;
|
||||
@property (strong, nonatomic) HXPhotoModel *model;
|
||||
@property (assign, nonatomic) BOOL singleSelected;
|
||||
@property (strong, nonatomic) UIColor *selectBgColor;
|
||||
@property (strong, nonatomic) UIColor *selectedTitleColor;
|
||||
@property (strong, nonatomic) UIColor *darkSelectBgColor;
|
||||
@property (strong, nonatomic) UIColor *darkSelectedTitleColor;
|
||||
@property (strong, nonatomic, readonly) CALayer *videoMaskLayer;
|
||||
@property (strong, nonatomic, readonly) UIButton *selectBtn;
|
||||
- (void)resetNetworkImage;
|
||||
- (void)cancelRequest;
|
||||
- (void)startRequestICloudAsset;
|
||||
- (void)bottomViewPrepareAnimation;
|
||||
- (void)bottomViewStartAnimation;
|
||||
- (void)setModel:(HXPhotoModel *)model emptyImage:(BOOL)emptyImage;
|
||||
- (void)setModelDataWithHighQuality:(BOOL)highQuality completion:(void (^)(HXPhotoViewCell *myCell))completion;
|
||||
@end
|
||||
|
||||
@interface HXPhotoCameraViewCell : UICollectionViewCell
|
||||
@property (strong, nonatomic) HXPhotoModel *model;
|
||||
@property (strong, nonatomic, readonly) HXCustomCameraController *cameraController;
|
||||
@property (strong, nonatomic) UIImage *cameraImage;
|
||||
@property (assign, nonatomic) BOOL cameraSelected;
|
||||
@property (assign, nonatomic) BOOL startSession;
|
||||
@property (strong, nonatomic) UIColor *bgColor;
|
||||
- (void)starRunning;
|
||||
- (void)stopRunning;
|
||||
@end
|
||||
|
||||
@interface HXPhotoLimitViewCell : UICollectionViewCell
|
||||
@property (strong, nonatomic) UIColor *bgColor;
|
||||
@property (strong, nonatomic) UIColor *bgDarkColor;
|
||||
@property (strong, nonatomic) UIColor *lineColor;
|
||||
@property (strong, nonatomic) UIColor *lineDarkColor;
|
||||
@property (strong, nonatomic) UIColor *textColor;
|
||||
@property (strong, nonatomic) UIColor *textDarkColor;
|
||||
@property (strong, nonatomic) UIFont *textFont;
|
||||
|
||||
- (void)config;
|
||||
@end
|
||||
|
||||
@interface HXPhotoViewSectionFooterView : UICollectionReusableView
|
||||
@property (assign, nonatomic) NSInteger photoCount;
|
||||
@property (assign, nonatomic) NSInteger videoCount;
|
||||
@property (strong, nonatomic) UIColor *bgColor;
|
||||
@property (strong, nonatomic) UIColor *textColor;
|
||||
@end
|
||||
|
||||
@protocol HXPhotoBottomViewDelegate <NSObject>
|
||||
@optional
|
||||
- (void)photoBottomViewDidPreviewBtn;
|
||||
- (void)photoBottomViewDidDoneBtn;
|
||||
- (void)photoBottomViewDidEditBtn;
|
||||
@end
|
||||
|
||||
@interface HXPhotoBottomView : UIView
|
||||
@property (weak, nonatomic) id<HXPhotoBottomViewDelegate> delegate;
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
@property (assign, nonatomic) BOOL previewBtnEnabled;
|
||||
@property (assign, nonatomic) BOOL doneBtnEnabled;
|
||||
@property (assign, nonatomic) NSInteger selectCount;
|
||||
@property (strong, nonatomic) UIButton *originalBtn;
|
||||
@property (strong, nonatomic) UIToolbar *bgView;
|
||||
- (void)requestPhotosBytes;
|
||||
@end
|
3599
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoViewController.m
generated
Normal file
3599
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXPhotoViewController.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
123
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXVideoEditViewController.h
generated
Normal file
123
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXVideoEditViewController.h
generated
Normal file
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// HXVideoEditViewController.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/12/31.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoManager.h"
|
||||
|
||||
@class
|
||||
HXVideoEditViewController,
|
||||
HXVideoEditBottomView,
|
||||
HXEditFrameView;
|
||||
|
||||
typedef void (^ HXVideoEditViewControllerDidDoneBlock)(HXPhotoModel *beforeModel, HXPhotoModel *afterModel, HXVideoEditViewController *viewController);
|
||||
typedef void (^ HXVideoEditViewControllerDidCancelBlock)(HXVideoEditViewController *viewController);
|
||||
|
||||
@protocol HXVideoEditViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
|
||||
/// 编辑完成
|
||||
/// @param videoEditViewController 视频编辑控制器
|
||||
/// @param beforeModel 编辑之前的模型
|
||||
/// @param afterModel 编辑之后的模型
|
||||
- (void)videoEditViewControllerDidDoneClick:(HXVideoEditViewController *)videoEditViewController beforeModel:(HXPhotoModel *)beforeModel afterModel:(HXPhotoModel *)afterModel;
|
||||
|
||||
/// 取消编辑
|
||||
/// @param videoEditViewController 视频编辑控制器
|
||||
- (void)videoEditViewControllerDidCancelClick:(HXVideoEditViewController *)videoEditViewController;
|
||||
@end
|
||||
@interface HXVideoEditViewController : UIViewController<UIViewControllerTransitioningDelegate>
|
||||
@property (weak, nonatomic) id<HXVideoEditViewControllerDelegate> delegate;
|
||||
|
||||
/// 需要编辑的模型
|
||||
@property (strong, nonatomic) HXPhotoModel *model;
|
||||
/// 照片管理类
|
||||
@property (strong, nonatomic) HXPhotoManager *manager;
|
||||
|
||||
@property (copy, nonatomic) HXVideoEditViewControllerDidDoneBlock doneBlock;
|
||||
@property (copy, nonatomic) HXVideoEditViewControllerDidCancelBlock cancelBlock;
|
||||
|
||||
@property (assign, nonatomic) BOOL outside;
|
||||
@property (assign, nonatomic) BOOL isInside;
|
||||
@property (strong, nonatomic) UIView *videoView;
|
||||
@property (strong, nonatomic) AVPlayerLayer *playerLayer;
|
||||
@property (strong, nonatomic) AVAsset *avAsset;
|
||||
|
||||
@property (strong, nonatomic) UIImageView *bgImageView;
|
||||
@property (assign, nonatomic) BOOL requestComplete;
|
||||
@property (assign, nonatomic) BOOL transitionCompletion;
|
||||
@property (assign, nonatomic) BOOL isCancel;
|
||||
|
||||
- (void)completeTransition;
|
||||
- (void)showBottomView;
|
||||
- (CGRect)getVideoRect;
|
||||
@end
|
||||
|
||||
|
||||
@protocol HXVideoEditBottomViewDelegate <NSObject>
|
||||
@optional
|
||||
- (void)videoEditBottomViewDidCancelClick:(HXVideoEditBottomView *)bottomView;
|
||||
- (void)videoEditBottomViewDidDoneClick:(HXVideoEditBottomView *)bottomView;
|
||||
- (void)videoEditBottomViewValidRectChanged:(HXVideoEditBottomView *)bottomView;
|
||||
- (void)videoEditBottomViewValidRectEndChanged:(HXVideoEditBottomView *)bottomView;
|
||||
|
||||
- (void)videoEditBottomViewIndicatorLinePanGestureBegan:(HXVideoEditBottomView *)bottomView frame:(CGRect)frame second:(CGFloat)second;
|
||||
- (void)videoEditBottomViewIndicatorLinePanGestureChanged:(HXVideoEditBottomView *)bottomView second:(CGFloat)second;
|
||||
- (void)videoEditBottomViewIndicatorLinePanGestureEnd:(HXVideoEditBottomView *)bottomView frame:(CGRect)frame second:(CGFloat)second;
|
||||
|
||||
@end
|
||||
@interface HXVideoEditBottomView : UIView
|
||||
@property (strong, nonatomic) UIButton *playBtn;
|
||||
@property (assign, nonatomic) CGFloat itemHeight;
|
||||
@property (assign, nonatomic) CGFloat itemWidth;
|
||||
@property (assign, nonatomic) CGFloat validRectX;
|
||||
@property (strong, nonatomic) HXPhotoModel *model;
|
||||
@property (strong, nonatomic) UICollectionView *collectionView;
|
||||
@property (strong, nonatomic) HXEditFrameView *editView;
|
||||
@property (strong, nonatomic) AVAsset *avAsset;
|
||||
@property (assign, nonatomic) CGFloat interval;
|
||||
@property (assign, nonatomic) CGFloat contentWidth;
|
||||
@property (assign, nonatomic) CGFloat singleItemSecond;
|
||||
@property (strong, nonatomic) NSMutableArray *dataArray;
|
||||
@property (strong, nonatomic) UIView *indicatorLine;
|
||||
@property (weak, nonatomic) id<HXVideoEditBottomViewDelegate> delegate;
|
||||
@property (copy, nonatomic) void (^ scrollViewDidScroll)(void);
|
||||
@property (copy, nonatomic) void (^ startTimer)(void);
|
||||
@property (strong, nonatomic) UILabel *startTimeLb;
|
||||
@property (strong, nonatomic) UILabel *endTimeLb;
|
||||
@property (strong, nonatomic) UILabel *totalTimeLb;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager;
|
||||
|
||||
- (void)removeLineView;
|
||||
- (void)startLineAnimationWithDuration:(NSTimeInterval)duration;
|
||||
- (void)panGestureStarAnimationWithDuration:(NSTimeInterval)duration;
|
||||
- (void)updateTimeLbsFrame;
|
||||
@end
|
||||
|
||||
@interface HXVideoEditBottomViewCell : UICollectionViewCell
|
||||
@property (strong, nonatomic) UIImageView *imageView;
|
||||
@end
|
||||
|
||||
|
||||
@protocol HXEditFrameViewDelegate <NSObject>
|
||||
|
||||
- (void)editViewValidRectChanged;
|
||||
|
||||
- (void)editViewValidRectEndChanged;
|
||||
|
||||
@end
|
||||
@interface HXEditFrameView : UIView
|
||||
@property (assign, nonatomic) CGFloat itemHeight;
|
||||
@property (assign, nonatomic) CGFloat itemWidth;
|
||||
@property (assign, nonatomic) CGFloat validRectX;
|
||||
@property (nonatomic, assign) CGRect validRect;
|
||||
@property (assign, nonatomic) CGFloat contentWidth;
|
||||
@property (assign, nonatomic) NSTimeInterval videoTime;
|
||||
@property (nonatomic, weak) id <HXEditFrameViewDelegate> delegate;
|
||||
- (instancetype)initWithManager:(HXPhotoManager *)manager;
|
||||
@end
|
||||
|
1162
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXVideoEditViewController.m
generated
Normal file
1162
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/Controller/HXVideoEditViewController.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,215 @@
|
|||
//
|
||||
// HXAssetManager.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2020/11/5.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <Photos/Photos.h>
|
||||
#import "HXPhotoTypes.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class HXAlbumModel;
|
||||
@interface HXAssetManager : NSObject
|
||||
|
||||
/// 获取智能相册
|
||||
+ (PHFetchResult<PHAssetCollection *> *)fetchSmartAlbumsWithOptions:(PHFetchOptions * _Nullable)options;
|
||||
|
||||
/// 获取用户创建的相册
|
||||
+ (PHFetchResult<PHAssetCollection *> *)fetchUserAlbumsWithOptions:(PHFetchOptions * _Nullable)options;
|
||||
|
||||
/// 获取相机胶卷
|
||||
+ (PHAssetCollection *)fetchCameraRollAlbumWithOptions:(PHFetchOptions * _Nullable)options;
|
||||
|
||||
/// 获取所有相册
|
||||
+ (void)enumerateAllAlbumsWithOptions:(PHFetchOptions * _Nullable)options
|
||||
usingBlock:(void (^)(PHAssetCollection *collection))enumerationBlock;
|
||||
|
||||
/// 获取所有相册模型
|
||||
+ (void)enumerateAllAlbumModelsWithOptions:(PHFetchOptions * _Nullable)options
|
||||
usingBlock:(void (^)(HXAlbumModel *albumModel))enumerationBlock;
|
||||
|
||||
/// 是否相机胶卷
|
||||
+ (BOOL)isCameraRollAlbum:(PHAssetCollection *)assetCollection;
|
||||
|
||||
/// 获取PHAssetCollection
|
||||
/// @param localIdentifier 本地标识符
|
||||
+ (PHAssetCollection *)fetchAssetCollectionWithIndentifier:(NSString *)localIdentifier;
|
||||
|
||||
/// 获取PHAsset
|
||||
/// @param localIdentifier 本地标识符
|
||||
+ (PHAsset *)fetchAssetWithLocalIdentifier:(NSString *)localIdentifier;
|
||||
|
||||
/// 获取PHAsset
|
||||
/// @param assetCollection 相册
|
||||
/// @param options 选项
|
||||
+ (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection
|
||||
options:(PHFetchOptions *)options;
|
||||
|
||||
/// Asset的原图
|
||||
+ (UIImage *)originImageForAsset:(PHAsset *)asset;
|
||||
|
||||
/// 请求视频地址
|
||||
+ (void)requestVideoURL:(PHAsset *)asset
|
||||
completion:(void (^ _Nullable)(NSURL * _Nullable videoURL))completion;
|
||||
|
||||
/// 请求获取image
|
||||
/// @param asset 需要获取的资源
|
||||
/// @param targetSize 指定返回的大小
|
||||
/// @param contentMode 内容模式
|
||||
/// @param options 选项
|
||||
/// @param completion 完成请求后调用的 block
|
||||
+ (PHImageRequestID)requestImageForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
contentMode:(PHImageContentMode)contentMode
|
||||
options:(PHImageRequestOptions * _Nullable)options
|
||||
completion:(void (^ _Nullable)(UIImage *result, NSDictionary<NSString *, id> *info))completion;
|
||||
|
||||
/// 异步请求 Asset 的缩略图,不会产生网络请求
|
||||
/// @param asset 需要获取的资源
|
||||
/// @param targetWidth 指定返回的缩略图的宽度
|
||||
/// @param completion 完成请求后调用的 block 会被多次调用
|
||||
+ (PHImageRequestID)requestThumbnailImageForAsset:(PHAsset *)asset
|
||||
targetWidth:(CGFloat)targetWidth
|
||||
completion:(void (^ _Nullable)(UIImage *result, NSDictionary<NSString *, id> *info))completion;
|
||||
|
||||
/// 异步请求 Asset 的缩略图,不会产生网络请求
|
||||
/// @param targetWidth 指定返回的缩略图的宽度
|
||||
/// @param deliveryMode 交付模式
|
||||
/// @param completion 完成请求后调用的 block
|
||||
+ (PHImageRequestID)requestThumbnailImageForAsset:(PHAsset *)asset
|
||||
targetWidth:(CGFloat)targetWidth
|
||||
deliveryMode:(PHImageRequestOptionsDeliveryMode)deliveryMode
|
||||
completion:(void (^ _Nullable)(UIImage *result, NSDictionary<NSString *, id> *info))completion;
|
||||
|
||||
/// 异步请求 Asset 的展示图
|
||||
/// @param targetSize 指定返回展示的大小
|
||||
/// @param networkAccessAllowed 允许网络请求
|
||||
/// @param progressHandler 存在iCloud上并且允许了网络请求才有回调,不在主线程上执行
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestPreviewImageForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(UIImage *result, NSDictionary<NSString *, id> *info))completion;
|
||||
|
||||
/// 请求获取imageData
|
||||
/// @param asset 需要获取的资源
|
||||
/// @param options 选项
|
||||
/// @param completion 完成请求后调用的 block
|
||||
+ (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset
|
||||
options:(PHImageRequestOptions * _Nullable)options
|
||||
completion:(void (^ _Nullable)(NSData *imageData, UIImageOrientation orientation, NSDictionary<NSString *, id> *info))completion;
|
||||
|
||||
/// 异步请求 Asset 的imageData
|
||||
/// @param version 请求版本,如果是GIF建议设置PHImageRequestOptionsVersionOriginal
|
||||
/// @param resizeMode 调整模式
|
||||
/// @param networkAccessAllowed 允许网络请求
|
||||
/// @param progressHandler 存在iCloud上并且允许了网络请求才有回调,不在主线程上执行
|
||||
/// @param completion 完成请求后调用的 block,只回调一次
|
||||
/// @return 返回请求图片的请求 id
|
||||
+ (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset
|
||||
version:(PHImageRequestOptionsVersion)version
|
||||
resizeMode:(PHImageRequestOptionsResizeMode)resizeMode
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(NSData *imageData, UIImageOrientation orientation, NSDictionary<NSString *, id> *info))completion;
|
||||
|
||||
/// 请求获取LivePhoto
|
||||
/// @param targetSize 指定返回的大小
|
||||
/// @param contentMode 内容模式
|
||||
/// @param options 选项
|
||||
/// @param completion 完成请求后调用的 block
|
||||
+ (PHLivePhotoRequestID)requestLivePhotoForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
contentMode:(PHImageContentMode)contentMode
|
||||
options:(PHLivePhotoRequestOptions * _Nullable)options
|
||||
completion:(void (^ _Nullable)(PHLivePhoto *livePhoto, NSDictionary<NSString *,id> * _Nonnull info))completion;
|
||||
|
||||
/// 异步请求 LivePhoto
|
||||
/// @param targetSize 指定返回的大小
|
||||
/// @param networkAccessAllowed 允许网络请求
|
||||
/// @param progressHandler 存在iCloud上并且允许了网络请求才有回调,不在主线程上执行
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHLivePhotoRequestID)requestPreviewLivePhotoForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(PHLivePhoto *livePhoto, NSDictionary<NSString *,id> * _Nonnull info))completion;
|
||||
|
||||
/// 请求获取 AVAsset
|
||||
/// @param options 选项
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestAVAssetForAsset:(PHAsset *)asset
|
||||
options:(PHVideoRequestOptions * _Nullable)options
|
||||
completion:(void (^ _Nullable)(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info))completion;
|
||||
|
||||
/// 请求获取 AVAsset
|
||||
/// @param networkAccessAllowed 允许网络请求
|
||||
/// @param progressHandler 存在iCloud上并且允许了网络请求才有回调,不在主线程上执行
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestAVAssetForAsset:(PHAsset *)asset
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info))completion;
|
||||
|
||||
/// 请求获取 AVPlayerItem
|
||||
/// @param options 选项
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestPlayerItemForAsset:(PHAsset *)asset
|
||||
options:(PHVideoRequestOptions * _Nullable)options
|
||||
completion:(void (^ _Nullable)(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info))completion;
|
||||
|
||||
/// 请求获取 AVPlayerItem
|
||||
/// @param networkAccessAllowed 允许网络请求
|
||||
/// @param progressHandler 存在iCloud上并且允许了网络请求才有回调,不在主线程上执行
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestPlayerItemForAsset:(PHAsset *)asset
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info))completion;
|
||||
|
||||
/// 请求获取 AVAssetExportSession
|
||||
/// @param options 选项
|
||||
/// @param exportPreset 导出质量
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestExportSessionForAsset:(PHAsset *)asset
|
||||
options:(PHVideoRequestOptions * _Nullable)options
|
||||
exportPreset:(NSString *)exportPreset
|
||||
completion:(void (^ _Nullable)(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info))completion;
|
||||
|
||||
/// 请求获取 AVAssetExportSession
|
||||
/// @param exportPreset 导出质量
|
||||
/// @param networkAccessAllowed 允许网络请求
|
||||
/// @param progressHandler 存在iCloud上并且允许了网络请求才有回调,不在主线程上执行
|
||||
/// @param completion 完成请求后调用的 block,只会回调一次
|
||||
+ (PHImageRequestID)requestExportSessionForAsset:(PHAsset *)asset
|
||||
exportPreset:(NSString *)exportPreset
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info))completion;
|
||||
|
||||
/// 获取视频地址,可压缩
|
||||
/// @param asset 对应的 PHAsset 对象
|
||||
/// @param fileURL 指定导出地址
|
||||
/// @param exportPreset 导出视频分辨率
|
||||
/// @param videoQuality 导出视频质量[0-10]
|
||||
/// @param resultHandler 导出结果
|
||||
+ (void)requestVideoURLForAsset:(PHAsset *)asset
|
||||
toFile:(NSURL * _Nullable)fileURL
|
||||
exportPreset:(HXVideoExportPreset)exportPreset
|
||||
videoQuality:(NSInteger)videoQuality
|
||||
resultHandler:(void (^ _Nullable)(NSURL * _Nullable))resultHandler;
|
||||
/// 获取是否成功完成
|
||||
/// @param info 获取时返回的信息
|
||||
+ (BOOL)downloadFininedForInfo:(NSDictionary *)info;
|
||||
|
||||
/// 资源是否在iCloud上
|
||||
/// @param info 获取时返回的信息
|
||||
+ (BOOL)isInCloudForInfo:(NSDictionary *)info;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,550 @@
|
|||
//
|
||||
// HXAssetManager.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2020/11/5.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXAssetManager.h"
|
||||
#import "HXAlbumModel.h"
|
||||
#import "NSString+HXExtension.h"
|
||||
#import "PHAsset+HXExtension.h"
|
||||
#import "HXPhotoTools.h"
|
||||
|
||||
@implementation HXAssetManager
|
||||
|
||||
+ (PHFetchResult<PHAssetCollection *> *)fetchSmartAlbumsWithOptions:(PHFetchOptions * _Nullable)options {
|
||||
return [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAny options:options];
|
||||
}
|
||||
|
||||
+ (PHFetchResult<PHAssetCollection *> *)fetchUserAlbumsWithOptions:(PHFetchOptions * _Nullable)options {
|
||||
return [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:options];
|
||||
}
|
||||
+ (void)enumerateAllAlbumsWithOptions:(PHFetchOptions * _Nullable)options
|
||||
usingBlock:(void (^)(PHAssetCollection *collection))enumerationBlock {
|
||||
PHFetchResult *smartAlbums = [self fetchSmartAlbumsWithOptions:options];
|
||||
PHFetchResult *userAlbums = [self fetchUserAlbumsWithOptions:options];
|
||||
NSArray *allAlbum = [NSArray arrayWithObjects:smartAlbums, userAlbums, nil];
|
||||
for (PHFetchResult *result in allAlbum) {
|
||||
for (PHAssetCollection *collection in result) {
|
||||
if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
|
||||
if (collection.estimatedAssetCount <= 0) continue;
|
||||
if (collection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumAllHidden) continue;
|
||||
if (collection.assetCollectionSubtype == 215) continue;
|
||||
if (collection.assetCollectionSubtype == 212) continue;
|
||||
if (collection.assetCollectionSubtype == 204) continue;
|
||||
if (collection.assetCollectionSubtype == 1000000201) continue;
|
||||
if (enumerationBlock) {
|
||||
enumerationBlock(collection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+ (void)enumerateAllAlbumModelsWithOptions:(PHFetchOptions * _Nullable)options
|
||||
usingBlock:(void (^)(HXAlbumModel *albumModel))enumerationBlock {
|
||||
[self enumerateAllAlbumsWithOptions:nil usingBlock:^(PHAssetCollection *collection) {
|
||||
HXAlbumModel *albumModel = [[HXAlbumModel alloc] initWithCollection:collection options:options];
|
||||
if (enumerationBlock) {
|
||||
enumerationBlock(albumModel);
|
||||
}
|
||||
}];
|
||||
}
|
||||
/// 获取相机胶卷
|
||||
+ (PHAssetCollection *)fetchCameraRollAlbumWithOptions:(PHFetchOptions * _Nullable)options {
|
||||
PHFetchResult *smartAlbums = [self fetchSmartAlbumsWithOptions:options];
|
||||
for (PHAssetCollection *collection in smartAlbums) {
|
||||
if (![collection isKindOfClass:[PHAssetCollection class]]) continue;
|
||||
if (collection.estimatedAssetCount <= 0) continue;
|
||||
if ([self isCameraRollAlbum:collection]) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
+ (BOOL)isCameraRollAlbum:(PHAssetCollection *)assetCollection {
|
||||
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;
|
||||
|
||||
if (version >= 800 && version <= 802) {
|
||||
return assetCollection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumRecentlyAdded;
|
||||
} else {
|
||||
return assetCollection.assetCollectionSubtype == PHAssetCollectionSubtypeSmartAlbumUserLibrary;
|
||||
}
|
||||
}
|
||||
+ (PHAssetCollection *)fetchAssetCollectionWithIndentifier:(NSString *)localIdentifier {
|
||||
return [[PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
|
||||
}
|
||||
|
||||
#pragma mark - < PHAsset >
|
||||
|
||||
+ (PHAsset *)fetchAssetWithLocalIdentifier:(NSString *)localIdentifier {
|
||||
return [[PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil] firstObject];
|
||||
}
|
||||
+ (PHFetchResult<PHAsset *> *)fetchAssetsInAssetCollection:(PHAssetCollection *)assetCollection
|
||||
options:(PHFetchOptions *)options {
|
||||
return [PHAsset fetchAssetsInAssetCollection:assetCollection options:options];
|
||||
}
|
||||
+ (UIImage *)originImageForAsset:(PHAsset *)asset {
|
||||
__block UIImage *resultImage = nil;
|
||||
PHImageRequestOptions *phImageRequestOptions = [[PHImageRequestOptions alloc] init];
|
||||
phImageRequestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
||||
phImageRequestOptions.networkAccessAllowed = YES;
|
||||
phImageRequestOptions.synchronous = YES;
|
||||
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:phImageRequestOptions resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
|
||||
resultImage = [UIImage imageWithData:imageData];
|
||||
}];
|
||||
return resultImage;
|
||||
}
|
||||
+ (void)requestVideoURL:(PHAsset *)asset completion:(void (^)(NSURL * _Nullable))completion {
|
||||
[self requestAVAssetForAsset:asset networkAccessAllowed:YES progressHandler:nil completion:^(AVAsset * _Nonnull avAsset, AVAudioMix * _Nonnull audioMix, NSDictionary * _Nonnull info) {
|
||||
[asset hx_checkForModificationsWithAssetPathMethodCompletion:^(BOOL isAdjusted) {
|
||||
NSString *fileName = [[NSString hx_fileName] stringByAppendingString:@".mp4"];
|
||||
NSString *fullPathToFile = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
|
||||
NSURL *videoURL = [NSURL fileURLWithPath:fullPathToFile];
|
||||
if (isAdjusted) {
|
||||
if ([avAsset isKindOfClass:AVURLAsset.class]) {
|
||||
NSFileManager *fileManager = [NSFileManager defaultManager];
|
||||
NSError *error;
|
||||
[fileManager copyItemAtURL:[(AVURLAsset *)avAsset URL] toURL:videoURL error:&error];
|
||||
if (error == nil) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (completion) {
|
||||
completion(videoURL);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];
|
||||
NSString *presetName;
|
||||
if ([presets containsObject:AVAssetExportPresetHighestQuality]) {
|
||||
presetName = AVAssetExportPresetHighestQuality;
|
||||
}else {
|
||||
presetName = AVAssetExportPresetMediumQuality;
|
||||
}
|
||||
AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:presetName];
|
||||
session.outputURL = videoURL;
|
||||
session.shouldOptimizeForNetworkUse = YES;
|
||||
|
||||
NSArray *supportedTypeArray = session.supportedFileTypes;
|
||||
if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
|
||||
session.outputFileType = AVFileTypeMPEG4;
|
||||
} else if (supportedTypeArray.count == 0) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (completion) {
|
||||
completion(nil);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}else {
|
||||
session.outputFileType = [supportedTypeArray objectAtIndex:0];
|
||||
}
|
||||
|
||||
[session exportAsynchronouslyWithCompletionHandler:^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([session status] == AVAssetExportSessionStatusCompleted) {
|
||||
if (completion) {
|
||||
completion(videoURL);
|
||||
}
|
||||
}else if ([session status] == AVAssetExportSessionStatusFailed ||
|
||||
[session status] == AVAssetExportSessionStatusCancelled) {
|
||||
if (completion) {
|
||||
completion(nil);
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
}else {
|
||||
PHAssetResource *videoResource = [PHAssetResource assetResourcesForAsset:asset].firstObject;
|
||||
PHAssetResourceRequestOptions *options = [[PHAssetResourceRequestOptions alloc] init];
|
||||
options.networkAccessAllowed = YES;
|
||||
[[PHAssetResourceManager defaultManager] writeDataForAssetResource:videoResource toFile:videoURL options:options completionHandler:^(NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!error) {
|
||||
if (completion) {
|
||||
completion(videoURL);
|
||||
}
|
||||
}else {
|
||||
completion(nil);
|
||||
}
|
||||
});
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
+ (CGSize)getAssetTargetSizeWithAsset:(PHAsset *)asset width:(CGFloat)width {
|
||||
if (!asset) {
|
||||
return CGSizeMake(width, width);
|
||||
}
|
||||
CGFloat scale = 0.8f;
|
||||
CGFloat aspectRatio = asset.pixelWidth / (CGFloat)asset.pixelHeight;
|
||||
CGFloat initialWidth = width;
|
||||
CGFloat height;
|
||||
if (asset.pixelWidth < width) {
|
||||
width = width * 0.5f;
|
||||
}
|
||||
height = width / aspectRatio;
|
||||
CGFloat maxHeight = [UIScreen mainScreen].bounds.size.height;
|
||||
if (height > maxHeight) {
|
||||
width = maxHeight / height * width * scale;
|
||||
height = maxHeight * scale;
|
||||
}
|
||||
if (height < initialWidth && width >= initialWidth) {
|
||||
width = initialWidth / height * width * scale;
|
||||
height = initialWidth * scale;
|
||||
}
|
||||
CGSize size = CGSizeMake(width, height);
|
||||
return size;
|
||||
}
|
||||
+ (PHImageRequestID)requestImageForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
contentMode:(PHImageContentMode)contentMode
|
||||
options:(PHImageRequestOptions *)options
|
||||
completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion {
|
||||
if (!asset) {
|
||||
completion(nil, nil);
|
||||
return -1;
|
||||
}
|
||||
return [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:targetSize contentMode:contentMode options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(result, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (PHImageRequestID)requestThumbnailImageForAsset:(PHAsset *)asset
|
||||
targetWidth:(CGFloat)targetWidth
|
||||
completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion {
|
||||
return [self requestThumbnailImageForAsset:asset targetWidth:targetWidth deliveryMode:PHImageRequestOptionsDeliveryModeOpportunistic completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(result, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (PHImageRequestID)requestThumbnailImageForAsset:(PHAsset *)asset
|
||||
targetWidth:(CGFloat)targetWidth
|
||||
deliveryMode:(PHImageRequestOptionsDeliveryMode)deliveryMode
|
||||
completion:(void (^)(UIImage *result, NSDictionary<NSString *, id> *info))completion {
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.resizeMode = PHImageRequestOptionsResizeModeFast;
|
||||
options.deliveryMode = deliveryMode;
|
||||
return [self requestImageForAsset:asset targetSize:[self getAssetTargetSizeWithAsset:asset width:targetWidth] contentMode:PHImageContentModeAspectFill options:options completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(result, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (PHImageRequestID)requestPreviewImageForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(UIImage *result, NSDictionary<NSString *, id> *info))completion; {
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.resizeMode = PHImageRequestOptionsResizeModeFast;
|
||||
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.networkAccessAllowed = networkAccessAllowed;
|
||||
options.progressHandler = progressHandler;
|
||||
return [self requestImageForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill options:options completion:^(UIImage * _Nonnull result, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(result, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (void)requestVideoURLForAsset:(PHAsset *)asset
|
||||
toFile:(NSURL * _Nullable)fileURL
|
||||
exportPreset:(HXVideoExportPreset)exportPreset
|
||||
videoQuality:(NSInteger)videoQuality
|
||||
resultHandler:(void (^ _Nullable)(NSURL * _Nullable))resultHandler {
|
||||
[self requestAVAssetForAsset:asset networkAccessAllowed:YES progressHandler:nil completion:^(AVAsset * _Nonnull asset, AVAudioMix * _Nonnull audioMix, NSDictionary * _Nonnull info) {
|
||||
if (asset == nil) {
|
||||
if (resultHandler) {
|
||||
resultHandler(nil);
|
||||
}
|
||||
return;
|
||||
}
|
||||
NSString *fileName = [[NSString hx_fileName] stringByAppendingString:@".mp4"];
|
||||
NSString *fullPathToFile = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
|
||||
NSURL *videoURL = fileURL ?: [NSURL fileURLWithPath:fullPathToFile];
|
||||
NSString *presetName = [self presetName:exportPreset];
|
||||
NSArray *presets = [AVAssetExportSession exportPresetsCompatibleWithAsset:asset];
|
||||
if (![presets containsObject:presetName]) {
|
||||
if (resultHandler) {
|
||||
resultHandler(nil);
|
||||
}
|
||||
return;
|
||||
}
|
||||
AVAssetExportSession *session = [AVAssetExportSession exportSessionWithAsset:asset presetName:presetName];
|
||||
session.outputURL = videoURL;
|
||||
session.shouldOptimizeForNetworkUse = YES;
|
||||
NSArray *supportedTypeArray = session.supportedFileTypes;
|
||||
if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
|
||||
session.outputFileType = AVFileTypeMPEG4;
|
||||
}else if (supportedTypeArray.count == 0) {
|
||||
if (resultHandler) {
|
||||
resultHandler(nil);
|
||||
}
|
||||
return;
|
||||
}else {
|
||||
session.outputFileType = [supportedTypeArray objectAtIndex:0];
|
||||
}
|
||||
if (videoQuality > 0) {
|
||||
session.fileLengthLimit = [self exportSessionFileLengthLimitWithSeconds:CMTimeGetSeconds(asset.duration) exportPreset:exportPreset videoQuality:videoQuality];
|
||||
}
|
||||
[session exportAsynchronouslyWithCompletionHandler:^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (session.status == AVAssetExportSessionStatusCompleted) {
|
||||
if (resultHandler) {
|
||||
resultHandler(videoURL);
|
||||
}
|
||||
}else {
|
||||
if (resultHandler) {
|
||||
resultHandler(nil);
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
}];
|
||||
}
|
||||
+ (NSString *)presetName:(HXVideoExportPreset)exportPreset {
|
||||
switch (exportPreset) {
|
||||
case HXVideoEditorExportPresetLowQuality:
|
||||
return AVAssetExportPresetLowQuality;
|
||||
case HXVideoEditorExportPresetMediumQuality:
|
||||
return AVAssetExportPresetMediumQuality;
|
||||
case HXVideoEditorExportPresetHighQuality:
|
||||
return AVAssetExportPresetHighestQuality;
|
||||
case HXVideoEditorExportPresetRatio_640x480:
|
||||
return AVAssetExportPreset640x480;
|
||||
case HXVideoEditorExportPresetRatio_960x540:
|
||||
return AVAssetExportPreset960x540;
|
||||
case HXVideoEditorExportPresetRatio_1280x720:
|
||||
return AVAssetExportPreset1280x720;
|
||||
default:
|
||||
return AVAssetExportPresetMediumQuality;
|
||||
}
|
||||
}
|
||||
+ (NSInteger)exportSessionFileLengthLimitWithSeconds:(CGFloat)seconds
|
||||
exportPreset:(HXVideoExportPreset)exportPreset
|
||||
videoQuality:(NSInteger)videoQuality {
|
||||
if (videoQuality > 0) {
|
||||
CGFloat ratioParam = 0;
|
||||
if (exportPreset == HXVideoEditorExportPresetRatio_640x480) {
|
||||
ratioParam = 0.02;
|
||||
}else if (exportPreset == HXVideoEditorExportPresetRatio_960x540) {
|
||||
ratioParam = 0.04;
|
||||
}else if (exportPreset == HXVideoEditorExportPresetRatio_1280x720) {
|
||||
ratioParam = 0.08;
|
||||
}
|
||||
NSInteger quality = MIN(videoQuality, 10);
|
||||
return seconds * ratioParam * quality * 1000 * 1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
+ (UIImageOrientation)imageOrientationWithCGImageOrientation:(CGImagePropertyOrientation)orientation {
|
||||
UIImageOrientation sureOrientation;
|
||||
if (orientation == kCGImagePropertyOrientationUp) {
|
||||
sureOrientation = UIImageOrientationUp;
|
||||
} else if (orientation == kCGImagePropertyOrientationUpMirrored) {
|
||||
sureOrientation = UIImageOrientationUpMirrored;
|
||||
} else if (orientation == kCGImagePropertyOrientationDown) {
|
||||
sureOrientation = UIImageOrientationDown;
|
||||
} else if (orientation == kCGImagePropertyOrientationDownMirrored) {
|
||||
sureOrientation = UIImageOrientationDownMirrored;
|
||||
} else if (orientation == kCGImagePropertyOrientationLeftMirrored) {
|
||||
sureOrientation = UIImageOrientationLeftMirrored;
|
||||
} else if (orientation == kCGImagePropertyOrientationRight) {
|
||||
sureOrientation = UIImageOrientationRight;
|
||||
} else if (orientation == kCGImagePropertyOrientationRightMirrored) {
|
||||
sureOrientation = UIImageOrientationRightMirrored;
|
||||
} else if (orientation == kCGImagePropertyOrientationLeft) {
|
||||
sureOrientation = UIImageOrientationLeft;
|
||||
} else {
|
||||
sureOrientation = UIImageOrientationUp;
|
||||
}
|
||||
return sureOrientation;
|
||||
}
|
||||
+ (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset
|
||||
options:(PHImageRequestOptions *)options
|
||||
completion:(void (^)(NSData *imageData, UIImageOrientation orientation, NSDictionary<NSString *, id> *info))completion {
|
||||
PHImageRequestID requestID;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
requestID = [[PHImageManager defaultManager] requestImageDataAndOrientationForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, CGImagePropertyOrientation orientation, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(imageData, [self imageOrientationWithCGImageOrientation:orientation], info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}else {
|
||||
requestID = [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(imageData, orientation, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
return requestID;
|
||||
}
|
||||
|
||||
+ (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset
|
||||
version:(PHImageRequestOptionsVersion)version
|
||||
resizeMode:(PHImageRequestOptionsResizeMode)resizeMode
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler)progressHandler
|
||||
completion:(void (^)(NSData *imageData, UIImageOrientation orientation, NSDictionary<NSString *, id> *info))completion {
|
||||
PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
|
||||
options.version = version;
|
||||
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.resizeMode = resizeMode;
|
||||
options.networkAccessAllowed = networkAccessAllowed;
|
||||
options.progressHandler = progressHandler;
|
||||
return [self requestImageDataForAsset:asset options:options completion:^(NSData * _Nonnull imageData, UIImageOrientation orientation, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(imageData, orientation, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (PHLivePhotoRequestID)requestLivePhotoForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
contentMode:(PHImageContentMode)contentMode
|
||||
options:(PHLivePhotoRequestOptions *)options
|
||||
completion:(void (^)(PHLivePhoto *livePhoto, NSDictionary<NSString *,id> * _Nonnull info))completion {
|
||||
return [[PHImageManager defaultManager] requestLivePhotoForAsset:asset targetSize:targetSize contentMode:contentMode options:options resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(livePhoto, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (PHLivePhotoRequestID)requestPreviewLivePhotoForAsset:(PHAsset *)asset
|
||||
targetSize:(CGSize)targetSize
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler)progressHandler
|
||||
completion:(void (^)(PHLivePhoto *livePhoto, NSDictionary<NSString *,id> * _Nonnull info))completion {
|
||||
PHLivePhotoRequestOptions *options = [[PHLivePhotoRequestOptions alloc] init];
|
||||
options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.networkAccessAllowed = networkAccessAllowed;
|
||||
options.progressHandler = progressHandler;
|
||||
return [self requestLivePhotoForAsset:asset targetSize:targetSize contentMode:PHImageContentModeAspectFill options:options completion:^(PHLivePhoto * _Nonnull livePhoto, NSDictionary<NSString *,id> * _Nonnull info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(livePhoto, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (PHImageRequestID)requestAVAssetForAsset:(PHAsset *)asset
|
||||
options:(PHVideoRequestOptions *)options
|
||||
completion:(void (^)(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info))completion {
|
||||
return [[PHImageManager defaultManager] requestAVAssetForVideo:asset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(asset, audioMix, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (PHImageRequestID)requestAVAssetForAsset:(PHAsset *)asset
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler)progressHandler
|
||||
completion:(void (^)(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info))completion {
|
||||
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
|
||||
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.networkAccessAllowed = networkAccessAllowed;
|
||||
options.progressHandler = progressHandler;
|
||||
return [self requestAVAssetForAsset:asset options:options completion:^(AVAsset * _Nonnull asset, AVAudioMix * _Nonnull audioMix, NSDictionary * _Nonnull info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(asset, audioMix, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (PHImageRequestID)requestPlayerItemForAsset:(PHAsset *)asset
|
||||
options:(PHVideoRequestOptions * _Nullable)options
|
||||
completion:(void (^ _Nullable)(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info))completion {
|
||||
return [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:options resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(playerItem, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
+ (PHImageRequestID)requestPlayerItemForAsset:(PHAsset *)asset
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info))completion {
|
||||
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
|
||||
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.networkAccessAllowed = networkAccessAllowed;
|
||||
options.progressHandler = progressHandler;
|
||||
return [self requestPlayerItemForAsset:asset options:options completion:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(playerItem, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (PHImageRequestID)requestExportSessionForAsset:(PHAsset *)asset
|
||||
options:(PHVideoRequestOptions * _Nullable)options
|
||||
exportPreset:(NSString *)exportPreset
|
||||
completion:(void (^ _Nullable)(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info))completion {
|
||||
return [[PHImageManager defaultManager] requestExportSessionForVideo:asset options:options exportPreset:exportPreset resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(exportSession, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (PHImageRequestID)requestExportSessionForAsset:(PHAsset *)asset
|
||||
exportPreset:(NSString *)exportPreset
|
||||
networkAccessAllowed:(BOOL)networkAccessAllowed
|
||||
progressHandler:(PHAssetImageProgressHandler _Nullable)progressHandler
|
||||
completion:(void (^ _Nullable)(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info))completion {
|
||||
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
|
||||
options.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
|
||||
options.networkAccessAllowed = networkAccessAllowed;
|
||||
options.progressHandler = progressHandler;
|
||||
return [self requestExportSessionForAsset:asset options:options exportPreset:exportPreset completion:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
|
||||
if (completion) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion(exportSession, info);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
+ (BOOL)downloadFininedForInfo:(NSDictionary *)info {
|
||||
BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
|
||||
return downloadFinined;
|
||||
}
|
||||
+ (BOOL)isInCloudForInfo:(NSDictionary *)info {
|
||||
return [[info objectForKey:PHImageResultIsInCloudKey] boolValue];
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,86 @@
|
|||
//
|
||||
// HXPhotoCommon.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/8.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HXPhotoConfiguration.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
#import "HXPhotoModel.h"
|
||||
#import "HXAlbumModel.h"
|
||||
#if __has_include(<AFNetworking/AFNetworking.h>)
|
||||
#import <AFNetworking/AFNetworking.h>
|
||||
#elif __has_include("AFNetworking.h")
|
||||
#import "AFNetworking.h"
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoCommon : NSObject
|
||||
@property (strong, nonatomic, nullable) NSBundle *languageBundle;
|
||||
@property (strong, nonatomic, nullable) NSBundle *photoPickerBundle;
|
||||
|
||||
/// 默认 AVAudioSessionCategoryPlayback
|
||||
@property (copy, nonatomic) AVAudioSessionCategory audioSessionCategory;
|
||||
/// 小图请求大小
|
||||
@property (assign, nonatomic) CGFloat requestWidth;
|
||||
/// 相册风格
|
||||
@property (assign, nonatomic) HXPhotoStyle photoStyle;
|
||||
/// 相册语言
|
||||
@property (assign, nonatomic) HXPhotoLanguageType languageType;
|
||||
/// 相机预览图片
|
||||
@property (strong, nonatomic) UIImage * _Nullable cameraImage;
|
||||
/// 相机预览imageURL
|
||||
@property (strong, nonatomic) NSURL * _Nullable cameraImageURL;
|
||||
/// 查看LivePhoto是否自动播放,为NO时需要长按才可播放
|
||||
@property (assign, nonatomic) BOOL livePhotoAutoPlay;
|
||||
/// 预览视频时是否自动播放
|
||||
@property (assign, nonatomic) HXVideoAutoPlayType videoAutoPlayType;
|
||||
/// 预览视频时是否先下载视频再播放
|
||||
@property (assign, nonatomic) BOOL downloadNetworkVideo;
|
||||
/// 状态栏
|
||||
@property (assign, nonatomic) BOOL isVCBasedStatusBarAppearance;
|
||||
/// ios13之后的3DTouch
|
||||
@property (assign, nonatomic) BOOL isHapticTouch;
|
||||
/// 点击完成按钮时是否需要下载网络视频
|
||||
@property (assign, nonatomic) BOOL requestNetworkAfter;
|
||||
|
||||
#if HasAFNetworking
|
||||
@property (assign, nonatomic) AFNetworkReachabilityStatus netStatus;
|
||||
@property (copy, nonatomic) void (^ reachabilityStatusChangeBlock)(AFNetworkReachabilityStatus netStatus);
|
||||
#endif
|
||||
/// 相机胶卷相册唯一标识符
|
||||
@property (copy, nonatomic) NSString * _Nullable cameraRollLocalIdentifier;
|
||||
/// 相机胶卷相册Result
|
||||
@property (copy, nonatomic) PHFetchResult * _Nullable cameraRollResult;
|
||||
/// 选择类型
|
||||
@property (assign, nonatomic) NSInteger selectType;
|
||||
/// 创建日期排序
|
||||
@property (assign, nonatomic) BOOL creationDateSort;
|
||||
/// 相册发生改变时,主要作用在选择部分可查看资源时
|
||||
@property (copy, nonatomic) void (^photoLibraryDidChange)(void);
|
||||
/// 设备id
|
||||
@property (copy, nonatomic) NSString *UUIDString;
|
||||
|
||||
@property (assign, nonatomic) PHImageRequestID clearAssetRequestID;
|
||||
|
||||
/// 下载视频
|
||||
/// @param videoURL 网络视频地址
|
||||
/// @param progress 下载进度
|
||||
/// @param success 下载成功
|
||||
/// @param failure 下载失败
|
||||
- (NSURLSessionDownloadTask * _Nullable)downloadVideoWithURL:(NSURL *)videoURL
|
||||
progress:(void (^ _Nullable)(float progress, long long downloadLength, long long totleLength, NSURL * _Nullable videoURL))progress
|
||||
downloadSuccess:(void (^ _Nullable)(NSURL * _Nullable filePath, NSURL * _Nullable videoURL))success
|
||||
downloadFailure:(void (^ _Nullable)(NSError * _Nullable error, NSURL * _Nullable videoURL))failure;
|
||||
|
||||
+ (instancetype)photoCommon;
|
||||
+ (void)deallocPhotoCommon;
|
||||
- (void)saveCamerImage;
|
||||
- (BOOL)isDark;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,325 @@
|
|||
//
|
||||
// HXPhotoCommon.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2019/1/8.
|
||||
// Copyright © 2019年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoCommon.h"
|
||||
#import "HXPhotoTools.h"
|
||||
|
||||
static dispatch_once_t once;
|
||||
static dispatch_once_t once1;
|
||||
static id instance;
|
||||
|
||||
@interface HXPhotoCommon ()<NSURLConnectionDataDelegate, PHPhotoLibraryChangeObserver>
|
||||
#if HasAFNetworking
|
||||
@property (strong, nonatomic) AFURLSessionManager *sessionManager;
|
||||
#endif
|
||||
@property (assign, nonatomic) BOOL hasAuthorization;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoCommon
|
||||
|
||||
|
||||
+ (instancetype)photoCommon {
|
||||
if (instance == nil) {
|
||||
dispatch_once(&once, ^{
|
||||
instance = [[HXPhotoCommon alloc] init];
|
||||
});
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
|
||||
if (instance == nil) {
|
||||
dispatch_once(&once1, ^{
|
||||
instance = [super allocWithZone:zone];
|
||||
});
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.audioSessionCategory = AVAudioSessionCategoryPlayback;
|
||||
self.isVCBasedStatusBarAppearance = [[[NSBundle mainBundle]objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"] boolValue];
|
||||
|
||||
#if HasAFNetworking
|
||||
self.sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
|
||||
[self listenNetWorkStatus];
|
||||
#endif
|
||||
NSURL *imageURL = [[NSUserDefaults standardUserDefaults] URLForKey:HXCameraImageKey];
|
||||
if (imageURL) {
|
||||
self.cameraImageURL = imageURL;
|
||||
}
|
||||
self.cameraRollLocalIdentifier = [[NSUserDefaults standardUserDefaults] objectForKey:@"HXCameraRollLocalIdentifier"];
|
||||
|
||||
PHAuthorizationStatus status = [HXPhotoTools authorizationStatus];
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
else if (@available(iOS 14, *)) {
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
self.cameraRollLocalIdentifier = nil;
|
||||
self.cameraRollResult = nil;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
|
||||
}else {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(requestAuthorizationCompletion) name:@"HXPhotoRequestAuthorizationCompletion" object:nil];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(requestAuthorizationCompletion) name:@"HXPhotoRequestAuthorizationCompletion" object:nil];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)setCameraRollLocalIdentifier:(NSString *)cameraRollLocalIdentifier {
|
||||
_cameraRollLocalIdentifier = cameraRollLocalIdentifier;
|
||||
if (cameraRollLocalIdentifier) {
|
||||
[[NSUserDefaults standardUserDefaults] setObject:cameraRollLocalIdentifier forKey:@"HXCameraRollLocalIdentifier"];
|
||||
}
|
||||
}
|
||||
- (void)requestAuthorizationCompletion {
|
||||
if (!self.hasAuthorization) {
|
||||
PHAuthorizationStatus status = [HXPhotoTools authorizationStatus];
|
||||
if (status == PHAuthorizationStatusAuthorized) {
|
||||
self.hasAuthorization = YES;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
|
||||
}
|
||||
#ifdef __IPHONE_14_0
|
||||
else if (@available(iOS 14, *)) {
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
self.cameraRollLocalIdentifier = nil;
|
||||
self.cameraRollResult = nil;
|
||||
self.hasAuthorization = YES;
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] registerChangeObserver:self];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - < PHPhotoLibraryChangeObserver >
|
||||
- (void)photoLibraryDidChange:(PHChange *)changeInstance {
|
||||
// if (!self.cameraRollResult) {
|
||||
// [self photoListReload];
|
||||
// return;
|
||||
// }
|
||||
PHFetchResultChangeDetails *collectionChanges = [changeInstance changeDetailsForFetchResult:self.cameraRollResult];
|
||||
if (collectionChanges) {
|
||||
if ([collectionChanges hasIncrementalChanges]) {
|
||||
if (collectionChanges.insertedObjects.count > 0 ||
|
||||
collectionChanges.removedObjects.count > 0 ||
|
||||
collectionChanges.changedObjects.count > 0 ||
|
||||
[collectionChanges hasMoves]) {
|
||||
PHFetchResult *result = collectionChanges.fetchResultAfterChanges;
|
||||
self.cameraRollResult = result;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"HXPhotoViewNeedReloadNotification" object:nil];
|
||||
});
|
||||
}
|
||||
}else {
|
||||
PHFetchResult *result = collectionChanges.fetchResultAfterChanges;
|
||||
self.cameraRollResult = result;
|
||||
[self photoListReload];
|
||||
}
|
||||
}
|
||||
}
|
||||
- (void)photoListReload {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
#ifdef __IPHONE_14_0
|
||||
if (@available(iOS 14, *)) {
|
||||
PHAuthorizationStatus status = [HXPhotoTools authorizationStatus];
|
||||
if (status == PHAuthorizationStatusLimited) {
|
||||
if (self.photoLibraryDidChange) {
|
||||
self.photoLibraryDidChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"HXPhotoViewNeedReloadNotification" object:nil];
|
||||
});
|
||||
}
|
||||
- (NSBundle *)languageBundle {
|
||||
if (!_languageBundle) {
|
||||
NSString *language = [NSLocale preferredLanguages].firstObject;
|
||||
HXPhotoLanguageType type = self.languageType;
|
||||
switch (type) {
|
||||
case HXPhotoLanguageTypeSc : {
|
||||
language = @"zh-Hans"; // 简体中文
|
||||
} break;
|
||||
case HXPhotoLanguageTypeTc : {
|
||||
language = @"zh-Hant"; // 繁體中文
|
||||
} break;
|
||||
case HXPhotoLanguageTypeJa : {
|
||||
// 日文
|
||||
language = @"ja";
|
||||
} break;
|
||||
case HXPhotoLanguageTypeKo : {
|
||||
// 韩文
|
||||
language = @"ko";
|
||||
} break;
|
||||
case HXPhotoLanguageTypeEn : {
|
||||
language = @"en";
|
||||
} break;
|
||||
default : {
|
||||
if ([language hasPrefix:@"en"]) {
|
||||
language = @"en";
|
||||
} else if ([language hasPrefix:@"zh"]) {
|
||||
if ([language rangeOfString:@"Hans"].location != NSNotFound) {
|
||||
language = @"zh-Hans"; // 简体中文
|
||||
} else { // zh-Hant\zh-HK\zh-TW
|
||||
language = @"zh-Hant"; // 繁體中文
|
||||
}
|
||||
} else if ([language hasPrefix:@"ja"]){
|
||||
// 日文
|
||||
language = @"ja";
|
||||
}else if ([language hasPrefix:@"ko"]) {
|
||||
// 韩文
|
||||
language = @"ko";
|
||||
}else {
|
||||
language = @"en";
|
||||
}
|
||||
}break;
|
||||
}
|
||||
[HXPhotoCommon photoCommon].languageBundle = [NSBundle bundleWithPath:[[NSBundle hx_photoPickerBundle] pathForResource:language ofType:@"lproj"]];
|
||||
}
|
||||
return _languageBundle;
|
||||
}
|
||||
- (NSString *)UUIDString {
|
||||
if (!_UUIDString) {
|
||||
_UUIDString = [[NSUUID UUID] UUIDString];
|
||||
}
|
||||
return _UUIDString;
|
||||
}
|
||||
- (BOOL)isDark {
|
||||
if (self.photoStyle == HXPhotoStyleDark) {
|
||||
return YES;
|
||||
}else if (self.photoStyle == HXPhotoStyleInvariant) {
|
||||
return NO;
|
||||
}
|
||||
#ifdef __IPHONE_13_0
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
- (void)saveCamerImage {
|
||||
if (self.cameraImage) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSData *imageData;
|
||||
NSString *suffix;
|
||||
if (UIImagePNGRepresentation(self.cameraImage)) {
|
||||
//返回为png图像。
|
||||
imageData = UIImagePNGRepresentation(self.cameraImage);
|
||||
suffix = @"png";
|
||||
}else {
|
||||
//返回为JPEG图像。
|
||||
imageData = UIImageJPEGRepresentation(self.cameraImage, 0.5);
|
||||
suffix = @"jpeg";
|
||||
}
|
||||
NSString *fileName = [HXCameraImageKey stringByAppendingString:[NSString stringWithFormat:@".%@",suffix]];
|
||||
NSArray *array = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
|
||||
NSString *fullPathToFile = [array.firstObject stringByAppendingPathComponent:fileName];
|
||||
|
||||
if ([imageData writeToFile:fullPathToFile atomically:YES]) {
|
||||
NSURL *imageURL = [NSURL fileURLWithPath:fullPathToFile];
|
||||
[[NSUserDefaults standardUserDefaults] setURL:imageURL forKey:HXCameraImageKey];
|
||||
self.cameraImageURL = imageURL;
|
||||
}
|
||||
self.cameraImage = nil;
|
||||
});
|
||||
}
|
||||
}
|
||||
- (void)setCameraImage:(UIImage *)cameraImage {
|
||||
if (!cameraImage) {
|
||||
_cameraImage = nil;
|
||||
}
|
||||
UIImage *image = [cameraImage hx_scaleImagetoScale:0.5];
|
||||
if (image) {
|
||||
_cameraImage = image;
|
||||
}else {
|
||||
_cameraImage = cameraImage;
|
||||
}
|
||||
}
|
||||
/** 初始化并监听网络变化 */
|
||||
- (void)listenNetWorkStatus {
|
||||
#if HasAFNetworking
|
||||
AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];
|
||||
self.netStatus = manager.networkReachabilityStatus;
|
||||
[manager startMonitoring];
|
||||
[manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
|
||||
self.netStatus = status;
|
||||
if (self.reachabilityStatusChangeBlock) {
|
||||
self.reachabilityStatusChangeBlock(status);
|
||||
}
|
||||
}];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (NSURLSessionDownloadTask * _Nullable)downloadVideoWithURL:(NSURL *)videoURL
|
||||
progress:(void (^)(float progress, long long downloadLength, long long totleLength, NSURL * _Nullable videoURL))progress
|
||||
downloadSuccess:(void (^)(NSURL * _Nullable filePath, NSURL * _Nullable videoURL))success
|
||||
downloadFailure:(void (^)(NSError * _Nullable error, NSURL * _Nullable videoURL))failure {
|
||||
NSString *videoFilePath = [HXPhotoTools getVideoURLFilePath:videoURL];
|
||||
|
||||
NSURL *videoFileURL = [NSURL fileURLWithPath:videoFilePath];
|
||||
if ([HXPhotoTools fileExistsAtVideoURL:videoURL]) {
|
||||
if (success) {
|
||||
success(videoFileURL, videoURL);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
#if HasAFNetworking
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:videoURL];
|
||||
/* 开始请求下载 */
|
||||
NSURLSessionDownloadTask *downloadTask = [self.sessionManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (progress) {
|
||||
progress(downloadProgress.fractionCompleted, downloadProgress.completedUnitCount, downloadProgress.totalUnitCount, videoURL);
|
||||
}
|
||||
});
|
||||
} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
|
||||
return videoFileURL;
|
||||
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (!error) {
|
||||
if (success) {
|
||||
success(filePath, videoURL);
|
||||
}
|
||||
}else {
|
||||
[[NSFileManager defaultManager] removeItemAtURL:videoFileURL error:nil];
|
||||
if (failure) {
|
||||
failure(error, videoURL);
|
||||
}
|
||||
}
|
||||
});
|
||||
}];
|
||||
[downloadTask resume];
|
||||
return downloadTask;
|
||||
#else
|
||||
/// pod导入的请改成 "HXPhotoPicker/SDWebImage_AF" 或 "HXPhotoPicker/YYWebImage_AF"
|
||||
NSSLog(@"没有导入AFNetworking网络框架无法下载视频");
|
||||
return nil;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (void)deallocPhotoCommon {
|
||||
once = 0;
|
||||
once1 = 0;
|
||||
instance = nil;
|
||||
}
|
||||
- (void)dealloc {
|
||||
[[PHPhotoLibrary sharedPhotoLibrary] unregisterChangeObserver:self];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"HXPhotoRequestAuthorizationCompletion" object:nil];
|
||||
#if HasAFNetworking
|
||||
[[AFNetworkReachabilityManager sharedManager] stopMonitoring];
|
||||
#endif
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,705 @@
|
|||
//
|
||||
// HXPhotoConfiguration.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/11/21.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoTypes.h"
|
||||
#import "HXPhotoEditConfiguration.h"
|
||||
|
||||
@class
|
||||
HXPhotoBottomView,
|
||||
HXPhotoPreviewBottomView,
|
||||
HXPhotoManager,
|
||||
HXPhotoModel,
|
||||
HXPhotoPreviewViewController;
|
||||
|
||||
@interface HXPhotoConfiguration : NSObject
|
||||
|
||||
/// 配置类型
|
||||
/// 一键配置UI和选择逻辑
|
||||
@property (assign, nonatomic) HXConfigurationType type;
|
||||
|
||||
/// 查看LivePhoto是否自动播放,为NO时需要长按才可播放
|
||||
@property (assign, nonatomic) BOOL livePhotoAutoPlay;
|
||||
|
||||
/// 预览大图时允许不先加载小图,直接加载原图
|
||||
@property (assign, nonatomic) BOOL allowPreviewDirectLoadOriginalImage;
|
||||
|
||||
/// 允许滑动的方式选择资源 - 默认允许
|
||||
/// 类似系统相册和QQ滑动选择逻辑
|
||||
@property (assign, nonatomic) BOOL allowSlidingSelection;
|
||||
|
||||
/// 照片列表取消按钮的位置
|
||||
/// 只在 albumShowMode = HXPhotoAlbumShowModePopup 时有效
|
||||
@property (assign, nonatomic) HXPhotoListCancelButtonLocationType photoListCancelLocation;
|
||||
|
||||
/// 照片编辑配置
|
||||
@property (strong, nonatomic) HXPhotoEditConfiguration *photoEditConfigur;
|
||||
|
||||
/// 相机界面是否开启定位 默认 YES
|
||||
@property (assign, nonatomic) BOOL cameraCanLocation;
|
||||
|
||||
/// 在系统相册删除资源时是否同步删除已选的同一资源
|
||||
//@property (assign, nonatomic) BOOL followSystemDeleteAssetToDeleteSelectAsset;
|
||||
|
||||
/// 是否使用仿微信的照片编辑 默认YES
|
||||
@property (assign, nonatomic) BOOL useWxPhotoEdit;
|
||||
|
||||
/// 选择网络视频时超出限制时长时是否裁剪 默认NO
|
||||
@property (assign, nonatomic) BOOL selectNetworkVideoCanEdit;
|
||||
|
||||
/// 相机拍照点击完成之后是否跳转编辑界面进行编辑
|
||||
@property (assign, nonatomic) BOOL cameraPhotoJumpEdit;
|
||||
|
||||
/// 旧版照片编辑才有效
|
||||
/// 照片编辑时底部比例选项
|
||||
/// 默认: @[@{@"原始值" : @"{0, 0}"},
|
||||
/// @{@"正方形" : @"{1, 1}"},
|
||||
/// @{@"2:3" : @"{2, 3}"},
|
||||
/// @{@"3:4" : @"{3, 4}"},
|
||||
/// @{@"9:16" : @"{9, 16}"},
|
||||
/// @{@"16:9" : @"{16, 9}"}]
|
||||
@property (copy, nonatomic) NSArray *photoEditCustomRatios;
|
||||
|
||||
/// 编辑后的照片/视频是否添加到系统相册中
|
||||
/// 只对旧版编辑有效
|
||||
/// 默认为NO
|
||||
@property (assign, nonatomic) BOOL editAssetSaveSystemAblum;
|
||||
|
||||
/// 预览视频时是否先下载视频再播放
|
||||
/// 只有当项目有AFNetworking网络框架的时候才有用
|
||||
/// pod导入时为 HXPhotoPicker/SDWebImage_AF 或 HXPhotoPicker/YYWebImage_AF
|
||||
@property (assign, nonatomic) BOOL downloadNetworkVideo;
|
||||
|
||||
/// 预览视频时是否自动播放
|
||||
@property (assign, nonatomic) HXVideoAutoPlayType videoAutoPlayType;
|
||||
|
||||
/// 相机聚焦框、完成按钮、录制进度的颜色
|
||||
@property (strong, nonatomic) UIColor *cameraFocusBoxColor;
|
||||
|
||||
/// 选择视频时超出限制时长是否自动跳转编辑界面
|
||||
/// 视频可以编辑时有效
|
||||
@property (assign, nonatomic) BOOL selectVideoBeyondTheLimitTimeAutoEdit;
|
||||
|
||||
/// 选择视频时是否限制照片大小
|
||||
@property (assign, nonatomic) BOOL selectVideoLimitSize;
|
||||
|
||||
/// 限制视频的大小 单位:b 字节
|
||||
/// 默认 0字节 不限制
|
||||
/// 网络视频不限制
|
||||
@property (assign, nonatomic) NSUInteger limitVideoSize;
|
||||
|
||||
/// 选择照片时是否限制照片大小
|
||||
@property (assign, nonatomic) BOOL selectPhotoLimitSize;
|
||||
|
||||
/// 限制照片的大小 单位:b 字节
|
||||
/// 默认 0字节 不限制
|
||||
/// 网络图片不限制
|
||||
@property (assign, nonatomic) NSUInteger limitPhotoSize;
|
||||
|
||||
/// 相机界面默认前置摄像头
|
||||
@property (assign, nonatomic) BOOL defaultFrontCamera;
|
||||
|
||||
/// 在照片列表选择照片完后点击完成时是否请求图片和视频地址
|
||||
/// 如果需要下载网络图片 [HXPhotoCommon photoCommon].requestNetworkAfter 设置为YES;
|
||||
/// 选中了原图则是原图,没选中则是高清图
|
||||
/// 并赋值给model的 thumbPhoto / previewPhoto / videoURL 属性
|
||||
/// 如果资源为视频 thumbPhoto 和 previewPhoto 就是视频封面
|
||||
/// model.videoURL 为视频地址
|
||||
@property (assign, nonatomic) BOOL requestImageAfterFinishingSelection;
|
||||
|
||||
/// 当原图按钮隐藏时获取地址时是否请求原图
|
||||
/// 为YES时 requestImageAfterFinishingSelection 获取的原图
|
||||
/// 为NO时 requestImageAfterFinishingSelection 获取的不是原图
|
||||
@property (assign, nonatomic) BOOL requestOriginalImage;
|
||||
|
||||
/// 当 requestImageAfterFinishingSelection = YES 并且选中的原图,导出的视频是否为最高质量
|
||||
/// 如果视频很大的话,导出高质量会很耗时
|
||||
/// 默认为NO
|
||||
@property (assign, nonatomic) BOOL exportVideoURLForHighestQuality;
|
||||
|
||||
/// 自定义相机内部拍照/录制类型
|
||||
@property (assign, nonatomic) HXPhotoCustomCameraType customCameraType;
|
||||
|
||||
/// 跳转预览界面时动画起始的view,使用方法参考demo12里的外部预览功能
|
||||
@property (copy, nonatomic) UIView * (^customPreviewFromView)(NSInteger currentIndex);
|
||||
|
||||
/// 跳转预览界面时动画起始的frame
|
||||
@property (copy, nonatomic) CGRect (^customPreviewFromRect)(NSInteger currentIndex);
|
||||
|
||||
/// 跳转预览界面时展现动画的image,使用方法参考demo12里的外部预览功能
|
||||
@property (copy, nonatomic) UIImage * (^customPreviewFromImage)(NSInteger currentIndex);
|
||||
|
||||
/// 退出预览界面时终点view,使用方法参考demo12里的外部预览功能
|
||||
@property (copy, nonatomic) UIView * (^customPreviewToView)(NSInteger currentIndex);
|
||||
|
||||
/// 暗黑模式下照片列表cell上选择按钮选中之后的数字标题颜色
|
||||
@property (strong, nonatomic) UIColor *cellDarkSelectTitleColor;
|
||||
|
||||
/// 暗黑模式下照片列表cell上选择按钮选中之后的按钮背景颜色
|
||||
@property (strong, nonatomic) UIColor *cellDarkSelectBgColor;
|
||||
|
||||
/// 暗黑模式下预览大图右上角选择按钮选中之后的数字标题颜色
|
||||
@property (strong, nonatomic) UIColor *previewDarkSelectTitleColor;
|
||||
|
||||
/// 暗黑模式下预览大图右上角选择按钮选中之后的按钮背景颜色
|
||||
@property (strong, nonatomic) UIColor *previewDarkSelectBgColor;
|
||||
|
||||
/// 相册风格
|
||||
@property (assign, nonatomic) HXPhotoStyle photoStyle;
|
||||
|
||||
/// 拍摄的画质 默认 AVCaptureSessionPreset1280x720
|
||||
@property (copy, nonatomic) NSString *sessionPreset;
|
||||
|
||||
/// 使用框架自带的相机录制视频时设置的编码格式, ios11以上
|
||||
/// iphone7及以上时系统默认AVVideoCodecHEVC
|
||||
/// HEVC仅支持iPhone 7及以上设备
|
||||
/// iphone6、6s 都不支持H.265,软解H265视频只有声音没有画面
|
||||
/// 当iphone7以下机型出现只有声音没有画面的问题,请将这个值设置为AVVideoCodecH264
|
||||
/// 替换成系统相机也可以解决
|
||||
@property (copy, nonatomic) NSString *videoCodecKey;
|
||||
|
||||
/// 原图按钮显示已选照片的大小
|
||||
@property (assign, nonatomic) BOOL showOriginalBytes;
|
||||
|
||||
/// 原图按钮显示已选照片大小时是否显示加载菊花
|
||||
@property (assign, nonatomic) BOOL showOriginalBytesLoading;
|
||||
|
||||
/// 导出裁剪视频的质量
|
||||
/// iPhoneX -> AVAssetExportPresetHighestQuality
|
||||
@property (copy, nonatomic) NSString *editVideoExportPresetName DEPRECATED_MSG_ATTRIBUTE("Invalid attribute, use editVideoExportPreset and videoQuality");
|
||||
|
||||
/// 导出裁剪视频的分辨率 默认 HXVideoEditorExportPresetRatio_960x540
|
||||
@property (assign, nonatomic) HXVideoEditorExportPreset editVideoExportPreset;
|
||||
/// 导出裁剪视频的质量[0-10] 默认 6
|
||||
@property (assign, nonatomic) NSInteger videoQuality;
|
||||
|
||||
/// 编辑视频时裁剪的最小秒数,如果小于1秒,则为1秒
|
||||
@property (assign, nonatomic) NSInteger minVideoClippingTime;
|
||||
|
||||
/// 编辑视频时裁剪的最大秒数 - default 15s
|
||||
/// 如果超过视频时长,则为视频时长
|
||||
@property (assign, nonatomic) NSInteger maxVideoClippingTime;
|
||||
|
||||
/// 预览大图时的长按响应事件
|
||||
/// previewViewController.outside
|
||||
/// yes -> use HXPhotoView preview
|
||||
/// no -> use HXPhotoViewController preview
|
||||
@property (copy, nonatomic) void (^ previewRespondsToLongPress)(UILongPressGestureRecognizer *longPress, HXPhotoModel *photoModel, HXPhotoManager *manager, HXPhotoPreviewViewController *previewViewController);
|
||||
|
||||
/// 语言类型
|
||||
@property (assign, nonatomic) HXPhotoLanguageType languageType;
|
||||
|
||||
/// 如果选择完照片返回之后
|
||||
/// 原有界面继承UIScrollView的视图都往下偏移一个导航栏距离的话
|
||||
/// 那么请将这个属性设置为YES,即可恢复。
|
||||
/// v2.3.7 之后的版本内部自动修复了
|
||||
@property (assign, nonatomic) BOOL restoreNavigationBar DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/// 照片列表是否按照片创建日期排序
|
||||
@property (assign, nonatomic) BOOL creationDateSort;
|
||||
|
||||
/// 相册列表展示方式
|
||||
@property (assign, nonatomic) HXPhotoAlbumShowMode albumShowMode;
|
||||
|
||||
/// 模型数组保存草稿时存在本地的文件名称 default HXPhotoPickerModelArray
|
||||
/// 如果有多个地方保存了草稿请设置不同的fileName
|
||||
@property (copy, nonatomic) NSString *localFileName;
|
||||
|
||||
/// 只针对 照片、视频不能同时选并且视频只能选择1个的时候隐藏掉视频cell右上角的选择按钮
|
||||
@property (assign, nonatomic) BOOL specialModeNeedHideVideoSelectBtn;
|
||||
|
||||
/// 视频是否可以编辑 default YES
|
||||
@property (assign, nonatomic) BOOL videoCanEdit;
|
||||
|
||||
/// 是否替换照片编辑界面 default NO
|
||||
@property (assign, nonatomic) BOOL replacePhotoEditViewController;
|
||||
|
||||
/// 图片编辑完成调用这个block 传入模型
|
||||
/// beforeModel 编辑之前的模型
|
||||
/// afterModel 编辑之后的模型
|
||||
@property (copy, nonatomic) void (^usePhotoEditComplete)(HXPhotoModel *beforeModel, HXPhotoModel *afterModel);
|
||||
|
||||
/// 是否替换视频编辑界面 default NO
|
||||
@property (assign, nonatomic) BOOL replaceVideoEditViewController;
|
||||
|
||||
/// 将要跳转编辑界面 在block内实现跳转
|
||||
/// isOutside 是否是HXPhotoView预览时的编辑
|
||||
/// beforeModel 编辑之前的模型
|
||||
@property (copy, nonatomic) void (^shouldUseEditAsset)(UIViewController *viewController, BOOL isOutside, HXPhotoManager *manager, HXPhotoModel *beforeModel);
|
||||
|
||||
/// 视频编辑完成调用这个block 传入模型
|
||||
/// beforeModel 编辑之前的模型
|
||||
/// afterModel 编辑之后的模型
|
||||
@property (copy, nonatomic) void (^useVideoEditComplete)(HXPhotoModel *beforeModel, HXPhotoModel *afterModel);
|
||||
|
||||
/// 照片是否可以编辑 default YES
|
||||
@property (assign, nonatomic) BOOL photoCanEdit;
|
||||
|
||||
/// push动画时长 default 0.45f
|
||||
@property (assign, nonatomic) NSTimeInterval pushTransitionDuration;
|
||||
|
||||
/// pop动画时长 default 0.35f
|
||||
@property (assign, nonatomic) NSTimeInterval popTransitionDuration;
|
||||
|
||||
/// 手势松开时返回的动画时长 default 0.35f
|
||||
@property (assign, nonatomic) NSTimeInterval popInteractiveTransitionDuration;
|
||||
|
||||
/// 旧版照片编辑才有效
|
||||
/// 是否可移动的裁剪框
|
||||
@property (assign, nonatomic) BOOL movableCropBox;
|
||||
|
||||
/// 旧版照片编辑才有效
|
||||
/// 可移动的裁剪框是否可以编辑大小
|
||||
@property (assign, nonatomic) BOOL movableCropBoxEditSize;
|
||||
|
||||
/// 旧版照片编辑才有效
|
||||
/// 可移动裁剪框的比例 (w,h) 一定要是宽比高哦!!!
|
||||
/// 当 movableCropBox = YES && movableCropBoxEditSize = YES 如果不设置比例即可自由编辑大小
|
||||
@property (assign, nonatomic) CGPoint movableCropBoxCustomRatio;
|
||||
|
||||
/// 是否替换相机控制器
|
||||
/// 使用自己的相机时需要调用下面两个block
|
||||
@property (assign, nonatomic) BOOL replaceCameraViewController;
|
||||
|
||||
/**
|
||||
将要跳转相机界面 在block内实现跳转
|
||||
demo1 里有示例(使用的是系统相机)
|
||||
*/
|
||||
@property (copy, nonatomic) void (^shouldUseCamera)(UIViewController *viewController, HXPhotoConfigurationCameraType cameraType, HXPhotoManager *manager);
|
||||
|
||||
/**
|
||||
相机拍照完成调用这个block 传入模型
|
||||
*/
|
||||
@property (copy, nonatomic) void (^useCameraComplete)(HXPhotoModel *model);
|
||||
|
||||
#pragma mark - < UI相关 >
|
||||
|
||||
/// 相册权限为选择部分时,照片列表添加cell的背景颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCellBackgroundColor;
|
||||
/// 相册权限为选择部分时,照片列表添加cell暗黑模式下的背景颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCellBackgroundDarkColor;
|
||||
/// 相册权限为选择部分时,照片列表添加cell的加号颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCellLineColor;
|
||||
/// 相册权限为选择部分时,照片列表添加cell暗黑模式下的加号颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCellLineDarkColor;
|
||||
/// 相册权限为选择部分时,照片列表添加cell的文字颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCellTextColor;
|
||||
/// 相册权限为选择部分时,照片列表添加cell暗黑模式下的文字颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCellTextDarkColor;
|
||||
/// 相册权限为选择部分时,照片列表添加cell的文字字体
|
||||
@property (strong, nonatomic) UIFont *photoListLimitCellTextFont;
|
||||
|
||||
/// 限制提示视图:背景样式
|
||||
@property (assign, nonatomic) UIBlurEffectStyle photoListLimitBlurStyle;
|
||||
/// 限制提示视图:文本颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitTextColor;
|
||||
/// 限制提示视图:设置按钮颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitSettingColor;
|
||||
/// 限制提示视图:关闭按钮颜色
|
||||
@property (strong, nonatomic) UIColor *photoListLimitCloseColor;
|
||||
|
||||
/// 照片列表上相机cell上的相机未预览时的图标
|
||||
@property (copy, nonatomic) NSString *photoListTakePhotoNormalImageNamed;
|
||||
|
||||
/// 照片列表上相机cell上的相机还是预览时的图标
|
||||
@property (copy, nonatomic) NSString *photoListTakePhotoSelectImageNamed;
|
||||
|
||||
/// 照片列表上相机cell的背景颜色
|
||||
@property (strong, nonatomic) UIColor *photoListTakePhotoBgColor;
|
||||
|
||||
/// 未授权时界面上提示文字显示的颜色
|
||||
@property (strong, nonatomic) UIColor *authorizationTipColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表竖屏时的高度
|
||||
*/
|
||||
@property (assign, nonatomic) CGFloat popupTableViewHeight;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表的背景颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewBgColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表横屏时的高度
|
||||
*/
|
||||
@property (assign, nonatomic) CGFloat popupTableViewHorizontalHeight;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell选中的颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellSelectColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell选中时的图标颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellSelectIconColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell高亮的颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellHighlightedColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell底部线的颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellLineColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell的背景颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellBgColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell上相册名称的颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellAlbumNameColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell上相册名称的字体
|
||||
*/
|
||||
@property (strong, nonatomic) UIFont *popupTableViewCellAlbumNameFont;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell上照片数量的颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *popupTableViewCellPhotoCountColor;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell上照片数量的字体
|
||||
*/
|
||||
@property (strong, nonatomic) UIFont *popupTableViewCellPhotoCountFont;
|
||||
|
||||
/**
|
||||
弹窗方式的相册列表Cell的高度
|
||||
*/
|
||||
@property (assign, nonatomic) CGFloat popupTableViewCellHeight;
|
||||
|
||||
/**
|
||||
显示底部照片数量信息 default YES
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL showBottomPhotoDetail;
|
||||
|
||||
/**
|
||||
完成按钮是否显示详情 default YES
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL doneBtnShowDetail;
|
||||
|
||||
/**
|
||||
是否支持旋转 默认YES
|
||||
- 如果不需要建议设置成NO
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL supportRotation;
|
||||
|
||||
/**
|
||||
状态栏样式 默认 UIStatusBarStyleDefault
|
||||
*/
|
||||
@property (assign, nonatomic) UIStatusBarStyle statusBarStyle;
|
||||
|
||||
/**
|
||||
cell选中时的背景颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *cellSelectedBgColor;
|
||||
|
||||
/**
|
||||
cell选中时的文字颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *cellSelectedTitleColor;
|
||||
|
||||
/**
|
||||
选中时数字的颜色
|
||||
*/
|
||||
@property (strong, nonatomic) UIColor *selectedTitleColor;
|
||||
|
||||
/// 预览界面选择按钮的背景颜色
|
||||
@property (strong, nonatomic) UIColor *previewSelectedBtnBgColor;
|
||||
|
||||
/// sectionHeader悬浮时的标题颜色
|
||||
/// 3.0.3之后的版本已移除此功能
|
||||
@property (strong, nonatomic) UIColor *sectionHeaderSuspensionTitleColor DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/// sectionHeader悬浮时的背景色
|
||||
/// 3.0.3之后的版本已移除此功能
|
||||
@property (strong, nonatomic) UIColor *sectionHeaderSuspensionBgColor DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/// 导航栏标题颜色
|
||||
@property (strong, nonatomic) UIColor *navigationTitleColor;
|
||||
|
||||
/// 照片列表导航栏标题箭头颜色
|
||||
@property (strong, nonatomic) UIColor *navigationTitleArrowColor;
|
||||
|
||||
/// 暗黑模式下照片列表导航栏标题箭头颜色
|
||||
@property (strong, nonatomic) UIColor *navigationTitleArrowDarkColor;
|
||||
|
||||
/// 导航栏是否半透明
|
||||
@property (assign, nonatomic) BOOL navBarTranslucent;
|
||||
|
||||
/// 导航栏背景颜色
|
||||
@property (strong, nonatomic) UIColor *navBarBackgroudColor;
|
||||
|
||||
/// 导航栏样式
|
||||
@property(nonatomic,assign) UIBarStyle navBarStyle;
|
||||
|
||||
/// 导航栏背景图片
|
||||
@property (strong, nonatomic) UIImage *navBarBackgroundImage;
|
||||
|
||||
#pragma mark - < 自定义titleView >
|
||||
/// 自定义照片列表导航栏titleView
|
||||
/// albumShowMode == HXPhotoAlbumShowModePopup 时才有效
|
||||
@property (copy, nonatomic) UIView *(^ photoListTitleView)(NSString *title);
|
||||
|
||||
/// 更新照片列表导航栏title
|
||||
@property (copy, nonatomic) void (^ updatePhotoListTitle)(NSString *title);
|
||||
|
||||
/// 照片列表改变titleView选中状态
|
||||
@property (copy, nonatomic) void (^ photoListChangeTitleViewSelected)(BOOL selected);
|
||||
|
||||
/// 获取照片列表导航栏titleView的选中状态
|
||||
@property (copy, nonatomic) BOOL (^ photoListTitleViewSelected)(void);
|
||||
|
||||
/// 照片列表titleView点击事件
|
||||
@property (copy, nonatomic) void (^ photoListTitleViewAction)(BOOL selected);
|
||||
|
||||
/// 照片列表背景颜色
|
||||
@property (strong, nonatomic) UIColor *photoListViewBgColor;
|
||||
|
||||
/// 照片列表底部照片数量文字颜色
|
||||
@property (strong, nonatomic) UIColor *photoListBottomPhotoCountTextColor;
|
||||
|
||||
/// 预览照片界面背景颜色
|
||||
@property (strong, nonatomic) UIColor *previewPhotoViewBgColor;
|
||||
|
||||
/// 相册列表背景颜色
|
||||
@property (strong, nonatomic) UIColor *albumListViewBgColor;
|
||||
|
||||
/// 相册列表cell背景颜色
|
||||
@property (strong, nonatomic) UIColor *albumListViewCellBgColor;
|
||||
|
||||
/// 相册列表cell上文字颜色
|
||||
@property (strong, nonatomic) UIColor *albumListViewCellTextColor;
|
||||
|
||||
/// 相册列表cell选中颜色
|
||||
@property (strong, nonatomic) UIColor *albumListViewCellSelectBgColor;
|
||||
|
||||
/// 相册列表cell底部线颜色
|
||||
@property (strong, nonatomic) UIColor *albumListViewCellLineColor;
|
||||
|
||||
/// 3.0.3之后的版本已移除此功能
|
||||
@property (assign, nonatomic) BOOL sectionHeaderTranslucent DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/// 导航栏标题颜色是否与主题色同步 默认NO
|
||||
/// 同步会过滤掉手动设置的导航栏标题颜色
|
||||
@property (assign, nonatomic) BOOL navigationTitleSynchColor;
|
||||
|
||||
/// 底部视图的背景颜色
|
||||
@property (strong, nonatomic) UIColor *bottomViewBgColor;
|
||||
|
||||
/// 底部视图的样式
|
||||
@property(nonatomic,assign) UIBarStyle bottomViewBarStyle;
|
||||
|
||||
/// 底部完成按钮背景颜色
|
||||
@property (strong, nonatomic) UIColor *bottomDoneBtnBgColor;
|
||||
|
||||
/// 底部完成按钮暗黑模式下的背景颜色
|
||||
@property (strong, nonatomic) UIColor *bottomDoneBtnDarkBgColor;
|
||||
|
||||
/// 底部完成按钮禁用状态下的背景颜色
|
||||
@property (strong, nonatomic) UIColor *bottomDoneBtnEnabledBgColor;
|
||||
|
||||
/// 底部完成按钮文字颜色
|
||||
@property (strong, nonatomic) UIColor *bottomDoneBtnTitleColor;
|
||||
|
||||
/// 底部视图是否半透明效果 默认YES
|
||||
@property (assign, nonatomic) BOOL bottomViewTranslucent;
|
||||
|
||||
/// 主题颜色 默认 tintColor
|
||||
@property (strong, nonatomic) UIColor *themeColor;
|
||||
|
||||
/// 预览界面底部已选照片的选中颜色
|
||||
@property (strong, nonatomic) UIColor *previewBottomSelectColor;
|
||||
|
||||
/// 是否可以改变原图按钮的tinColor
|
||||
@property (assign, nonatomic) BOOL changeOriginalTinColor;
|
||||
|
||||
/// 原图按钮普通状态下的按钮图标名
|
||||
/// 改变主题颜色后建议也改下原图按钮的图标
|
||||
@property (copy, nonatomic) NSString *originalNormalImageName;
|
||||
|
||||
/// 原图按钮图片的tintColor,设置这个颜色可改变图片的颜色
|
||||
@property (strong, nonatomic) UIColor *originalBtnImageTintColor;
|
||||
|
||||
/// 原图按钮选中状态下的按钮图标名
|
||||
/// 改变主题颜色后建议也改下原图按钮的图标
|
||||
@property (copy, nonatomic) NSString *originalSelectedImageName;
|
||||
|
||||
/// 是否隐藏原图按钮 默认 NO
|
||||
@property (assign, nonatomic) BOOL hideOriginalBtn;
|
||||
|
||||
/// sectionHeader 是否显示照片的位置信息
|
||||
/// 3.0.3之后的版本已移除此功能
|
||||
@property (assign, nonatomic) BOOL sectionHeaderShowPhotoLocation DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/**
|
||||
相机cell是否显示预览
|
||||
屏幕宽 320 -> NO
|
||||
other -> YES
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL cameraCellShowPreview;
|
||||
|
||||
/**
|
||||
横屏时是否隐藏状态栏 默认显示 暂不支持修改
|
||||
*/
|
||||
//@property (assign, nonatomic) BOOL horizontalHideStatusBar;
|
||||
|
||||
/**
|
||||
横屏时相册每行个数 默认6个
|
||||
*/
|
||||
@property (assign, nonatomic) NSInteger horizontalRowCount;
|
||||
|
||||
/**
|
||||
是否需要显示日期section 默认NO
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL showDateSectionHeader;
|
||||
|
||||
/// 照片列表倒序
|
||||
@property (assign, nonatomic) BOOL reverseDate;
|
||||
|
||||
#pragma mark - < 基本配置 >
|
||||
/**
|
||||
相册列表每行多少个照片 默认4个 iphone 4s / 5 默认3个
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger rowCount;
|
||||
|
||||
/**
|
||||
最大选择数 - 必填
|
||||
如果照片最大数和视频最大数都为0时,则可以混合添加
|
||||
当照片选了1张时 视频就还可以选择9个
|
||||
当照片选了5张时 视频就还可以选择5个
|
||||
视频同理
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger maxNum;
|
||||
|
||||
/**
|
||||
照片最大选择数 默认9 - 必填
|
||||
如果为0时,最大数则为maxNum 减去 视频已选数
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger photoMaxNum;
|
||||
|
||||
/**
|
||||
视频最大选择数 默认1 - 必填
|
||||
如果为0时,最大数则为maxNum 减去 照片已选数
|
||||
*/
|
||||
@property (assign, nonatomic) NSUInteger videoMaxNum;
|
||||
|
||||
/**
|
||||
是否打开相机功能
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL openCamera;
|
||||
|
||||
/**
|
||||
是否开启查看GIF图片功能 - 默认开启
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL lookGifPhoto;
|
||||
|
||||
/**
|
||||
是否开启查看LivePhoto功能呢 - 默认 NO
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL lookLivePhoto;
|
||||
|
||||
/**
|
||||
图片和视频是否能够同时选择 默认 NO
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL selectTogether;
|
||||
|
||||
/**
|
||||
相机视频录制最大秒数 - 默认60s
|
||||
*/
|
||||
@property (assign, nonatomic) NSTimeInterval videoMaximumDuration;
|
||||
|
||||
/**
|
||||
相机视频录制最小秒数 - 默认3s
|
||||
*/
|
||||
@property (assign, nonatomic) NSTimeInterval videoMinimumDuration;
|
||||
|
||||
/**
|
||||
* 删除临时的照片/视频 -
|
||||
注:相机拍摄的照片并没有保存到系统相册 或 是本地图片
|
||||
如果当这样的照片都没有被选中时会清空这些照片 有一张选中了就不会删..
|
||||
- 默认 NO
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL deleteTemporaryPhoto;
|
||||
|
||||
/**
|
||||
* 拍摄的 照片/视频 是否保存到系统相册 默认NO
|
||||
* 支持添加到自定义相册 - (需9.0以上)
|
||||
*/
|
||||
@property (assign, nonatomic) BOOL saveSystemAblum;
|
||||
|
||||
/// 拍摄的照片/视频保存到指定相册的名称 默认 DisplayName
|
||||
/// 需9.0以上系统才可以保存到自定义相册 , 以下的系统只保存到相机胶卷...
|
||||
@property (copy, nonatomic) NSString *customAlbumName;
|
||||
|
||||
/// 视频能选择的最大秒数 - 默认 3分钟/180秒
|
||||
/// 当视频超过能选的最大时长,如果视频可以编辑那么在列表选择的时候会自动跳转视频裁剪界面
|
||||
@property (assign, nonatomic) NSInteger videoMaximumSelectDuration;
|
||||
|
||||
/// 视频能选择的最小秒数 - 默认 0秒 - 不限制
|
||||
@property (assign, nonatomic) NSInteger videoMinimumSelectDuration;
|
||||
|
||||
/// 是否为单选模式 默认 NO HXPhotoView 不支持
|
||||
@property (assign, nonatomic) BOOL singleSelected;
|
||||
|
||||
/// 单选模式下选择图片时是否直接跳转到编辑界面 - 默认 NO
|
||||
@property (assign, nonatomic) BOOL singleJumpEdit;
|
||||
|
||||
/// 是否开启3DTouch预览功能 默认 YES
|
||||
@property (assign, nonatomic) BOOL open3DTouchPreview;
|
||||
|
||||
/// 下载iCloud上的资源
|
||||
/// 3.0.3 之后的版本已无效
|
||||
@property (assign, nonatomic) BOOL downloadICloudAsset DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/// 是否过滤iCloud上的资源
|
||||
/// 3.0.3 之后的版本已无效
|
||||
@property (assign, nonatomic) BOOL filtrationICloudAsset DEPRECATED_MSG_ATTRIBUTE("Invalid attribute");
|
||||
|
||||
/// 列表小图照片清晰度 越大越清晰、越消耗性能
|
||||
/// 设置太大的话获取图片资源时耗时长且内存消耗大可能会引起界面卡顿
|
||||
@property (assign, nonatomic) CGFloat clarityScale;
|
||||
|
||||
#pragma mark - < block返回的视图 >
|
||||
/// 设置导航栏
|
||||
@property (copy, nonatomic) void (^navigationBar)(UINavigationBar *navigationBar, UIViewController *viewController);
|
||||
|
||||
/// 照片列表底部View
|
||||
@property (copy, nonatomic) void (^photoListBottomView)(HXPhotoBottomView *bottomView);
|
||||
|
||||
/// 预览界面底部View
|
||||
@property (copy, nonatomic) void (^previewBottomView)(HXPhotoPreviewBottomView *bottomView);
|
||||
|
||||
/// 相册列表的collectionView
|
||||
/// 旋转屏幕时也会调用
|
||||
@property (copy, nonatomic) void (^albumListCollectionView)(UICollectionView *collectionView);
|
||||
|
||||
/// 相册列表的tableView
|
||||
/// 旋转屏幕时也会调用
|
||||
@property (copy, nonatomic) void (^albumListTableView)(UITableView *tableView);
|
||||
|
||||
/// 弹窗样式的相册列表
|
||||
/// 旋转屏幕时也会调用
|
||||
@property (copy, nonatomic) void (^popupAlbumTableView)(UITableView *tableView);
|
||||
|
||||
/// 相片列表的collectionView
|
||||
/// 旋转屏幕时也会调用
|
||||
@property (copy, nonatomic) void (^photoListCollectionView)(UICollectionView *collectionView);
|
||||
|
||||
/// 预览界面的collectionView
|
||||
/// 旋转屏幕时也会调用
|
||||
@property (copy, nonatomic) void (^previewCollectionView)(UICollectionView *collectionView);
|
||||
|
||||
@end
|
|
@ -0,0 +1,333 @@
|
|||
//
|
||||
// HXPhotoConfiguration.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/11/21.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoConfiguration.h"
|
||||
#import "HXPhotoTools.h"
|
||||
#import "UIColor+HXExtension.h"
|
||||
|
||||
@implementation HXPhotoConfiguration
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
self.open3DTouchPreview = YES;
|
||||
self.openCamera = YES;
|
||||
self.lookLivePhoto = NO;
|
||||
self.lookGifPhoto = YES;
|
||||
self.selectTogether = NO;
|
||||
self.showOriginalBytesLoading = NO;
|
||||
self.exportVideoURLForHighestQuality = NO;
|
||||
self.maxNum = 10;
|
||||
self.photoMaxNum = 9;
|
||||
self.videoMaxNum = 1;
|
||||
self.showBottomPhotoDetail = YES;
|
||||
self.videoMaximumSelectDuration = 3 * 60.f;
|
||||
self.videoMinimumSelectDuration = 0.f;
|
||||
self.videoMaximumDuration = 60.f;
|
||||
self.videoMinimumDuration = 3.f;
|
||||
if ([UIScreen mainScreen].bounds.size.width != 320 && [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
|
||||
self.cameraCellShowPreview = YES;
|
||||
}
|
||||
self.customAlbumName = [NSBundle mainBundle].infoDictionary[(NSString *)kCFBundleNameKey];
|
||||
self.horizontalRowCount = 6;
|
||||
self.supportRotation = YES;
|
||||
self.pushTransitionDuration = 0.45f;
|
||||
self.popTransitionDuration = 0.35f;
|
||||
self.popInteractiveTransitionDuration = 0.45f;
|
||||
self.doneBtnShowDetail = YES;
|
||||
self.videoCanEdit = YES;
|
||||
self.photoCanEdit = YES;
|
||||
self.localFileName = @"HXPhotoPickerModelArray";
|
||||
self.languageType = HXPhotoLanguageTypeSys;
|
||||
self.popupTableViewCellHeight = 65.f;
|
||||
if (HX_IS_IPhoneX_All) {
|
||||
// self.editVideoExportPresetName = AVAssetExportPresetHighestQuality;
|
||||
self.popupTableViewHeight = 450;
|
||||
}else {
|
||||
// self.editVideoExportPresetName = AVAssetExportPresetMediumQuality;
|
||||
self.popupTableViewHeight = 350;
|
||||
}
|
||||
self.editVideoExportPreset = HXVideoEditorExportPresetRatio_960x540;
|
||||
self.videoQuality = 6;
|
||||
self.popupTableViewHorizontalHeight = 250;
|
||||
self.albumShowMode = HXPhotoAlbumShowModeDefault;
|
||||
|
||||
self.cellDarkSelectTitleColor = [UIColor whiteColor];
|
||||
self.cellDarkSelectBgColor = [UIColor colorWithRed:0.15 green:0.15 blue:0.15 alpha:1];
|
||||
self.previewDarkSelectBgColor = [UIColor whiteColor];
|
||||
self.previewDarkSelectTitleColor = [UIColor blackColor];
|
||||
[HXPhotoCommon photoCommon].photoStyle = HXPhotoStyleDefault;
|
||||
self.defaultFrontCamera = NO;
|
||||
|
||||
self.popupTableViewBgColor = [UIColor whiteColor];
|
||||
self.albumListViewBgColor = [UIColor whiteColor];
|
||||
self.photoListViewBgColor = [UIColor whiteColor];
|
||||
self.previewPhotoViewBgColor = [UIColor whiteColor];
|
||||
self.albumListViewCellBgColor = [UIColor whiteColor];
|
||||
self.albumListViewCellTextColor = [UIColor blackColor];
|
||||
self.albumListViewCellSelectBgColor = nil;
|
||||
self.albumListViewCellLineColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.15];
|
||||
self.photoListBottomPhotoCountTextColor = [UIColor colorWithRed:51.f / 255.f green:51.f / 255.f blue:51.f / 255.f alpha:1];
|
||||
|
||||
self.limitPhotoSize = 0;
|
||||
self.limitVideoSize = 0;
|
||||
self.selectPhotoLimitSize = NO;
|
||||
self.selectVideoLimitSize = NO;
|
||||
self.navBarTranslucent = YES;
|
||||
self.bottomViewTranslucent = YES;
|
||||
self.selectVideoBeyondTheLimitTimeAutoEdit = NO;
|
||||
self.videoAutoPlayType = HXVideoAutoPlayTypeOnce;
|
||||
self.previewSelectedBtnBgColor = self.themeColor;
|
||||
self.changeOriginalTinColor = YES;
|
||||
self.downloadNetworkVideo = YES;
|
||||
self.cameraCanLocation = YES;
|
||||
self.editAssetSaveSystemAblum = NO;
|
||||
self.photoEditCustomRatios = @[@{@"原始值" : @"{0, 0}"}, @{@"正方形" : @"{1, 1}"}, @{@"2:3" : @"{2, 3}"}, @{@"3:4" : @"{3, 4}"}, @{@"9:16" : @"{9, 16}"}, @{@"16:9" : @"{16, 9}"}];
|
||||
self.useWxPhotoEdit = YES;
|
||||
if (HX_IS_IPhoneX_All) {
|
||||
_clarityScale = 1.9;
|
||||
}else {
|
||||
_clarityScale = 1.5;
|
||||
}
|
||||
if ([UIScreen mainScreen].bounds.size.width == 320) {
|
||||
self.rowCount = 3;
|
||||
}else {
|
||||
if ([HXPhotoTools isIphone6]) {
|
||||
self.rowCount = 3;
|
||||
}else {
|
||||
self.rowCount = 4;
|
||||
}
|
||||
}
|
||||
self.allowSlidingSelection = YES;
|
||||
self.livePhotoAutoPlay = YES;
|
||||
|
||||
self.photoListLimitBlurStyle = UIBlurEffectStyleLight;
|
||||
self.photoListLimitTextColor = [UIColor hx_colorWithHexStr:@"#666666"];
|
||||
self.photoListLimitSettingColor = self.themeColor;
|
||||
self.photoListLimitCloseColor = self.themeColor;
|
||||
|
||||
self.photoListLimitCellBackgroundColor = [UIColor hx_colorWithHexStr:@"#f1f1f1"];
|
||||
self.photoListLimitCellBackgroundDarkColor = [UIColor hx_colorWithHexStr:@"#333333"];
|
||||
self.photoListLimitCellLineColor = [UIColor hx_colorWithHexStr:@"#999999"];
|
||||
self.photoListLimitCellLineDarkColor = [UIColor hx_colorWithHexStr:@"#ffffff"];
|
||||
self.photoListLimitCellTextColor = [UIColor hx_colorWithHexStr:@"#999999"];
|
||||
self.photoListLimitCellTextDarkColor = [UIColor hx_colorWithHexStr:@"#ffffff"];
|
||||
self.photoListLimitCellTextFont = [UIFont hx_mediumPingFangOfSize:14];
|
||||
}
|
||||
- (void)setLivePhotoAutoPlay:(BOOL)livePhotoAutoPlay {
|
||||
_livePhotoAutoPlay = livePhotoAutoPlay;
|
||||
[HXPhotoCommon photoCommon].livePhotoAutoPlay = livePhotoAutoPlay;
|
||||
}
|
||||
- (UIColor *)cameraFocusBoxColor {
|
||||
if (!_cameraFocusBoxColor) {
|
||||
_cameraFocusBoxColor = [UIColor colorWithRed:0 green:0.47843137254901963 blue:1 alpha:1];
|
||||
}
|
||||
return _cameraFocusBoxColor;
|
||||
}
|
||||
- (void)setVideoAutoPlayType:(HXVideoAutoPlayType)videoAutoPlayType {
|
||||
_videoAutoPlayType = videoAutoPlayType;
|
||||
[HXPhotoCommon photoCommon].videoAutoPlayType = videoAutoPlayType;
|
||||
}
|
||||
- (void)setDownloadNetworkVideo:(BOOL)downloadNetworkVideo {
|
||||
_downloadNetworkVideo = downloadNetworkVideo;
|
||||
[HXPhotoCommon photoCommon].downloadNetworkVideo = downloadNetworkVideo;
|
||||
}
|
||||
- (void)setPhotoStyle:(HXPhotoStyle)photoStyle {
|
||||
_photoStyle = photoStyle;
|
||||
[HXPhotoCommon photoCommon].photoStyle = photoStyle;
|
||||
}
|
||||
- (void)setCreationDateSort:(BOOL)creationDateSort {
|
||||
if ([HXPhotoCommon photoCommon].creationDateSort != creationDateSort) {
|
||||
[HXPhotoCommon photoCommon].cameraRollResult = nil;
|
||||
}
|
||||
_creationDateSort = creationDateSort;
|
||||
[HXPhotoCommon photoCommon].creationDateSort = creationDateSort;
|
||||
}
|
||||
- (void)setLanguageType:(HXPhotoLanguageType)languageType {
|
||||
if ([HXPhotoCommon photoCommon].languageType != languageType) {
|
||||
[HXPhotoCommon photoCommon].languageBundle = nil;
|
||||
}
|
||||
_languageType = languageType;
|
||||
[HXPhotoCommon photoCommon].languageType = languageType;
|
||||
}
|
||||
- (void)setClarityScale:(CGFloat)clarityScale {
|
||||
if (clarityScale <= 0.f) {
|
||||
if (HX_IS_IPhoneX_All) {
|
||||
_clarityScale = 1.9;
|
||||
}else {
|
||||
_clarityScale = 1.5;
|
||||
}
|
||||
}else {
|
||||
_clarityScale = clarityScale;
|
||||
}
|
||||
CGFloat width = ([UIScreen mainScreen].bounds.size.width - 1 * self.rowCount - 1 ) / self.rowCount;
|
||||
[HXPhotoCommon photoCommon].requestWidth = width * clarityScale;
|
||||
}
|
||||
- (void)setRowCount:(NSUInteger)rowCount {
|
||||
_rowCount = rowCount;
|
||||
CGFloat width = ([UIScreen mainScreen].bounds.size.width - 1 * rowCount - 1 ) / rowCount;
|
||||
[HXPhotoCommon photoCommon].requestWidth = width * self.clarityScale;
|
||||
}
|
||||
- (UIColor *)themeColor {
|
||||
if (!_themeColor) {
|
||||
_themeColor = [UIColor colorWithRed:0 green:0.47843137254901963 blue:1 alpha:1];
|
||||
}
|
||||
return _themeColor;
|
||||
}
|
||||
- (NSString *)originalNormalImageName {
|
||||
if (!_originalNormalImageName) {
|
||||
_originalNormalImageName = @"hx_original_normal";
|
||||
}
|
||||
return _originalNormalImageName;
|
||||
}
|
||||
- (NSString *)originalSelectedImageName {
|
||||
if (!_originalSelectedImageName) {
|
||||
_originalSelectedImageName = @"hx_original_selected";
|
||||
}
|
||||
return _originalSelectedImageName;
|
||||
}
|
||||
- (void)setVideoMaximumSelectDuration:(NSInteger)videoMaximumSelectDuration {
|
||||
if (videoMaximumSelectDuration <= 0) {
|
||||
videoMaximumSelectDuration = MAXFLOAT;
|
||||
}
|
||||
_videoMaximumSelectDuration = videoMaximumSelectDuration;
|
||||
}
|
||||
- (void)setVideoMaximumDuration:(NSTimeInterval)videoMaximumDuration {
|
||||
if (videoMaximumDuration <= self.videoMinimumDuration) {
|
||||
videoMaximumDuration = self.videoMinimumDuration + 1.f;
|
||||
}
|
||||
_videoMaximumDuration = videoMaximumDuration;
|
||||
}
|
||||
- (CGPoint)movableCropBoxCustomRatio {
|
||||
return _movableCropBoxCustomRatio;
|
||||
}
|
||||
- (NSInteger)minVideoClippingTime {
|
||||
if (_minVideoClippingTime < 1) {
|
||||
_minVideoClippingTime = 1;
|
||||
}
|
||||
return _minVideoClippingTime;
|
||||
}
|
||||
- (NSInteger)maxVideoClippingTime {
|
||||
if (!_maxVideoClippingTime) {
|
||||
_maxVideoClippingTime = 15;
|
||||
}
|
||||
return _maxVideoClippingTime;
|
||||
}
|
||||
- (UIColor *)authorizationTipColor {
|
||||
if (!_authorizationTipColor) {
|
||||
_authorizationTipColor = [UIColor blackColor];
|
||||
}
|
||||
return _authorizationTipColor;
|
||||
}
|
||||
- (void)setType:(HXConfigurationType)type {
|
||||
_type = type;
|
||||
if (type == HXConfigurationTypeWXChat) {
|
||||
[self setWxConfiguration];
|
||||
self.videoMaximumSelectDuration = 60.f * 5.f;
|
||||
self.selectVideoBeyondTheLimitTimeAutoEdit = NO;
|
||||
self.photoMaxNum = 0;
|
||||
self.videoMaxNum = 0;
|
||||
self.maxNum = 9;
|
||||
self.selectTogether = YES;
|
||||
}else if (type == HXConfigurationTypeWXMoment) {
|
||||
[self setWxConfiguration];
|
||||
self.videoMaximumDuration = 15;
|
||||
self.videoMaximumSelectDuration = 15;
|
||||
self.selectVideoBeyondTheLimitTimeAutoEdit = YES;
|
||||
self.photoMaxNum = 9;
|
||||
self.videoMaxNum = 1;
|
||||
self.maxNum = 9;
|
||||
self.selectTogether = NO;
|
||||
}
|
||||
}
|
||||
- (void)setWxConfiguration {
|
||||
self.videoCanEdit = YES;
|
||||
self.specialModeNeedHideVideoSelectBtn = YES;
|
||||
self.cameraPhotoJumpEdit = YES;
|
||||
self.saveSystemAblum = YES;
|
||||
self.albumShowMode = HXPhotoAlbumShowModePopup;
|
||||
self.photoListCancelLocation = HXPhotoListCancelButtonLocationTypeLeft;
|
||||
self.cameraCellShowPreview = NO;
|
||||
|
||||
// 原图按钮设置
|
||||
self.changeOriginalTinColor = NO;
|
||||
self.originalNormalImageName = @"hx_original_normal_wx";
|
||||
self.originalSelectedImageName = @"hx_original_selected_wx";
|
||||
|
||||
// 颜色设置
|
||||
UIColor *wxColor = [UIColor hx_colorWithHexStr:@"#07C160"];
|
||||
self.statusBarStyle = UIStatusBarStyleLightContent;
|
||||
self.themeColor = [UIColor whiteColor];
|
||||
self.photoEditConfigur.themeColor = wxColor;
|
||||
self.previewBottomSelectColor = wxColor;
|
||||
self.navBarBackgroudColor = nil;
|
||||
self.navBarStyle = UIBarStyleBlack;
|
||||
self.navigationTitleArrowColor = [UIColor hx_colorWithHexStr:@"#B2B2B2"];
|
||||
self.navigationTitleArrowDarkColor = [UIColor hx_colorWithHexStr:@"#B2B2B2"];
|
||||
self.cameraFocusBoxColor = wxColor;
|
||||
self.authorizationTipColor = [UIColor whiteColor];
|
||||
self.navigationTitleSynchColor = YES;
|
||||
self.cellSelectedBgColor = wxColor;
|
||||
self.cellSelectedTitleColor = [UIColor whiteColor];
|
||||
self.cellDarkSelectBgColor = wxColor;
|
||||
self.cellDarkSelectTitleColor = [UIColor whiteColor];
|
||||
self.photoListLimitBlurStyle = UIBlurEffectStyleDark;
|
||||
self.photoListLimitTextColor = [UIColor hx_colorWithHexStr:@"#999999"];
|
||||
self.photoListLimitSettingColor = wxColor;
|
||||
self.photoListLimitCloseColor = [UIColor whiteColor];
|
||||
self.previewSelectedBtnBgColor = wxColor;
|
||||
self.selectedTitleColor = [UIColor whiteColor];
|
||||
self.previewDarkSelectBgColor = wxColor;
|
||||
self.previewDarkSelectTitleColor = [UIColor whiteColor];
|
||||
self.bottomDoneBtnBgColor = wxColor;
|
||||
self.bottomDoneBtnDarkBgColor = wxColor;
|
||||
self.bottomDoneBtnEnabledBgColor = [[UIColor hx_colorWithHexStr:@"#666666"] colorWithAlphaComponent:0.3];
|
||||
self.bottomDoneBtnTitleColor = [UIColor whiteColor];
|
||||
// self.bottomViewBgColor = [UIColor hx_colorWithHexStr:@"#141414"];
|
||||
self.bottomViewBgColor = nil;
|
||||
self.bottomViewBarStyle = UIBarStyleBlack;
|
||||
|
||||
self.popupTableViewCellBgColor = [UIColor hx_colorWithHexStr:@"#2E2F30"];
|
||||
self.popupTableViewCellLineColor = [[UIColor hx_colorWithHexStr:@"#434344"] colorWithAlphaComponent:0.6];
|
||||
self.popupTableViewCellSelectColor = [UIColor clearColor];
|
||||
self.popupTableViewCellSelectIconColor = wxColor;
|
||||
self.popupTableViewCellHighlightedColor = [UIColor colorWithRed:0.125 green:0.125 blue:0.125 alpha:1];
|
||||
self.popupTableViewBgColor = [UIColor colorWithRed:0.125 green:0.125 blue:0.125 alpha:1];
|
||||
self.popupTableViewCellPhotoCountColor = [UIColor whiteColor];
|
||||
self.popupTableViewCellAlbumNameColor = [UIColor whiteColor];
|
||||
self.popupTableViewHeight = HX_ScreenHeight * 0.65;
|
||||
|
||||
self.albumListViewBgColor = [UIColor hx_colorWithHexStr:@"#2E2F30"];
|
||||
self.albumListViewCellBgColor = [UIColor hx_colorWithHexStr:@"#2E2F30"];
|
||||
self.albumListViewCellSelectBgColor = [UIColor colorWithRed:0.125 green:0.125 blue:0.125 alpha:1];
|
||||
self.albumListViewCellLineColor = [[UIColor hx_colorWithHexStr:@"#434344"] colorWithAlphaComponent:0.6];
|
||||
self.albumListViewCellTextColor = [UIColor whiteColor];
|
||||
|
||||
self.photoListViewBgColor = [UIColor hx_colorWithHexStr:@"#2E2F30"];
|
||||
self.photoListBottomPhotoCountTextColor = [UIColor whiteColor];
|
||||
self.previewPhotoViewBgColor = [UIColor blackColor];
|
||||
|
||||
self.photoListLimitCellBackgroundColor = [UIColor hx_colorWithHexStr:@"#383838"];
|
||||
self.photoListLimitCellLineColor = [UIColor hx_colorWithHexStr:@"#ffffff"];
|
||||
self.photoListLimitCellTextColor = [UIColor hx_colorWithHexStr:@"#ffffff"];
|
||||
}
|
||||
- (HXPhotoEditConfiguration *)photoEditConfigur {
|
||||
if (!_photoEditConfigur) {
|
||||
_photoEditConfigur = [[HXPhotoEditConfiguration alloc] init];
|
||||
_photoEditConfigur.themeColor = self.themeColor;
|
||||
_photoEditConfigur.supportRotation = self.supportRotation;
|
||||
}
|
||||
return _photoEditConfigur;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,228 @@
|
|||
//
|
||||
// HXPhotoDefine.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2017/11/24.
|
||||
// Copyright © 2017年 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef HXPhotoDefine_h
|
||||
#define HXPhotoDefine_h
|
||||
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
|
||||
/// 当前版本
|
||||
#define HXVersion @"3.3.2"
|
||||
|
||||
// 日志输出
|
||||
#ifdef DEBUG
|
||||
#define NSSLog(FORMAT, ...) fprintf(stderr,"%s:%d\t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
|
||||
#else
|
||||
#define NSSLog(...)
|
||||
#endif
|
||||
|
||||
/// 如果想要HXPhotoView的item大小自定义设置,请修改为 1
|
||||
/// 如果为pod导入的话,请使用 pod 'HXPhotoPicker/CustomItem'
|
||||
/// 并且实现HXPhotoView的代理
|
||||
/// - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath isAddItem:(BOOL)isAddItem photoView:(HXPhotoView *)photoView
|
||||
/// 如果不实现此代理,item的小大将默认 (100, 100)
|
||||
#define HXPhotoViewCustomItemSize 0
|
||||
|
||||
#define HXRound(x) (round(x*100000)/100000)
|
||||
#define HXRoundHundreds(x) (round(x*100)/100)
|
||||
#define HXRoundDecade(x) (round(x*10)/10)
|
||||
|
||||
#define HXRoundFrame(rect) CGRectMake(HXRound(rect.origin.x), HXRound(rect.origin.y), HXRound(rect.size.width), HXRound(rect.size.height))
|
||||
#define HXRoundFrameHundreds(rect) CGRectMake(HXRoundHundreds(rect.origin.x), HXRoundHundreds(rect.origin.y), HXRoundHundreds(rect.size.width), HXRoundHundreds(rect.size.height))
|
||||
|
||||
#define HXEncodeKey @"HXModelArray"
|
||||
|
||||
#define HXCameraImageKey @"HXCameraImageURLKey"
|
||||
|
||||
#define HXPhotoPickerLibraryCaches [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]
|
||||
|
||||
#define HXPhotoPickerDocuments [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
|
||||
|
||||
//#define HXPhotoPickerLocalModelsPath [HXPhotoPickerDocuments stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/localModels", HXPhotoHeaderSearchPath]]
|
||||
|
||||
#define HXPhotoPickerLocalModelsPath [HXPhotoPickerLibraryCaches stringByAppendingPathComponent:@"localModels"]
|
||||
|
||||
#define HXPhotoHeaderSearchPath @"com.silence.hxphotopicker"
|
||||
|
||||
#define HXPhotoPickerAssetCachesPath [HXPhotoPickerLibraryCaches stringByAppendingPathComponent:HXPhotoHeaderSearchPath]
|
||||
|
||||
#define HXPhotoPickerCachesDownloadPath [HXPhotoPickerAssetCachesPath stringByAppendingPathComponent:@"download"]
|
||||
|
||||
#define HXPhotoPickerDownloadVideosPath [HXPhotoPickerCachesDownloadPath stringByAppendingPathComponent:@"videos"]
|
||||
|
||||
#define HXPhotoPickerDownloadPhotosPath [HXPhotoPickerCachesDownloadPath stringByAppendingPathComponent:@"photos"]
|
||||
|
||||
#define HXPhotoPickerCachesLivePhotoPath [HXPhotoPickerAssetCachesPath stringByAppendingPathComponent:@"LivePhoto"]
|
||||
|
||||
#define HXPhotoPickerLivePhotoVideosPath [HXPhotoPickerCachesLivePhotoPath stringByAppendingPathComponent:@"videos"]
|
||||
|
||||
#define HXPhotoPickerLivePhotoImagesPath [HXPhotoPickerCachesLivePhotoPath stringByAppendingPathComponent:@"images"]
|
||||
|
||||
#define HXShowLog NO
|
||||
|
||||
#define HX_UI_IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
|
||||
|
||||
#define HX_ALLOW_LOCATION ([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] || [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])
|
||||
|
||||
#define HX_PREFERS_STATUS_BAR_HIDDEN [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIViewControllerBasedStatusBarAppearance"] boolValue]
|
||||
|
||||
#define HasAFNetworking (__has_include(<AFNetworking/AFNetworking.h>) || __has_include("AFNetworking.h"))
|
||||
|
||||
#define HasYYWebImage (__has_include(<YYWebImage/YYWebImage.h>) || __has_include("YYWebImage.h"))
|
||||
|
||||
#define HasYYKit (__has_include(<YYKit/YYKit.h>) || __has_include("YYKit.h"))
|
||||
|
||||
#define HasYYKitOrWebImage (__has_include(<YYWebImage/YYWebImage.h>) || __has_include("YYWebImage.h") || __has_include(<YYKit/YYKit.h>) || __has_include("YYKit.h"))
|
||||
|
||||
#define HasSDWebImage (__has_include(<SDWebImage/UIImageView+WebCache.h>) || __has_include("UIImageView+WebCache.h"))
|
||||
|
||||
#define HX_ScreenWidth [UIScreen mainScreen].bounds.size.width
|
||||
#define HX_ScreenHeight [UIScreen mainScreen].bounds.size.height
|
||||
|
||||
#define HX_IS_IPHONEX (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)))
|
||||
|
||||
// 判断iPhone X
|
||||
#define HX_Is_iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) : NO)
|
||||
|
||||
//判断iPHoneXr
|
||||
#define HX_Is_iPhoneXR ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(828, 1792), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
//判断iPHoneXs
|
||||
#define HX_Is_iPhoneXS ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1125, 2436), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
//判断iPhoneXs Max
|
||||
#define HX_Is_iPhoneXS_MAX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1242, 2688), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
//判断iPHone12 mini
|
||||
#define HX_Is_iPhoneTwelveMini ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1080, 2340), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
//判断iPHone12 和 iPHone12 Pro
|
||||
#define HX_Is_iPhoneTwelvePro ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1170, 2532), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
//判断iPHone12 ProMax
|
||||
#define HX_Is_iPhoneTwelveProMax ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1284, 2778), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
#define HX_Is_iPhone14ProMax ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1290, 2796), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
#define HX_Is_iPhone14Pro ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? CGSizeEqualToSize(CGSizeMake(1179, 2556), [[UIScreen mainScreen] currentMode].size) && !HX_UI_IS_IPAD : NO)
|
||||
|
||||
#define HX_IS_IPhoneX_All (HX_Is_iPhoneX || HX_Is_iPhoneXR || HX_Is_iPhoneXS || HX_Is_iPhoneXS_MAX || HX_IS_IPHONEX || HX_Is_iPhoneTwelveMini || HX_Is_iPhoneTwelvePro || HX_Is_iPhoneTwelveProMax || HX_Is_iPhone14Pro || HX_Is_iPhone14ProMax)
|
||||
|
||||
// 导航栏 + 状态栏 的高度
|
||||
#define hxNavigationBarHeight ((HX_UI_IS_IPAD ? 50 : 44) + HXStatusBarHeight)
|
||||
#define hxTopMargin (HX_IS_IPhoneX_All ? 44 : 0)
|
||||
#define hxBottomMargin (HX_IS_IPhoneX_All ? 34 : 0)
|
||||
#define HXStatusBarHeight [HXPhotoTools getStatusBarHeight]
|
||||
|
||||
#define HX_IOS14_Later ([UIDevice currentDevice].systemVersion.floatValue >= 14.0f)
|
||||
|
||||
#define HX_IOS13_Later ([UIDevice currentDevice].systemVersion.floatValue >= 13.0f)
|
||||
|
||||
#define HX_IOS11_Later ([UIDevice currentDevice].systemVersion.floatValue >= 11.0f)
|
||||
|
||||
#define HX_IOS11_Earlier ([UIDevice currentDevice].systemVersion.floatValue < 11.0f)
|
||||
|
||||
#define HX_IOS10_Later ([UIDevice currentDevice].systemVersion.floatValue >= 10.0f)
|
||||
|
||||
#define HX_IOS91Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f)
|
||||
|
||||
#define HX_IOS9Later ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f)
|
||||
|
||||
#define HX_IOS82Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.2f)
|
||||
|
||||
#define HX_IOS9Earlier ([UIDevice currentDevice].systemVersion.floatValue < 9.0f)
|
||||
|
||||
// 弱引用
|
||||
#define HXWeakSelf __weak typeof(self) weakSelf = self;
|
||||
// 强引用
|
||||
#define HXStrongSelf __strong typeof(weakSelf) strongSelf = weakSelf;
|
||||
|
||||
#pragma mark - Hash
|
||||
|
||||
#define HX_MAX_FILE_EXTENSION_LENGTH (NAME_MAX - CC_MD5_DIGEST_LENGTH * 2 - 1)
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
static inline NSString * _Nonnull HXDiskCacheFileNameForKey(NSString * _Nullable key, BOOL addExt) {
|
||||
const char *str = key.UTF8String;
|
||||
if (str == NULL) {
|
||||
str = "";
|
||||
}
|
||||
unsigned char r[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5(str, (CC_LONG)strlen(str), r);
|
||||
NSURL *keyURL = [NSURL URLWithString:key];
|
||||
NSString *ext = keyURL ? keyURL.pathExtension : key.pathExtension;
|
||||
// File system has file name length limit, we need to check if ext is too long, we don't add it to the filename
|
||||
if (ext.length > HX_MAX_FILE_EXTENSION_LENGTH) {
|
||||
ext = nil;
|
||||
}
|
||||
NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
|
||||
r[11], r[12], r[13], r[14], r[15]];
|
||||
if (addExt) {
|
||||
filename = [filename stringByAppendingFormat:@"%@", ext.length == 0 ? @"" : [NSString stringWithFormat:@".%@", ext]];
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
CG_INLINE UIAlertController * _Nullable hx_showAlert(UIViewController * _Nullable vc,
|
||||
NSString * _Nullable title,
|
||||
NSString * _Nullable message,
|
||||
NSString * _Nullable buttonTitle1,
|
||||
NSString * _Nullable buttonTitle2,
|
||||
dispatch_block_t _Nullable buttonTitle1Handler,
|
||||
dispatch_block_t _Nullable buttonTitle2Handler) {
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
|
||||
UIPopoverPresentationController *pop = [alertController popoverPresentationController];
|
||||
pop.permittedArrowDirections = UIPopoverArrowDirectionAny;
|
||||
pop.sourceView = vc.view;
|
||||
pop.sourceRect = vc.view.bounds;
|
||||
}
|
||||
|
||||
if (buttonTitle1) {
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:buttonTitle1
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (buttonTitle1Handler) buttonTitle1Handler();
|
||||
}];
|
||||
[alertController addAction:cancelAction];
|
||||
}
|
||||
if (buttonTitle2) {
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:buttonTitle2
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * _Nonnull action) {
|
||||
if (buttonTitle2Handler) buttonTitle2Handler();
|
||||
}];
|
||||
[alertController addAction:okAction];
|
||||
}
|
||||
[vc presentViewController:alertController animated:YES completion:nil];
|
||||
return alertController;
|
||||
}
|
||||
|
||||
|
||||
#define HXAlbumCameraRoll @"HXAlbumCameraRoll"
|
||||
#define HXAlbumPanoramas @"HXAlbumPanoramas"
|
||||
#define HXAlbumVideos @"HXAlbumVideos"
|
||||
#define HXAlbumFavorites @"HXAlbumFavorites"
|
||||
#define HXAlbumTimelapses @"HXAlbumTimelapses"
|
||||
#define HXAlbumRecentlyAdded @"HXAlbumRecentlyAdded"
|
||||
#define HXAlbumRecents @"HXAlbumRecents"
|
||||
#define HXAlbumBursts @"HXAlbumBursts"
|
||||
#define HXAlbumSlomoVideos @"HXAlbumSlomoVideos"
|
||||
#define HXAlbumSelfPortraits @"HXAlbumSelfPortraits"
|
||||
#define HXAlbumScreenshots @"HXAlbumScreenshots"
|
||||
#define HXAlbumDepthEffect @"HXAlbumDepthEffect"
|
||||
#define HXAlbumLivePhotos @"HXAlbumLivePhotos"
|
||||
#define HXAlbumAnimated @"HXAlbumAnimated"
|
||||
|
||||
#endif /* HXPhotoDefine_h */
|
87
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Controller/HX_PhotoEditViewController.h
generated
Normal file
87
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Controller/HX_PhotoEditViewController.h
generated
Normal file
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// HX_PhotoEditViewController.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/20.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import "HXPhotoEdit.h"
|
||||
#import "HXPhotoEditConfiguration.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HX_PhotoEditViewController, HXPhotoModel;
|
||||
|
||||
typedef void (^ HX_PhotoEditViewControllerDidFinishBlock)(HXPhotoEdit * _Nullable photoEdit, HXPhotoModel *photoModel, HX_PhotoEditViewController *viewController);
|
||||
typedef void (^ HX_PhotoEditViewControllerDidCancelBlock)(HX_PhotoEditViewController *viewController);
|
||||
|
||||
@protocol HX_PhotoEditViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
/// 照片编辑完成
|
||||
/// @param photoEditingVC 编辑控制器
|
||||
/// @param photoEdit 编辑完之后的数据,如果为nil。则未处理
|
||||
- (void)photoEditingController:(HX_PhotoEditViewController *)photoEditingVC
|
||||
didFinishPhotoEdit:(HXPhotoEdit * _Nullable)photoEdit
|
||||
photoModel:(HXPhotoModel *)photoModel;
|
||||
|
||||
/// 取消编辑
|
||||
/// @param photoEditingVC 编辑控制器
|
||||
- (void)photoEditingControllerDidCancel:(HX_PhotoEditViewController *)photoEditingVC;
|
||||
@end
|
||||
|
||||
@interface HX_PhotoEditViewController : UIViewController<UIViewControllerTransitioningDelegate>
|
||||
|
||||
@property (strong, nonatomic) HXPhotoModel *photoModel;
|
||||
|
||||
/// 编辑的数据
|
||||
/// 传入之前的编辑数据可以在原有基础上继续编辑
|
||||
@property (strong, nonatomic) HXPhotoEdit *photoEdit;
|
||||
/// 编辑原图
|
||||
@property (strong, nonatomic) UIImage *editImage;
|
||||
/// 编辑配置
|
||||
@property (strong, nonatomic) HXPhotoEditConfiguration *configuration;
|
||||
/// 只要裁剪
|
||||
@property (assign, nonatomic) BOOL onlyCliping;
|
||||
/// 是否保存到系统相册
|
||||
/// 当保存系统相册时photoEdit会为空
|
||||
@property (assign, nonatomic) BOOL saveAlbum;
|
||||
/// 保存到自定义相册的名称
|
||||
@property (copy, nonatomic) NSString *albumName;
|
||||
/// 照片定位信息
|
||||
@property (strong, nonatomic) CLLocation *location;
|
||||
|
||||
/// 是否支持旋转,优先级比 configuration.supportRotation 高
|
||||
@property (assign, nonatomic) BOOL supportRotation;
|
||||
|
||||
@property (weak, nonatomic) id<HX_PhotoEditViewControllerDelegate> delegate;
|
||||
|
||||
@property (copy, nonatomic) HX_PhotoEditViewControllerDidFinishBlock finishBlock;
|
||||
|
||||
@property (copy, nonatomic) HX_PhotoEditViewControllerDidCancelBlock cancelBlock;
|
||||
|
||||
- (instancetype)initWithConfiguration:(HXPhotoEditConfiguration *)configuration;
|
||||
- (instancetype)initWithPhotoEdit:(HXPhotoEdit *)photoEdit
|
||||
configuration:(HXPhotoEditConfiguration *)configuration;
|
||||
- (instancetype)initWithEditImage:(UIImage *)editImage
|
||||
configuration:(HXPhotoEditConfiguration *)configuration;
|
||||
|
||||
|
||||
#pragma mark - < other >
|
||||
@property (assign, nonatomic) BOOL imageRequestComplete;
|
||||
@property (assign, nonatomic) BOOL transitionCompletion;
|
||||
@property (assign, nonatomic) BOOL isCancel;
|
||||
- (CGRect)getImageFrame;
|
||||
- (void)showBgViews;
|
||||
- (void)completeTransition:(UIImage *)image;
|
||||
- (CGRect)getDismissImageFrame;
|
||||
- (UIImage *)getCurrentImage;
|
||||
- (void)hideImageView;
|
||||
- (void)hiddenTopBottomView;
|
||||
- (void)showTopBottomView;
|
||||
@property (assign, nonatomic) BOOL isAutoBack;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
1032
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Controller/HX_PhotoEditViewController.m
generated
Normal file
1032
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Controller/HX_PhotoEditViewController.m
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// HXPhotoEdit.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEdit : NSObject<NSCoding>
|
||||
/// 编辑封面
|
||||
@property (nonatomic, readonly) UIImage *editPosterImage;
|
||||
/// 编辑预览图片
|
||||
@property (nonatomic, readonly) UIImage *editPreviewImage;
|
||||
/// 编辑图片数据
|
||||
@property (nonatomic, readonly) NSData *editPreviewData;
|
||||
/// 编辑原图片本地临时地址
|
||||
@property (nonatomic, readonly) NSString *imagePath;
|
||||
/// 编辑数据
|
||||
@property (nonatomic, readonly) NSDictionary *editData;
|
||||
|
||||
- (instancetype)initWithEditImagePath:(NSString *)imagePath previewImage:(UIImage *)previewImage data:(NSDictionary *)data;
|
||||
|
||||
- (void)clearData;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// HXPhotoEdit.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEdit.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "HXMECancelBlock.h"
|
||||
|
||||
@interface HXPhotoEdit ()
|
||||
/// 编辑封面
|
||||
@property (nonatomic, strong) UIImage *editPosterImage;
|
||||
/// 编辑预览图片
|
||||
@property (nonatomic, strong) UIImage *editPreviewImage;
|
||||
/// 编辑图片数据
|
||||
@property (nonatomic, strong) NSData *editPreviewData;
|
||||
/// 编辑原图片临时地址
|
||||
@property (nonatomic, copy) NSString *imagePath;
|
||||
/// 编辑数据
|
||||
@property (nonatomic, copy) NSDictionary *editData;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEdit
|
||||
|
||||
- (instancetype)initWithEditImagePath:(NSString *)imagePath previewImage:(UIImage *)previewImage data:(NSDictionary *)data {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if (!previewImage) {
|
||||
NSData *data = [NSData dataWithContentsOfFile:imagePath];
|
||||
previewImage = [UIImage imageWithData:data];
|
||||
}
|
||||
[self setEditingImage:previewImage];
|
||||
_imagePath = imagePath;
|
||||
_editData = data;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - private
|
||||
- (void)clearData {
|
||||
self.editPreviewImage = nil;
|
||||
self.editPosterImage = nil;
|
||||
self.imagePath = nil;
|
||||
self.editData = nil;
|
||||
}
|
||||
- (void)setEditingImage:(UIImage *)editPreviewImage {
|
||||
_editPreviewImage = editPreviewImage;
|
||||
/** 设置编辑封面 */
|
||||
CGFloat width = MIN(80.f * 2.f, MIN(editPreviewImage.size.width, editPreviewImage.size.height));
|
||||
CGSize size = [UIImage hx_scaleImageSizeBySize:editPreviewImage.size targetSize:CGSizeMake(width, width) isBoth:YES];
|
||||
_editPosterImage = [editPreviewImage hx_scaleToFitSize:size];
|
||||
}
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super init]) {
|
||||
self.editPosterImage = [aDecoder decodeObjectForKey:@"editPosterImage"];
|
||||
self.editPreviewImage = [aDecoder decodeObjectForKey:@"editPreviewImage"];
|
||||
self.editPreviewData = [aDecoder decodeObjectForKey:@"editPreviewData"];
|
||||
self.imagePath = [aDecoder decodeObjectForKey:@"imagePath"];
|
||||
self.editData = [aDecoder decodeObjectForKey:@"editData"];
|
||||
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (NSData *)editPreviewData {
|
||||
if (!_editPreviewData) {
|
||||
_editPreviewData = HX_UIImageJPEGRepresentation(self.editPreviewImage);
|
||||
}
|
||||
return _editPreviewData;
|
||||
}
|
||||
- (void)encodeWithCoder:(NSCoder *)aCoder {
|
||||
[aCoder encodeObject:self.editPosterImage forKey:@"editPosterImage"];
|
||||
[aCoder encodeObject:self.editPreviewImage forKey:@"editPreviewImage"];
|
||||
[aCoder encodeObject:self.editPreviewData forKey:@"editPreviewData"];
|
||||
[aCoder encodeObject:self.imagePath forKey:@"imagePath"];
|
||||
[aCoder encodeObject:self.editData forKey:@"editData"];
|
||||
}
|
||||
@end
|
90
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/HXPhotoEditConfiguration.h
generated
Normal file
90
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/HXPhotoEditConfiguration.h
generated
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// HXPhotoEditConfiguration.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/6.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoEditChartletModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXPhotoEditAspectRatio) {
|
||||
HXPhotoEditAspectRatioType_None, // 不设置比例
|
||||
HXPhotoEditAspectRatioType_Original, // 原图比例
|
||||
HXPhotoEditAspectRatioType_1x1,
|
||||
HXPhotoEditAspectRatioType_3x2,
|
||||
HXPhotoEditAspectRatioType_4x3,
|
||||
HXPhotoEditAspectRatioType_5x3,
|
||||
HXPhotoEditAspectRatioType_15x9,
|
||||
HXPhotoEditAspectRatioType_16x9,
|
||||
HXPhotoEditAspectRatioType_16x10,
|
||||
HXPhotoEditAspectRatioType_Custom // 自定义比例
|
||||
};
|
||||
|
||||
@interface HXPhotoEditConfiguration : NSObject
|
||||
|
||||
/// 主题色
|
||||
@property (strong, nonatomic) UIColor *themeColor;
|
||||
|
||||
/// 只要裁剪功能
|
||||
@property (assign, nonatomic) BOOL onlyCliping;
|
||||
|
||||
/// 是否支持旋转
|
||||
/// 旋转之后会重置编辑的内容
|
||||
@property (assign, nonatomic) BOOL supportRotation;
|
||||
|
||||
/// 不可旋转时支持的方向
|
||||
@property (assign, nonatomic) UIInterfaceOrientationMask supportedInterfaceOrientations;
|
||||
|
||||
|
||||
#pragma mark - < 画笔相关 >
|
||||
/// 画笔颜色数组
|
||||
@property (copy, nonatomic) NSArray<UIColor *> *drawColors;
|
||||
|
||||
/// 默认选择的画笔颜色下标
|
||||
/// 与 drawColors 对应,默认 2
|
||||
@property (assign, nonatomic) NSInteger defaultDarwColorIndex;
|
||||
|
||||
/// 画笔默认宽度为最大宽度的50%
|
||||
/// 画笔最大宽度
|
||||
/// 默认 12.f
|
||||
@property (assign, nonatomic) CGFloat brushLineMaxWidth;
|
||||
|
||||
/// 画笔最小宽度
|
||||
/// 默认 2.f
|
||||
@property (assign, nonatomic) CGFloat brushLineMinWidth;
|
||||
|
||||
#pragma mark - < 贴图相关 >
|
||||
/// 贴图模型数组
|
||||
@property (copy, nonatomic) NSArray<HXPhotoEditChartletTitleModel *> *chartletModels;
|
||||
|
||||
/// 请求获取贴图模型
|
||||
/// block会在贴图列表弹出之后调用
|
||||
/// 优先级高于 chartletModels
|
||||
@property (copy, nonatomic) void (^ requestChartletModels)(void(^ chartletModels)(NSArray<HXPhotoEditChartletTitleModel *> *chartletModels));
|
||||
|
||||
#pragma mark - < 文字贴图相关 >
|
||||
/// 文字颜色数组
|
||||
@property (copy, nonatomic) NSArray<UIColor *> *textColors;
|
||||
/// 文字字体
|
||||
@property (strong, nonatomic) UIFont *textFont;
|
||||
/// 最大文本长度限制
|
||||
@property (assign, nonatomic) NSInteger maximumLimitTextLength;
|
||||
|
||||
#pragma mark - < 裁剪相关 >
|
||||
/// 固定裁剪比例
|
||||
@property (assign, nonatomic) HXPhotoEditAspectRatio aspectRatio;
|
||||
/// 自定义固定比例
|
||||
/// 设置自定义比例必须设置 aspectRatio = HXPhotoEditAspectRatioType_Custom,否则无效
|
||||
@property (assign, nonatomic) CGSize customAspectRatio;
|
||||
|
||||
/// 圆形裁剪框,只要裁剪功能 并且 固定裁剪比例为 HXPhotoEditAspectRatioType_1x1 时有效
|
||||
@property (assign, nonatomic) BOOL isRoundCliping;
|
||||
|
||||
@property (assign, nonatomic) CGSize clippingMinSize;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
75
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/HXPhotoEditConfiguration.m
generated
Normal file
75
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/HXPhotoEditConfiguration.m
generated
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// HXPhotoEditConfiguration.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/6.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditConfiguration.h"
|
||||
#import "UIColor+HXExtension.h"
|
||||
|
||||
@implementation HXPhotoEditConfiguration
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.maximumLimitTextLength = 0;
|
||||
self.supportRotation = YES;
|
||||
self.clippingMinSize = CGSizeMake(80, 80);
|
||||
self.supportedInterfaceOrientations = UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (CGFloat)brushLineMaxWidth {
|
||||
if (!_brushLineMaxWidth) {
|
||||
_brushLineMaxWidth = 12.f;
|
||||
}
|
||||
return _brushLineMaxWidth;
|
||||
}
|
||||
- (CGFloat)brushLineMinWidth {
|
||||
if (!_brushLineMinWidth) {
|
||||
_brushLineMinWidth = 3.f;
|
||||
}
|
||||
return _brushLineMinWidth;
|
||||
}
|
||||
- (UIColor *)themeColor {
|
||||
if (!_themeColor) {
|
||||
_themeColor = [UIColor hx_colorWithHexStr:@"#07C160"];
|
||||
}
|
||||
return _themeColor;
|
||||
}
|
||||
- (NSArray<UIColor *> *)drawColors {
|
||||
if (!_drawColors) {
|
||||
_drawColors = @[[UIColor hx_colorWithHexStr:@"#ffffff"], [UIColor hx_colorWithHexStr:@"#2B2B2B"], [UIColor hx_colorWithHexStr:@"#FA5150"], [UIColor hx_colorWithHexStr:@"#FEC200"], [UIColor hx_colorWithHexStr:@"#07C160"], [UIColor hx_colorWithHexStr:@"#10ADFF"], [UIColor hx_colorWithHexStr:@"#6467EF"]];
|
||||
self.defaultDarwColorIndex = 2;
|
||||
}
|
||||
return _drawColors;
|
||||
}
|
||||
- (NSArray<UIColor *> *)textColors {
|
||||
if (!_textColors) {
|
||||
_textColors = @[[UIColor hx_colorWithHexStr:@"#ffffff"], [UIColor hx_colorWithHexStr:@"#2B2B2B"], [UIColor hx_colorWithHexStr:@"#FA5150"], [UIColor hx_colorWithHexStr:@"#FEC200"], [UIColor hx_colorWithHexStr:@"#07C160"], [UIColor hx_colorWithHexStr:@"#10ADFF"], [UIColor hx_colorWithHexStr:@"#6467EF"]];
|
||||
}
|
||||
return _textColors;
|
||||
}
|
||||
- (UIFont *)textFont {
|
||||
if (!_textFont) {
|
||||
_textFont = [UIFont boldSystemFontOfSize:25];
|
||||
}
|
||||
return _textFont;
|
||||
}
|
||||
- (NSArray<HXPhotoEditChartletTitleModel *> *)chartletModels {
|
||||
if (!_chartletModels) {
|
||||
HXPhotoEditChartletTitleModel *netModel = [HXPhotoEditChartletTitleModel modelWithImageNamed:@"hx_sticker_cover"];
|
||||
|
||||
NSArray *imageNames = @[@"chongya", @"jintianfenkeai", @"keaibiaoq", @"saihong", @"xiaochuzhujiao", @"yuanqimanman", @"yuanqishaonv", @"zaizaijia", @"haoxinqing", @"housailei", @"kehaixing", @"wow", @"woxiangfazipai" ];
|
||||
NSMutableArray *models = [NSMutableArray array];
|
||||
for (NSString *imageNamed in imageNames) {
|
||||
HXPhotoEditChartletModel *subModel = [HXPhotoEditChartletModel modelWithImageNamed:[NSString stringWithFormat:@"hx_sticker_%@", imageNamed]];
|
||||
[models addObject:subModel];
|
||||
}
|
||||
netModel.models = models.copy;
|
||||
_chartletModels = @[netModel];
|
||||
}
|
||||
return _chartletModels;
|
||||
}
|
||||
@end
|
65
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXMECancelBlock.h
generated
Normal file
65
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXMECancelBlock.h
generated
Normal file
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// HXMECancelBlock.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void(^hx_me_dispatch_cancelable_block_t)(BOOL cancel);
|
||||
OBJC_EXTERN hx_me_dispatch_cancelable_block_t hx_dispatch_block_t(NSTimeInterval delay, void(^block)(void));
|
||||
OBJC_EXTERN void hx_me_dispatch_cancel(hx_me_dispatch_cancelable_block_t block);
|
||||
|
||||
OBJC_EXTERN double const HXMediaEditMinRate;
|
||||
OBJC_EXTERN double const HXMediaEditMaxRate;
|
||||
|
||||
OBJC_EXTERN CGRect HXMediaEditProundRect(CGRect rect);
|
||||
|
||||
|
||||
extern __attribute__((overloadable)) NSData * _Nullable HX_UIImagePNGRepresentation(UIImage * image);
|
||||
|
||||
extern __attribute__((overloadable)) NSData * _Nullable HX_UIImageJPEGRepresentation(UIImage * image);
|
||||
|
||||
extern __attribute__((overloadable)) NSData * _Nullable HX_UIImageRepresentation(UIImage * image, CFStringRef __nonnull type, NSError * _Nullable __autoreleasing * _Nullable error);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
图片解码
|
||||
|
||||
@param imageRef 图片
|
||||
@param size 图片大小(根据大小与contentMode缩放图片,传入CGSizeZero不处理大小)
|
||||
@param contentMode 内容布局(仅支持UIViewContentModeScaleAspectFill与UIViewContentModeScaleAspectFit,与size搭配)
|
||||
@param orientation 图片方向(imageRef的方向,会自动更正为up,如果传入up则不更正)
|
||||
@return 返回解码后的图片,如果失败,则返回NULL
|
||||
*/
|
||||
CG_EXTERN CGImageRef _Nullable HX_CGImageScaleDecodedFromCopy(CGImageRef imageRef, CGSize size, UIViewContentMode contentMode, UIImageOrientation orientation);
|
||||
|
||||
/**
|
||||
图片解码
|
||||
|
||||
@param imageRef 图片
|
||||
@return 返回解码后的图片,如果失败,则返回NULL
|
||||
*/
|
||||
CG_EXTERN CGImageRef _Nullable HX_CGImageDecodedFromCopy(CGImageRef imageRef);
|
||||
|
||||
/**
|
||||
图片解码
|
||||
|
||||
@param image 图片
|
||||
@return 返回解码后的图片,如果失败,则返回NULL
|
||||
*/
|
||||
CG_EXTERN CGImageRef _Nullable HX_CGImageDecodedCopy(UIImage *image);
|
||||
|
||||
/**
|
||||
图片解码
|
||||
|
||||
@param image 图片
|
||||
@return 返回解码后的图片,如果失败,则返回自身
|
||||
*/
|
||||
UIKIT_EXTERN UIImage * HX_UIImageDecodedCopy(UIImage *image);
|
||||
NS_ASSUME_NONNULL_END
|
274
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXMECancelBlock.m
generated
Normal file
274
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXMECancelBlock.m
generated
Normal file
|
@ -0,0 +1,274 @@
|
|||
//
|
||||
// HXMECancelBlock.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXMECancelBlock.h"
|
||||
#import <ImageIO/ImageIO.h>
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
|
||||
hx_me_dispatch_cancelable_block_t hx_dispatch_block_t(NSTimeInterval delay, void(^block)(void))
|
||||
{
|
||||
__block hx_me_dispatch_cancelable_block_t cancelBlock = nil;
|
||||
hx_me_dispatch_cancelable_block_t delayBlcok = ^(BOOL cancel){
|
||||
if (!cancel) {
|
||||
if ([NSThread isMainThread]) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
if (cancelBlock) {
|
||||
cancelBlock = nil;
|
||||
}
|
||||
};
|
||||
cancelBlock = delayBlcok;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (cancelBlock) {
|
||||
cancelBlock(NO);
|
||||
}
|
||||
});
|
||||
return delayBlcok;
|
||||
}
|
||||
|
||||
void hx_me_dispatch_cancel(hx_me_dispatch_cancelable_block_t block)
|
||||
{
|
||||
if (block) {
|
||||
block(YES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
double const HXMediaEditMinRate = 0.5f;
|
||||
double const HXMediaEditMaxRate = 2.f;
|
||||
|
||||
CGRect HXMediaEditProundRect(CGRect rect)
|
||||
{
|
||||
rect.origin.x = ((int)(rect.origin.x + 0.5) * 1.f);
|
||||
rect.origin.y = ((int)(rect.origin.y + 0.5) * 1.f);
|
||||
rect.size.width = ((int)(rect.size.width + 0.5) * 1.f);
|
||||
rect.size.height = ((int)(rect.size.height + 0.5) * 1.f);
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
__attribute__((overloadable)) NSData * HX_UIImagePNGRepresentation(UIImage *image) {
|
||||
return HX_UIImageRepresentation(image, kUTTypePNG, nil);
|
||||
}
|
||||
|
||||
__attribute__((overloadable)) NSData * HX_UIImageJPEGRepresentation(UIImage *image) {
|
||||
return HX_UIImageRepresentation(image, kUTTypeJPEG, nil);
|
||||
}
|
||||
|
||||
__attribute__((overloadable)) NSData * HX_UIImageRepresentation(UIImage *image, CFStringRef __nonnull type, NSError * __autoreleasing *error) {
|
||||
|
||||
if (!image) {
|
||||
return nil;
|
||||
}
|
||||
NSDictionary *userInfo = nil;
|
||||
{
|
||||
NSMutableData *mutableData = [NSMutableData data];
|
||||
|
||||
CGImageDestinationRef destination = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)mutableData, type, 1, NULL);
|
||||
|
||||
CGImageDestinationAddImage(destination, [image CGImage], NULL);
|
||||
|
||||
BOOL success = CGImageDestinationFinalize(destination);
|
||||
CFRelease(destination);
|
||||
|
||||
if (!success) {
|
||||
userInfo = @{
|
||||
NSLocalizedDescriptionKey: NSLocalizedString(@"Could not finalize image destination", nil)
|
||||
};
|
||||
|
||||
goto _error;
|
||||
}
|
||||
|
||||
return [NSData dataWithData:mutableData];
|
||||
}
|
||||
_error: {
|
||||
if (error) {
|
||||
*error = [[NSError alloc] initWithDomain:@"com.compuserve.image.error" code:-1 userInfo:userInfo];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
inline static CGAffineTransform HX_CGAffineTransformExchangeOrientation(UIImageOrientation imageOrientation, CGSize size)
|
||||
{
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
|
||||
switch (imageOrientation) {
|
||||
case UIImageOrientationDown:
|
||||
case UIImageOrientationDownMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, size.width, size.height);
|
||||
transform = CGAffineTransformRotate(transform, M_PI);
|
||||
break;
|
||||
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, size.width, 0);
|
||||
transform = CGAffineTransformRotate(transform, M_PI_2);
|
||||
break;
|
||||
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, 0, size.height);
|
||||
transform = CGAffineTransformRotate(transform, -M_PI_2);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (imageOrientation) {
|
||||
case UIImageOrientationUpMirrored:
|
||||
case UIImageOrientationDownMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, size.width, 0);
|
||||
transform = CGAffineTransformScale(transform, -1, 1);
|
||||
break;
|
||||
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRightMirrored:
|
||||
transform = CGAffineTransformTranslate(transform, size.height, 0);
|
||||
transform = CGAffineTransformScale(transform, -1, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return transform;
|
||||
}
|
||||
CGImageRef HX_CGImageScaleDecodedFromCopy(CGImageRef imageRef, CGSize size, UIViewContentMode contentMode, UIImageOrientation orientation)
|
||||
{
|
||||
CGImageRef newImage = NULL;
|
||||
@autoreleasepool {
|
||||
if (!imageRef) return NULL;
|
||||
size_t width = CGImageGetWidth(imageRef);
|
||||
size_t height = CGImageGetHeight(imageRef);
|
||||
if (width == 0 || height == 0) return NULL;
|
||||
|
||||
switch (orientation) {
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
// Grr...
|
||||
{
|
||||
CGFloat tmpWidth = width;
|
||||
width = height;
|
||||
height = tmpWidth;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (size.width > 0 && size.height > 0) {
|
||||
float verticalRadio = size.height*1.0/height;
|
||||
float horizontalRadio = size.width*1.0/width;
|
||||
|
||||
|
||||
float radio = 1;
|
||||
if (contentMode == UIViewContentModeScaleAspectFill) {
|
||||
if(verticalRadio > horizontalRadio)
|
||||
{
|
||||
radio = verticalRadio;
|
||||
}
|
||||
else
|
||||
{
|
||||
radio = horizontalRadio;
|
||||
}
|
||||
} else if (contentMode == UIViewContentModeScaleAspectFit) {
|
||||
if(verticalRadio < horizontalRadio)
|
||||
{
|
||||
radio = verticalRadio;
|
||||
}
|
||||
else
|
||||
{
|
||||
radio = horizontalRadio;
|
||||
}
|
||||
} else {
|
||||
if(verticalRadio>1 && horizontalRadio>1)
|
||||
{
|
||||
radio = verticalRadio > horizontalRadio ? horizontalRadio : verticalRadio;
|
||||
}
|
||||
else
|
||||
{
|
||||
radio = verticalRadio < horizontalRadio ? verticalRadio : horizontalRadio;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
width = roundf(width*radio);
|
||||
height = roundf(height*radio);
|
||||
}
|
||||
|
||||
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef) & kCGBitmapAlphaInfoMask;
|
||||
BOOL hasAlpha = NO;
|
||||
if (alphaInfo == kCGImageAlphaPremultipliedLast ||
|
||||
alphaInfo == kCGImageAlphaPremultipliedFirst ||
|
||||
alphaInfo == kCGImageAlphaLast ||
|
||||
alphaInfo == kCGImageAlphaFirst) {
|
||||
hasAlpha = YES;
|
||||
}
|
||||
|
||||
CGAffineTransform transform = HX_CGAffineTransformExchangeOrientation(orientation, CGSizeMake(width, height));
|
||||
// BGRA8888 (premultiplied) or BGRX8888
|
||||
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
|
||||
bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
|
||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, colorSpace, bitmapInfo);
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
if (!context) return NULL;
|
||||
CGContextConcatCTM(context, transform);
|
||||
switch (orientation) {
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationRightMirrored:
|
||||
// Grr...
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, height, width), imageRef); // decode
|
||||
break;
|
||||
default:
|
||||
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); // decode
|
||||
break;
|
||||
}
|
||||
newImage = CGBitmapContextCreateImage(context);
|
||||
CGContextRelease(context);
|
||||
}
|
||||
return newImage;
|
||||
}
|
||||
|
||||
CGImageRef HX_CGImageDecodedFromCopy(CGImageRef imageRef)
|
||||
{
|
||||
return HX_CGImageScaleDecodedFromCopy(imageRef, CGSizeZero, UIViewContentModeScaleAspectFit, UIImageOrientationUp);
|
||||
}
|
||||
|
||||
|
||||
CGImageRef HX_CGImageDecodedCopy(UIImage *image)
|
||||
{
|
||||
if (!image) return NULL;
|
||||
if (image.images.count > 1) {
|
||||
return NULL;
|
||||
}
|
||||
CGImageRef imageRef = image.CGImage;
|
||||
if (!imageRef) return NULL;
|
||||
CGImageRef newImageRef = HX_CGImageDecodedFromCopy(imageRef);
|
||||
|
||||
return newImageRef;
|
||||
}
|
||||
|
||||
UIImage *HX_UIImageDecodedCopy(UIImage *image)
|
||||
{
|
||||
CGImageRef imageRef = HX_CGImageDecodedCopy(image);
|
||||
if (!imageRef) return image;
|
||||
UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
|
||||
CGImageRelease(imageRef);
|
||||
|
||||
return newImage;
|
||||
}
|
47
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditChartletModel.h
generated
Normal file
47
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditChartletModel.h
generated
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// HXPhotoEditChartletModel.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/2.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXPhotoEditChartletModelType) {
|
||||
HXPhotoEditChartletModelType_Image, // UIImage
|
||||
HXPhotoEditChartletModelType_ImageNamed, // NSString
|
||||
HXPhotoEditChartletModelType_NetworkURL // NSURL
|
||||
};
|
||||
|
||||
@interface HXPhotoEditChartletModel : NSObject
|
||||
/// 当前资源类型
|
||||
@property (assign, nonatomic) HXPhotoEditChartletModelType type;
|
||||
/// 图片对象
|
||||
@property (strong, nonatomic) UIImage *image;
|
||||
/// 图片名
|
||||
@property (copy, nonatomic) NSString *imageNamed;
|
||||
/// 网络图片地址
|
||||
@property (strong, nonatomic) NSURL *networkURL;
|
||||
|
||||
+ (instancetype)modelWithImage:(UIImage *)image;
|
||||
+ (instancetype)modelWithImageNamed:(NSString *)imageNamed;
|
||||
+ (instancetype)modelWithNetworkNURL:(NSURL *)networkURL;
|
||||
|
||||
|
||||
// other
|
||||
@property (assign, nonatomic) BOOL loadCompletion;
|
||||
@end
|
||||
|
||||
|
||||
@interface HXPhotoEditChartletTitleModel : HXPhotoEditChartletModel
|
||||
// 贴图数组
|
||||
@property (copy, nonatomic) NSArray<HXPhotoEditChartletModel *> *models;
|
||||
|
||||
// other
|
||||
@property (assign, nonatomic) BOOL selected;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
35
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditChartletModel.m
generated
Normal file
35
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditChartletModel.m
generated
Normal file
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// HXPhotoEditChartletModel.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/2.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditChartletModel.h"
|
||||
|
||||
@implementation HXPhotoEditChartletModel
|
||||
|
||||
+ (instancetype)modelWithImage:(UIImage *)image {
|
||||
HXPhotoEditChartletModel *model = [[self alloc] init];
|
||||
model.type = HXPhotoEditChartletModelType_Image;
|
||||
model.image = image;
|
||||
return model;
|
||||
}
|
||||
+ (instancetype)modelWithImageNamed:(NSString *)imageNamed {
|
||||
HXPhotoEditChartletModel *model = [[self alloc] init];
|
||||
model.type = HXPhotoEditChartletModelType_ImageNamed;
|
||||
model.imageNamed = imageNamed;
|
||||
return model;
|
||||
}
|
||||
+ (instancetype)modelWithNetworkNURL:(NSURL *)networkURL {
|
||||
HXPhotoEditChartletModel *model = [[self alloc] init];
|
||||
model.type = HXPhotoEditChartletModelType_NetworkURL;
|
||||
model.networkURL = networkURL;
|
||||
return model;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditChartletTitleModel
|
||||
|
||||
@end
|
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditGraffitiColorModel.h
generated
Normal file
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditGraffitiColorModel.h
generated
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorModel.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/22.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditGraffitiColorModel : NSObject
|
||||
@property (strong, nonatomic) UIColor *color;
|
||||
@property (assign, nonatomic) BOOL selected;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
13
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditGraffitiColorModel.m
generated
Normal file
13
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/Model/HXPhotoEditGraffitiColorModel.m
generated
Normal file
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorModel.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/22.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGraffitiColorModel.h"
|
||||
|
||||
@implementation HXPhotoEditGraffitiColorModel
|
||||
|
||||
@end
|
100
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoClippingView.h
generated
Normal file
100
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoClippingView.h
generated
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// HXPhotoClippingView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXPhotoClippingViewMirrorType) {
|
||||
HXPhotoClippingViewMirrorType_None = 0, // 没有镜像翻转
|
||||
HXPhotoClippingViewMirrorType_Horizontal // 水平翻转
|
||||
};
|
||||
|
||||
@protocol HXPhotoClippingViewDelegate;
|
||||
@class HXPhotoEditImageView, HXPhotoEditConfiguration;
|
||||
@interface HXPhotoClippingView : UIScrollView
|
||||
@property (nonatomic, strong, readonly) HXPhotoEditImageView *imageView;
|
||||
@property (nonatomic, strong) UIImage *image;
|
||||
/// 获取除图片以外的编辑图层
|
||||
/// @param rect 大小
|
||||
/// @param rotate 旋转角度
|
||||
- (UIImage *)editOtherImagesInRect:(CGRect)rect rotate:(CGFloat)rotate;
|
||||
|
||||
@property (strong, nonatomic) HXPhotoEditConfiguration *configuration;
|
||||
|
||||
@property (nonatomic, weak) id<HXPhotoClippingViewDelegate> clippingDelegate;
|
||||
/** 首次缩放后需要记录最小缩放值 */
|
||||
@property (nonatomic, readonly) CGFloat first_minimumZoomScale;
|
||||
/** 与父视图中心偏差坐标 */
|
||||
@property (nonatomic, assign) CGPoint offsetSuperCenter;
|
||||
|
||||
/// 自定义固定比例
|
||||
@property (assign, nonatomic) CGSize customRatioSize;
|
||||
/** 是否重置中 */
|
||||
@property (nonatomic, readonly) BOOL isReseting;
|
||||
/** 是否旋转中 */
|
||||
@property (nonatomic, readonly) BOOL isRotating;
|
||||
/** 是否镜像翻转中 */
|
||||
@property (nonatomic, assign) BOOL isMirrorFlip;
|
||||
/** 是否水平翻转 */
|
||||
@property (assign, nonatomic) HXPhotoClippingViewMirrorType mirrorType;
|
||||
/** 旋转系数 */
|
||||
@property (assign, nonatomic, readonly) NSInteger angle;
|
||||
/** 是否缩放中 */
|
||||
//@property (nonatomic, readonly) BOOL isZooming;
|
||||
/** 是否可还原 */
|
||||
@property (nonatomic, readonly) BOOL canReset;
|
||||
/// 显示界面的缩放率
|
||||
@property (nonatomic, assign) CGFloat screenScale;
|
||||
/** 以某个位置作为可还原的参照物 */
|
||||
- (BOOL)canResetWithRect:(CGRect)trueFrame;
|
||||
|
||||
/** 可编辑范围 */
|
||||
@property (nonatomic, assign) CGRect editRect;
|
||||
/** 剪切范围 */
|
||||
@property (nonatomic, assign) CGRect cropRect;
|
||||
/** 手势开关,一般编辑模式下开启 默认NO */
|
||||
@property (nonatomic, assign) BOOL useGesture;
|
||||
|
||||
@property (nonatomic, assign) BOOL fixedAspectRatio;
|
||||
- (void)zoomToRect:(CGRect)rect;
|
||||
/** 缩小到指定坐标 */
|
||||
- (void)zoomOutToRect:(CGRect)toRect;
|
||||
/** 放大到指定坐标(必须大于当前坐标) */
|
||||
- (void)zoomInToRect:(CGRect)toRect;
|
||||
/** 旋转 */
|
||||
- (void)rotateClockwise:(BOOL)clockwise;
|
||||
/// 镜像翻转
|
||||
- (void)mirrorFlip;
|
||||
/** 还原 */
|
||||
- (void)reset;
|
||||
/** 还原到某个位置 */
|
||||
- (void)resetToRect:(CGRect)rect;
|
||||
/** 取消 */
|
||||
- (void)cancel;
|
||||
/** 数据 */
|
||||
@property (nonatomic, strong, nullable) NSDictionary *photoEditData;
|
||||
- (void)changeSubviewFrame;
|
||||
- (void)resetRotateAngle;
|
||||
- (void)clearCoverage;
|
||||
@end
|
||||
|
||||
@protocol HXPhotoClippingViewDelegate <NSObject>
|
||||
|
||||
/** 同步缩放视图(调用zoomOutToRect才会触发) */
|
||||
- (void (^ _Nullable)(CGRect))clippingViewWillBeginZooming:(HXPhotoClippingView *)clippingView;
|
||||
- (void)clippingViewDidZoom:(HXPhotoClippingView *)clippingView;
|
||||
- (void)clippingViewDidEndZooming:(HXPhotoClippingView *)clippingView;
|
||||
|
||||
/** 移动视图 */
|
||||
- (void)clippingViewWillBeginDragging:(HXPhotoClippingView *)clippingView;
|
||||
- (void)clippingViewDidEndDecelerating:(HXPhotoClippingView *)clippingView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
911
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoClippingView.m
generated
Normal file
911
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoClippingView.m
generated
Normal file
|
@ -0,0 +1,911 @@
|
|||
//
|
||||
// HXPhotoClippingView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoClippingView.h"
|
||||
#import "HXPhotoEditImageView.h"
|
||||
#import "HXPhotoEditStickerItemView.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "HXPhotoEditStickerItemContentView.h"
|
||||
#import "HXMECancelBlock.h"
|
||||
|
||||
#define HXDefaultMaximumZoomScale 5.f
|
||||
|
||||
NSString *const kHXClippingViewData = @"HXClippingViewData";
|
||||
NSString *const kHXStickerViewData_screenScale = @"HXStickerViewData_screenScale";
|
||||
NSString *const kHXClippingViewData_frame = @"HXClippingViewData_frame";
|
||||
NSString *const kHXClippingViewData_zoomScale = @"HXClippingViewData_zoomScale";
|
||||
NSString *const kHXClippingViewData_contentSize = @"HXClippingViewData_contentSize";
|
||||
NSString *const kHXClippingViewData_contentOffset = @"HXClippingViewData_contentOffset";
|
||||
NSString *const kHXClippingViewData_minimumZoomScale = @"HXClippingViewData_minimumZoomScale";
|
||||
NSString *const kHXClippingViewData_maximumZoomScale = @"HXClippingViewData_maximumZoomScale";
|
||||
NSString *const kHXClippingViewData_clipsToBounds = @"HXClippingViewData_clipsToBounds";
|
||||
NSString *const kHXClippingViewData_transform = @"HXClippingViewData_transform";
|
||||
NSString *const kHXClippingViewData_angle = @"HXClippingViewData_angle";
|
||||
NSString *const kHXClippingViewData_mirror = @"HXClippingViewData_mirror";
|
||||
|
||||
NSString *const kHXClippingViewData_first_minimumZoomScale = @"HXClippingViewData_first_minimumZoomScale";
|
||||
|
||||
NSString *const kHXClippingViewData_zoomingView = @"HXClippingViewData_zoomingView";
|
||||
|
||||
@interface HXPhotoClippingView ()<UIScrollViewDelegate>
|
||||
@property (nonatomic, strong) HXPhotoEditImageView *imageView;
|
||||
/** 开始的基础坐标 */
|
||||
@property (nonatomic, assign) CGRect normalRect;
|
||||
/** 处理完毕的基础坐标(因为可能会被父类在缩放时改变当前frame的问题,导致记录坐标不正确) */
|
||||
@property (nonatomic, assign) CGRect saveRect;
|
||||
/** 首次缩放后需要记录最小缩放值,否则在多次重复编辑后由于大小发生改变,导致最小缩放值不准确,还原不回实际大小 */
|
||||
@property (nonatomic, assign) CGFloat first_minimumZoomScale;
|
||||
/** 旋转系数 */
|
||||
@property (nonatomic, assign) NSInteger angle;
|
||||
/** 默认最大化缩放 */
|
||||
@property (nonatomic, assign) CGFloat defaultMaximumZoomScale;
|
||||
|
||||
/** 记录剪裁前的数据 */
|
||||
@property (nonatomic, assign) CGRect old_frame;
|
||||
@property (nonatomic, assign) NSInteger old_angle;
|
||||
@property (nonatomic, assign) BOOL old_mirrorHorizontally;
|
||||
@property (nonatomic, assign) HXPhotoClippingViewMirrorType old_mirrorType;
|
||||
@property (nonatomic, assign) CGFloat old_zoomScale;
|
||||
@property (nonatomic, assign) CGSize old_contentSize;
|
||||
@property (nonatomic, assign) CGPoint old_contentOffset;
|
||||
@property (nonatomic, assign) CGFloat old_minimumZoomScale;
|
||||
@property (nonatomic, assign) CGFloat old_maximumZoomScale;
|
||||
@property (nonatomic, assign) CGAffineTransform old_transform;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoClippingView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)setup {
|
||||
|
||||
self.scrollsToTop = NO;
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
|
||||
if (@available(iOS 11.0, *)){
|
||||
[self setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
|
||||
}
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
self.automaticallyAdjustsScrollIndicatorInsets = NO;
|
||||
}
|
||||
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.clipsToBounds = NO;
|
||||
self.delegate = self;
|
||||
self.minimumZoomScale = 1.0f;
|
||||
self.maximumZoomScale = HXDefaultMaximumZoomScale;
|
||||
self.defaultMaximumZoomScale = HXDefaultMaximumZoomScale;
|
||||
self.alwaysBounceHorizontal = YES;
|
||||
self.alwaysBounceVertical = YES;
|
||||
self.angle = 0;
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
self.offsetSuperCenter = CGPointZero;
|
||||
self.useGesture = NO;
|
||||
|
||||
self.imageView = [[HXPhotoEditImageView alloc] initWithFrame:self.bounds];
|
||||
HXWeakSelf
|
||||
self.imageView.moveCenter = ^BOOL(CGRect rect) {
|
||||
/** 判断缩放后贴图是否超出边界线 */
|
||||
CGRect newRect = [weakSelf.imageView convertRect:rect toView:weakSelf];
|
||||
CGRect clipTransRect = CGRectApplyAffineTransform(weakSelf.frame, weakSelf.transform);
|
||||
CGRect screenRect = (CGRect){weakSelf.contentOffset, clipTransRect.size};
|
||||
screenRect = CGRectInset(screenRect, 22, 22);
|
||||
return !CGRectIntersectsRect(screenRect, newRect);
|
||||
};
|
||||
self.imageView.getMinScale = ^CGFloat(CGSize size) {
|
||||
return MIN( 35 / size.width, 35 / size.height);
|
||||
};
|
||||
self.imageView.getMaxScale = ^CGFloat(CGSize size) {
|
||||
CGRect clipTransRect = CGRectApplyAffineTransform(weakSelf.frame, weakSelf.transform);
|
||||
CGRect screenRect = (CGRect){weakSelf.contentOffset, clipTransRect.size};
|
||||
CGFloat width = screenRect.size.width * weakSelf.screenScale;
|
||||
CGFloat height = screenRect.size.height * weakSelf.screenScale;
|
||||
if (width > HX_ScreenWidth) {
|
||||
width = HX_ScreenWidth;
|
||||
}
|
||||
if (height > HX_ScreenHeight) {
|
||||
height = HX_ScreenHeight;
|
||||
}
|
||||
CGFloat maxSize = MIN(size.width, size.height);
|
||||
return MAX( (width + 35) / maxSize, (height + 35) / maxSize);
|
||||
};
|
||||
[self addSubview:self.imageView];
|
||||
|
||||
/** 默认编辑范围 */
|
||||
_editRect = self.bounds;
|
||||
}
|
||||
- (void)changeSubviewFrame {
|
||||
_editRect = self.bounds;
|
||||
self.imageView.frame = self.bounds;
|
||||
[self.imageView changeSubviewFrame];
|
||||
}
|
||||
- (void)clearCoverage {
|
||||
[self.imageView clearCoverage];
|
||||
}
|
||||
- (void)setConfiguration:(HXPhotoEditConfiguration *)configuration {
|
||||
_configuration = configuration;
|
||||
self.imageView.configuration = configuration;
|
||||
}
|
||||
- (void)setScreenScale:(CGFloat)screenScale {
|
||||
_screenScale = screenScale;
|
||||
self.imageView.screenScale = screenScale;
|
||||
}
|
||||
- (void)setImage:(UIImage *)image {
|
||||
_image = image;
|
||||
[self setZoomScale:1.f];
|
||||
if (image) {
|
||||
if (self.frame.size.width < self.frame.size.height) {
|
||||
self.defaultMaximumZoomScale = [UIScreen mainScreen].bounds.size.width * HXDefaultMaximumZoomScale / self.frame.size.width;
|
||||
} else {
|
||||
self.defaultMaximumZoomScale = [UIScreen mainScreen].bounds.size.height * HXDefaultMaximumZoomScale / self.frame.size.height;
|
||||
}
|
||||
self.maximumZoomScale = self.defaultMaximumZoomScale;
|
||||
}
|
||||
self.normalRect = self.frame;
|
||||
self.saveRect = self.frame;
|
||||
self.contentSize = self.hx_size;
|
||||
self.imageView.frame = self.bounds;
|
||||
self.imageView.image = image;
|
||||
}
|
||||
|
||||
/** 获取除图片以外的编辑图层 */
|
||||
- (UIImage *)editOtherImagesInRect:(CGRect)rect rotate:(CGFloat)rotate {
|
||||
CGRect inRect = [self.superview convertRect:rect toView:self.imageView];
|
||||
/** 参数取整,否则可能会出现1像素偏差 */
|
||||
// inRect = HXMediaEditProundRect(inRect);
|
||||
|
||||
return [self.imageView editOtherImagesInRect:inRect rotate:rotate mirrorHorizontally:self.mirrorType == HXPhotoClippingViewMirrorType_Horizontal];
|
||||
}
|
||||
|
||||
- (void)setCropRect:(CGRect)cropRect {
|
||||
/** 记录当前数据 */
|
||||
self.old_transform = self.transform;
|
||||
self.old_angle = self.angle;
|
||||
self.old_mirrorType = self.mirrorType;
|
||||
self.old_frame = self.frame;
|
||||
self.old_zoomScale = self.zoomScale;
|
||||
self.old_contentSize = self.contentSize;
|
||||
self.old_contentOffset = self.contentOffset;
|
||||
self.old_minimumZoomScale = self.minimumZoomScale;
|
||||
self.old_maximumZoomScale = self.maximumZoomScale;
|
||||
|
||||
_cropRect = cropRect;
|
||||
|
||||
/** 当前UI位置未改变时,获取contentOffset与contentSize */
|
||||
/** 计算未改变前当前视图在contentSize的位置比例 */
|
||||
CGPoint contentOffset = self.contentOffset;
|
||||
CGFloat scaleX = MAX(contentOffset.x / (self.contentSize.width - self.hx_w), 0);
|
||||
CGFloat scaleY = MAX(contentOffset.y / (self.contentSize.height - self.hx_h), 0);
|
||||
|
||||
BOOL isHorizontal = NO;
|
||||
if (self.fixedAspectRatio) {
|
||||
if (self.angle % 180 != 0) {
|
||||
isHorizontal = YES;
|
||||
scaleX = MAX(contentOffset.x / (self.contentSize.width - self.hx_h), 0);
|
||||
scaleY = MAX(contentOffset.y / (self.contentSize.height - self.hx_w), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取contentOffset必须在设置contentSize之前,否则重置frame 或 contentSize后contentOffset会发送变化 */
|
||||
|
||||
CGRect oldFrame = self.frame;
|
||||
self.frame = cropRect;
|
||||
self.saveRect = self.frame;
|
||||
|
||||
CGFloat scale = self.zoomScale;
|
||||
/** 视图位移 */
|
||||
CGFloat scaleZX = CGRectGetWidth(cropRect)/(CGRectGetWidth(oldFrame)/scale);
|
||||
CGFloat scaleZY = CGRectGetHeight(cropRect)/(CGRectGetHeight(oldFrame)/scale);
|
||||
|
||||
CGFloat zoomScale = MIN(scaleZX, scaleZY);
|
||||
|
||||
[self resetMinimumZoomScale];
|
||||
self.maximumZoomScale = (zoomScale > self.defaultMaximumZoomScale ? zoomScale : self.defaultMaximumZoomScale);
|
||||
[self setZoomScale:zoomScale];
|
||||
|
||||
/** 记录首次最小缩放值 */
|
||||
if (self.first_minimumZoomScale == 0) {
|
||||
self.first_minimumZoomScale = self.minimumZoomScale;
|
||||
}
|
||||
|
||||
/** 重设contentSize */
|
||||
self.contentSize = self.imageView.hx_size;
|
||||
|
||||
if (isHorizontal) {
|
||||
/** 获取当前contentOffset的最大限度,根据之前的位置比例计算实际偏移坐标 */
|
||||
contentOffset.x = isnan(scaleX) ? contentOffset.x : (scaleX > 0 ? (HXRound(self.contentSize.width) - HXRound(self.hx_h)) * scaleX : contentOffset.x);
|
||||
contentOffset.y = isnan(scaleY) ? contentOffset.y : (scaleY > 0 ? (HXRound(self.contentSize.height) - HXRound(self.hx_w)) * scaleY : contentOffset.y);
|
||||
}else {
|
||||
/** 获取当前contentOffset的最大限度,根据之前的位置比例计算实际偏移坐标 */
|
||||
contentOffset.x = isnan(scaleX) ? contentOffset.x : (scaleX > 0 ? (HXRound(self.contentSize.width) - HXRound(self.hx_w)) * scaleX : contentOffset.x);
|
||||
contentOffset.y = isnan(scaleY) ? contentOffset.y : (scaleY > 0 ? (HXRound(self.contentSize.height) - HXRound(self.hx_h)) * scaleY : contentOffset.y);
|
||||
}
|
||||
/** 计算坐标偏移与保底值 */
|
||||
CGRect zoomViewRect = self.imageView.frame;
|
||||
CGRect selfRect = CGRectApplyAffineTransform(self.frame, self.transform);
|
||||
|
||||
CGFloat contentOffsetX = MIN(MAX(contentOffset.x, 0),zoomViewRect.size.width - selfRect.size.width);
|
||||
|
||||
CGFloat contentOfssetY = MIN(MAX(contentOffset.y, 0),zoomViewRect.size.height - selfRect.size.height);
|
||||
|
||||
self.contentOffset = CGPointMake(contentOffsetX, contentOfssetY);
|
||||
}
|
||||
|
||||
/** 取消 */
|
||||
- (void)cancel {
|
||||
if (!CGRectEqualToRect(self.old_frame, CGRectZero)) {
|
||||
self.transform = self.old_transform;
|
||||
self.angle = self.old_angle;
|
||||
self.mirrorType = self.old_mirrorType;
|
||||
self.frame = self.old_frame;
|
||||
self.saveRect = self.frame;
|
||||
self.minimumZoomScale = self.old_minimumZoomScale;
|
||||
self.maximumZoomScale = self.old_maximumZoomScale;
|
||||
self.zoomScale = self.old_zoomScale;
|
||||
self.contentSize = self.old_contentSize;
|
||||
self.contentOffset = self.old_contentOffset;
|
||||
}
|
||||
}
|
||||
- (void)resetRotateAngle {
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
self.angle = 0;
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
}
|
||||
- (void)reset {
|
||||
[self resetToRect:CGRectZero];
|
||||
}
|
||||
|
||||
- (void)resetToRect:(CGRect)rect {
|
||||
if (!_isReseting) {
|
||||
_isReseting = YES;
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
if (CGRectEqualToRect(rect, CGRectZero)) {
|
||||
[UIView animateWithDuration:0.25
|
||||
delay:0.0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
self.angle = 0;
|
||||
self.minimumZoomScale = self.first_minimumZoomScale;
|
||||
[self setZoomScale:self.minimumZoomScale];
|
||||
self.frame = (CGRect){CGPointZero, self.imageView.hx_size};
|
||||
self.center = CGPointMake(self.superview.center.x-self.offsetSuperCenter.x/2, self.superview.center.y-self.offsetSuperCenter.y/2);
|
||||
self.saveRect = self.frame;
|
||||
/** 重设contentSize */
|
||||
self.contentSize = self.imageView.hx_size;
|
||||
/** 重置contentOffset */
|
||||
self.contentOffset = CGPointZero;
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginZooming:)]) {
|
||||
void (^block)(CGRect) = [self.clippingDelegate clippingViewWillBeginZooming:self];
|
||||
if (block) block(self.frame);
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndZooming:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndZooming:self];
|
||||
}
|
||||
self->_isReseting = NO;
|
||||
}];
|
||||
} else {
|
||||
[UIView animateWithDuration:0.25
|
||||
delay:0.0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
self.angle = 0;
|
||||
self.minimumZoomScale = self.first_minimumZoomScale;
|
||||
[self setZoomScale:self.minimumZoomScale];
|
||||
self.frame = (CGRect){CGPointZero, self.imageView.hx_size};
|
||||
self.center = CGPointMake(self.superview.center.x-self.offsetSuperCenter.x/2, self.superview.center.y-self.offsetSuperCenter.y/2);
|
||||
/** 重设contentSize */
|
||||
self.contentSize = self.imageView.hx_size;
|
||||
/** 重置contentOffset */
|
||||
self.contentOffset = CGPointZero;
|
||||
[self zoomInToRect:rect];
|
||||
[self zoomOutToRect:rect completion:^{
|
||||
self->_isReseting = NO;
|
||||
}];
|
||||
} completion:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)canReset {
|
||||
CGRect superViewRect = self.superview.bounds;
|
||||
CGFloat x = (HXRoundDecade(CGRectGetWidth(superViewRect)) - HXRoundDecade(CGRectGetWidth(self.imageView.frame))) / 2 - HXRoundDecade(self.offsetSuperCenter.x) / 2;
|
||||
CGFloat y = (HXRoundDecade(CGRectGetHeight(superViewRect)) - HXRoundDecade(CGRectGetHeight(self.imageView.frame))) / 2 - HXRoundDecade(self.offsetSuperCenter.y) / 2;
|
||||
CGRect trueFrame = CGRectMake(x ,y , HXRoundDecade(CGRectGetWidth(self.imageView.frame))
|
||||
, HXRoundDecade(CGRectGetHeight(self.imageView.frame)));
|
||||
return [self canResetWithRect:trueFrame];
|
||||
}
|
||||
|
||||
- (BOOL)canResetWithRect:(CGRect)trueFrame {
|
||||
BOOL canReset = !(CGAffineTransformIsIdentity(self.transform)
|
||||
&& HXRound(self.zoomScale) == HXRound(self.minimumZoomScale)
|
||||
&& [self verifyRect:trueFrame]);
|
||||
if (self.fixedAspectRatio && !canReset) {
|
||||
if (fabs((fabs(HXRoundHundreds(self.contentSize.width) - HXRoundHundreds(self.hx_w)) / 2 - HXRoundHundreds(self.contentOffset.x))) >= 0.999) {
|
||||
canReset = YES;
|
||||
}else if (fabs((fabs(HXRoundHundreds(self.contentSize.height) - HXRoundHundreds(self.hx_h)) / 2 - HXRoundHundreds(self.contentOffset.y))) >= 0.999) {
|
||||
canReset = YES;
|
||||
}
|
||||
}
|
||||
return canReset;
|
||||
}
|
||||
|
||||
- (CGRect)cappedCropRectInImageRectWithCropRect:(CGRect)cropRect {
|
||||
CGRect rect = [self convertRect:self.imageView.frame toView:self.superview];
|
||||
if (CGRectGetMinX(cropRect) < CGRectGetMinX(rect)) {
|
||||
cropRect.origin.x = CGRectGetMinX(rect);
|
||||
}
|
||||
if (CGRectGetMinY(cropRect) < CGRectGetMinY(rect)) {
|
||||
cropRect.origin.y = CGRectGetMinY(rect);
|
||||
}
|
||||
if (CGRectGetMaxX(cropRect) > CGRectGetMaxX(rect)) {
|
||||
cropRect.size.width = CGRectGetMaxX(rect) - CGRectGetMinX(cropRect);
|
||||
}
|
||||
if (CGRectGetMaxY(cropRect) > CGRectGetMaxY(rect)) {
|
||||
cropRect.size.height = CGRectGetMaxY(rect) - CGRectGetMinY(cropRect);
|
||||
}
|
||||
|
||||
return cropRect;
|
||||
}
|
||||
|
||||
#pragma mark 缩小到指定坐标
|
||||
- (void)zoomOutToRect:(CGRect)toRect {
|
||||
[self zoomOutToRect:toRect completion:nil];
|
||||
}
|
||||
- (void)zoomOutToRect:(CGRect)toRect completion:(void (^)(void))completion {
|
||||
/** 屏幕在滚动时 不触发该功能 */
|
||||
if (self.dragging || self.decelerating) {
|
||||
return;
|
||||
}
|
||||
|
||||
CGRect rect = [self cappedCropRectInImageRectWithCropRect:toRect];
|
||||
|
||||
CGFloat width = CGRectGetWidth(rect);
|
||||
CGFloat height = CGRectGetHeight(rect);
|
||||
|
||||
/** 新增了放大功能:这里需要重新计算最小缩放系数 */
|
||||
[self resetMinimumZoomScale];
|
||||
[self setZoomScale:self.zoomScale];
|
||||
|
||||
CGFloat scale = MIN(CGRectGetWidth(self.editRect) / width, CGRectGetHeight(self.editRect) / height);
|
||||
|
||||
/** 指定位置=当前显示位置 或者 当前缩放已达到最大,并且仍然发生缩放的情况; 免去以下计算,以当前显示大小为准 */
|
||||
if (CGRectEqualToRect(HXRoundFrame(self.frame), HXRoundFrame(rect)) || (HXRound(self.zoomScale) == HXRound(self.maximumZoomScale) && HXRound(scale) > 1.f)) {
|
||||
|
||||
[UIView animateWithDuration:0.25
|
||||
delay:0.0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
/** 只需要移动到中点 */
|
||||
self.center = CGPointMake(self.superview.center.x-self.offsetSuperCenter.x/2, self.superview.center.y-self.offsetSuperCenter.y/2);
|
||||
self.saveRect = self.frame;
|
||||
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginZooming:)]) {
|
||||
void (^block)(CGRect) = [self.clippingDelegate clippingViewWillBeginZooming:self];
|
||||
if (block) block(self.frame);
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndZooming:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndZooming:self];
|
||||
}
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
CGFloat scaledWidth = width * scale;
|
||||
CGFloat scaledHeight = height * scale;
|
||||
/** 计算缩放比例 */
|
||||
CGFloat zoomScale = MIN(self.zoomScale * scale, self.maximumZoomScale);
|
||||
/** 特殊图片计算 比例100:1 或 1:100 的情况 */
|
||||
CGRect zoomViewRect = CGRectApplyAffineTransform(self.imageView.frame, self.transform);
|
||||
scaledWidth = MIN(scaledWidth, CGRectGetWidth(zoomViewRect) * (zoomScale / self.minimumZoomScale));
|
||||
scaledHeight = MIN(scaledHeight, CGRectGetHeight(zoomViewRect) * (zoomScale / self.minimumZoomScale));
|
||||
|
||||
/** 计算实际显示坐标 */
|
||||
CGRect cropRect = CGRectMake((CGRectGetWidth(self.superview.bounds) - scaledWidth) / 2 - self.offsetSuperCenter.x/2,
|
||||
(CGRectGetHeight(self.superview.bounds) - scaledHeight) / 2 - self.offsetSuperCenter.y/2,
|
||||
scaledWidth,
|
||||
scaledHeight);
|
||||
|
||||
/** 计算偏移值 */
|
||||
__block CGPoint contentOffset = self.contentOffset;
|
||||
if (!([self verifyRect:cropRect] && zoomScale == self.zoomScale)) { /** 实际位置与当前位置一致不做位移处理 && 缩放系数一致 */
|
||||
/** 获取相对坐标 */
|
||||
CGRect zoomRect = [self.superview convertRect:rect toView:self];
|
||||
contentOffset.x = zoomRect.origin.x * zoomScale / self.zoomScale;
|
||||
contentOffset.y = zoomRect.origin.y * zoomScale / self.zoomScale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[UIView animateWithDuration:0.25
|
||||
delay:0.0
|
||||
options:UIViewAnimationOptionBeginFromCurrentState
|
||||
animations:^{
|
||||
self.frame = cropRect;
|
||||
self.saveRect = self.frame;
|
||||
[self setZoomScale:zoomScale];
|
||||
/** 重新调整contentSize */
|
||||
self.contentSize = self.imageView.hx_size;
|
||||
[self setContentOffset:contentOffset];
|
||||
|
||||
/** 设置完实际大小后再次计算最小缩放系数 */
|
||||
[self resetMinimumZoomScale];
|
||||
[self setZoomScale:self.zoomScale];
|
||||
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginZooming:)]) {
|
||||
void (^block)(CGRect) = [self.clippingDelegate clippingViewWillBeginZooming:self];
|
||||
if (block) block(self.frame);
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndZooming:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndZooming:self];
|
||||
}
|
||||
if (completion) {
|
||||
completion();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)zoomToRect:(CGRect)rect {
|
||||
self.frame = rect;
|
||||
[self resetMinimumZoomScale];
|
||||
|
||||
[self setZoomScale:self.zoomScale];
|
||||
}
|
||||
|
||||
#pragma mark 放大到指定坐标(必须大于当前坐标)
|
||||
- (void)zoomInToRect:(CGRect)toRect {
|
||||
/** 屏幕在滚动时 不触发该功能 */
|
||||
if (self.dragging || self.decelerating) {
|
||||
return;
|
||||
}
|
||||
CGRect zoomingRect = [self convertRect:self.imageView.frame toView:self.superview];
|
||||
/** 判断坐标是否超出当前坐标范围 */
|
||||
if ((CGRectGetMinX(toRect) + FLT_EPSILON) < CGRectGetMinX(zoomingRect)
|
||||
|| (CGRectGetMinY(toRect) + FLT_EPSILON) < CGRectGetMinY(zoomingRect)
|
||||
|| (CGRectGetMaxX(toRect) - FLT_EPSILON) > (CGRectGetMaxX(zoomingRect)+0.5) /** 兼容计算过程的误差0.几的情况 */
|
||||
|| (CGRectGetMaxY(toRect) - FLT_EPSILON) > (CGRectGetMaxY(zoomingRect)+0.5)
|
||||
) {
|
||||
|
||||
/** 取最大值缩放 */
|
||||
CGRect myFrame = self.frame;
|
||||
myFrame.origin.x = MIN(myFrame.origin.x, toRect.origin.x);
|
||||
myFrame.origin.y = MIN(myFrame.origin.y, toRect.origin.y);
|
||||
myFrame.size.width = MAX(myFrame.size.width, toRect.size.width);
|
||||
myFrame.size.height = MAX(myFrame.size.height, toRect.size.height);
|
||||
self.frame = myFrame;
|
||||
|
||||
[self resetMinimumZoomScale];
|
||||
[self setZoomScale:self.zoomScale];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark 旋转
|
||||
- (void)rotateClockwise:(BOOL)clockwise {
|
||||
/** 屏幕在滚动时 不触发该功能 */
|
||||
if (self.dragging || self.decelerating) {
|
||||
return;
|
||||
}
|
||||
if (!_isRotating) {
|
||||
_isRotating = YES;
|
||||
if (self.mirrorType == HXPhotoClippingViewMirrorType_Horizontal) {
|
||||
clockwise = YES;
|
||||
}
|
||||
NSInteger newAngle = self.angle;
|
||||
newAngle = clockwise ? newAngle + 90 : newAngle - 90;
|
||||
if (newAngle <= -360 || newAngle >= 360)
|
||||
newAngle = 0;
|
||||
|
||||
_angle = newAngle;
|
||||
|
||||
[UIView animateWithDuration:0.35f delay:0.0f usingSpringWithDamping:1.0f initialSpringVelocity:0.8f options:UIViewAnimationOptionBeginFromCurrentState animations:^{
|
||||
|
||||
[self transformRotate:self.angle];
|
||||
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginZooming:)]) {
|
||||
void (^block)(CGRect) = [self.clippingDelegate clippingViewWillBeginZooming:self];
|
||||
if (block) block(self.frame);
|
||||
}
|
||||
|
||||
} completion:^(BOOL complete) {
|
||||
self->_isRotating = NO;
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndZooming:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndZooming:self];
|
||||
}
|
||||
}];
|
||||
|
||||
}
|
||||
}
|
||||
/// 镜像翻转
|
||||
- (void)mirrorFlip {
|
||||
if (self.dragging || self.decelerating) {
|
||||
return;
|
||||
}
|
||||
if (!self.isMirrorFlip) {
|
||||
self.isMirrorFlip = YES;
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginZooming:)]) {
|
||||
[self.clippingDelegate clippingViewWillBeginZooming:self];
|
||||
}
|
||||
CGFloat angleInRadians = 0.0f;
|
||||
switch (self.angle) {
|
||||
case 90: angleInRadians = M_PI_2; break;
|
||||
case -90: angleInRadians = -M_PI_2; break;
|
||||
case 180: angleInRadians = M_PI; break;
|
||||
case -180: angleInRadians = -M_PI; break;
|
||||
case 270: angleInRadians = (M_PI + M_PI_2); break;
|
||||
case -270: angleInRadians = -(M_PI + M_PI_2); break;
|
||||
default: break;
|
||||
}
|
||||
CGAffineTransform rotateTransform = CGAffineTransformRotate(CGAffineTransformIdentity ,angleInRadians);
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
if (self.mirrorType == HXPhotoClippingViewMirrorType_None) {
|
||||
// 没有镜像翻转
|
||||
if (self.angle == 0) {
|
||||
// 上
|
||||
self.transform = CGAffineTransformScale(rotateTransform ,-1.0, 1.0);
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_Horizontal;
|
||||
}else if (self.angle == -90 || self.angle == 90) {
|
||||
// 左
|
||||
self.transform = CGAffineTransformScale(rotateTransform ,1.0, -1.0);
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_Horizontal;
|
||||
self.angle = 270;
|
||||
}else if (self.angle == -180 || self.angle == 180) {
|
||||
// 下
|
||||
self.transform = CGAffineTransformScale(rotateTransform ,-1.0, 1.0);
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_Horizontal;
|
||||
}else if (self.angle == -270 || self.angle == 270) {
|
||||
// 右
|
||||
self.transform = CGAffineTransformScale(CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI_2), -1, 1);
|
||||
self.angle = 90;
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_Horizontal;
|
||||
}
|
||||
}else if (self.mirrorType == HXPhotoClippingViewMirrorType_Horizontal){
|
||||
// 水平翻转了
|
||||
if (self.angle == 0) {
|
||||
// 上
|
||||
self.transform = CGAffineTransformScale(rotateTransform ,1.0, 1.0);
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
}else if (self.angle == -90 || self.angle == 90) {
|
||||
// 左
|
||||
CGAffineTransform transfrom = CGAffineTransformRotate(CGAffineTransformIdentity, -(M_PI + M_PI_2));
|
||||
self.transform = transfrom;
|
||||
self.angle = -270;
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
}else if (self.angle == -180 || self.angle == 180) {
|
||||
// 下
|
||||
self.transform = CGAffineTransformScale(rotateTransform ,1.0, 1.0);
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
}else if (self.angle == -270 || self.angle == 270) {
|
||||
// 右
|
||||
self.transform = CGAffineTransformScale(CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI_2) , 1, 1);
|
||||
self.angle = -90;
|
||||
self.mirrorType = HXPhotoClippingViewMirrorType_None;
|
||||
}
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
self.isMirrorFlip = NO;
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndZooming:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndZooming:self];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
- (CGAffineTransform)getCurrentMirrorFlip {
|
||||
if (self.mirrorType == HXPhotoClippingViewMirrorType_Horizontal){
|
||||
// 水平翻转了
|
||||
return CGAffineTransformScale(CGAffineTransformIdentity ,-1.0, 1.0);
|
||||
}
|
||||
return CGAffineTransformIdentity;
|
||||
}
|
||||
#pragma mark - UIScrollViewDelegate
|
||||
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginDragging:)]) {
|
||||
[self.clippingDelegate clippingViewWillBeginDragging:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
|
||||
if (!decelerate) {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndDecelerating:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndDecelerating:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndDecelerating:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndDecelerating:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
|
||||
return self.imageView;
|
||||
}
|
||||
|
||||
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewWillBeginZooming:)]) {
|
||||
void (^block)(CGRect) = [self.clippingDelegate clippingViewWillBeginZooming:self];
|
||||
block(self.frame);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
|
||||
self.contentInset = UIEdgeInsetsZero;
|
||||
self.scrollIndicatorInsets = UIEdgeInsetsZero;
|
||||
if (scrollView.isZooming || scrollView.isZoomBouncing) {
|
||||
/** 代码调整zoom,会导致居中计算错误,必须2指控制UI自动缩放时才调用 */
|
||||
[self refreshImageZoomViewCenter];
|
||||
}
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidZoom:)]) {
|
||||
[self.clippingDelegate clippingViewDidZoom:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(nullable UIView *)view atScale:(CGFloat)scale {
|
||||
if ([self.clippingDelegate respondsToSelector:@selector(clippingViewDidEndZooming:)]) {
|
||||
[self.clippingDelegate clippingViewDidEndZooming:self];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
- (void)refreshImageZoomViewCenter {
|
||||
CGRect rect = CGRectApplyAffineTransform(self.frame, self.transform);
|
||||
|
||||
CGFloat offsetX = (rect.size.width > self.contentSize.width) ? ((rect.size.width - self.contentSize.width) * 0.5) : 0.0;
|
||||
CGFloat offsetY = (rect.size.height > self.contentSize.height) ? ((rect.size.height - self.contentSize.height) * 0.5) : 0.0;
|
||||
self.imageView.center = CGPointMake(self.contentSize.width * 0.5 + offsetX, self.contentSize.height * 0.5 + offsetY);
|
||||
}
|
||||
|
||||
#pragma mark - 验证当前大小是否被修改
|
||||
- (BOOL)verifyRect:(CGRect)r_rect {
|
||||
/** 计算缩放率 */
|
||||
CGRect rect = CGRectApplyAffineTransform(r_rect, self.transform);
|
||||
/** 模糊匹配 */
|
||||
BOOL isEqual = CGRectEqualToRect(rect, self.frame);
|
||||
|
||||
if (isEqual == NO) {
|
||||
/** 精准验证 */
|
||||
// 允许0.5f以内的误差
|
||||
if (fabs(self.hx_x - rect.origin.x) <= 0.5f) {
|
||||
rect = CGRectMake(self.frame.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
||||
}
|
||||
if (fabs(self.hx_y - rect.origin.y) <= 0.5f) {
|
||||
rect = CGRectMake(rect.origin.x, self.frame.origin.y, rect.size.width, rect.size.height);
|
||||
}
|
||||
if (fabs(self.hx_w - rect.size.width) <= 0.5f) {
|
||||
rect = CGRectMake(rect.origin.x, rect.origin.y, self.frame.size.width, rect.size.height);
|
||||
}
|
||||
if (fabs(self.hx_h - rect.size.height) <= 0.5f) {
|
||||
rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, self.frame.size.height);
|
||||
}
|
||||
|
||||
BOOL x = HXRoundDecade(CGRectGetMinX(rect)) == HXRoundDecade(CGRectGetMinX(self.frame));
|
||||
|
||||
BOOL y = HXRoundDecade(CGRectGetMinY(rect)) == HXRoundDecade(CGRectGetMinY(self.frame));
|
||||
BOOL w = HXRoundDecade(CGRectGetWidth(rect)) == HXRoundDecade(CGRectGetWidth(self.frame));
|
||||
BOOL h = HXRoundDecade(CGRectGetHeight(rect)) == HXRoundDecade(CGRectGetHeight(self.frame));
|
||||
isEqual = x && y && w && h;
|
||||
}
|
||||
return isEqual;
|
||||
}
|
||||
|
||||
#pragma mark - 旋转视图
|
||||
- (void)transformRotate:(NSInteger)angle {
|
||||
//Convert the new angle to radians
|
||||
CGFloat angleInRadians = 0.0f;
|
||||
switch (angle) {
|
||||
case 90: angleInRadians = M_PI_2; break;
|
||||
case -90: angleInRadians = -M_PI_2; break;
|
||||
case 180: angleInRadians = M_PI; break;
|
||||
case -180: angleInRadians = -M_PI; break;
|
||||
case 270: angleInRadians = (M_PI + M_PI_2); break;
|
||||
case -270: angleInRadians = -(M_PI + M_PI_2); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
|
||||
/** 不用重置变形,使用center与bounds来计算原来的frame */
|
||||
CGPoint center = self.center;
|
||||
CGRect bounds = self.bounds;
|
||||
CGRect oldRect = CGRectMake(center.x-0.5*bounds.size.width, center.y-0.5*bounds.size.height, bounds.size.width, bounds.size.height);
|
||||
CGFloat width = CGRectGetWidth(oldRect);
|
||||
CGFloat height = CGRectGetHeight(oldRect);
|
||||
if (self.fixedAspectRatio) {
|
||||
if (angle%180 == 0) { /** 旋转基数时需要互换宽高 */
|
||||
CGFloat tempWidth = width;
|
||||
width = height;
|
||||
height = tempWidth;
|
||||
}
|
||||
}else {
|
||||
if (angle%180 != 0) { /** 旋转基数时需要互换宽高 */
|
||||
CGFloat tempWidth = width;
|
||||
width = height;
|
||||
height = tempWidth;
|
||||
}
|
||||
}
|
||||
/** 改变变形之前获取偏移量,变形后再计算偏移量比例移动 */
|
||||
CGPoint contentOffset = self.contentOffset;
|
||||
CGFloat marginXScale = 0.5;
|
||||
if (self.fixedAspectRatio) {
|
||||
CGFloat w = ((angle%180 == 0) ? self.hx_h : self.hx_w);
|
||||
if (self.contentSize.width - w > 0) {
|
||||
marginXScale = contentOffset.x / (self.contentSize.width - w);
|
||||
if (marginXScale == 0) {
|
||||
marginXScale = 0.5;
|
||||
}
|
||||
marginXScale = HXRound(marginXScale);
|
||||
}
|
||||
}
|
||||
CGFloat marginYScale = 0.5f;
|
||||
if (self.fixedAspectRatio) {
|
||||
CGFloat h = ((angle%180 == 0) ? self.hx_w : self.hx_h);
|
||||
if (self.contentSize.height - h > 0) {
|
||||
marginYScale = contentOffset.y / (self.contentSize.height - h);
|
||||
if (marginYScale == 0) {
|
||||
marginYScale = 0.5;
|
||||
}
|
||||
marginYScale = HXRound(marginYScale);
|
||||
}
|
||||
}
|
||||
|
||||
/** 调整变形 */
|
||||
CGAffineTransform transform = CGAffineTransformRotate([self getCurrentMirrorFlip], angleInRadians);
|
||||
self.transform = transform;
|
||||
|
||||
/** 计算变形后的坐标拉伸到编辑范围 */
|
||||
CGRect frame = HXRoundFrameHundreds(AVMakeRectWithAspectRatioInsideRect(CGSizeMake(width, height), self.editRect));
|
||||
self.frame = frame;
|
||||
/** 重置最小缩放比例 */
|
||||
[self resetMinimumZoomScale];
|
||||
/** 计算缩放比例 */
|
||||
CGFloat scale = MIN(CGRectGetWidth(self.frame) / width, CGRectGetHeight(self.frame) / height);
|
||||
/** 转移缩放目标 */
|
||||
self.zoomScale *= scale;
|
||||
/** 修正旋转后到偏移量 */
|
||||
if (self.fixedAspectRatio) {
|
||||
if (angle%180 != 0) { /** 旋转基数时需要互换宽高 */
|
||||
contentOffset.x = fabs(self.contentSize.width - self.hx_h) * marginXScale;
|
||||
contentOffset.y = fabs(self.contentSize.height - self.hx_w) * marginYScale;
|
||||
}else {
|
||||
contentOffset.x = fabs(self.contentSize.width - self.hx_w) * marginXScale;
|
||||
contentOffset.y = fabs(self.contentSize.height - self.hx_h) * marginYScale;
|
||||
}
|
||||
}else {
|
||||
contentOffset.x *= scale;
|
||||
contentOffset.y *= scale;
|
||||
}
|
||||
self.contentOffset = contentOffset;
|
||||
}
|
||||
|
||||
#pragma mark - 重置最小缩放比例
|
||||
- (void)resetMinimumZoomScale {
|
||||
/** 重置最小缩放比例 */
|
||||
CGRect rotateNormalRect = CGRectApplyAffineTransform(self.normalRect, self.transform);
|
||||
if (CGSizeEqualToSize(rotateNormalRect.size, CGSizeZero)) {
|
||||
/** size为0时候不能继续,否则minimumZoomScale=+Inf,会无法缩放 */
|
||||
return;
|
||||
}
|
||||
CGFloat minimumZoomScale = MAX(CGRectGetWidth(self.frame) / CGRectGetWidth(rotateNormalRect), CGRectGetHeight(self.frame) / CGRectGetHeight(rotateNormalRect));
|
||||
self.minimumZoomScale = minimumZoomScale;
|
||||
}
|
||||
|
||||
#pragma mark - 重写父类方法
|
||||
|
||||
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
|
||||
// if ([[self.imageView subviews] containsObject:view]) {
|
||||
// if (event.allTouches.count == 1) { /** 1个手指 */
|
||||
// return YES;
|
||||
// } else if (event.allTouches.count == 2) { /** 2个手指 */
|
||||
// return NO;
|
||||
// }
|
||||
// }
|
||||
return [super touchesShouldBegin:touches withEvent:event inContentView:view];
|
||||
}
|
||||
|
||||
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
|
||||
// if ([[self.imageView subviews] containsObject:view]) {
|
||||
// return NO;
|
||||
// } else if (![[self subviews] containsObject:view]) { /** 非自身子视图 */
|
||||
// return NO;
|
||||
// }
|
||||
return [super touchesShouldCancelInContentView:view];
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
UIView *view = [super hitTest:point withEvent:event];
|
||||
if (!view) {
|
||||
CGPoint sPoint = [self convertPoint:point toView:self.imageView.stickerView];
|
||||
if (CGRectContainsPoint(self.imageView.stickerView.selectItemView.frame, sPoint)) {
|
||||
self.imageView.stickerView.hitTestSubView = YES;
|
||||
return self.imageView.stickerView.selectItemView.contentView;
|
||||
}else {
|
||||
[self.imageView.stickerView removeSelectItem];
|
||||
}
|
||||
}
|
||||
if (view == self.imageView) { /** 不触发下一层UI响应 */
|
||||
return self;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
||||
/** 控制自身手势 */
|
||||
return self.useGesture;
|
||||
}
|
||||
|
||||
#pragma mark - 数据
|
||||
- (NSDictionary *)photoEditData
|
||||
{
|
||||
NSMutableDictionary *data = [@{} mutableCopy];
|
||||
|
||||
if ([self canReset]) { /** 可还原证明已编辑过 */
|
||||
// CGRect trueFrame = CGRectApplyAffineTransform(self.frame, CGAffineTransformInvert(self.transform));
|
||||
NSDictionary *myData = @{kHXClippingViewData_frame:[NSValue valueWithCGRect:self.saveRect]
|
||||
, kHXClippingViewData_zoomScale:@(self.zoomScale)
|
||||
, kHXClippingViewData_contentSize:[NSValue valueWithCGSize:self.contentSize]
|
||||
, kHXClippingViewData_contentOffset:[NSValue valueWithCGPoint:self.contentOffset]
|
||||
, kHXClippingViewData_minimumZoomScale:@(self.minimumZoomScale)
|
||||
, kHXClippingViewData_maximumZoomScale:@(self.maximumZoomScale)
|
||||
, kHXClippingViewData_clipsToBounds:@(self.clipsToBounds)
|
||||
, kHXClippingViewData_first_minimumZoomScale:@(self.first_minimumZoomScale)
|
||||
, kHXClippingViewData_transform:[NSValue valueWithCGAffineTransform:self.transform]
|
||||
, kHXClippingViewData_angle:@(self.angle)
|
||||
, kHXClippingViewData_mirror : @(self.mirrorType)
|
||||
, kHXStickerViewData_screenScale:@(self.screenScale)
|
||||
};
|
||||
[data setObject:myData forKey:kHXClippingViewData];
|
||||
}
|
||||
|
||||
NSDictionary *imageViewData = self.imageView.photoEditData;
|
||||
if (imageViewData) [data setObject:imageViewData forKey:kHXClippingViewData_zoomingView];
|
||||
|
||||
if (data.count) {
|
||||
return data;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setPhotoEditData:(NSDictionary *)photoEditData
|
||||
{
|
||||
NSDictionary *myData = photoEditData[kHXClippingViewData];
|
||||
if (myData) {
|
||||
self.transform = [myData[kHXClippingViewData_transform] CGAffineTransformValue];
|
||||
self.angle = [myData[kHXClippingViewData_angle] integerValue];
|
||||
self.mirrorType = [myData[kHXClippingViewData_mirror] integerValue];
|
||||
self.saveRect = [myData[kHXClippingViewData_frame] CGRectValue];
|
||||
self.frame = self.saveRect;
|
||||
self.minimumZoomScale = [myData[kHXClippingViewData_minimumZoomScale] floatValue];
|
||||
self.maximumZoomScale = [myData[kHXClippingViewData_maximumZoomScale] floatValue];
|
||||
self.zoomScale = [myData[kHXClippingViewData_zoomScale] floatValue];
|
||||
self.contentSize = [myData[kHXClippingViewData_contentSize] CGSizeValue];
|
||||
self.contentOffset = [myData[kHXClippingViewData_contentOffset] CGPointValue];
|
||||
self.clipsToBounds = [myData[kHXClippingViewData_clipsToBounds] boolValue];
|
||||
self.first_minimumZoomScale = [myData[kHXClippingViewData_first_minimumZoomScale] floatValue];
|
||||
self.screenScale = [myData[kHXStickerViewData_screenScale] floatValue];
|
||||
}
|
||||
|
||||
self.imageView.photoEditData = photoEditData[kHXClippingViewData_zoomingView];
|
||||
}
|
||||
|
||||
@end
|
19
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletContentViewCell.h
generated
Normal file
19
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletContentViewCell.h
generated
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// HXPhotoEditChartletContentViewCell.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/2.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class HXPhotoEditChartletModel;
|
||||
@interface HXPhotoEditChartletContentViewCell : UICollectionViewCell
|
||||
@property (weak, nonatomic, readonly) IBOutlet UICollectionView *collectionView;
|
||||
@property (copy, nonatomic) NSArray<HXPhotoEditChartletModel *> *models;
|
||||
@property (copy, nonatomic) void (^ selectCellBlock)(UIImage *image);
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
66
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletContentViewCell.m
generated
Normal file
66
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletContentViewCell.m
generated
Normal file
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// HXPhotoEditChartletContentViewCell.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/2.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditChartletContentViewCell.h"
|
||||
#import "HXPhotoEditChartletModel.h"
|
||||
#import "HXPhotoEditChartletListView.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
|
||||
@interface HXPhotoEditChartletContentViewCell ()<UICollectionViewDataSource, UICollectionViewDelegate>
|
||||
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionViewFlowLayout *flowLayout;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *collectionLeftConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *collectionRightConstraint;
|
||||
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditChartletContentViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
if (@available(iOS 11.0, *)){
|
||||
[self.collectionView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
|
||||
}
|
||||
CGFloat width;
|
||||
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown || HX_UI_IS_IPAD) {
|
||||
width = (HX_ScreenWidth - 5 * 20) / 4;
|
||||
self.flowLayout.sectionInset = UIEdgeInsetsMake(75, 20, 20, 20);
|
||||
}else {
|
||||
self.flowLayout.sectionInset = UIEdgeInsetsMake(75, 20 + hxTopMargin, 20, 20 + hxTopMargin);
|
||||
width = ((HX_ScreenWidth - hxTopMargin * 2) - 9 * 20) / 8;
|
||||
}
|
||||
self.flowLayout.itemSize = CGSizeMake(width, width);
|
||||
self.flowLayout.minimumLineSpacing = 20;
|
||||
self.flowLayout.minimumInteritemSpacing = 20;
|
||||
|
||||
[self.collectionView registerClass:[HXPhotoEditChartletListViewCell class] forCellWithReuseIdentifier:@"HXPhotoEditChartletListViewCell_Id"];
|
||||
}
|
||||
- (void)setModels:(NSArray<HXPhotoEditChartletModel *> *)models {
|
||||
_models = models;
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.models.count;
|
||||
}
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HXPhotoEditChartletListViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HXPhotoEditChartletListViewCell_Id" forIndexPath:indexPath];
|
||||
cell.model = self.models[indexPath.item];
|
||||
return cell;
|
||||
}
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (self.selectCellBlock) {
|
||||
HXPhotoEditChartletListViewCell *cell = (HXPhotoEditChartletListViewCell *)[collectionView cellForItemAtIndexPath:indexPath];
|
||||
if (!cell.imageView.image) {
|
||||
return;
|
||||
}
|
||||
self.selectCellBlock(cell.imageView.image);
|
||||
}
|
||||
}
|
||||
@end
|
28
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletListView.h
generated
Normal file
28
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletListView.h
generated
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// HXPhotoEditChartletListView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/23.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class HXPhotoEditChartletModel, HXPhotoEditChartletTitleModel, HXPhotoEditConfiguration;
|
||||
@interface HXPhotoEditChartletListView : UIView
|
||||
+ (void)showEmojiViewWithConfiguration:(HXPhotoEditConfiguration *)configuration
|
||||
completion:(void (^ _Nullable)(UIImage *image))completion;
|
||||
+ (void)showEmojiViewWithModels:(NSArray<HXPhotoEditChartletTitleModel *> *)models
|
||||
completion:(void (^ _Nullable)(UIImage *image))completion;
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditChartletListViewCell : UICollectionViewCell
|
||||
@property (strong, nonatomic) UIImageView *imageView;
|
||||
@property (strong, nonatomic) HXPhotoEditChartletTitleModel *titleModel;
|
||||
@property (strong, nonatomic) HXPhotoEditChartletModel *model;
|
||||
@property (assign, nonatomic) BOOL showMask;
|
||||
- (void)setShowMask:(BOOL)showMask isAnimate:(BOOL)isAnimate;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
462
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletListView.m
generated
Normal file
462
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletListView.m
generated
Normal file
|
@ -0,0 +1,462 @@
|
|||
//
|
||||
// HXPhotoEditChartletListView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/23.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditChartletListView.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "HXPhotoEditChartletPreviewView.h"
|
||||
#import "HXPhotoEditChartletModel.h"
|
||||
#import "HXPhotoEditChartletContentViewCell.h"
|
||||
#import "UIImageView+HXExtension.h"
|
||||
#import "HXPhotoEditConfiguration.h"
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
|
||||
#define HXclViewHeight HX_UI_IS_IPAD ? 500 : (([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown) ? (HX_IS_IPhoneX_All ? 400 : 350) : 200)
|
||||
|
||||
|
||||
@interface HXPhotoEditChartletListView ()<UICollectionViewDataSource, UICollectionViewDelegate>
|
||||
@property (weak, nonatomic) IBOutlet UIView *bgView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *contentView;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *arrowBtn;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionViewFlowLayout *flowLayout;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewBottomConstraint;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *collectionViewHeightConstraint;
|
||||
@property (copy, nonatomic) void (^ selectImageCompletion)(UIImage *image);
|
||||
@property (copy, nonatomic) NSArray *models;
|
||||
@property (strong, nonatomic) HXPhotoEditChartletPreviewView *currentPreview;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionView *titleCollectionView;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionViewFlowLayout *titleFlowLayout;
|
||||
@property (weak, nonatomic) IBOutlet UIVisualEffectView *titleView;
|
||||
@property (strong, nonatomic) NSIndexPath *currentSelectTitleIndexPath;
|
||||
@property (assign, nonatomic) CGFloat contentViewBottom;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *arrowRightConstraint;
|
||||
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *loadingView;
|
||||
@property (strong, nonatomic) HXPhotoEditConfiguration *configuration;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditChartletListView
|
||||
|
||||
|
||||
+ (void)showEmojiViewWithConfiguration:(HXPhotoEditConfiguration *)configuration
|
||||
completion:(void (^ _Nullable)(UIImage *image))completion {
|
||||
HXPhotoEditChartletListView *view = [HXPhotoEditChartletListView initView];
|
||||
view.selectImageCompletion = completion;
|
||||
view.configuration = configuration;
|
||||
view.frame = [UIScreen mainScreen].bounds;
|
||||
[[UIApplication sharedApplication].keyWindow addSubview:view];
|
||||
[view show];
|
||||
}
|
||||
|
||||
+ (void)showEmojiViewWithModels:(NSArray<HXPhotoEditChartletTitleModel *> *)models
|
||||
completion:(void (^ _Nullable)(UIImage *image))completion {
|
||||
HXPhotoEditChartletListView *view = [HXPhotoEditChartletListView initView];
|
||||
view.selectImageCompletion = completion;
|
||||
view.models = models;
|
||||
view.frame = [UIScreen mainScreen].bounds;
|
||||
[[UIApplication sharedApplication].keyWindow addSubview:view];
|
||||
[view show];
|
||||
}
|
||||
|
||||
+ (instancetype)initView {
|
||||
return [[[NSBundle hx_photoPickerBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.loadingView.hidesWhenStopped = YES;
|
||||
if (@available(iOS 11.0, *)){
|
||||
[self.collectionView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
|
||||
[self.titleCollectionView setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
|
||||
}
|
||||
[self.arrowBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_pull_down"] forState:UIControlStateNormal];
|
||||
self.contentViewBottomConstraint.constant = -(HXclViewHeight + hxBottomMargin);
|
||||
self.collectionViewHeightConstraint.constant = HXclViewHeight + hxBottomMargin;
|
||||
[self.bgView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(hide)]];
|
||||
self.bgView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
|
||||
|
||||
self.contentView.layer.masksToBounds = YES;
|
||||
if (HX_IOS11_Later) {
|
||||
[self.contentView hx_radiusWithRadius:8 corner:UIRectCornerTopLeft | UIRectCornerTopRight];
|
||||
}
|
||||
|
||||
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
|
||||
if (orientation == UIInterfaceOrientationLandscapeRight || orientation == UIInterfaceOrientationLandscapeLeft) {
|
||||
self.arrowRightConstraint.constant = hxTopMargin;
|
||||
self.titleFlowLayout.sectionInset = UIEdgeInsetsMake(12.5, 20 + hxTopMargin, 12.5, 20);
|
||||
}else {
|
||||
self.titleFlowLayout.sectionInset = UIEdgeInsetsMake(12.5, 20, 12.5, 20);
|
||||
}
|
||||
|
||||
self.titleFlowLayout.itemSize = CGSizeMake(35, 35);
|
||||
self.titleFlowLayout.minimumInteritemSpacing = 20;
|
||||
self.titleFlowLayout.minimumLineSpacing = 20;
|
||||
|
||||
self.titleCollectionView.dataSource = self;
|
||||
self.titleCollectionView.delegate = self;
|
||||
[self.titleCollectionView registerClass:[HXPhotoEditChartletListViewCell class] forCellWithReuseIdentifier:@"HXPhotoEditChartletListViewCellId"];
|
||||
|
||||
self.flowLayout.itemSize = CGSizeMake(HX_ScreenWidth, HXclViewHeight + hxBottomMargin);
|
||||
self.flowLayout.minimumLineSpacing = 0;
|
||||
self.flowLayout.minimumInteritemSpacing = 0;
|
||||
|
||||
self.collectionView.pagingEnabled = YES;
|
||||
self.collectionView.dataSource = self;
|
||||
self.collectionView.delegate = self;
|
||||
|
||||
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([HXPhotoEditChartletContentViewCell class]) bundle:[NSBundle hx_photoPickerBundle]] forCellWithReuseIdentifier:@"HXPhotoEditChartletContentViewCellId"];
|
||||
|
||||
|
||||
UILongPressGestureRecognizer *longPgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecongizerClick:)];
|
||||
[self addGestureRecognizer:longPgr];
|
||||
|
||||
UIPanGestureRecognizer *panPgr = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panPressGestureRecongizerClick:)];
|
||||
[self.titleView addGestureRecognizer:panPgr];
|
||||
self.contentViewBottom = 0;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationWillChanged) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil];
|
||||
}
|
||||
- (void)deviceOrientationWillChanged {
|
||||
[self removeFromSuperview];
|
||||
}
|
||||
- (void)setConfiguration:(HXPhotoEditConfiguration *)configuration {
|
||||
_configuration = configuration;
|
||||
|
||||
if (configuration.requestChartletModels) {
|
||||
[self.loadingView startAnimating];
|
||||
HXWeakSelf
|
||||
configuration.requestChartletModels(^(NSArray<HXPhotoEditChartletTitleModel *> * _Nonnull chartletModels) {
|
||||
if (!weakSelf) {
|
||||
return;
|
||||
}
|
||||
[weakSelf.loadingView stopAnimating];
|
||||
weakSelf.models = chartletModels;
|
||||
[weakSelf.collectionView reloadData];
|
||||
[weakSelf.titleCollectionView reloadData];
|
||||
});
|
||||
}else {
|
||||
self.models = configuration.chartletModels;
|
||||
}
|
||||
}
|
||||
- (void)setModels:(NSArray *)models {
|
||||
_models = models;
|
||||
for (HXPhotoEditChartletTitleModel *model in models) {
|
||||
model.selected = NO;
|
||||
}
|
||||
HXPhotoEditChartletTitleModel *model = models.firstObject;
|
||||
model.selected = YES;
|
||||
self.currentSelectTitleIndexPath = [NSIndexPath indexPathForItem:0 inSection:0];
|
||||
}
|
||||
- (void)panPressGestureRecongizerClick:(UIPanGestureRecognizer *)panPgr {
|
||||
CGPoint point = [panPgr translationInView:self.titleView];
|
||||
if (panPgr.state == UIGestureRecognizerStateBegan) {
|
||||
CGFloat contentViewBottom = self.contentViewBottom - point.y;
|
||||
if (contentViewBottom > 0) {
|
||||
contentViewBottom = 0;
|
||||
}
|
||||
self.contentViewBottomConstraint.constant = contentViewBottom;
|
||||
}else if (panPgr.state == UIGestureRecognizerStateChanged) {
|
||||
CGFloat contentViewBottom = self.contentViewBottom - point.y;
|
||||
if (contentViewBottom > 0) {
|
||||
contentViewBottom = 0;
|
||||
}
|
||||
self.contentViewBottomConstraint.constant = contentViewBottom;
|
||||
}else if (panPgr.state == UIGestureRecognizerStateEnded ||
|
||||
panPgr.state == UIGestureRecognizerStateCancelled) {
|
||||
if (self.contentViewBottomConstraint.constant < -100.f) {
|
||||
[self hide];
|
||||
}else {
|
||||
[UIView animateWithDuration:0.15 animations:^{
|
||||
self.contentViewBottomConstraint.constant = 0;
|
||||
[self layoutIfNeeded];
|
||||
}];
|
||||
}
|
||||
self.contentViewBottom = 0;
|
||||
}
|
||||
}
|
||||
- (void)longPressGestureRecongizerClick:(UILongPressGestureRecognizer *)longPgr {
|
||||
CGPoint point = [longPgr locationInView:self.collectionView];
|
||||
NSIndexPath *indexPath = [self.collectionView indexPathForItemAtPoint:point];
|
||||
if (indexPath) {
|
||||
HXPhotoEditChartletContentViewCell *cell = (HXPhotoEditChartletContentViewCell *)[self.collectionView cellForItemAtIndexPath:indexPath];
|
||||
point = [longPgr locationInView:cell];
|
||||
point = [cell convertPoint:point toView:cell.collectionView];
|
||||
NSIndexPath *contentIndexPath = [cell.collectionView indexPathForItemAtPoint:point];
|
||||
if (contentIndexPath) {
|
||||
HXPhotoEditChartletListViewCell *contentCell = (HXPhotoEditChartletListViewCell *)[cell.collectionView cellForItemAtIndexPath:contentIndexPath];
|
||||
CGRect cellFrame = [cell.collectionView convertRect:contentCell.frame toView:self];
|
||||
CGFloat cellY = cellFrame.origin.y;
|
||||
if (cellY < self.contentView.hx_y + 60.f) {
|
||||
cellY = self.contentView.hx_y + 60.f;
|
||||
}
|
||||
CGPoint showPoint = CGPointMake(cellFrame.origin.x + cellFrame.size.width / 2, cellY);
|
||||
if (!self.currentPreview) {
|
||||
contentCell.showMask = YES;
|
||||
self.currentPreview = [self createdPreviewViewWithImage:contentCell.imageView.image point:showPoint cell:contentCell];
|
||||
[self addSubview:self.currentPreview];
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
self.currentPreview.alpha = 1;
|
||||
}];
|
||||
}else {
|
||||
if (contentCell != self.currentPreview.cell) {
|
||||
[self.currentPreview removeFromSuperview];
|
||||
self.currentPreview = [self createdPreviewViewWithImage:contentCell.imageView.image point:showPoint cell:contentCell];
|
||||
self.currentPreview.alpha = 1;
|
||||
[self addSubview:self.currentPreview];
|
||||
}
|
||||
}
|
||||
}else {
|
||||
[self removePreviewView];
|
||||
}
|
||||
}else {
|
||||
[self removePreviewView];
|
||||
}
|
||||
if (longPgr.state == UIGestureRecognizerStateEnded ||
|
||||
longPgr.state == UIGestureRecognizerStateCancelled) {
|
||||
[self removePreviewView];
|
||||
}
|
||||
}
|
||||
- (void)removePreviewView {
|
||||
HXPhotoEditChartletPreviewView *previewView = self.currentPreview;
|
||||
previewView.cell.showMask = NO;
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
previewView.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
[previewView removeFromSuperview];
|
||||
}];
|
||||
self.currentPreview = nil;
|
||||
}
|
||||
- (HXPhotoEditChartletPreviewView *)createdPreviewViewWithImage:(UIImage *)image point:(CGPoint)point cell:(HXPhotoEditChartletListViewCell *)cell {
|
||||
HXPhotoEditChartletPreviewView *preview = [HXPhotoEditChartletPreviewView showPreviewWithModel:cell.model atPoint:point];
|
||||
preview.alpha = 0;
|
||||
preview.cell = cell;
|
||||
return preview;
|
||||
}
|
||||
- (IBAction)pullDownBtnClick:(UIButton *)sender {
|
||||
[self hide];
|
||||
}
|
||||
- (void)show {
|
||||
[self layoutIfNeeded];
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
self.bgView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3];
|
||||
self.contentViewBottomConstraint.constant = 0;
|
||||
[self layoutIfNeeded];
|
||||
}];
|
||||
}
|
||||
- (void)hide {
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
self.bgView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0];
|
||||
self.contentViewBottomConstraint.constant = -(HXclViewHeight + hxBottomMargin);
|
||||
[self layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
[self removeFromSuperview];
|
||||
}];
|
||||
}
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
if (collectionView == self.titleCollectionView) {
|
||||
return 1;
|
||||
}
|
||||
return self.models.count;
|
||||
}
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
if (collectionView == self.titleCollectionView) {
|
||||
return self.models.count;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (collectionView == self.collectionView) {
|
||||
HXPhotoEditChartletContentViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HXPhotoEditChartletContentViewCellId" forIndexPath:indexPath];
|
||||
HXPhotoEditChartletTitleModel *titleModel = self.models[indexPath.section];
|
||||
cell.models = titleModel.models;
|
||||
HXWeakSelf
|
||||
cell.selectCellBlock = ^(UIImage * _Nonnull image) {
|
||||
if (weakSelf.selectImageCompletion) {
|
||||
weakSelf.selectImageCompletion(image);
|
||||
}
|
||||
[weakSelf hide];
|
||||
};
|
||||
return cell;
|
||||
}
|
||||
HXPhotoEditChartletListViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HXPhotoEditChartletListViewCellId" forIndexPath:indexPath];
|
||||
cell.titleModel = self.models[indexPath.item];
|
||||
return cell;
|
||||
}
|
||||
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (collectionView == self.titleCollectionView) {
|
||||
HXPhotoEditChartletTitleModel *titleModel = self.models[indexPath.item];
|
||||
[(HXPhotoEditChartletListViewCell *)cell setShowMask:titleModel.selected isAnimate:NO];
|
||||
}
|
||||
}
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (collectionView == self.titleCollectionView) {
|
||||
if (self.currentSelectTitleIndexPath.item == indexPath.item) {
|
||||
return;
|
||||
}
|
||||
[self.collectionView setContentOffset:CGPointMake(HX_ScreenWidth * indexPath.item, 0) animated:NO];
|
||||
return;
|
||||
}
|
||||
}
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (scrollView == self.collectionView) {
|
||||
CGFloat width = HX_ScreenWidth;
|
||||
CGFloat offsetx = self.collectionView.contentOffset.x;
|
||||
if (self.models.count) {
|
||||
NSInteger currentIndex = (offsetx + width * 0.5) / width;
|
||||
if (currentIndex > self.models.count - 1) {
|
||||
currentIndex = self.models.count - 1;
|
||||
}
|
||||
if (currentIndex < 0) {
|
||||
currentIndex = 0;
|
||||
}
|
||||
if (self.currentSelectTitleIndexPath.item == currentIndex) {
|
||||
return;
|
||||
}
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:currentIndex inSection:0];
|
||||
HXPhotoEditChartletListViewCell *cell = (HXPhotoEditChartletListViewCell *)[self.titleCollectionView cellForItemAtIndexPath:indexPath];
|
||||
cell.showMask = YES;
|
||||
cell.titleModel.selected = YES;
|
||||
|
||||
HXPhotoEditChartletListViewCell *selectCell = (HXPhotoEditChartletListViewCell *)[self.titleCollectionView cellForItemAtIndexPath:self.currentSelectTitleIndexPath];
|
||||
if (selectCell) {
|
||||
selectCell.showMask = NO;
|
||||
selectCell.titleModel.selected = NO;
|
||||
}else {
|
||||
HXPhotoEditChartletTitleModel *titleModel = self.models[self.currentSelectTitleIndexPath.item];
|
||||
titleModel.selected = NO;
|
||||
}
|
||||
|
||||
self.currentSelectTitleIndexPath = indexPath;
|
||||
|
||||
[self.titleCollectionView scrollToItemAtIndexPath:self.currentSelectTitleIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditChartletListViewCell ()
|
||||
@property (strong, nonatomic) UIView *bgMaskView;
|
||||
@property (strong, nonatomic) UIActivityIndicatorView *loadingView;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditChartletListViewCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self.contentView addSubview:self.bgMaskView];
|
||||
[self.contentView addSubview:self.imageView];
|
||||
[self.contentView addSubview:self.loadingView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)setTitleModel:(HXPhotoEditChartletTitleModel *)titleModel {
|
||||
_titleModel = titleModel;
|
||||
if (titleModel.type == HXPhotoEditChartletModelType_Image) {
|
||||
[self.loadingView stopAnimating];
|
||||
self.imageView.image = titleModel.image;
|
||||
}else if (titleModel.type == HXPhotoEditChartletModelType_ImageNamed) {
|
||||
[self.loadingView stopAnimating];
|
||||
UIImage *image = [UIImage hx_imageContentsOfFile:titleModel.imageNamed];
|
||||
self.imageView.image = image;
|
||||
}else if (titleModel.type == HXPhotoEditChartletModelType_NetworkURL) {
|
||||
HXWeakSelf
|
||||
if (!titleModel.loadCompletion) {
|
||||
[self.loadingView startAnimating];
|
||||
}
|
||||
[self.imageView hx_setImageWithURL:titleModel.networkURL progress:^(CGFloat progress) {
|
||||
if (progress < 1) {
|
||||
[weakSelf.loadingView startAnimating];
|
||||
}
|
||||
} completed:^(UIImage *image, NSError *error) {
|
||||
weakSelf.titleModel.loadCompletion = YES;
|
||||
[weakSelf.loadingView stopAnimating];
|
||||
}];
|
||||
}
|
||||
[self setShowMask:titleModel.selected isAnimate:NO];
|
||||
self.showMask = titleModel.selected;
|
||||
}
|
||||
- (void)setModel:(HXPhotoEditChartletModel *)model {
|
||||
_model = model;
|
||||
if (model.type == HXPhotoEditChartletModelType_Image) {
|
||||
[self.loadingView stopAnimating];
|
||||
self.imageView.image = model.image;
|
||||
}else if (model.type == HXPhotoEditChartletModelType_ImageNamed) {
|
||||
[self.loadingView stopAnimating];
|
||||
UIImage *image = [UIImage hx_imageContentsOfFile:model.imageNamed];
|
||||
self.imageView.image = image;
|
||||
}else if (model.type == HXPhotoEditChartletModelType_NetworkURL) {
|
||||
if (!model.loadCompletion) {
|
||||
[self.loadingView startAnimating];
|
||||
}
|
||||
HXWeakSelf
|
||||
[self.imageView hx_setImageWithURL:model.networkURL progress:^(CGFloat progress) {
|
||||
if (progress < 1) {
|
||||
[weakSelf.loadingView startAnimating];
|
||||
}
|
||||
} completed:^(UIImage *image, NSError *error) {
|
||||
weakSelf.model.loadCompletion = YES;
|
||||
[weakSelf.loadingView stopAnimating];
|
||||
}];
|
||||
}
|
||||
}
|
||||
- (void)setShowMask:(BOOL)showMask {
|
||||
[self setShowMask:showMask isAnimate:YES];
|
||||
}
|
||||
- (void)setShowMask:(BOOL)showMask isAnimate:(BOOL)isAnimate {
|
||||
_showMask = showMask;
|
||||
if (isAnimate) {
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
self.bgMaskView.alpha = showMask ? 1 :0;
|
||||
}];
|
||||
}else {
|
||||
self.bgMaskView.alpha = showMask ? 1 :0;
|
||||
}
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
self.imageView.frame = CGRectMake(2.5, 2.5, self.hx_w - 5, self.hx_h - 5);
|
||||
self.bgMaskView.frame = CGRectMake(-5, -5, self.hx_w + 10, self.hx_h + 10);
|
||||
self.loadingView.center = CGPointMake(self.hx_w / 2, self.hx_h / 2);
|
||||
if (HX_IOS11_Earlier) {
|
||||
[self.bgMaskView hx_radiusWithRadius:5.f corner:UIRectCornerAllCorners];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] init];
|
||||
_imageView.clipsToBounds = YES;
|
||||
_imageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
- (UIView *)bgMaskView {
|
||||
if (!_bgMaskView) {
|
||||
_bgMaskView = [[UIView alloc] init];
|
||||
_bgMaskView.alpha = 0;
|
||||
_bgMaskView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.3f];
|
||||
if (HX_IOS11_Later) {
|
||||
[_bgMaskView hx_radiusWithRadius:5.f corner:UIRectCornerAllCorners];
|
||||
}
|
||||
}
|
||||
return _bgMaskView;
|
||||
}
|
||||
- (UIActivityIndicatorView *)loadingView {
|
||||
if (!_loadingView) {
|
||||
_loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
|
||||
_loadingView.hidesWhenStopped = YES;
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
@end
|
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletPreviewView.h
generated
Normal file
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletPreviewView.h
generated
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// HXPhotoEditChartletPreviewView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class HXPhotoEditChartletListViewCell, HXPhotoEditChartletModel;
|
||||
@interface HXPhotoEditChartletPreviewView : UIView
|
||||
@property (weak, nonatomic) HXPhotoEditChartletListViewCell *cell;
|
||||
+ (instancetype)showPreviewWithModel:(HXPhotoEditChartletModel *)model atPoint:(CGPoint)point;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
170
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletPreviewView.m
generated
Normal file
170
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditChartletPreviewView.m
generated
Normal file
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// HXPhotoEditChartletPreviewView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditChartletPreviewView.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
#import "HXPhotoEditChartletModel.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "UIImageView+HXExtension.h"
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
|
||||
@interface HXPhotoEditChartletPreviewView ()
|
||||
@property (strong, nonatomic) UIActivityIndicatorView *loadingView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *contentView;
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
|
||||
@property (assign, nonatomic) CGSize imageSize;
|
||||
@property (assign, nonatomic) CGRect viewFrame;
|
||||
@property (assign, nonatomic) CGPoint point;
|
||||
@property (assign, nonatomic) CGFloat triangleX;
|
||||
@property (strong, nonatomic) HXPhotoEditChartletModel *model;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditChartletPreviewView
|
||||
|
||||
+ (instancetype)showPreviewWithModel:(HXPhotoEditChartletModel *)model atPoint:(CGPoint)point {
|
||||
HXPhotoEditChartletPreviewView *view = [self initView];
|
||||
view.point = point;
|
||||
view.model = model;
|
||||
return view;
|
||||
}
|
||||
|
||||
+ (instancetype)initView {
|
||||
return [[[NSBundle hx_photoPickerBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
|
||||
}
|
||||
|
||||
- (void)drawRect:(CGRect)rect {
|
||||
[super drawRect:rect];
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextBeginPath(context);
|
||||
CGContextMoveToPoint (context, self.triangleX - 15, self.hx_h - 20);
|
||||
CGContextAddLineToPoint(context, self.triangleX + 15, self.hx_h - 20);
|
||||
CGContextAddLineToPoint(context, self.triangleX, self.hx_h);
|
||||
CGContextClosePath(context);
|
||||
CGContextSetRGBFillColor(context, 1, 1, 1, 1);
|
||||
CGContextFillPath(context);
|
||||
}
|
||||
- (void)setModel:(HXPhotoEditChartletModel *)model {
|
||||
_model = model;
|
||||
if (model.type == HXPhotoEditChartletModelType_Image) {
|
||||
self.imageView.image = model.image;
|
||||
self.imageSize = self.imageView.image.size;
|
||||
[self updateFrame];
|
||||
}else if (model.type == HXPhotoEditChartletModelType_ImageNamed) {
|
||||
UIImage *image = [UIImage hx_imageContentsOfFile:model.imageNamed];
|
||||
self.imageView.image = image;
|
||||
self.imageSize = self.imageView.image.size;
|
||||
[self updateFrame];
|
||||
}else if (model.type == HXPhotoEditChartletModelType_NetworkURL) {
|
||||
self.loadingView.hidden = NO;
|
||||
[self.loadingView startAnimating];
|
||||
self.imageSize = CGSizeMake(HX_ScreenWidth / 3, HX_ScreenWidth / 3);
|
||||
[self updateFrame];
|
||||
[self layoutIfNeeded];
|
||||
HXWeakSelf
|
||||
[self.imageView hx_setImageWithURL:model.networkURL progress:^(CGFloat progress) {
|
||||
if (progress < 1) {
|
||||
weakSelf.loadingView.hidden = NO;
|
||||
[weakSelf.loadingView startAnimating];
|
||||
}
|
||||
} completed:^(UIImage *image, NSError *error) {
|
||||
weakSelf.loadingView.hidden = YES;
|
||||
[weakSelf.loadingView stopAnimating];
|
||||
weakSelf.viewFrame = CGRectZero;
|
||||
weakSelf.imageSize = weakSelf.imageView.image.size;
|
||||
[UIView animateWithDuration:0.25 animations:^{
|
||||
[weakSelf updateFrame];
|
||||
[weakSelf layoutIfNeeded];
|
||||
[weakSelf setNeedsDisplay];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
- (void)updateFrame {
|
||||
self.frame = self.viewFrame;
|
||||
self.loadingView.center = CGPointMake(self.hx_w / 2, self.hx_h / 2 - 5);
|
||||
}
|
||||
- (CGRect)viewFrame {
|
||||
if (CGRectIsEmpty(_viewFrame)) {
|
||||
CGFloat width = HX_ScreenWidth / 2;
|
||||
CGFloat height = width;
|
||||
CGFloat imgWidth = self.imageSize.width;
|
||||
CGFloat imgHeight = self.imageSize.height;
|
||||
if ([[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIInterfaceOrientationPortraitUpsideDown || HX_UI_IS_IPAD) {
|
||||
if (imgWidth > imgHeight) {
|
||||
width = HX_ScreenWidth - 40;
|
||||
}else if (imgHeight > imgWidth) {
|
||||
height = HX_ScreenWidth - 40;
|
||||
}
|
||||
}else {
|
||||
width = HX_ScreenHeight / 2;
|
||||
height = width;
|
||||
if (imgWidth > imgHeight) {
|
||||
width = HX_ScreenHeight - 40;
|
||||
}else if (imgHeight > imgWidth) {
|
||||
height = HX_ScreenHeight - 40;
|
||||
}
|
||||
}
|
||||
CGFloat w;
|
||||
CGFloat h;
|
||||
|
||||
if (imgWidth > width) {
|
||||
imgHeight = width / imgWidth * imgHeight;
|
||||
}
|
||||
if (imgHeight > height) {
|
||||
w = height / self.imageSize.height * imgWidth;
|
||||
h = height;
|
||||
}else {
|
||||
if (imgWidth > width) {
|
||||
w = width;
|
||||
}else {
|
||||
w = imgWidth;
|
||||
}
|
||||
h = imgHeight;
|
||||
}
|
||||
w += 10;
|
||||
h += 20;
|
||||
CGFloat x = self.point.x - w / 2;
|
||||
CGFloat y = self.point.y - 10 - h;
|
||||
if (x + w > HX_ScreenWidth - 15) {
|
||||
x = HX_ScreenWidth - 15 - w;
|
||||
}
|
||||
if (x < 15) {
|
||||
x = 15;
|
||||
}
|
||||
self.triangleX = self.point.x - x;
|
||||
_viewFrame = CGRectMake(x, y, w, h);
|
||||
}
|
||||
return _viewFrame;
|
||||
}
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
[self addSubview:self.loadingView];
|
||||
if (HX_IOS11_Later) {
|
||||
[self.contentView hx_radiusWithRadius:5 corner:UIRectCornerAllCorners];
|
||||
}
|
||||
self.layer.shadowOffset = CGSizeMake(0, 0);
|
||||
self.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||
self.layer.shadowRadius = 5.f;
|
||||
self.layer.shadowOpacity = 0.3f;
|
||||
_viewFrame = CGRectZero;
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
if (HX_IOS11_Earlier) {
|
||||
[self.contentView hx_radiusWithRadius:5 corner:UIRectCornerAllCorners];
|
||||
}
|
||||
}
|
||||
- (UIActivityIndicatorView *)loadingView {
|
||||
if (!_loadingView) {
|
||||
_loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
||||
_loadingView.hidden = YES;
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
@end
|
56
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditClippingToolBar.h
generated
Normal file
56
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditClippingToolBar.h
generated
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// HXPhotoEditClippingToolBar.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/30.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class HXPhotoEditClippingToolBarRotaioModel;
|
||||
@interface HXPhotoEditClippingToolBar : UIView
|
||||
@property (assign, nonatomic) BOOL enableRotaio;
|
||||
@property (strong, nonatomic) UIColor *themeColor;
|
||||
@property (assign, nonatomic) BOOL enableReset;
|
||||
@property (copy, nonatomic) void (^ didBtnBlock)(NSInteger tag);
|
||||
|
||||
@property (copy, nonatomic) void (^ didRotateBlock)(void);
|
||||
@property (copy, nonatomic) void (^ didMirrorHorizontallyBlock)(void);
|
||||
|
||||
@property (copy, nonatomic) void (^ selectedRotaioBlock)(HXPhotoEditClippingToolBarRotaioModel *model);
|
||||
+ (instancetype)initView;
|
||||
|
||||
- (void)resetRotate;
|
||||
|
||||
- (void)setRotateAlpha:(CGFloat)alpha;
|
||||
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditClippingToolBarHeader : UICollectionReusableView
|
||||
@property (assign, nonatomic) BOOL enableRotaio;
|
||||
@property (copy, nonatomic) void (^ didRotateBlock)(void);
|
||||
@property (copy, nonatomic) void (^ didMirrorHorizontallyBlock)(void);
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditClippingToolBarHeaderViewCell : UICollectionViewCell
|
||||
@property (strong, nonatomic) UIColor *themeColor;
|
||||
@property (strong, nonatomic) HXPhotoEditClippingToolBarRotaioModel *model;
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditClippingToolBarRotaioModel : NSObject
|
||||
|
||||
@property (assign, nonatomic) CGSize size;
|
||||
|
||||
@property (assign, nonatomic) CGSize scaleSize;
|
||||
|
||||
@property (assign, nonatomic) CGFloat widthRatio;
|
||||
@property (assign, nonatomic) CGFloat heightRatio;
|
||||
|
||||
@property (copy, nonatomic) NSString *scaleText;
|
||||
|
||||
@property (assign, nonatomic) BOOL isSelected;
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
337
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditClippingToolBar.m
generated
Normal file
337
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditClippingToolBar.m
generated
Normal file
|
@ -0,0 +1,337 @@
|
|||
//
|
||||
// HXPhotoEditClippingToolBar.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/30.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditClippingToolBar.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
#import "UIButton+HXExtension.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "UIFont+HXExtension.h"
|
||||
#import "UILabel+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
|
||||
#define HXScaleViewSize 28.f
|
||||
|
||||
@interface HXPhotoEditClippingToolBar ()<UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout>
|
||||
@property (weak, nonatomic) IBOutlet UIButton *confirmBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *cancelBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *resetBtn;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
|
||||
@property (copy, nonatomic) NSArray<HXPhotoEditClippingToolBarRotaioModel *> *models;
|
||||
@property (strong, nonatomic) HXPhotoEditClippingToolBarRotaioModel *currentSelectedModel;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditClippingToolBar
|
||||
|
||||
+ (instancetype)initView {
|
||||
return [[[NSBundle hx_photoPickerBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
[self.confirmBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_clip_confirm"] forState:UIControlStateNormal];
|
||||
[self.cancelBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_clip_cancel"] forState:UIControlStateNormal];
|
||||
self.resetBtn.enabled = NO;
|
||||
[self.resetBtn setTitle:[NSBundle hx_localizedStringForKey:@"还原"] forState:UIControlStateNormal];
|
||||
|
||||
UICollectionViewFlowLayout *flowlayout = (id)self.collectionView.collectionViewLayout;
|
||||
flowlayout.minimumInteritemSpacing = 20;
|
||||
flowlayout.sectionInset = UIEdgeInsetsMake(0, 20, 0, 10);
|
||||
flowlayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
|
||||
self.collectionView.dataSource = self;
|
||||
self.collectionView.delegate = self;
|
||||
|
||||
[self.collectionView registerClass:[HXPhotoEditClippingToolBarHeader class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"HXPhotoEditClippingToolBarHeaderId"];
|
||||
[self.collectionView registerClass:[HXPhotoEditClippingToolBarHeaderViewCell class] forCellWithReuseIdentifier:@"HXPhotoEditClippingToolBarHeaderViewCellId"];
|
||||
}
|
||||
- (void)resetRotate {
|
||||
self.currentSelectedModel.isSelected = NO;
|
||||
self.currentSelectedModel = self.models.firstObject;
|
||||
self.currentSelectedModel.isSelected = YES;
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
- (void)setRotateAlpha:(CGFloat)alpha {
|
||||
if (alpha == 1) {
|
||||
self.collectionView.userInteractionEnabled = YES;
|
||||
}else {
|
||||
self.collectionView.userInteractionEnabled = NO;
|
||||
}
|
||||
self.collectionView.alpha = alpha;
|
||||
}
|
||||
- (void)setEnableReset:(BOOL)enableReset {
|
||||
_enableReset = enableReset;
|
||||
self.resetBtn.enabled = enableReset;
|
||||
}
|
||||
- (IBAction)didBtnClick:(UIButton *)sender {
|
||||
if (self.enableRotaio) {
|
||||
[self resetRotate];
|
||||
[self.collectionView setContentOffset:CGPointMake(0, 0) animated:YES];
|
||||
}
|
||||
if (self.didBtnBlock) {
|
||||
self.didBtnBlock(sender.tag);
|
||||
}
|
||||
}
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
if (self.enableRotaio) {
|
||||
return self.models.count;
|
||||
}else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HXPhotoEditClippingToolBarHeaderViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"HXPhotoEditClippingToolBarHeaderViewCellId" forIndexPath:indexPath];
|
||||
cell.themeColor = self.themeColor;
|
||||
cell.model = self.models[indexPath.item];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
||||
if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
|
||||
HXPhotoEditClippingToolBarHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"HXPhotoEditClippingToolBarHeaderId" forIndexPath:indexPath];
|
||||
header.enableRotaio = self.enableRotaio;
|
||||
header.didRotateBlock = self.didRotateBlock;
|
||||
header.didMirrorHorizontallyBlock = self.didMirrorHorizontallyBlock;
|
||||
return header;
|
||||
}
|
||||
return [UICollectionReusableView new];
|
||||
}
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HXPhotoEditClippingToolBarRotaioModel *model = self.models[indexPath.item];
|
||||
if (!CGSizeEqualToSize(model.scaleSize, CGSizeZero)) {
|
||||
return model.scaleSize;
|
||||
}
|
||||
CGFloat scaleWidth = HXScaleViewSize + 10;
|
||||
if (!model.widthRatio || model.widthRatio == 1) {
|
||||
model.size = CGSizeMake(HXScaleViewSize, HXScaleViewSize);
|
||||
model.scaleSize = CGSizeMake(HXScaleViewSize, scaleWidth);
|
||||
}else {
|
||||
CGFloat scale = scaleWidth / model.widthRatio;
|
||||
CGFloat width = model.widthRatio * scale;
|
||||
CGFloat height = model.heightRatio * scale;
|
||||
if (height > scaleWidth) {
|
||||
height = scaleWidth;
|
||||
width = scaleWidth / model.heightRatio * model.widthRatio;
|
||||
}
|
||||
model.size = CGSizeMake(width, height);
|
||||
if (height < scaleWidth) {
|
||||
height = scaleWidth;
|
||||
}
|
||||
CGFloat textWidth = [UILabel hx_getTextWidthWithText:model.scaleText height:height - 3 font:[UIFont hx_mediumHelveticaNeueOfSize:12]] + 5;
|
||||
if (width < textWidth) {
|
||||
height = textWidth / width * height;
|
||||
width = textWidth;
|
||||
if (height > 45.f) {
|
||||
height = 45.f;
|
||||
}
|
||||
model.size = CGSizeMake(width, height);
|
||||
}
|
||||
model.scaleSize = CGSizeMake(width, height);
|
||||
}
|
||||
return model.scaleSize;
|
||||
}
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
return CGSizeMake(100, 50);
|
||||
}
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSIndexPath *selectedIndexPath;
|
||||
if (self.currentSelectedModel) {
|
||||
selectedIndexPath = [NSIndexPath indexPathForItem:[self.models indexOfObject:self.currentSelectedModel] inSection:0];
|
||||
}
|
||||
if (selectedIndexPath && selectedIndexPath.item == indexPath.item) {
|
||||
return;
|
||||
}
|
||||
self.currentSelectedModel.isSelected = NO;
|
||||
HXPhotoEditClippingToolBarRotaioModel *model = self.models[indexPath.item];
|
||||
model.isSelected = YES;
|
||||
if (self.selectedRotaioBlock) {
|
||||
self.selectedRotaioBlock(model);
|
||||
}
|
||||
self.currentSelectedModel = model;
|
||||
if (selectedIndexPath) {
|
||||
[collectionView reloadItemsAtIndexPaths:@[indexPath, selectedIndexPath]];
|
||||
}else {
|
||||
[collectionView reloadItemsAtIndexPaths:@[indexPath]];
|
||||
}
|
||||
}
|
||||
- (NSArray<HXPhotoEditClippingToolBarRotaioModel *> *)models {
|
||||
if (!_models) {
|
||||
NSArray *scaleArray = @[@[@0, @0], @[@1, @1], @[@3, @2], @[@2, @3], @[@4, @3], @[@3, @4], @[@16, @9], @[@9, @16]];
|
||||
NSMutableArray *modelArray = [NSMutableArray array];
|
||||
for (NSArray *array in scaleArray) {
|
||||
HXPhotoEditClippingToolBarRotaioModel *model = [[HXPhotoEditClippingToolBarRotaioModel alloc] init];
|
||||
model.widthRatio = [array.firstObject floatValue];
|
||||
model.heightRatio = [array.lastObject floatValue];
|
||||
if (modelArray.count == 0) {
|
||||
model.isSelected = YES;
|
||||
self.currentSelectedModel = model;
|
||||
}
|
||||
[modelArray addObject:model];
|
||||
}
|
||||
_models = modelArray.copy;
|
||||
}
|
||||
return _models;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditClippingToolBarHeader ()
|
||||
@property (strong, nonatomic) UIButton *rotateBtn;
|
||||
@property (strong, nonatomic) UIButton *mirrorHorizontallyBtn;
|
||||
@property (strong, nonatomic) UIView *lineView;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditClippingToolBarHeader
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.rotateBtn];
|
||||
[self addSubview:self.mirrorHorizontallyBtn];
|
||||
[self addSubview:self.lineView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)setEnableRotaio:(BOOL)enableRotaio {
|
||||
_enableRotaio = enableRotaio;
|
||||
self.lineView.hidden = !enableRotaio;
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
self.rotateBtn.hx_centerY = self.hx_h / 2;
|
||||
self.rotateBtn.hx_x = 20;
|
||||
|
||||
self.mirrorHorizontallyBtn.hx_x = CGRectGetMaxX(self.rotateBtn.frame) + 10;
|
||||
self.mirrorHorizontallyBtn.hx_centerY = self.rotateBtn.hx_centerY;
|
||||
|
||||
self.lineView.hx_x = self.hx_w - 2;
|
||||
self.lineView.hx_centerY = self.hx_h / 2;
|
||||
}
|
||||
|
||||
- (UIButton *)rotateBtn {
|
||||
if (!_rotateBtn) {
|
||||
_rotateBtn = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[_rotateBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_clip_rotate"] forState:UIControlStateNormal];
|
||||
_rotateBtn.hx_size = _rotateBtn.currentImage.size;
|
||||
_rotateBtn.tintColor = [UIColor whiteColor];
|
||||
[_rotateBtn addTarget:self action:@selector(didRotateBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_rotateBtn hx_setEnlargeEdgeWithTop:5 right:5 bottom:5 left:5];
|
||||
}
|
||||
return _rotateBtn;
|
||||
}
|
||||
- (void)didRotateBtnClick:(UIButton *)button {
|
||||
if (self.didRotateBlock) {
|
||||
self.didRotateBlock();
|
||||
}
|
||||
}
|
||||
- (UIButton *)mirrorHorizontallyBtn {
|
||||
if (!_mirrorHorizontallyBtn) {
|
||||
_mirrorHorizontallyBtn = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[_mirrorHorizontallyBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_clip_mirror_horizontally"] forState:UIControlStateNormal];
|
||||
_mirrorHorizontallyBtn.hx_size = _rotateBtn.currentImage.size;
|
||||
_mirrorHorizontallyBtn.tintColor = [UIColor whiteColor];
|
||||
[_mirrorHorizontallyBtn addTarget:self action:@selector(didMirrorHorizontallyBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_mirrorHorizontallyBtn hx_setEnlargeEdgeWithTop:5 right:5 bottom:5 left:5];
|
||||
}
|
||||
return _mirrorHorizontallyBtn;
|
||||
}
|
||||
- (void)didMirrorHorizontallyBtnClick:(UIButton *)button {
|
||||
if (self.didMirrorHorizontallyBlock) {
|
||||
self.didMirrorHorizontallyBlock();
|
||||
}
|
||||
}
|
||||
- (UIView *)lineView {
|
||||
if (!_lineView) {
|
||||
_lineView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 2, 20)];
|
||||
_lineView.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
return _lineView;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface HXPhotoEditClippingToolBarHeaderViewCell ()
|
||||
@property (strong, nonatomic) UIImageView *scaleImageView;
|
||||
@property (strong, nonatomic) UIView *scaleView;
|
||||
@property (strong, nonatomic) UILabel *scaleLb;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditClippingToolBarHeaderViewCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self.contentView addSubview:self.scaleView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)setModel:(HXPhotoEditClippingToolBarRotaioModel *)model {
|
||||
_model = model;
|
||||
[self setSubviewFrame];
|
||||
self.scaleLb.text = model.scaleText;
|
||||
if (!model.widthRatio) {
|
||||
self.scaleView.layer.borderWidth = 0.f;
|
||||
self.scaleImageView.hidden = NO;
|
||||
}else {
|
||||
self.scaleView.layer.borderWidth = 1.25f;
|
||||
self.scaleImageView.hidden = YES;
|
||||
}
|
||||
if (model.isSelected) {
|
||||
self.scaleImageView.tintColor = self.themeColor;
|
||||
self.scaleView.layer.borderColor = self.themeColor.CGColor;
|
||||
self.scaleLb.textColor = self.themeColor;
|
||||
}else {
|
||||
self.scaleImageView.tintColor = UIColor.whiteColor;
|
||||
self.scaleView.layer.borderColor = UIColor.whiteColor.CGColor;
|
||||
self.scaleLb.textColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
- (void)setSubviewFrame {
|
||||
self.scaleView.hx_size = self.model.size;
|
||||
self.scaleView.center = CGPointMake(self.model.scaleSize.width / 2, self.model.scaleSize.height / 2);
|
||||
self.scaleLb.frame = CGRectMake(1.5, 1.5, self.scaleView.hx_w - 3, self.scaleView.hx_h - 3);
|
||||
self.scaleImageView.frame = self.scaleView.bounds;
|
||||
if (HX_IOS11_Earlier) {
|
||||
[self.scaleView hx_radiusWithRadius:2 corner:UIRectCornerAllCorners];
|
||||
}
|
||||
}
|
||||
- (UIView *)scaleView {
|
||||
if (!_scaleView) {
|
||||
_scaleView = [[UIView alloc] init];
|
||||
if (HX_IOS11_Later) {
|
||||
[_scaleView hx_radiusWithRadius:2 corner:UIRectCornerAllCorners];
|
||||
}
|
||||
[_scaleView addSubview:self.scaleImageView];
|
||||
[_scaleView addSubview:self.scaleLb];
|
||||
}
|
||||
return _scaleView;
|
||||
}
|
||||
- (UIImageView *)scaleImageView {
|
||||
if (!_scaleImageView) {
|
||||
_scaleImageView = [[UIImageView alloc] initWithImage:[[UIImage hx_imageContentsOfFile:@"hx_photo_edit_clip_free"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
|
||||
}
|
||||
return _scaleImageView;
|
||||
}
|
||||
- (UILabel *)scaleLb {
|
||||
if (!_scaleLb) {
|
||||
_scaleLb = [[UILabel alloc] init];
|
||||
_scaleLb.textColor = [UIColor whiteColor];
|
||||
_scaleLb.textAlignment = NSTextAlignmentCenter;
|
||||
_scaleLb.font = [UIFont hx_mediumHelveticaNeueOfSize:12];
|
||||
}
|
||||
return _scaleLb;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditClippingToolBarRotaioModel
|
||||
- (NSString *)scaleText {
|
||||
if (!self.widthRatio) {
|
||||
return [NSBundle hx_localizedStringForKey:@"自由"];
|
||||
}else {
|
||||
return [NSString stringWithFormat:@"%ld:%ld", (NSInteger)self.widthRatio, (NSInteger)self.heightRatio];
|
||||
}
|
||||
}
|
||||
@end
|
40
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditDrawView.h
generated
Normal file
40
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditDrawView.h
generated
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// HXPhotoEditDrawView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/23.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditDrawView : UIView
|
||||
|
||||
@property (assign, nonatomic) CGFloat lineWidth;
|
||||
@property (strong, nonatomic) UIColor *lineColor;
|
||||
@property (copy, nonatomic) void (^ beganDraw)(void);
|
||||
@property (copy, nonatomic) void (^ endDraw)(void);
|
||||
|
||||
/** 正在绘画 */
|
||||
@property (nonatomic, readonly) BOOL isDrawing;
|
||||
/** 图层数量 */
|
||||
@property (nonatomic, readonly) NSUInteger count;
|
||||
/// 显示界面的缩放率
|
||||
@property (nonatomic, assign) CGFloat screenScale;
|
||||
|
||||
@property (assign, nonatomic) BOOL enabled;
|
||||
|
||||
/** 数据 */
|
||||
@property (nonatomic, strong, nullable) NSDictionary *data;
|
||||
|
||||
/// 是否可以撤销
|
||||
- (BOOL)canUndo;
|
||||
|
||||
/// 撤销
|
||||
- (void)undo;
|
||||
- (void)clearCoverage;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
176
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditDrawView.m
generated
Normal file
176
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditDrawView.m
generated
Normal file
|
@ -0,0 +1,176 @@
|
|||
//
|
||||
// HXPhotoEditDrawView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/23.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditDrawView.h"
|
||||
|
||||
NSString *const kHXDrawViewData = @"HXDrawViewData";
|
||||
|
||||
@interface HXDrawBezierPath : UIBezierPath
|
||||
@property (strong, nonatomic) UIColor *color;
|
||||
@end
|
||||
|
||||
@implementation HXDrawBezierPath
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditDrawView ()
|
||||
/// 笔画
|
||||
@property (strong, nonatomic) NSMutableArray <HXDrawBezierPath *>*lineArray;
|
||||
/// 图层
|
||||
@property (strong, nonatomic) NSMutableArray <CAShapeLayer *>*slayerArray;
|
||||
@property (assign, nonatomic) BOOL isWork;
|
||||
@property (assign, nonatomic) BOOL isBegan;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditDrawView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.lineWidth = 5.f;
|
||||
self.lineColor = [UIColor whiteColor];
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.clipsToBounds = YES;
|
||||
self.exclusiveTouch = YES;
|
||||
self.lineArray = @[].mutableCopy;
|
||||
self.slayerArray = @[].mutableCopy;
|
||||
self.enabled = YES;
|
||||
self.screenScale = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (CAShapeLayer *)createShapeLayer:(HXDrawBezierPath *)path {
|
||||
CAShapeLayer *slayer = [CAShapeLayer layer];
|
||||
slayer.path = path.CGPath;
|
||||
slayer.backgroundColor = [UIColor clearColor].CGColor;
|
||||
slayer.fillColor = [UIColor clearColor].CGColor;
|
||||
slayer.lineCap = kCALineCapRound;
|
||||
slayer.lineJoin = kCALineJoinRound;
|
||||
slayer.strokeColor = path.color.CGColor;
|
||||
slayer.lineWidth = path.lineWidth;
|
||||
return slayer;
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||||
if ([event allTouches].count == 1 && self.enabled) {
|
||||
self.isWork = NO;
|
||||
self.isBegan = YES;
|
||||
HXDrawBezierPath *path = [[HXDrawBezierPath alloc] init];
|
||||
UITouch *touch = [touches anyObject];
|
||||
CGPoint point = [touch locationInView:self];
|
||||
path.lineWidth = self.lineWidth;
|
||||
path.lineCapStyle = kCGLineCapRound;
|
||||
path.lineJoinStyle = kCGLineJoinRound;
|
||||
[path moveToPoint:point];
|
||||
path.color = self.lineColor;
|
||||
[self.lineArray addObject:path];
|
||||
|
||||
CAShapeLayer *slayer = [self createShapeLayer:path];
|
||||
[self.layer addSublayer:slayer];
|
||||
[self.slayerArray addObject:slayer];
|
||||
} else {
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||||
if ([event allTouches].count == 1 && self.enabled){
|
||||
UITouch *touch = [touches anyObject];
|
||||
CGPoint point = [touch locationInView:self];
|
||||
HXDrawBezierPath *path = self.lineArray.lastObject;
|
||||
if (!CGPointEqualToPoint(path.currentPoint, point)) {
|
||||
if (self.beganDraw) {
|
||||
self.beganDraw();
|
||||
}
|
||||
self.isBegan = NO;
|
||||
self.isWork = YES;
|
||||
[path addLineToPoint:point];
|
||||
CAShapeLayer *slayer = self.slayerArray.lastObject;
|
||||
slayer.path = path.CGPath;
|
||||
}
|
||||
} else {
|
||||
[super touchesMoved:touches withEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event {
|
||||
if ([event allTouches].count == 1 && self.enabled){
|
||||
if (self.isWork) {
|
||||
if (self.endDraw) {
|
||||
self.endDraw();
|
||||
}
|
||||
} else {
|
||||
[self undo];
|
||||
}
|
||||
} else {
|
||||
[super touchesEnded:touches withEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
|
||||
if ([event allTouches].count == 1 && self.enabled){
|
||||
if (self.isWork) {
|
||||
if (self.endDraw) {
|
||||
self.endDraw();
|
||||
}
|
||||
} else {
|
||||
[self undo];
|
||||
}
|
||||
} else {
|
||||
[super touchesCancelled:touches withEvent:event];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)enabled {
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
- (BOOL)canUndo {
|
||||
return self.lineArray.count;
|
||||
}
|
||||
|
||||
- (void)undo {
|
||||
[self.slayerArray.lastObject removeFromSuperlayer];
|
||||
[self.slayerArray removeLastObject];
|
||||
[self.lineArray removeLastObject];
|
||||
}
|
||||
- (BOOL)isDrawing {
|
||||
if (!self.userInteractionEnabled || !self.enabled) {
|
||||
return NO;
|
||||
}
|
||||
return _isWork;
|
||||
}
|
||||
/** 图层数量 */
|
||||
- (NSUInteger)count {
|
||||
return self.lineArray.count;
|
||||
}
|
||||
|
||||
- (void)clearCoverage {
|
||||
[self.lineArray removeAllObjects];
|
||||
[self.slayerArray performSelector:@selector(removeFromSuperlayer)];
|
||||
[self.slayerArray removeAllObjects];
|
||||
}
|
||||
#pragma mark - 数据
|
||||
- (NSDictionary *)data {
|
||||
if (self.lineArray.count) {
|
||||
return @{kHXDrawViewData:[self.lineArray copy]};
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setData:(NSDictionary *)data {
|
||||
NSArray *lineArray = data[kHXDrawViewData];
|
||||
if (lineArray.count) {
|
||||
for (HXDrawBezierPath *path in lineArray) {
|
||||
CAShapeLayer *slayer = [self createShapeLayer:path];
|
||||
[self.layer addSublayer:slayer];
|
||||
[self.slayerArray addObject:slayer];
|
||||
}
|
||||
[self.lineArray addObjectsFromArray:lineArray];
|
||||
}
|
||||
}
|
||||
@end
|
22
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorSizeView.h
generated
Normal file
22
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorSizeView.h
generated
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorSizeView.h
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2020/8/14.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditGraffitiColorSizeView : UIView
|
||||
@property (assign, nonatomic) CGFloat scale;
|
||||
|
||||
@property (copy, nonatomic) void (^ changeColorSize)(CGFloat scale);
|
||||
|
||||
+ (instancetype)initView;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
70
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorSizeView.m
generated
Normal file
70
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorSizeView.m
generated
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorSizeView.m
|
||||
// HXPhotoPickerExample
|
||||
//
|
||||
// Created by Silence on 2020/8/14.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGraffitiColorSizeView.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPreviewVideoView.h"
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
|
||||
@interface HXPhotoEditGraffitiColorSizeView ()
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *indicatorView;
|
||||
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *indicatorViewCenterYConstraint;
|
||||
@property (assign, nonatomic) CGFloat indicatorCenterY;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditGraffitiColorSizeView
|
||||
|
||||
+ (instancetype)initView {
|
||||
return [[[NSBundle hx_photoPickerBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
if (CGRectContainsPoint(CGRectMake(self.indicatorView.hx_x - 10, self.indicatorView.hx_y - 10, self.indicatorView.hx_w + 20, self.indicatorView.hx_h + 20), point)) {
|
||||
return self.indicatorView;
|
||||
}
|
||||
return [super hitTest:point withEvent:event];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.scale = 0.5f;
|
||||
self.imageView.image = [UIImage hx_imageContentsOfFile:@"hx_photo_edit_graffiti_size_backgroud"];
|
||||
[self.indicatorView hx_radiusWithRadius:10.f corner:UIRectCornerAllCorners];
|
||||
self.indicatorView.layer.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.6f].CGColor;
|
||||
self.indicatorView.layer.shadowOpacity = 0.56f;
|
||||
self.indicatorView.layer.shadowRadius = 10.f;
|
||||
|
||||
HXPanGestureRecognizer *panGesture = [[HXPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognizerClick:)];
|
||||
|
||||
[self.indicatorView addGestureRecognizer:panGesture];
|
||||
}
|
||||
|
||||
- (void)panGestureRecognizerClick:(UIPanGestureRecognizer *)panGesture {
|
||||
CGPoint point = [panGesture translationInView:self];
|
||||
if (panGesture.state == UIGestureRecognizerStateBegan) {
|
||||
self.indicatorCenterY = self.indicatorViewCenterYConstraint.constant;
|
||||
}
|
||||
CGFloat centerY = self.indicatorCenterY + point.y;
|
||||
if (centerY < -(self.hx_h / 2)) {
|
||||
centerY = -(self.hx_h / 2);
|
||||
}else if (centerY > self.hx_h / 2) {
|
||||
centerY = self.hx_h / 2;
|
||||
}
|
||||
|
||||
self.indicatorViewCenterYConstraint.constant = centerY;
|
||||
|
||||
CGFloat scale = 1 - self.indicatorView.hx_centerY / self.hx_h;
|
||||
self.scale = scale;
|
||||
if (self.changeColorSize) {
|
||||
self.changeColorSize(scale);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
22
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorView.h
generated
Normal file
22
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorView.h
generated
Normal file
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/20.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditGraffitiColorView : UIView
|
||||
@property (copy, nonatomic) NSArray<UIColor *> *drawColors;
|
||||
@property (assign, nonatomic) NSInteger defaultDarwColorIndex;
|
||||
@property (copy, nonatomic) void (^ selectColorBlock)(UIColor *color);
|
||||
@property (copy, nonatomic) void (^ undoBlock)(void);
|
||||
@property (assign, nonatomic) BOOL undo;
|
||||
+ (instancetype)initView;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
92
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorView.m
generated
Normal file
92
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorView.m
generated
Normal file
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/20.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGraffitiColorView.h"
|
||||
#import "HXPhotoEditGraffitiColorViewCell.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
|
||||
@interface HXPhotoEditGraffitiColorView ()<UICollectionViewDataSource, UICollectionViewDelegate>
|
||||
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
|
||||
@property (weak, nonatomic) IBOutlet UICollectionViewFlowLayout *flowLayout;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *repealBtn;
|
||||
@property (strong, nonatomic) NSMutableArray *colorModels;
|
||||
@property (strong, nonatomic) HXPhotoEditGraffitiColorModel *currentSelectModel;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditGraffitiColorView
|
||||
|
||||
+ (instancetype)initView {
|
||||
return [[[NSBundle hx_photoPickerBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.repealBtn.enabled = NO;
|
||||
|
||||
self.flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
self.flowLayout.sectionInset = UIEdgeInsetsMake(0, 15, 0, 0);
|
||||
self.flowLayout.minimumInteritemSpacing = 5;
|
||||
self.flowLayout.itemSize = CGSizeMake(37.f, 37.f);
|
||||
|
||||
[self.repealBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_repeal"] forState:UIControlStateNormal];
|
||||
|
||||
self.collectionView.dataSource = self;
|
||||
self.collectionView.delegate = self;
|
||||
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([HXPhotoEditGraffitiColorViewCell class]) bundle:[NSBundle hx_photoPickerBundle]] forCellWithReuseIdentifier:NSStringFromClass([HXPhotoEditGraffitiColorViewCell class])];
|
||||
}
|
||||
- (void)setUndo:(BOOL)undo {
|
||||
_undo = undo;
|
||||
self.repealBtn.enabled = undo;
|
||||
}
|
||||
- (void)setDrawColors:(NSArray<UIColor *> *)drawColors {
|
||||
_drawColors = drawColors;
|
||||
self.colorModels = @[].mutableCopy;
|
||||
for (UIColor *color in drawColors) {
|
||||
HXPhotoEditGraffitiColorModel *model = [[HXPhotoEditGraffitiColorModel alloc] init];
|
||||
model.color = color;
|
||||
[self.colorModels addObject:model];
|
||||
if (self.colorModels.count == self.defaultDarwColorIndex + 1) {
|
||||
model.selected = YES;
|
||||
self.currentSelectModel = model;
|
||||
}
|
||||
}
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.colorModels.count;
|
||||
}
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HXPhotoEditGraffitiColorViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([HXPhotoEditGraffitiColorViewCell class]) forIndexPath:indexPath];
|
||||
cell.model = self.colorModels[indexPath.item];
|
||||
return cell;
|
||||
}
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
HXPhotoEditGraffitiColorModel *model = self.colorModels[indexPath.item];
|
||||
if (self.currentSelectModel == model) {
|
||||
return;
|
||||
}
|
||||
if (self.currentSelectModel.selected) {
|
||||
self.currentSelectModel.selected = NO;
|
||||
HXPhotoEditGraffitiColorViewCell *beforeCell = (HXPhotoEditGraffitiColorViewCell *)[collectionView cellForItemAtIndexPath:[NSIndexPath indexPathForItem:[self.colorModels indexOfObject:self.currentSelectModel] inSection:0]];
|
||||
[beforeCell setSelected:NO];
|
||||
}
|
||||
model.selected = YES;
|
||||
self.currentSelectModel = model;
|
||||
if (self.selectColorBlock) {
|
||||
self.selectColorBlock(model.color);
|
||||
}
|
||||
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
|
||||
}
|
||||
- (IBAction)didRepealBtnClick:(id)sender {
|
||||
if (self.undoBlock) {
|
||||
self.undoBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorViewCell.h
generated
Normal file
18
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorViewCell.h
generated
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorViewCell.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/22.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoEditGraffitiColorModel.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditGraffitiColorViewCell : UICollectionViewCell
|
||||
@property (strong, nonatomic) HXPhotoEditGraffitiColorModel *model;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
55
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorViewCell.m
generated
Normal file
55
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGraffitiColorViewCell.m
generated
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// HXPhotoEditGraffitiColorViewCell.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/22.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGraffitiColorViewCell.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "UIColor+HXExtension.h"
|
||||
|
||||
@interface HXPhotoEditGraffitiColorViewCell ()
|
||||
@property (weak, nonatomic) IBOutlet UIView *colorView;
|
||||
@property (weak, nonatomic) IBOutlet UIView *colorCenterView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditGraffitiColorViewCell
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
// Initialization code
|
||||
|
||||
self.colorView.backgroundColor = [UIColor whiteColor];
|
||||
[self.colorView hx_radiusWithRadius:11.f corner:UIRectCornerAllCorners];
|
||||
[self.colorCenterView hx_radiusWithRadius:16.f / 2.f corner:UIRectCornerAllCorners];
|
||||
}
|
||||
|
||||
- (void)setModel:(HXPhotoEditGraffitiColorModel *)model {
|
||||
_model = model;
|
||||
if ([model.color hx_colorIsWhite]) {
|
||||
self.colorView.backgroundColor = [UIColor hx_colorWithHexStr:@"#dadada"];
|
||||
}else {
|
||||
self.colorView.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
self.colorCenterView.backgroundColor = model.color;
|
||||
[self setupColor];
|
||||
}
|
||||
- (void)setupColor {
|
||||
if (self.model.selected) {
|
||||
self.colorView.transform = CGAffineTransformMakeScale(1.2, 1.2);
|
||||
}else {
|
||||
self.colorView.transform = CGAffineTransformIdentity;
|
||||
}
|
||||
}
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
self.model.selected = selected;
|
||||
[UIView animateWithDuration:0.2 animations:^{
|
||||
[self setupColor];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
23
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridLayer.h
generated
Normal file
23
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridLayer.h
generated
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// HXPhotoEditGridLayer.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditGridLayer : CAShapeLayer
|
||||
|
||||
@property (nonatomic, assign) CGRect gridRect;
|
||||
- (void)setGridRect:(CGRect)gridRect animated:(BOOL)animated;
|
||||
- (void)setGridRect:(CGRect)gridRect animated:(BOOL)animated completion:(void (^ _Nullable)(BOOL finished))completion;
|
||||
@property (nonatomic, assign) BOOL isRound;
|
||||
@property (nonatomic, strong) UIColor *bgColor;
|
||||
@property (nonatomic, strong) UIColor *gridColor;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
239
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridLayer.m
generated
Normal file
239
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridLayer.m
generated
Normal file
|
@ -0,0 +1,239 @@
|
|||
//
|
||||
// HXPhotoEditGridLayer.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGridLayer.h"
|
||||
|
||||
NSString *const hxGridLayerAnimtionKey = @"hxGridLayerAnimtionKey";
|
||||
|
||||
@interface HXPhotoEditGridLayer ()<CAAnimationDelegate>
|
||||
@property (weak, nonatomic) CAShapeLayer *topLeftCornerLayer;
|
||||
@property (weak, nonatomic) CAShapeLayer *topRightCornerLayer;
|
||||
@property (weak, nonatomic) CAShapeLayer *bottomLeftCornerLayer;
|
||||
@property (weak, nonatomic) CAShapeLayer *bottomRightCornerLayer;
|
||||
@property (weak, nonatomic) CAShapeLayer *middleLineLayer;
|
||||
@property (nonatomic, copy) void (^callback)(BOOL finished);
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditGridLayer
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
CAShapeLayer *topLeftCornerLayer = [self creatLayer:NO];
|
||||
CAShapeLayer *topRightCornerLayer = [self creatLayer:NO];
|
||||
CAShapeLayer *bottomLeftCornerLayer = [self creatLayer:NO];
|
||||
CAShapeLayer *bottomRightCornerLayer = [self creatLayer:NO];
|
||||
CAShapeLayer *middleLineLayer = [self creatLayer:YES];
|
||||
[self addSublayer:topLeftCornerLayer];
|
||||
[self addSublayer:topRightCornerLayer];
|
||||
[self addSublayer:bottomLeftCornerLayer];
|
||||
[self addSublayer:bottomRightCornerLayer];
|
||||
[self addSublayer:middleLineLayer];
|
||||
self.topLeftCornerLayer = topLeftCornerLayer;
|
||||
self.topRightCornerLayer = topRightCornerLayer;
|
||||
self.bottomLeftCornerLayer = bottomLeftCornerLayer;
|
||||
self.bottomRightCornerLayer = bottomRightCornerLayer;
|
||||
self.middleLineLayer = middleLineLayer;
|
||||
self.contentsScale = [[UIScreen mainScreen] scale];
|
||||
_bgColor = [UIColor clearColor];
|
||||
_gridColor = [UIColor blackColor];
|
||||
self.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.6].CGColor;
|
||||
self.shadowRadius = 2.f;
|
||||
self.shadowOffset = CGSizeZero;
|
||||
self.shadowOpacity = .5f;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (CAShapeLayer *)creatLayer:(BOOL)shadow {
|
||||
CAShapeLayer *layer = [CAShapeLayer layer];
|
||||
layer.contentsScale = [[UIScreen mainScreen] scale];
|
||||
if (shadow) {
|
||||
layer.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.4].CGColor;
|
||||
layer.shadowRadius = 1.f;
|
||||
layer.shadowOffset = CGSizeZero;
|
||||
layer.shadowOpacity = .4f;
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
- (void)setIsRound:(BOOL)isRound {
|
||||
_isRound = isRound;
|
||||
if (isRound) {
|
||||
[self.topLeftCornerLayer removeFromSuperlayer];
|
||||
[self.topRightCornerLayer removeFromSuperlayer];
|
||||
[self.bottomLeftCornerLayer removeFromSuperlayer];
|
||||
[self.bottomRightCornerLayer removeFromSuperlayer];
|
||||
[self.middleLineLayer removeFromSuperlayer];
|
||||
}
|
||||
}
|
||||
- (void)setGridRect:(CGRect)gridRect {
|
||||
[self setGridRect:gridRect animated:NO];
|
||||
}
|
||||
|
||||
- (void)setGridRect:(CGRect)gridRect animated:(BOOL)animated {
|
||||
[self setGridRect:gridRect animated:animated completion:nil];
|
||||
}
|
||||
- (void)setGridRect:(CGRect)gridRect animated:(BOOL)animated completion:(void (^)(BOOL finished))completion {
|
||||
_gridRect = gridRect;
|
||||
if (completion) {
|
||||
self.callback = completion;
|
||||
}
|
||||
|
||||
CGPathRef path = [self drawGrid];
|
||||
if (animated) {
|
||||
if (!self.isRound) {
|
||||
[self setMiddleLine];
|
||||
[self setAllCorner:UIRectCornerTopLeft];
|
||||
[self setAllCorner:UIRectCornerTopRight];
|
||||
[self setAllCorner:UIRectCornerBottomLeft];
|
||||
[self setAllCorner:UIRectCornerBottomRight];
|
||||
}
|
||||
CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"path"];
|
||||
animate.duration = 0.25f;
|
||||
animate.fromValue = (__bridge id _Nullable)(self.path);
|
||||
animate.toValue = (__bridge id _Nullable)(path);
|
||||
animate.removedOnCompletion = NO;
|
||||
animate.delegate = self;
|
||||
self.path = path;
|
||||
[self addAnimation:animate forKey:hxGridLayerAnimtionKey];
|
||||
|
||||
} else {
|
||||
if (!self.isRound) {
|
||||
self.topLeftCornerLayer.path = [self setAllCornerPath:UIRectCornerTopLeft].CGPath;
|
||||
self.topRightCornerLayer.path = [self setAllCornerPath:UIRectCornerTopRight].CGPath;
|
||||
self.bottomLeftCornerLayer.path = [self setAllCornerPath:UIRectCornerBottomLeft].CGPath;
|
||||
self.bottomRightCornerLayer.path = [self setAllCornerPath:UIRectCornerBottomRight].CGPath;
|
||||
self.middleLineLayer.path = [self setMiddleLinePath].CGPath;
|
||||
}
|
||||
self.path = path;
|
||||
if (self.callback) {
|
||||
self.callback(YES);
|
||||
self.callback = nil;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
|
||||
if ([self animationForKey:hxGridLayerAnimtionKey] == anim) {
|
||||
if (self.callback) {
|
||||
self.callback(flag);
|
||||
self.callback = nil;
|
||||
}
|
||||
[self removeAnimationForKey:hxGridLayerAnimtionKey];
|
||||
}
|
||||
}
|
||||
- (UIBezierPath *)setAllCornerPath:(UIRectCorner)rectConrner {
|
||||
CGFloat lineWidth = 3.f;
|
||||
CGFloat length = 20.f;
|
||||
CGFloat margin = lineWidth / 2.f - 0.2f;
|
||||
CGRect rct = self.gridRect;
|
||||
UIBezierPath *path = [UIBezierPath bezierPath];
|
||||
if (rectConrner == UIRectCornerTopLeft) {
|
||||
[path moveToPoint:CGPointMake(rct.origin.x + length, rct.origin.y - lineWidth / 2)];
|
||||
[path addLineToPoint:CGPointMake(rct.origin.x - margin, rct.origin.y - margin)];
|
||||
[path addLineToPoint:CGPointMake(rct.origin.x - margin, rct.origin.y + length)];
|
||||
}else if (rectConrner == UIRectCornerTopRight) {
|
||||
[path moveToPoint:CGPointMake(CGRectGetMaxX(rct) - length, rct.origin.y - margin)];
|
||||
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rct) + margin, rct.origin.y - margin)];
|
||||
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rct) + margin, rct.origin.y + length)];
|
||||
}else if (rectConrner == UIRectCornerBottomLeft) {
|
||||
[path moveToPoint:CGPointMake(rct.origin.x - margin, CGRectGetMaxY(rct) - length)];
|
||||
[path addLineToPoint:CGPointMake(rct.origin.x - margin, CGRectGetMaxY(rct) + margin)];
|
||||
[path addLineToPoint:CGPointMake(rct.origin.x + length, CGRectGetMaxY(rct) + margin)];
|
||||
}else if (rectConrner == UIRectCornerBottomRight) {
|
||||
[path moveToPoint:CGPointMake(CGRectGetMaxX(rct) - length, CGRectGetMaxY(rct) + margin)];
|
||||
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rct) + margin, CGRectGetMaxY(rct) + margin)];
|
||||
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rct) + margin, CGRectGetMaxY(rct) - length)];
|
||||
}
|
||||
return path;
|
||||
}
|
||||
- (CAAnimation *)setAllCorner:(UIRectCorner)rectConrner {
|
||||
CGFloat lineWidth = 2;
|
||||
UIBezierPath *path = [self setAllCornerPath:rectConrner];
|
||||
CAShapeLayer *layer;
|
||||
if (rectConrner == UIRectCornerTopLeft) {
|
||||
layer = self.topLeftCornerLayer;
|
||||
}else if (rectConrner == UIRectCornerTopRight) {
|
||||
layer = self.topRightCornerLayer;
|
||||
}else if (rectConrner == UIRectCornerBottomLeft) {
|
||||
layer = self.bottomLeftCornerLayer;
|
||||
}else if (rectConrner == UIRectCornerBottomRight) {
|
||||
layer = self.bottomRightCornerLayer;
|
||||
}
|
||||
layer.fillColor = self.bgColor.CGColor;
|
||||
layer.strokeColor = self.gridColor.CGColor;
|
||||
layer.lineWidth = lineWidth;
|
||||
|
||||
CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"path"];
|
||||
animate.duration = 0.25f;
|
||||
animate.fromValue = (__bridge id _Nullable)(layer.path);
|
||||
animate.toValue = (__bridge id _Nullable)(path.CGPath);
|
||||
animate.removedOnCompletion = NO;
|
||||
layer.path = path.CGPath;
|
||||
[layer addAnimation:animate forKey:nil];
|
||||
return animate;
|
||||
}
|
||||
- (UIBezierPath *)setMiddleLinePath {
|
||||
CGRect rct = self.gridRect;
|
||||
CGFloat widthMargin = rct.size.width / 3;
|
||||
CGFloat heightMargin = rct.size.height / 3;
|
||||
UIBezierPath *path = [UIBezierPath bezierPath];
|
||||
[path moveToPoint:CGPointMake(rct.origin.x, rct.origin.y + heightMargin)];
|
||||
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rct), rct.origin.y + heightMargin)];
|
||||
|
||||
[path moveToPoint:CGPointMake(rct.origin.x, rct.origin.y + heightMargin * 2)];
|
||||
[path addLineToPoint:CGPointMake(CGRectGetMaxX(rct), rct.origin.y + heightMargin * 2)];
|
||||
|
||||
[path moveToPoint:CGPointMake(rct.origin.x + widthMargin, rct.origin.y)];
|
||||
[path addLineToPoint:CGPointMake(rct.origin.x + widthMargin, CGRectGetMaxY(rct))];
|
||||
|
||||
[path moveToPoint:CGPointMake(rct.origin.x + widthMargin * 2, rct.origin.y)];
|
||||
[path addLineToPoint:CGPointMake(rct.origin.x + widthMargin * 2, CGRectGetMaxY(rct))];
|
||||
return path;
|
||||
}
|
||||
- (CAAnimation *)setMiddleLine {
|
||||
self.middleLineLayer.fillColor = self.bgColor.CGColor;
|
||||
self.middleLineLayer.strokeColor = self.gridColor.CGColor;
|
||||
self.middleLineLayer.lineWidth = 0.5f;
|
||||
UIBezierPath *path = [self setMiddleLinePath];
|
||||
|
||||
CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"path"];
|
||||
animate.duration = 0.25f;
|
||||
animate.fromValue = (__bridge id _Nullable)(self.middleLineLayer.path);
|
||||
animate.toValue = (__bridge id _Nullable)(path.CGPath);
|
||||
animate.removedOnCompletion = NO;
|
||||
self.middleLineLayer.path = path.CGPath;
|
||||
|
||||
[self.middleLineLayer addAnimation:animate forKey:nil];
|
||||
return animate;
|
||||
}
|
||||
|
||||
- (CGPathRef)drawGrid {
|
||||
self.fillColor = self.bgColor.CGColor;
|
||||
self.strokeColor = self.gridColor.CGColor;
|
||||
self.lineWidth = 1;
|
||||
// self.borderWidth = 1.5f;
|
||||
CGRect rct = self.gridRect;
|
||||
UIBezierPath *path;
|
||||
if (self.isRound) {
|
||||
path = [UIBezierPath bezierPathWithRoundedRect:rct cornerRadius:rct.size.width / 2.f];
|
||||
}else {
|
||||
path = [UIBezierPath bezierPathWithRect:rct];
|
||||
}
|
||||
return path.CGPath;
|
||||
}
|
||||
- (void)layoutSublayers {
|
||||
[super layoutSublayers];
|
||||
|
||||
self.topLeftCornerLayer.frame = self.frame;
|
||||
self.topRightCornerLayer.frame = self.frame;
|
||||
self.bottomLeftCornerLayer.frame = self.frame;
|
||||
self.bottomRightCornerLayer.frame = self.frame;
|
||||
self.middleLineLayer.frame = self.frame;
|
||||
}
|
||||
@end
|
26
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridMaskLayer.h
generated
Normal file
26
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridMaskLayer.h
generated
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// HXPhotoEditGridMaskLayer.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditGridMaskLayer : CAShapeLayer
|
||||
|
||||
/** 遮罩颜色 */
|
||||
@property (nonatomic, assign) CGColorRef maskColor;
|
||||
@property (nonatomic, assign) BOOL isRound;
|
||||
/** 遮罩范围 */
|
||||
@property (nonatomic, assign, setter=setMaskRect:) CGRect maskRect;
|
||||
- (void)setMaskRect:(CGRect)maskRect animated:(BOOL)animated;
|
||||
/** 取消遮罩 */
|
||||
- (void)clearMask;
|
||||
- (void)clearMaskWithAnimated:(BOOL)animated;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
88
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridMaskLayer.m
generated
Normal file
88
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridMaskLayer.m
generated
Normal file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// HXPhotoEditGridMaskLayer.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGridMaskLayer.h"
|
||||
|
||||
@implementation HXPhotoEditGridMaskLayer
|
||||
@synthesize maskColor = _maskColor;
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
[self customInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)customInit {
|
||||
self.contentsScale = [[UIScreen mainScreen] scale];
|
||||
}
|
||||
|
||||
- (void)setMaskColor:(CGColorRef)maskColor {
|
||||
self.fillColor = maskColor;
|
||||
self.fillRule = kCAFillRuleEvenOdd;
|
||||
}
|
||||
|
||||
- (CGColorRef)maskColor {
|
||||
return self.fillColor;
|
||||
}
|
||||
|
||||
- (void)setMaskRect:(CGRect)maskRect {
|
||||
[self setMaskRect:maskRect animated:NO];
|
||||
}
|
||||
|
||||
- (void)setMaskRect:(CGRect)maskRect animated:(BOOL)animated {
|
||||
_maskRect = maskRect;
|
||||
CGPathRef path = nil;
|
||||
if (CGRectEqualToRect(CGRectZero, maskRect)) {
|
||||
path = [self newDrawClearGrid];
|
||||
} else {
|
||||
path = [self newDrawGrid];
|
||||
}
|
||||
[self removeAnimationForKey:@"hx_maskLayer_opacityAnimate"];
|
||||
if (animated) {
|
||||
CABasicAnimation *animate = [CABasicAnimation animationWithKeyPath:@"opacity"];
|
||||
animate.duration = 0.25f;
|
||||
animate.fromValue = @(0.0);
|
||||
animate.toValue = @(1.0);
|
||||
self.path = path;
|
||||
[self addAnimation:animate forKey:@"hx_maskLayer_opacityAnimate"];
|
||||
} else {
|
||||
self.path = path;
|
||||
}
|
||||
CGPathRelease(path);
|
||||
}
|
||||
|
||||
- (void)clearMask {
|
||||
[self clearMaskWithAnimated:NO];
|
||||
}
|
||||
|
||||
- (void)clearMaskWithAnimated:(BOOL)animated {
|
||||
[self setMaskRect:CGRectZero animated:animated];
|
||||
|
||||
}
|
||||
|
||||
- (CGPathRef)newDrawGrid {
|
||||
CGRect maskRect = self.maskRect;
|
||||
CGMutablePathRef mPath = CGPathCreateMutable();
|
||||
CGPathAddRect(mPath, NULL, self.bounds);
|
||||
if (self.isRound) {
|
||||
CGPathAddRoundedRect(mPath, NULL, maskRect, maskRect.size.width / 2.f, maskRect.size.height / 2.f);
|
||||
}else {
|
||||
CGPathAddRect(mPath, NULL, maskRect);
|
||||
}
|
||||
return mPath;
|
||||
}
|
||||
|
||||
- (CGPathRef)newDrawClearGrid {
|
||||
CGMutablePathRef mPath = CGPathCreateMutable();
|
||||
CGPathAddRect(mPath, NULL, self.bounds);
|
||||
CGPathAddRect(mPath, NULL, self.bounds);
|
||||
return mPath;
|
||||
}
|
||||
@end
|
81
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridView.h
generated
Normal file
81
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridView.h
generated
Normal file
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// HXPhotoEditGridView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoEditGridLayer.h"
|
||||
#import "HXPhotoEditGridMaskLayer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXPhotoEditGridViewAspectRatioType) {
|
||||
HXPhotoEditGridViewAspectRatioType_None, // 不设置比例
|
||||
HXPhotoEditGridViewAspectRatioType_Original, // 原图比例
|
||||
HXPhotoEditGridViewAspectRatioType_1x1,
|
||||
HXPhotoEditGridViewAspectRatioType_3x2,
|
||||
HXPhotoEditGridViewAspectRatioType_4x3,
|
||||
HXPhotoEditGridViewAspectRatioType_5x3,
|
||||
HXPhotoEditGridViewAspectRatioType_15x9,
|
||||
HXPhotoEditGridViewAspectRatioType_16x9,
|
||||
HXPhotoEditGridViewAspectRatioType_16x10,
|
||||
HXPhotoEditGridViewAspectRatioType_Custom
|
||||
};
|
||||
@protocol HXPhotoEditGridViewDelegate;
|
||||
@interface HXPhotoEditGridView : UIView
|
||||
@property (nonatomic, assign) CGRect gridRect;
|
||||
@property (nonatomic, weak, readonly) HXPhotoEditGridMaskLayer *gridMaskLayer;
|
||||
- (void)setGridRect:(CGRect)gridRect animated:(BOOL)animated;
|
||||
- (void)setGridRect:(CGRect)gridRect maskLayer:(BOOL)isMaskLayer animated:(BOOL)animated;
|
||||
- (void)setGridRect:(CGRect)gridRect maskLayer:(BOOL)isMaskLayer animated:(BOOL)animated completion:(void (^ _Nullable)(BOOL finished))completion;
|
||||
/** 最小尺寸 CGSizeMake(80, 80); */
|
||||
@property (nonatomic, assign) CGSize controlMinSize;
|
||||
/** 最大尺寸 CGRectInset(self.bounds, 20, 20) */
|
||||
@property (nonatomic, assign) CGRect controlMaxRect;
|
||||
/** 原图尺寸 */
|
||||
@property (nonatomic, assign) CGSize controlSize;
|
||||
|
||||
/** 显示遮罩层(触发拖动条件必须设置为YES)default is YES */
|
||||
@property (nonatomic, assign) BOOL showMaskLayer;
|
||||
|
||||
/** 是否正在拖动 */
|
||||
@property(nonatomic,readonly,getter=isDragging) BOOL dragging;
|
||||
|
||||
/** 比例是否水平翻转 */
|
||||
@property (nonatomic, assign) BOOL aspectRatioHorizontally;
|
||||
/** 设置固定比例 */
|
||||
@property (nonatomic, assign) HXPhotoEditGridViewAspectRatioType aspectRatio;
|
||||
/// 自定义固定比例
|
||||
@property (assign, nonatomic) CGSize customRatioSize;
|
||||
- (void)setAspectRatio:(HXPhotoEditGridViewAspectRatioType)aspectRatio animated:(BOOL)animated;
|
||||
|
||||
- (void)setupAspectRatio:(HXPhotoEditGridViewAspectRatioType)aspectRatio;
|
||||
|
||||
@property (nonatomic, weak) id<HXPhotoEditGridViewDelegate> delegate;
|
||||
/** 遮罩颜色 */
|
||||
@property (nonatomic, assign) CGColorRef maskColor;
|
||||
@property (nonatomic, weak, readonly) HXPhotoEditGridLayer *gridLayer;
|
||||
|
||||
@property (nonatomic, assign) BOOL isRound;
|
||||
/** 长宽比例描述 */
|
||||
- (NSArray <NSString *>*)aspectRatioDescs;
|
||||
|
||||
- (void)setAspectRatioWithoutDelegate:(HXPhotoEditGridViewAspectRatioType)aspectRatio;;
|
||||
|
||||
- (void)changeSubviewFrame:(CGRect)frame;
|
||||
@end
|
||||
|
||||
@protocol HXPhotoEditGridViewDelegate <NSObject>
|
||||
|
||||
- (void)gridViewDidBeginResizing:(HXPhotoEditGridView *)gridView;
|
||||
- (void)gridViewDidResizing:(HXPhotoEditGridView *)gridView;
|
||||
- (void)gridViewDidEndResizing:(HXPhotoEditGridView *)gridView;
|
||||
|
||||
/** 调整长宽比例 */
|
||||
- (void)gridViewDidAspectRatio:(HXPhotoEditGridView *)gridView;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
533
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridView.m
generated
Normal file
533
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditGridView.m
generated
Normal file
|
@ -0,0 +1,533 @@
|
|||
//
|
||||
// HXPhotoEditGridView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditGridView.h"
|
||||
#import "HXPhotoEditResizeControl.h"
|
||||
|
||||
/** 可控范围 */
|
||||
const CGFloat HXControlWidth = 30.f;
|
||||
@interface HXPhotoEditGridView ()<HXPhotoEditResizeControlDelegate>
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *topLeftCornerView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *topRightCornerView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *bottomLeftCornerView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *bottomRightCornerView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *topEdgeView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *leftEdgeView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *bottomEdgeView;
|
||||
@property (nonatomic, weak) HXPhotoEditResizeControl *rightEdgeView;
|
||||
@property (nonatomic, weak) HXPhotoEditGridMaskLayer *gridMaskLayer;
|
||||
|
||||
@property (nonatomic, assign) CGRect initialRect;
|
||||
|
||||
@property (nonatomic, weak) HXPhotoEditGridLayer *gridLayer;
|
||||
|
||||
@property (nonatomic, readonly) CGSize aspectRatioSize;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditGridView
|
||||
@synthesize dragging = _dragging;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self customInit];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)customInit {
|
||||
/** 遮罩 */
|
||||
HXPhotoEditGridMaskLayer *gridMaskLayer = [[HXPhotoEditGridMaskLayer alloc] init];
|
||||
gridMaskLayer.frame = self.bounds;
|
||||
gridMaskLayer.maskColor = [UIColor blackColor].CGColor;
|
||||
[self.layer addSublayer:gridMaskLayer];
|
||||
self.gridMaskLayer = gridMaskLayer;
|
||||
|
||||
/** 宫格 */
|
||||
HXPhotoEditGridLayer *gridLayer = [[HXPhotoEditGridLayer alloc] init];
|
||||
gridLayer.frame = self.bounds;
|
||||
// gridLayer.lineWidth = 2.f;
|
||||
gridLayer.bgColor = [UIColor clearColor];
|
||||
gridLayer.gridColor = [UIColor clearColor];
|
||||
|
||||
[self.layer addSublayer:gridLayer];
|
||||
self.gridLayer = gridLayer;
|
||||
|
||||
self.gridRect = CGRectInset(self.bounds, 20, 20);
|
||||
self.controlMinSize = CGSizeMake(80, 80);
|
||||
self.controlMaxRect = CGRectInset(self.bounds, 20, 20);
|
||||
self.controlSize = CGSizeZero;
|
||||
/** 遮罩范围 */
|
||||
self.showMaskLayer = YES;
|
||||
|
||||
self.topLeftCornerView = [self createResizeControl];
|
||||
self.topRightCornerView = [self createResizeControl];
|
||||
self.bottomLeftCornerView = [self createResizeControl];
|
||||
self.bottomRightCornerView = [self createResizeControl];
|
||||
|
||||
self.topEdgeView = [self createResizeControl];
|
||||
self.leftEdgeView = [self createResizeControl];
|
||||
self.bottomEdgeView = [self createResizeControl];
|
||||
self.rightEdgeView = [self createResizeControl];
|
||||
}
|
||||
|
||||
- (void)changeSubviewFrame:(CGRect)frame {
|
||||
self.gridRect = CGRectInset(CGRectMake(0, 0, frame.size.width, frame.size.height), 20, 20);
|
||||
self.controlMaxRect = CGRectInset(CGRectMake(0, 0, frame.size.width, frame.size.height), 20, 20);
|
||||
}
|
||||
- (void)setMaskColor:(CGColorRef)maskColor {
|
||||
_maskColor = maskColor;
|
||||
self.gridMaskLayer.maskColor = maskColor;
|
||||
}
|
||||
- (void)setIsRound:(BOOL)isRound {
|
||||
_isRound = isRound;
|
||||
self.gridLayer.isRound = isRound;
|
||||
self.gridMaskLayer.isRound = isRound;
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
self.gridLayer.frame = self.bounds;
|
||||
self.gridMaskLayer.frame = self.bounds;
|
||||
|
||||
CGRect rect = self.gridRect;
|
||||
|
||||
self.topLeftCornerView.frame = (CGRect){CGRectGetMinX(rect) - CGRectGetWidth(self.topLeftCornerView.bounds) / 2, CGRectGetMinY(rect) - CGRectGetHeight(self.topLeftCornerView.bounds) / 2, self.topLeftCornerView.bounds.size};
|
||||
self.topRightCornerView.frame = (CGRect){CGRectGetMaxX(rect) - CGRectGetWidth(self.topRightCornerView.bounds) / 2, CGRectGetMinY(rect) - CGRectGetHeight(self.topRightCornerView.bounds) / 2, self.topRightCornerView.bounds.size};
|
||||
self.bottomLeftCornerView.frame = (CGRect){CGRectGetMinX(rect) - CGRectGetWidth(self.bottomLeftCornerView.bounds) / 2, CGRectGetMaxY(rect) - CGRectGetHeight(self.bottomLeftCornerView.bounds) / 2, self.bottomLeftCornerView.bounds.size};
|
||||
self.bottomRightCornerView.frame = (CGRect){CGRectGetMaxX(rect) - CGRectGetWidth(self.bottomRightCornerView.bounds) / 2, CGRectGetMaxY(rect) - CGRectGetHeight(self.bottomRightCornerView.bounds) / 2, self.bottomRightCornerView.bounds.size};
|
||||
|
||||
self.topEdgeView.frame = (CGRect){CGRectGetMaxX(self.topLeftCornerView.frame), CGRectGetMinY(rect) - CGRectGetHeight(self.topEdgeView.frame) / 2, CGRectGetMinX(self.topRightCornerView.frame) - CGRectGetMaxX(self.topLeftCornerView.frame), CGRectGetHeight(self.topEdgeView.bounds)};
|
||||
self.leftEdgeView.frame = (CGRect){CGRectGetMinX(rect) - CGRectGetWidth(self.leftEdgeView.frame) / 2, CGRectGetMaxY(self.topLeftCornerView.frame), CGRectGetWidth(self.leftEdgeView.bounds), CGRectGetMinY(self.bottomLeftCornerView.frame) - CGRectGetMaxY(self.topLeftCornerView.frame)};
|
||||
self.bottomEdgeView.frame = (CGRect){CGRectGetMaxX(self.bottomLeftCornerView.frame), CGRectGetMinY(self.bottomLeftCornerView.frame), CGRectGetMinX(self.bottomRightCornerView.frame) - CGRectGetMaxX(self.bottomLeftCornerView.frame), CGRectGetHeight(self.bottomEdgeView.bounds)};
|
||||
self.rightEdgeView.frame = (CGRect){CGRectGetMaxX(rect) - CGRectGetWidth(self.rightEdgeView.bounds) / 2, CGRectGetMaxY(self.topRightCornerView.frame), CGRectGetWidth(self.rightEdgeView.bounds), CGRectGetMinY(self.bottomRightCornerView.frame) - CGRectGetMaxY(self.topRightCornerView.frame)};
|
||||
}
|
||||
|
||||
- (void)setShowMaskLayer:(BOOL)showMaskLayer {
|
||||
if (_showMaskLayer != showMaskLayer) {
|
||||
_showMaskLayer = showMaskLayer;
|
||||
if (showMaskLayer) {
|
||||
/** 还原遮罩 */
|
||||
[self.gridMaskLayer setMaskRect:self.gridRect animated:YES];
|
||||
} else {
|
||||
/** 扩大遮罩范围 */
|
||||
[self.gridMaskLayer clearMaskWithAnimated:YES];
|
||||
}
|
||||
}
|
||||
// self.userInteractionEnabled = showMaskLayer;
|
||||
}
|
||||
|
||||
- (BOOL)isDragging {
|
||||
return _dragging;
|
||||
}
|
||||
|
||||
#pragma mark - lf_resizeConrolDelegate
|
||||
|
||||
- (void)resizeConrolDidBeginResizing:(HXPhotoEditResizeControl *)resizeConrol {
|
||||
self.initialRect = self.gridRect;
|
||||
_dragging = YES;
|
||||
// self.showMaskLayer = NO;
|
||||
if ([self.delegate respondsToSelector:@selector(gridViewDidBeginResizing:)]) {
|
||||
[self.delegate gridViewDidBeginResizing:self];
|
||||
}
|
||||
}
|
||||
- (void)resizeConrolDidResizing:(HXPhotoEditResizeControl *)resizeConrol {
|
||||
CGRect gridRect = [self cropRectMakeWithResizeControlView:resizeConrol];
|
||||
[self setGridRect:gridRect maskLayer:NO];
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(gridViewDidResizing:)]) {
|
||||
[self.delegate gridViewDidResizing:self];
|
||||
}
|
||||
}
|
||||
- (void)resizeConrolDidEndResizing:(HXPhotoEditResizeControl *)resizeConrol {
|
||||
[self enableCornerViewUserInteraction:nil];
|
||||
if ([self.delegate respondsToSelector:@selector(gridViewDidEndResizing:)]) {
|
||||
[self.delegate gridViewDidEndResizing:self];
|
||||
}
|
||||
_dragging = NO;
|
||||
}
|
||||
|
||||
- (void)setGridRect:(CGRect)gridRect {
|
||||
[self setGridRect:gridRect maskLayer:YES];
|
||||
}
|
||||
- (void)setGridRect:(CGRect)gridRect maskLayer:(BOOL)isMaskLayer {
|
||||
[self setGridRect:gridRect maskLayer:isMaskLayer animated:NO];
|
||||
}
|
||||
- (void)setGridRect:(CGRect)gridRect animated:(BOOL)animated {
|
||||
[self setGridRect:gridRect maskLayer:NO animated:animated];
|
||||
}
|
||||
- (void)setGridRect:(CGRect)gridRect maskLayer:(BOOL)isMaskLayer animated:(BOOL)animated {
|
||||
[self setGridRect:gridRect maskLayer:isMaskLayer animated:animated completion:nil];
|
||||
}
|
||||
- (void)setGridRect:(CGRect)gridRect maskLayer:(BOOL)isMaskLayer animated:(BOOL)animated completion:(void (^ _Nullable)(BOOL finished))completion {
|
||||
CGSize size = self.aspectRatioSize;
|
||||
if (!CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
/** 计算比例后高度 */
|
||||
CGFloat newHeight = gridRect.size.width * (size.height/size.width);
|
||||
/** 超出最大高度计算 */
|
||||
if (newHeight > _controlMaxRect.size.height) {
|
||||
CGFloat newWidth = gridRect.size.width * (_controlMaxRect.size.height/newHeight);
|
||||
CGFloat diffWidth = gridRect.size.width - newWidth;
|
||||
gridRect.size.width = newWidth;
|
||||
gridRect.origin.x = gridRect.origin.x + diffWidth/2;
|
||||
newHeight = _controlMaxRect.size.height;
|
||||
}
|
||||
CGFloat diffHeight = gridRect.size.height - newHeight;
|
||||
gridRect.size.height = newHeight;
|
||||
gridRect.origin.y = gridRect.origin.y + diffHeight/2;
|
||||
}
|
||||
|
||||
_gridRect = gridRect;
|
||||
[self setNeedsLayout];
|
||||
[self.gridLayer setGridRect:gridRect animated:animated completion:completion];
|
||||
if (isMaskLayer && _showMaskLayer) {
|
||||
[self.gridMaskLayer setMaskRect:gridRect animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAspectRatioWithoutDelegate:(HXPhotoEditGridViewAspectRatioType)aspectRatio {
|
||||
if (_aspectRatio != aspectRatio) {
|
||||
_aspectRatio = aspectRatio;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setupAspectRatio:(HXPhotoEditGridViewAspectRatioType)aspectRatio {
|
||||
_aspectRatio = aspectRatio;
|
||||
CGSize size = self.aspectRatioSize;
|
||||
CGRect gridRect = self.gridRect;
|
||||
if (!CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
/** 计算比例后高度 */
|
||||
CGFloat newHeight = gridRect.size.width * (size.height/size.width);
|
||||
/** 超出最大高度计算 */
|
||||
if (newHeight > _controlMaxRect.size.height) {
|
||||
CGFloat newWidth = gridRect.size.width * (_controlMaxRect.size.height/newHeight);
|
||||
CGFloat diffWidth = gridRect.size.width - newWidth;
|
||||
gridRect.size.width = newWidth;
|
||||
gridRect.origin.x = gridRect.origin.x + diffWidth/2;
|
||||
newHeight = _controlMaxRect.size.height;
|
||||
}
|
||||
CGFloat diffHeight = gridRect.size.height - newHeight;
|
||||
gridRect.size.height = newHeight;
|
||||
gridRect.origin.y = gridRect.origin.y + diffHeight/2;
|
||||
}
|
||||
_gridRect = gridRect;
|
||||
}
|
||||
- (void)setAspectRatio:(HXPhotoEditGridViewAspectRatioType)aspectRatio {
|
||||
[self setAspectRatio:aspectRatio animated:NO];
|
||||
}
|
||||
|
||||
- (void)setAspectRatio:(HXPhotoEditGridViewAspectRatioType)aspectRatio animated:(BOOL)animated {
|
||||
if (_aspectRatio != aspectRatio) {
|
||||
_aspectRatio = aspectRatio;
|
||||
|
||||
CGSize size = self.aspectRatioSize;
|
||||
if (!CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self setGridRect:self.gridRect maskLayer:NO animated:animated completion:^(BOOL finished) {
|
||||
if ([weakSelf.delegate respondsToSelector:@selector(gridViewDidAspectRatio:)]) {
|
||||
[weakSelf.delegate gridViewDidAspectRatio:weakSelf];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray <NSString *>*)aspectRatioDescs {
|
||||
if (_aspectRatioHorizontally) {
|
||||
static NSArray <NSString *> *aspectRatioHorizontally = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *custom = [NSString stringWithFormat:@"%dx%d", (int)self.customRatioSize.width, (int)self.customRatioSize.height];
|
||||
aspectRatioHorizontally = @[@"Original", @"1x1", @"3x2", @"4x3", @"5x3", @"15x9", @"16x9", @"16x10", custom];
|
||||
});
|
||||
return aspectRatioHorizontally;
|
||||
} else {
|
||||
static NSArray <NSString *> *aspectRatioVertical = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *custom = [NSString stringWithFormat:@"%dx%d", (int)self.customRatioSize.height, (int)self.customRatioSize.width];
|
||||
aspectRatioVertical = @[@"Original", @"1x1", @"2x3", @"3x4", @"3x5", @"9x15", @"9x16", @"10x16", custom];
|
||||
});
|
||||
return aspectRatioVertical;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - private
|
||||
|
||||
- (CGSize)aspectRatioSize {
|
||||
if (self.aspectRatioHorizontally) {
|
||||
switch (self.aspectRatio) {
|
||||
case HXPhotoEditGridViewAspectRatioType_None:
|
||||
return CGSizeZero;
|
||||
case HXPhotoEditGridViewAspectRatioType_Original:
|
||||
if (self.controlSize.width == 0 || self.controlSize.height == 0) {
|
||||
return CGSizeZero;
|
||||
}
|
||||
return CGSizeMake(1, self.controlSize.height/self.controlSize.width);
|
||||
case HXPhotoEditGridViewAspectRatioType_1x1:
|
||||
return CGSizeMake(1, 1);
|
||||
case HXPhotoEditGridViewAspectRatioType_3x2:
|
||||
return CGSizeMake(3, 2);
|
||||
case HXPhotoEditGridViewAspectRatioType_4x3:
|
||||
return CGSizeMake(4, 3);
|
||||
case HXPhotoEditGridViewAspectRatioType_5x3:
|
||||
return CGSizeMake(5, 3);
|
||||
case HXPhotoEditGridViewAspectRatioType_15x9:
|
||||
return CGSizeMake(15, 9);
|
||||
case HXPhotoEditGridViewAspectRatioType_16x9:
|
||||
return CGSizeMake(16, 9);
|
||||
case HXPhotoEditGridViewAspectRatioType_16x10:
|
||||
return CGSizeMake(16, 10);
|
||||
case HXPhotoEditGridViewAspectRatioType_Custom:
|
||||
return self.customRatioSize;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (self.aspectRatio) {
|
||||
case HXPhotoEditGridViewAspectRatioType_None:
|
||||
return CGSizeZero;
|
||||
case HXPhotoEditGridViewAspectRatioType_Original:
|
||||
if (self.controlSize.width == 0 || self.controlSize.height == 0) {
|
||||
return CGSizeZero;
|
||||
}
|
||||
return CGSizeMake(self.controlSize.width/self.controlSize.height, 1);
|
||||
case HXPhotoEditGridViewAspectRatioType_1x1:
|
||||
return CGSizeMake(1, 1);
|
||||
case HXPhotoEditGridViewAspectRatioType_3x2:
|
||||
return CGSizeMake(2, 3);
|
||||
case HXPhotoEditGridViewAspectRatioType_4x3:
|
||||
return CGSizeMake(3, 4);
|
||||
case HXPhotoEditGridViewAspectRatioType_5x3:
|
||||
return CGSizeMake(3, 5);
|
||||
case HXPhotoEditGridViewAspectRatioType_15x9:
|
||||
return CGSizeMake(9, 15);
|
||||
case HXPhotoEditGridViewAspectRatioType_16x9:
|
||||
return CGSizeMake(9, 16);
|
||||
case HXPhotoEditGridViewAspectRatioType_16x10:
|
||||
return CGSizeMake(10, 16);
|
||||
case HXPhotoEditGridViewAspectRatioType_Custom:
|
||||
return self.customRatioSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
- (HXPhotoEditResizeControl *)createResizeControl {
|
||||
HXPhotoEditResizeControl *control = [[HXPhotoEditResizeControl alloc] initWithFrame:(CGRect){CGPointZero, CGSizeMake(HXControlWidth, HXControlWidth)}];
|
||||
control.delegate = self;
|
||||
[self addSubview:control];
|
||||
return control;
|
||||
}
|
||||
|
||||
- (CGRect)cropRectMakeWithResizeControlView:(HXPhotoEditResizeControl *)resizeControlView {
|
||||
CGRect rect = self.gridRect;
|
||||
|
||||
CGSize aspectRatioSize = self.aspectRatioSize;
|
||||
CGFloat widthRatio = aspectRatioSize.height == 0 ? 0 : aspectRatioSize.width/aspectRatioSize.height;
|
||||
CGFloat heightRatio = aspectRatioSize.width == 0 ? 0 : aspectRatioSize.height/aspectRatioSize.width;
|
||||
|
||||
if (resizeControlView == self.topEdgeView) {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) + resizeControlView.translation.y * widthRatio / 2,
|
||||
CGRectGetMinY(self.initialRect) + resizeControlView.translation.y,
|
||||
CGRectGetWidth(self.initialRect) - resizeControlView.translation.y * widthRatio,
|
||||
CGRectGetHeight(self.initialRect) - resizeControlView.translation.y);
|
||||
} else if (resizeControlView == self.leftEdgeView) {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) + resizeControlView.translation.x,
|
||||
CGRectGetMinY(self.initialRect) + resizeControlView.translation.x * heightRatio / 2,
|
||||
CGRectGetWidth(self.initialRect) - resizeControlView.translation.x,
|
||||
CGRectGetHeight(self.initialRect) - resizeControlView.translation.x * heightRatio);
|
||||
} else if (resizeControlView == self.bottomEdgeView) {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) - resizeControlView.translation.y * widthRatio / 2,
|
||||
CGRectGetMinY(self.initialRect),
|
||||
CGRectGetWidth(self.initialRect) + resizeControlView.translation.y * widthRatio,
|
||||
CGRectGetHeight(self.initialRect) + resizeControlView.translation.y);
|
||||
} else if (resizeControlView == self.rightEdgeView) {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect),
|
||||
CGRectGetMinY(self.initialRect) - resizeControlView.translation.x * heightRatio / 2,
|
||||
CGRectGetWidth(self.initialRect) + resizeControlView.translation.x,
|
||||
CGRectGetHeight(self.initialRect) + resizeControlView.translation.x * heightRatio);
|
||||
} else if (resizeControlView == self.topLeftCornerView) {
|
||||
/** 固定大小比例 */
|
||||
if (heightRatio && widthRatio) {
|
||||
CGFloat trans = self.aspectRatioHorizontally ? MAX(resizeControlView.translation.x, resizeControlView.translation.y) : MIN(resizeControlView.translation.x, resizeControlView.translation.y);
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) + trans,
|
||||
CGRectGetMinY(self.initialRect) + trans * heightRatio,
|
||||
CGRectGetWidth(self.initialRect) - trans,
|
||||
CGRectGetHeight(self.initialRect) - trans * heightRatio);
|
||||
} else {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) + resizeControlView.translation.x,
|
||||
CGRectGetMinY(self.initialRect) + resizeControlView.translation.y,
|
||||
CGRectGetWidth(self.initialRect) - resizeControlView.translation.x,
|
||||
CGRectGetHeight(self.initialRect) - resizeControlView.translation.y);
|
||||
}
|
||||
} else if (resizeControlView == self.topRightCornerView) {
|
||||
/** 固定大小比例 */
|
||||
if (heightRatio && widthRatio) {
|
||||
CGFloat trans = self.aspectRatioHorizontally ? MAX(resizeControlView.translation.x * -1, resizeControlView.translation.y) : MIN(resizeControlView.translation.x * -1, resizeControlView.translation.y);
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect),
|
||||
CGRectGetMinY(self.initialRect) + trans * heightRatio,
|
||||
CGRectGetWidth(self.initialRect) - trans,
|
||||
CGRectGetHeight(self.initialRect) - trans * heightRatio);
|
||||
} else {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect),
|
||||
CGRectGetMinY(self.initialRect) + resizeControlView.translation.y,
|
||||
CGRectGetWidth(self.initialRect) + resizeControlView.translation.x,
|
||||
CGRectGetHeight(self.initialRect) - resizeControlView.translation.y);
|
||||
}
|
||||
} else if (resizeControlView == self.bottomLeftCornerView) {
|
||||
/** 固定大小比例 */
|
||||
if (heightRatio && widthRatio) {
|
||||
CGFloat trans = self.aspectRatioHorizontally ? MAX(resizeControlView.translation.x, resizeControlView.translation.y * -1) : MIN(resizeControlView.translation.x, resizeControlView.translation.y * -1);
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) + trans,
|
||||
CGRectGetMinY(self.initialRect),
|
||||
CGRectGetWidth(self.initialRect) - trans,
|
||||
CGRectGetHeight(self.initialRect) - trans * heightRatio);
|
||||
} else {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect) + resizeControlView.translation.x,
|
||||
CGRectGetMinY(self.initialRect),
|
||||
CGRectGetWidth(self.initialRect) - resizeControlView.translation.x,
|
||||
CGRectGetHeight(self.initialRect) + resizeControlView.translation.y);
|
||||
}
|
||||
} else if (resizeControlView == self.bottomRightCornerView) {
|
||||
/** 固定大小比例 */
|
||||
if (heightRatio && widthRatio) {
|
||||
CGFloat trans = self.aspectRatioHorizontally ? MAX(resizeControlView.translation.x * -1, resizeControlView.translation.y * -1) : MIN(resizeControlView.translation.x * -1, resizeControlView.translation.y * -1);
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect),
|
||||
CGRectGetMinY(self.initialRect),
|
||||
CGRectGetWidth(self.initialRect) - trans,
|
||||
CGRectGetHeight(self.initialRect) - trans * heightRatio);
|
||||
} else {
|
||||
rect = CGRectMake(CGRectGetMinX(self.initialRect),
|
||||
CGRectGetMinY(self.initialRect),
|
||||
CGRectGetWidth(self.initialRect) + resizeControlView.translation.x,
|
||||
CGRectGetHeight(self.initialRect) + resizeControlView.translation.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (heightRatio && widthRatio) {
|
||||
/** 限制长宽同时少于最小值,不处理 */
|
||||
if (ceil(rect.size.width) < ceil(_controlMinSize.width) && ceil(rect.size.height) < ceil(_controlMinSize.height)) {
|
||||
return self.gridRect;
|
||||
}
|
||||
}
|
||||
|
||||
/** ps:
|
||||
此处判断 不能使用CGRectGet开头的方法,计算会有问题;
|
||||
当rect = (origin = (x = 50, y = 618), size = (width = 61, height = -488)) 时,
|
||||
CGRectGetMaxY(rect) = 618;CGRectGetHeight(rect) = 488
|
||||
*/
|
||||
|
||||
/** 限制x/y 超出左上角 最大限度 */
|
||||
if (ceil(rect.origin.x) < ceil(CGRectGetMinX(_controlMaxRect))) {
|
||||
rect.origin.x = _controlMaxRect.origin.x;
|
||||
rect.size.width = CGRectGetMaxX(self.initialRect)-rect.origin.x;
|
||||
}
|
||||
if (ceil(rect.origin.y) < ceil(CGRectGetMinY(_controlMaxRect))) {
|
||||
rect.origin.y = _controlMaxRect.origin.y;
|
||||
rect.size.height = CGRectGetMaxY(self.initialRect)-rect.origin.y;
|
||||
}
|
||||
|
||||
/** 限制宽度/高度 超出 最大限度 */
|
||||
if (ceil(rect.origin.x+rect.size.width) > ceil(CGRectGetMaxX(_controlMaxRect))) {
|
||||
rect.size.width = CGRectGetMaxX(_controlMaxRect) - CGRectGetMinX(rect);
|
||||
}
|
||||
if (ceil(rect.origin.y+rect.size.height) > ceil(CGRectGetMaxY(_controlMaxRect))) {
|
||||
rect.size.height = CGRectGetMaxY(_controlMaxRect) - CGRectGetMinY(rect);
|
||||
}
|
||||
|
||||
/** 限制宽度/高度 小于 最小限度 */
|
||||
if (ceil(rect.size.width) <= ceil(_controlMinSize.width)) {
|
||||
/** 左上、左、左下 处理x最小值 */
|
||||
if (resizeControlView == self.topLeftCornerView || resizeControlView == self.leftEdgeView || resizeControlView == self.bottomLeftCornerView) {
|
||||
rect.origin.x = CGRectGetMaxX(self.initialRect) - _controlMinSize.width;
|
||||
}
|
||||
rect.size.width = _controlMinSize.width;
|
||||
if (heightRatio && widthRatio) {
|
||||
rect.size.height = rect.size.width * heightRatio;
|
||||
/** 左、右 处理x最小值中间 */
|
||||
if (resizeControlView == self.leftEdgeView || resizeControlView == self.rightEdgeView) {
|
||||
rect.origin.y = CGRectGetMaxY(self.initialRect) - CGRectGetHeight(self.initialRect)/2 - rect.size.height/2;
|
||||
}
|
||||
/** 上、下 处理y最小值中间 */
|
||||
if (resizeControlView == self.topEdgeView || resizeControlView == self.bottomEdgeView) {
|
||||
rect.origin.x = CGRectGetMaxX(self.initialRect) - CGRectGetWidth(self.initialRect)/2 - _controlMinSize.width/2;
|
||||
}
|
||||
/** 左上、上、右上 处理y最小值底部 */
|
||||
if (resizeControlView == self.topLeftCornerView || resizeControlView == self.topEdgeView || resizeControlView == self.topRightCornerView) {
|
||||
rect.origin.y = CGRectGetMaxY(self.initialRect) - rect.size.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ceil(rect.size.height) <= ceil(_controlMinSize.height)) {
|
||||
/** 左上、上、右上 处理y最小值底部 */
|
||||
if (resizeControlView == self.topLeftCornerView || resizeControlView == self.topEdgeView || resizeControlView == self.topRightCornerView) {
|
||||
rect.origin.y = CGRectGetMaxY(self.initialRect) - _controlMinSize.height;
|
||||
}
|
||||
rect.size.height = _controlMinSize.height;
|
||||
if (heightRatio && widthRatio) {
|
||||
rect.size.width = rect.size.height * widthRatio;
|
||||
/** 左、右 处理y最小值中间 */
|
||||
if (resizeControlView == self.leftEdgeView || resizeControlView == self.rightEdgeView) {
|
||||
rect.origin.y = CGRectGetMaxY(self.initialRect) - CGRectGetHeight(self.initialRect)/2 - _controlMinSize.height/2;
|
||||
}
|
||||
/** 上、下 处理x最小值中间 */
|
||||
if (resizeControlView == self.topEdgeView || resizeControlView == self.bottomEdgeView) {
|
||||
rect.origin.x = CGRectGetMaxX(self.initialRect) - CGRectGetWidth(self.initialRect)/2 - rect.size.width/2;
|
||||
}
|
||||
|
||||
/** 左上、左、左下 处理x最小值 */
|
||||
if (resizeControlView == self.topLeftCornerView || resizeControlView == self.leftEdgeView || resizeControlView == self.bottomLeftCornerView) {
|
||||
rect.origin.x = CGRectGetMaxX(self.initialRect) - rect.size.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 固定大小比例 */
|
||||
if (heightRatio && widthRatio) {
|
||||
if (rect.size.width == _controlMaxRect.size.width) {
|
||||
rect.origin.y = self.initialRect.origin.y;
|
||||
rect.size.height = rect.size.width * heightRatio;
|
||||
} else if (rect.size.height == _controlMaxRect.size.height) {
|
||||
rect.origin.x = self.initialRect.origin.x;
|
||||
rect.size.width = rect.size.height * widthRatio;
|
||||
}
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
UIView *view = [super hitTest:point withEvent:event];
|
||||
if (self == view) {
|
||||
return nil;
|
||||
}
|
||||
[self enableCornerViewUserInteraction:view];
|
||||
return view;
|
||||
}
|
||||
|
||||
- (void)enableCornerViewUserInteraction:(UIView *)view {
|
||||
for (UIView *control in self.subviews) {
|
||||
if ([control isKindOfClass:[HXPhotoEditResizeControl class]]) {
|
||||
if (view) {
|
||||
if (control == view) {
|
||||
control.userInteractionEnabled = YES;
|
||||
} else {
|
||||
control.userInteractionEnabled = NO;
|
||||
}
|
||||
} else {
|
||||
control.userInteractionEnabled = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
47
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditImageView.h
generated
Normal file
47
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditImageView.h
generated
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// HXPhotoEditImageView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/23.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "HXPhotoEditDrawView.h"
|
||||
#import "HXPhotoEditStickerView.h"
|
||||
#import "HXPhotoEditSplashView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXPhotoEditImageViewType) {
|
||||
HXPhotoEditImageViewTypeNormal = 0, //!< 正常情况
|
||||
HXPhotoEditImageViewTypeDraw = 1, //!< 绘图状态
|
||||
HXPhotoEditImageViewTypeSplash = 2 //!< 绘图状态
|
||||
};
|
||||
@class HXPhotoEditConfiguration;
|
||||
@interface HXPhotoEditImageView : UIView
|
||||
@property (strong, nonatomic, readonly) UIImageView *imageView;
|
||||
@property (strong, nonatomic) UIImage *image;
|
||||
@property (assign, nonatomic) HXPhotoEditImageViewType type;
|
||||
@property (strong, nonatomic, readonly) HXPhotoEditDrawView *drawView;
|
||||
@property (strong, nonatomic, readonly) HXPhotoEditStickerView *stickerView;
|
||||
@property (strong, nonatomic, readonly) HXPhotoEditSplashView *splashView;
|
||||
|
||||
@property (assign, nonatomic) BOOL splashViewEnable;
|
||||
/// 显示界面的缩放率
|
||||
@property (nonatomic, assign) CGFloat screenScale;
|
||||
|
||||
/** 贴图是否需要移到屏幕中心 */
|
||||
@property (nonatomic, copy) BOOL(^moveCenter)(CGRect rect);
|
||||
@property (nonatomic, copy, nullable) CGFloat (^ getMinScale)(CGSize size);
|
||||
@property (nonatomic, copy, nullable) CGFloat (^ getMaxScale)(CGSize size);
|
||||
|
||||
@property (strong, nonatomic) HXPhotoEditConfiguration *configuration;
|
||||
/** 数据 */
|
||||
@property (nonatomic, strong, nullable) NSDictionary *photoEditData;
|
||||
- (UIImage * _Nullable)editOtherImagesInRect:(CGRect)rect rotate:(CGFloat)rotate mirrorHorizontally:(BOOL)mirrorHorizontally;
|
||||
- (void)changeSubviewFrame;
|
||||
- (void)clearCoverage;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
221
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditImageView.m
generated
Normal file
221
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditImageView.m
generated
Normal file
|
@ -0,0 +1,221 @@
|
|||
//
|
||||
// HXPhotoEditImageView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/23.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditImageView.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPhotoEditStickerItemView.h"
|
||||
#import "HXPhotoEditStickerItemContentView.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "UIView+HXExtension.h"
|
||||
#import "HXPhotoDefine.h"
|
||||
|
||||
NSString *const kHXImageViewData_draw = @"HXImageViewData_draw";
|
||||
NSString *const kHXImageViewData_sticker = @"HXImageViewData_sticker";
|
||||
NSString *const kHXImageViewData_splash = @"HXImageViewData_splash";
|
||||
NSString *const kHXImageViewData_filter = @"HXImageViewData_filter";
|
||||
|
||||
@interface HXPhotoEditImageView ()
|
||||
@property (strong, nonatomic) UIImageView *imageView;
|
||||
@property (strong, nonatomic) HXPhotoEditDrawView *drawView;
|
||||
@property (strong, nonatomic) HXPhotoEditStickerView *stickerView;
|
||||
@property (strong, nonatomic) HXPhotoEditSplashView *splashView;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditImageView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.imageView];
|
||||
[self addSubview:self.splashView];
|
||||
[self addSubview:self.drawView];
|
||||
[self addSubview:self.stickerView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)changeSubviewFrame {
|
||||
self.imageView.frame = self.bounds;
|
||||
self.drawView.frame = self.imageView.frame;
|
||||
self.stickerView.frame = self.bounds;
|
||||
self.splashView.frame = self.bounds;
|
||||
}
|
||||
- (void)clearCoverage {
|
||||
// [self.drawView clearCoverage];
|
||||
// [self.stickerView clearCoverage];
|
||||
// [self.splashView clearCoverage];
|
||||
}
|
||||
- (void)setType:(HXPhotoEditImageViewType)type {
|
||||
self.drawView.userInteractionEnabled = NO;
|
||||
self.splashView.userInteractionEnabled = NO;
|
||||
if (type == HXPhotoEditImageViewTypeDraw) {
|
||||
self.drawView.userInteractionEnabled = YES;
|
||||
}else if (type == HXPhotoEditImageViewTypeSplash) {
|
||||
self.splashView.userInteractionEnabled = YES;
|
||||
}
|
||||
}
|
||||
- (void)setImage:(UIImage *)image {
|
||||
_image = image;
|
||||
self.imageView.image = image;
|
||||
}
|
||||
|
||||
- (void)setMoveCenter:(BOOL (^)(CGRect))moveCenter {
|
||||
_moveCenter = moveCenter;
|
||||
if (moveCenter) {
|
||||
self.stickerView.moveCenter = moveCenter;
|
||||
} else {
|
||||
self.stickerView.moveCenter = nil;
|
||||
}
|
||||
}
|
||||
- (void)setGetMaxScale:(CGFloat (^)(CGSize))getMaxScale {
|
||||
_getMaxScale = getMaxScale;
|
||||
if (getMaxScale) {
|
||||
self.stickerView.getMaxScale = getMaxScale;
|
||||
}else {
|
||||
self.stickerView.getMaxScale = nil;
|
||||
}
|
||||
}
|
||||
- (void)setGetMinScale:(CGFloat (^)(CGSize))getMinScale {
|
||||
_getMinScale = getMinScale;
|
||||
if (getMinScale) {
|
||||
self.stickerView.getMinScale = getMinScale;
|
||||
}else {
|
||||
self.stickerView.getMinScale = nil;
|
||||
}
|
||||
}
|
||||
- (void)setScreenScale:(CGFloat)screenScale {
|
||||
_screenScale = screenScale;
|
||||
self.drawView.screenScale = screenScale;
|
||||
self.stickerView.screenScale = screenScale;
|
||||
self.splashView.screenScale = screenScale;
|
||||
}
|
||||
- (UIImage * _Nullable)editOtherImagesInRect:(CGRect)rect rotate:(CGFloat)rotate mirrorHorizontally:(BOOL)mirrorHorizontally {
|
||||
UIImage *image = nil;
|
||||
NSMutableArray *array = nil;
|
||||
for (UIView *subView in self.subviews) {
|
||||
if (subView == self.imageView) {
|
||||
continue;
|
||||
} else if ([subView isKindOfClass:[HXPhotoEditDrawView class]]) {
|
||||
if (((HXPhotoEditDrawView *)subView).count == 0) {
|
||||
continue;
|
||||
}
|
||||
} else if ([subView isKindOfClass:[HXPhotoEditStickerView class]]) {
|
||||
if (((HXPhotoEditStickerView *)subView).count == 0) {
|
||||
continue;
|
||||
}
|
||||
} else if ([subView isKindOfClass:[HXPhotoEditSplashView class]]) {
|
||||
if (!((HXPhotoEditSplashView *)subView).canUndo) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (array == nil) {
|
||||
array = [NSMutableArray arrayWithCapacity:3];
|
||||
}
|
||||
UIImage *subImage = [subView hx_captureImageAtFrame:rect];
|
||||
subView.layer.contents = (id)nil;
|
||||
if (subImage) {
|
||||
[array addObject:subImage];
|
||||
}
|
||||
}
|
||||
if (array.count) {
|
||||
image = [UIImage hx_mergeimages:array];
|
||||
if (rotate || mirrorHorizontally) {
|
||||
NSInteger angle = fabs(rotate * 180 / M_PI - 360);
|
||||
if (angle == 0 || angle == 360) {
|
||||
if (mirrorHorizontally) {
|
||||
image = [image hx_rotationImage:UIImageOrientationUpMirrored];
|
||||
}
|
||||
}else if (angle == 90) {
|
||||
if (!mirrorHorizontally) {
|
||||
image = [image hx_rotationImage:UIImageOrientationLeft];
|
||||
}else {
|
||||
image = [image hx_rotationImage:UIImageOrientationRightMirrored];
|
||||
}
|
||||
}else if (angle == 180) {
|
||||
if (!mirrorHorizontally) {
|
||||
image = [image hx_rotationImage:UIImageOrientationDown];
|
||||
}else {
|
||||
image = [image hx_rotationImage:UIImageOrientationDownMirrored];
|
||||
}
|
||||
}else if (angle == 270) {
|
||||
if (!mirrorHorizontally) {
|
||||
image = [image hx_rotationImage:UIImageOrientationRight];
|
||||
}else {
|
||||
image = [image hx_rotationImage:UIImageOrientationLeftMirrored];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
- (void)setConfiguration:(HXPhotoEditConfiguration *)configuration {
|
||||
_configuration = configuration;
|
||||
self.stickerView.configuration = configuration;
|
||||
}
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
self.imageView.frame = self.bounds;
|
||||
self.drawView.frame = self.imageView.frame;
|
||||
self.stickerView.frame = self.bounds;
|
||||
self.splashView.frame = self.bounds;
|
||||
}
|
||||
- (UIImageView *)imageView {
|
||||
if (!_imageView) {
|
||||
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
|
||||
_imageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_imageView.clipsToBounds = YES;
|
||||
}
|
||||
return _imageView;
|
||||
}
|
||||
- (HXPhotoEditDrawView *)drawView {
|
||||
if (!_drawView) {
|
||||
_drawView = [[HXPhotoEditDrawView alloc] initWithFrame:self.bounds];
|
||||
_drawView.userInteractionEnabled = NO;
|
||||
}
|
||||
return _drawView;
|
||||
}
|
||||
- (HXPhotoEditStickerView *)stickerView {
|
||||
if (!_stickerView) {
|
||||
_stickerView = [[HXPhotoEditStickerView alloc] initWithFrame:self.bounds];
|
||||
}
|
||||
return _stickerView;
|
||||
}
|
||||
- (HXPhotoEditSplashView *)splashView {
|
||||
if (!_splashView) {
|
||||
_splashView = [[HXPhotoEditSplashView alloc] initWithFrame:self.bounds];
|
||||
_splashView.userInteractionEnabled = NO;
|
||||
HXWeakSelf
|
||||
_splashView.splashColor = ^UIColor *(CGPoint point) {
|
||||
return [weakSelf.imageView hx_colorOfPoint:point];
|
||||
};
|
||||
}
|
||||
return _splashView;
|
||||
}
|
||||
#pragma mark - 数据
|
||||
- (NSDictionary *)photoEditData {
|
||||
NSDictionary *drawData = self.drawView.data;
|
||||
NSDictionary *stickerData = self.stickerView.data;
|
||||
NSDictionary *splashData = self.splashView.data;
|
||||
|
||||
NSMutableDictionary *data = [@{} mutableCopy];
|
||||
if (drawData) [data setObject:drawData forKey:kHXImageViewData_draw];
|
||||
if (stickerData) [data setObject:stickerData forKey:kHXImageViewData_sticker];
|
||||
if (splashData) [data setObject:splashData forKey:kHXImageViewData_splash];
|
||||
|
||||
if (data.count) {
|
||||
return data;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setPhotoEditData:(NSDictionary *)photoEditData {
|
||||
self.drawView.data = photoEditData[kHXImageViewData_draw];
|
||||
self.stickerView.data = photoEditData[kHXImageViewData_sticker];
|
||||
self.splashView.data = photoEditData[kHXImageViewData_splash];
|
||||
}
|
||||
@end
|
23
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditMosaicView.h
generated
Normal file
23
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditMosaicView.h
generated
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// HXPhotoEditMosaicView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/22.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface HXPhotoEditMosaicView : UIView
|
||||
/// 主题色
|
||||
/// 默认微信主题色
|
||||
@property (strong, nonatomic) UIColor *themeColor;
|
||||
@property (copy, nonatomic) void (^ didBtnBlock)(NSInteger tag);
|
||||
@property (copy, nonatomic) void (^ undoBlock)(void);
|
||||
@property (assign, nonatomic) BOOL undo;
|
||||
+ (instancetype)initView;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
71
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditMosaicView.m
generated
Normal file
71
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditMosaicView.m
generated
Normal file
|
@ -0,0 +1,71 @@
|
|||
//
|
||||
// HXPhotoEditMosaicView.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/22.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditMosaicView.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
#import "NSBundle+HXPhotoPicker.h"
|
||||
|
||||
@interface HXPhotoEditMosaicView ()
|
||||
@property (weak, nonatomic) IBOutlet UIButton *normalBtn;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *colorBtn;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIButton *undoBtn;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditMosaicView
|
||||
|
||||
+ (instancetype)initView {
|
||||
return [[[NSBundle hx_photoPickerBundle] loadNibNamed:NSStringFromClass(self) owner:nil options:nil] lastObject];
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.undoBtn.enabled = NO;
|
||||
|
||||
UIImage *normalImage = [[UIImage hx_imageContentsOfFile:@"hx_photo_edit_mosaic_normal"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
[self.normalBtn setImage:normalImage forState:UIControlStateNormal];
|
||||
[self.normalBtn setImage:normalImage forState:UIControlStateSelected];
|
||||
|
||||
UIImage *colorImage = [[UIImage hx_imageContentsOfFile:@"hx_photo_edit_mosaic_color"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
[self.colorBtn setImage:colorImage forState:UIControlStateNormal];
|
||||
[self.colorBtn setImage:colorImage forState:UIControlStateSelected];
|
||||
|
||||
[self.undoBtn setImage:[UIImage hx_imageContentsOfFile:@"hx_photo_edit_repeal"] forState:UIControlStateNormal];
|
||||
}
|
||||
- (void)setThemeColor:(UIColor *)themeColor {
|
||||
_themeColor = themeColor;
|
||||
self.normalBtn.selected = YES;
|
||||
self.normalBtn.imageView.tintColor = themeColor;
|
||||
}
|
||||
- (void)setUndo:(BOOL)undo {
|
||||
_undo = undo;
|
||||
self.undoBtn.enabled = undo;
|
||||
}
|
||||
- (IBAction)didBtnClick:(UIButton *)button {
|
||||
if (button.tag == 0) {
|
||||
self.normalBtn.selected = YES;
|
||||
self.normalBtn.imageView.tintColor = self.themeColor;
|
||||
self.colorBtn.selected = NO;
|
||||
self.colorBtn.imageView.tintColor = nil;
|
||||
}else {
|
||||
self.colorBtn.selected = YES;
|
||||
self.colorBtn.imageView.tintColor = self.themeColor;
|
||||
self.normalBtn.selected = NO;
|
||||
self.normalBtn.imageView.tintColor = nil;
|
||||
}
|
||||
if (self.didBtnBlock) {
|
||||
self.didBtnBlock(button.tag);
|
||||
}
|
||||
}
|
||||
- (IBAction)didUndoBtn:(UIButton *)button {
|
||||
if (self.undoBlock) {
|
||||
self.undoBlock();
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
28
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditResizeControl.h
generated
Normal file
28
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditResizeControl.h
generated
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// HXPhotoEditResizeControl.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol HXPhotoEditResizeControlDelegate;
|
||||
|
||||
@interface HXPhotoEditResizeControl : UIView
|
||||
@property (weak, nonatomic) id<HXPhotoEditResizeControlDelegate> delegate;
|
||||
@property (nonatomic, readonly) CGPoint translation;
|
||||
@property (nonatomic, getter=isEnabled) BOOL enabled;
|
||||
@end
|
||||
|
||||
@protocol HXPhotoEditResizeControlDelegate <NSObject>
|
||||
|
||||
- (void)resizeConrolDidBeginResizing:(HXPhotoEditResizeControl *)resizeConrol;
|
||||
- (void)resizeConrolDidResizing:(HXPhotoEditResizeControl *)resizeConrol;
|
||||
- (void)resizeConrolDidEndResizing:(HXPhotoEditResizeControl *)resizeConrol;
|
||||
|
||||
@end
|
||||
NS_ASSUME_NONNULL_END
|
61
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditResizeControl.m
generated
Normal file
61
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditResizeControl.m
generated
Normal file
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// HXPhotoEditResizeControl.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/6/29.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditResizeControl.h"
|
||||
|
||||
@interface HXPhotoEditResizeControl ()
|
||||
@property (nonatomic, readwrite) CGPoint translation;
|
||||
@property (nonatomic) CGPoint startPoint;
|
||||
@property (nonatomic, strong) UIPanGestureRecognizer *gestureRecognizer;
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditResizeControl
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
|
||||
[self addGestureRecognizer:gestureRecognizer];
|
||||
_gestureRecognizer = gestureRecognizer;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEnabled {
|
||||
return self.gestureRecognizer.isEnabled;
|
||||
}
|
||||
|
||||
- (void)setEnabled:(BOOL)enabled {
|
||||
self.gestureRecognizer.enabled = enabled;
|
||||
}
|
||||
|
||||
- (void)handlePan:(UIPanGestureRecognizer *)gestureRecognizer {
|
||||
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
|
||||
CGPoint translationInView = [gestureRecognizer translationInView:self.superview];
|
||||
self.startPoint = CGPointMake(roundf(translationInView.x), translationInView.y);
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(resizeConrolDidBeginResizing:)]) {
|
||||
[self.delegate resizeConrolDidBeginResizing:self];
|
||||
}
|
||||
} else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
|
||||
CGPoint translation = [gestureRecognizer translationInView:self.superview];
|
||||
self.translation = CGPointMake(roundf(self.startPoint.x + translation.x),
|
||||
roundf(self.startPoint.y + translation.y));
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(resizeConrolDidResizing:)]) {
|
||||
[self.delegate resizeConrolDidResizing:self];
|
||||
}
|
||||
} else if (gestureRecognizer.state == UIGestureRecognizerStateEnded || gestureRecognizer.state == UIGestureRecognizerStateCancelled) {
|
||||
if ([self.delegate respondsToSelector:@selector(resizeConrolDidEndResizing:)]) {
|
||||
[self.delegate resizeConrolDidEndResizing:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
31
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditSplashMaskLayer.h
generated
Normal file
31
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditSplashMaskLayer.h
generated
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// HXPhotoEditSplashMaskLayer.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
@interface HXPhotoEditSplashBlur : NSObject
|
||||
|
||||
@property (nonatomic, assign) CGRect rect;
|
||||
@property (nonatomic, strong, nullable) UIColor *color;
|
||||
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditSplashImageBlur : HXPhotoEditSplashBlur
|
||||
|
||||
@property (nonatomic, copy) NSString *imageName;
|
||||
|
||||
@end
|
||||
|
||||
@interface HXPhotoEditSplashMaskLayer : CALayer
|
||||
@property (nonatomic, strong) NSMutableArray <HXPhotoEditSplashBlur *>*lineArray;;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
123
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditSplashMaskLayer.m
generated
Normal file
123
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditSplashMaskLayer.m
generated
Normal file
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// HXPhotoEditSplashMaskLayer.m
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import "HXPhotoEditSplashMaskLayer.h"
|
||||
#import "UIImage+HXExtension.h"
|
||||
|
||||
#define HXRadiansToDegrees(x) (180.0 * x / M_PI)
|
||||
|
||||
CGFloat angleBetweenPoints(CGPoint startPoint, CGPoint endPoint) {
|
||||
CGPoint Xpoint = CGPointMake(startPoint.x + 100, startPoint.y);
|
||||
|
||||
CGFloat a = endPoint.x - startPoint.x;
|
||||
CGFloat b = endPoint.y - startPoint.y;
|
||||
CGFloat c = Xpoint.x - startPoint.x;
|
||||
CGFloat d = Xpoint.y - startPoint.y;
|
||||
|
||||
CGFloat rads = acos(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
|
||||
|
||||
if (startPoint.y>endPoint.y) {
|
||||
rads = -rads;
|
||||
}
|
||||
return rads;
|
||||
}
|
||||
|
||||
CGFloat angleBetweenLines(CGPoint line1Start, CGPoint line1End, CGPoint line2Start, CGPoint line2End) {
|
||||
|
||||
CGFloat a = line1End.x - line1Start.x;
|
||||
CGFloat b = line1End.y - line1Start.y;
|
||||
CGFloat c = line2End.x - line2Start.x;
|
||||
CGFloat d = line2End.y - line2Start.y;
|
||||
|
||||
CGFloat rads = acos(((a*c) + (b*d)) / ((sqrt(a*a + b*b)) * (sqrt(c*c + d*d))));
|
||||
|
||||
return HXRadiansToDegrees(rads);
|
||||
}
|
||||
|
||||
@implementation HXPhotoEditSplashBlur
|
||||
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditSplashImageBlur
|
||||
|
||||
@end
|
||||
@interface HXPhotoEditSplashMaskLayer ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation HXPhotoEditSplashMaskLayer
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
// self.contentsScale = [[UIScreen mainScreen] scale];
|
||||
self.backgroundColor = [UIColor clearColor].CGColor;
|
||||
_lineArray = [@[] mutableCopy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)drawInContext:(CGContextRef)context {
|
||||
UIGraphicsPushContext( context );
|
||||
|
||||
[[UIColor clearColor] setFill];
|
||||
UIRectFill(self.bounds);
|
||||
|
||||
CGContextSetLineCap(context, kCGLineCapRound);
|
||||
CGContextSetLineJoin(context, kCGLineJoinRound);
|
||||
|
||||
for (NSInteger i = 0; i < self.lineArray.count; i++) {
|
||||
HXPhotoEditSplashBlur *blur = self.lineArray[i];
|
||||
CGRect rect = blur.rect;
|
||||
|
||||
CGContextSetStrokeColorWithColor(context, (blur.color ? blur.color.CGColor : [UIColor clearColor].CGColor));
|
||||
|
||||
// 模糊矩形可以用到,用于填充矩形
|
||||
CGContextSetFillColorWithColor(context, (blur.color ? blur.color.CGColor : [UIColor clearColor].CGColor));
|
||||
|
||||
|
||||
if ([blur isMemberOfClass:[HXPhotoEditSplashImageBlur class]]) {
|
||||
|
||||
UIImage *image = [UIImage hx_imageNamed:((HXPhotoEditSplashImageBlur *)blur).imageName];
|
||||
|
||||
if (image) {
|
||||
// CGPoint firstPoint = CGPointZero;
|
||||
// if (i > 0) {
|
||||
// HXPhotoEditSplashBlur *prevBlur = self.lineArray[i-1];
|
||||
// firstPoint = prevBlur.rect.origin;
|
||||
// }
|
||||
/** 创建颜色图片 */
|
||||
CGColorSpaceRef colorRef = CGColorSpaceCreateDeviceRGB();
|
||||
CGContextRef contextRef = CGBitmapContextCreate(nil, image.size.width, image.size.height, 8, image.size.width*4, colorRef, kCGImageAlphaPremultipliedFirst);
|
||||
|
||||
CGRect imageRect = CGRectMake(0, 0, image.size.width, image.size.height);
|
||||
CGContextClipToMask(contextRef, imageRect, image.CGImage);
|
||||
CGContextSetFillColorWithColor(contextRef, (blur.color ? blur.color.CGColor : [UIColor clearColor].CGColor));
|
||||
CGContextFillRect(contextRef,imageRect);
|
||||
|
||||
/** 生成图片 */
|
||||
CGImageRef imageRef = CGBitmapContextCreateImage(contextRef);
|
||||
|
||||
CGContextDrawImage(context, rect, imageRef);
|
||||
|
||||
CGImageRelease(imageRef);
|
||||
CGContextRelease(contextRef);
|
||||
CGColorSpaceRelease(colorRef);
|
||||
}
|
||||
|
||||
} else {
|
||||
// 模糊矩形 填充 画完一个小正方形
|
||||
CGContextFillRect(context, rect);
|
||||
}
|
||||
}
|
||||
|
||||
UIGraphicsPopContext();
|
||||
}
|
||||
@end
|
||||
|
46
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditSplashView.h
generated
Normal file
46
ProductApp/Pods/HXPhotoPicker/HXPhotoPicker/HXPhotoEdit/View/HXPhotoEditSplashView.h
generated
Normal file
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// HXPhotoEditSplashView.h
|
||||
// photoEditDemo
|
||||
//
|
||||
// Created by Silence on 2020/7/1.
|
||||
// Copyright © 2020 Silence. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, HXPhotoEditSplashStateType) {
|
||||
/** 马赛克 */
|
||||
HXPhotoEditSplashStateType_Mosaic,
|
||||
/** 高斯模糊 */
|
||||
HXPhotoEditSplashStateType_Blurry,
|
||||
/** 画笔涂抹 */
|
||||
HXPhotoEditSplashStateType_Paintbrush,
|
||||
};
|
||||
|
||||
@interface HXPhotoEditSplashView : UIView
|
||||
|
||||
/// 显示界面的缩放率
|
||||
@property (nonatomic, assign) CGFloat screenScale;
|
||||
|
||||
/** 数据 */
|
||||
@property (nonatomic, strong, nullable) NSDictionary *data;
|
||||
|
||||
@property (nonatomic, copy) void(^splashBegan)(void);
|
||||
@property (nonatomic, copy) void(^splashEnded)(void);
|
||||
/** 绘画颜色 */
|
||||
@property (nonatomic, copy) UIColor *(^splashColor)(CGPoint point);
|
||||
|
||||
/** 改变模糊状态 */
|
||||
@property (nonatomic, assign) HXPhotoEditSplashStateType state;
|
||||
|
||||
/** 是否可撤销 */
|
||||
- (BOOL)canUndo;
|
||||
|
||||
//撤销
|
||||
- (void)undo;
|
||||
- (void)clearCoverage;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue