Unverified Commit cfa54ffe authored by 谭真's avatar 谭真 Committed by GitHub

Merge pull request #1507 from iiHorizon/master

支持单个视频的裁剪
parents 4c6020a7 0ab502fb
......@@ -43,7 +43,6 @@
903996931F447604005E77C2 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 903996921F447604005E77C2 /* Photos.framework */; };
90A74B85203287C200D84C2A /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 90A74B83203287C200D84C2A /* Localizable.strings */; };
90CE84AE1C3A89EF003D0779 /* TZImageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84AD1C3A89EF003D0779 /* TZImageManager.m */; };
90CE84B71C3BABB6003D0779 /* TZVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */; };
9F763A4A1FA071D000D9E526 /* TZImagePickerController.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9F763A421FA071CF00D9E526 /* TZImagePickerController.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9F763A501FA072E500D9E526 /* TZImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EEFF71C2BBF9500EA709B /* TZImagePickerController.m */; };
9F763A521FA072E500D9E526 /* TZPhotoPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 900EEFFD1C2BD58B00EA709B /* TZPhotoPickerController.m */; };
......@@ -72,6 +71,11 @@
9F763A761FA0741D00D9E526 /* TZImageManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 90CE84AC1C3A89EF003D0779 /* TZImageManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
9F763A771FA0741D00D9E526 /* TZImageCropManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 6DC84D081DF5358500A107A9 /* TZImageCropManager.h */; };
9F763A781FA0741D00D9E526 /* TZLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 902938D61EE2D02C000F2F8F /* TZLocationManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
B606A9C4265FD53200F5493E /* TZVideoCropController.m in Sources */ = {isa = PBXBuildFile; fileRef = B606A9C2265FD53200F5493E /* TZVideoCropController.m */; };
B606A9CE265FD5F700F5493E /* TZVideoPlayerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */; };
B662C36F2662914D006A672A /* TZVideoEditedPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B662C36E2662914D006A672A /* TZVideoEditedPreviewController.m */; };
B662C37326629179006A672A /* TZVideoEditedPreviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B662C36E2662914D006A672A /* TZVideoEditedPreviewController.m */; };
B6977B0A265FDB280028BA31 /* TZVideoCropController.m in Sources */ = {isa = PBXBuildFile; fileRef = B606A9C2265FD53200F5493E /* TZVideoCropController.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -182,6 +186,10 @@
90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZVideoPlayerController.m; sourceTree = "<group>"; };
9F763A421FA071CF00D9E526 /* TZImagePickerController.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TZImagePickerController.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9F763A451FA071D000D9E526 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B606A9C2265FD53200F5493E /* TZVideoCropController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TZVideoCropController.m; sourceTree = "<group>"; };
B606A9C3265FD53200F5493E /* TZVideoCropController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TZVideoCropController.h; sourceTree = "<group>"; };
B662C36D2662914D006A672A /* TZVideoEditedPreviewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TZVideoEditedPreviewController.h; sourceTree = "<group>"; };
B662C36E2662914D006A672A /* TZVideoEditedPreviewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TZVideoEditedPreviewController.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -320,6 +328,10 @@
90CE84B61C3BABB6003D0779 /* TZVideoPlayerController.m */,
6D46082F1DFFC60D004FB009 /* TZGifPhotoPreviewController.h */,
6D4608301DFFC60D004FB009 /* TZGifPhotoPreviewController.m */,
B606A9C3265FD53200F5493E /* TZVideoCropController.h */,
B606A9C2265FD53200F5493E /* TZVideoCropController.m */,
B662C36D2662914D006A672A /* TZVideoEditedPreviewController.h */,
B662C36E2662914D006A672A /* TZVideoEditedPreviewController.m */,
6DD050291DF659ED0057C78D /* TZProgressView.h */,
6DD0502A1DF659ED0057C78D /* TZProgressView.m */,
90CE84AC1C3A89EF003D0779 /* TZImageManager.h */,
......@@ -573,10 +585,11 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B606A9CE265FD5F700F5493E /* TZVideoPlayerController.m in Sources */,
B662C36F2662914D006A672A /* TZVideoEditedPreviewController.m in Sources */,
9038D5911C3974F0007DE549 /* TZTestCell.m in Sources */,
900EF00F1C2C0B1100EA709B /* TZAssetModel.m in Sources */,
900EEFFE1C2BD58B00EA709B /* TZPhotoPickerController.m in Sources */,
90CE84B71C3BABB6003D0779 /* TZVideoPlayerController.m in Sources */,
900EF0021C2BD7E400EA709B /* TZAssetCell.m in Sources */,
6DD0502B1DF659ED0057C78D /* TZProgressView.m in Sources */,
6D32B9BD1CD83640005CE1E0 /* LxGridViewFlowLayout.m in Sources */,
......@@ -587,6 +600,7 @@
901F2295215CABD600F604ED /* FLAnimatedImage.m in Sources */,
900E65841C2BB8D5003D9A9E /* AppDelegate.m in Sources */,
9005E2B3257A462E002A8682 /* UIView+TZLayout.m in Sources */,
B606A9C4265FD53200F5493E /* TZVideoCropController.m in Sources */,
901F2296215CABD600F604ED /* FLAnimatedImageView.m in Sources */,
9019FD8D21EC25D7009ADEAE /* TZImageUploadOperation.m in Sources */,
900E65811C2BB8D5003D9A9E /* main.m in Sources */,
......@@ -619,6 +633,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B662C37326629179006A672A /* TZVideoEditedPreviewController.m in Sources */,
B6977B0A265FDB280028BA31 /* TZVideoCropController.m in Sources */,
901CC3FB21CB757500C55443 /* TZImageRequestOperation.m in Sources */,
9F763A501FA072E500D9E526 /* TZImagePickerController.m in Sources */,
9F763A521FA072E500D9E526 /* TZPhotoPickerController.m in Sources */,
......
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
\ No newline at end of file
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "hx_videoedit_left@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "hx_videoedit_right@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -80,6 +80,9 @@
- (PHImageRequestID)getOriginalPhotoDataWithAsset:(PHAsset *)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
- (PHImageRequestID)getOriginalPhotoDataWithAsset:(PHAsset *)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion;
/// Get Image For VideoURL
- (UIImage *)getImageWithVideoURL:(NSURL *)videoURL;
/// Save photo 保存照片
- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(PHAsset *asset, NSError *error))completion;
- (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(PHAsset *asset, NSError *error))completion;
......@@ -96,6 +99,7 @@
/// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480
- (void)getVideoOutputPathWithAsset:(PHAsset *)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
- (void)getVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
- (void)getVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName timeRange:(CMTimeRange)timeRange success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
/// 新的导出视频API,解决iOS14 iCloud视频导出失败的问题,未大量测试,请大家多多测试,有问题群里反馈
- (void)requestVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure;
/// 得到视频原始文件地址
......
......@@ -494,6 +494,22 @@ static dispatch_once_t onceToken;
}];
}
- (UIImage *)getImageWithVideoURL:(NSURL *)videoURL {
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
if (!asset) {
return nil;
}
AVAssetImageGenerator *generator =[[AVAssetImageGenerator alloc] initWithAsset:asset];
generator.appliesPreferredTrackTransform = YES;
generator.apertureMode = AVAssetImageGeneratorApertureModeEncodedPixels;
CFTimeInterval time = 0.1;
CGImageRef imageRef = [generator copyCGImageAtTime:CMTimeMake(time, 60) actualTime:NULL error:nil];
UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
CGImageRelease(imageRef);
return image;
}
#pragma mark - Save photo
- (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(PHAsset *asset, NSError *error))completion {
......@@ -637,19 +653,27 @@ static dispatch_once_t onceToken;
}
- (void)getVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
[self getVideoOutputPathWithAsset:asset presetName:presetName timeRange:kCMTimeRangeZero success:success failure:failure];
}
- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
[self startExportVideoWithVideoAsset:videoAsset timeRange:kCMTimeRangeZero presetName:presetName success:success failure:failure];
}
- (void)getVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName timeRange:(CMTimeRange)timeRange success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
if (@available(iOS 14.0, *)) {
[self requestVideoOutputPathWithAsset:asset presetName:presetName success:success failure:failure];
[self requestVideoOutputPathWithAsset:asset presetName:presetName timeRange:timeRange success:success failure:failure];
return;
}
[[PHImageManager defaultManager] requestAVAssetForVideo:asset options:[self getVideoRequestOptions] resultHandler:^(AVAsset* avasset, AVAudioMix* audioMix, NSDictionary* info){
// NSLog(@"Info:\n%@",info);
AVURLAsset *videoAsset = (AVURLAsset*)avasset;
// NSLog(@"AVAsset URL: %@",myAsset.URL);
[self startExportVideoWithVideoAsset:videoAsset presetName:presetName success:success failure:failure];
[self startExportVideoWithVideoAsset:videoAsset timeRange:timeRange presetName:presetName success:success failure:failure];
}];
}
- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
- (void)startExportVideoWithVideoAsset:(AVURLAsset *)videoAsset timeRange:(CMTimeRange)timeRange presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
if (!presetName) {
presetName = AVAssetExportPresetMediumQuality;
}
......@@ -665,6 +689,9 @@ static dispatch_once_t onceToken;
// Optimize for network use.
session.shouldOptimizeForNetworkUse = true;
if (!CMTimeRangeEqual(timeRange, kCMTimeRangeZero)) {
session.timeRange = timeRange;
}
NSArray *supportedTypeArray = session.supportedFileTypes;
if ([supportedTypeArray containsObject:AVFileTypeMPEG4]) {
......@@ -708,7 +735,7 @@ static dispatch_once_t onceToken;
}
}
- (void)requestVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
- (void)requestVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName timeRange:(CMTimeRange)timeRange success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure {
if (!presetName) {
presetName = AVAssetExportPresetMediumQuality;
}
......@@ -717,6 +744,9 @@ static dispatch_once_t onceToken;
exportSession.outputURL = [NSURL fileURLWithPath:outputPath];
exportSession.shouldOptimizeForNetworkUse = NO;
exportSession.outputFileType = AVFileTypeMPEG4;
if (!CMTimeRangeEqual(timeRange, kCMTimeRangeZero)) {
exportSession.timeRange = timeRange;
}
[exportSession exportAsynchronouslyWithCompletionHandler:^{
[self handleVideoExportResult:exportSession outputPath:outputPath success:success failure:failure];
}];
......
......@@ -2,6 +2,7 @@
"OK" = "حسنا";
"Back" = "الى الخلف";
"Done" = "فعله";
"Edit" = "تعديل";
"Sorry" = "آسف";
"Cancel" = "إلغاء";
"Setting" = "ضبط";
......
......@@ -2,6 +2,7 @@
"OK" = "Добре";
"Back" = "обратно";
"Done" = "Свършен";
"Edit" = "редактиране";
"Sorry" = "съжалявам";
"Cancel" = "Отказ";
"Setting" = "обстановка";
......
......@@ -2,6 +2,7 @@
"OK" = "OK";
"Back" = "Zadní";
"Done" = "Hotovo";
"Edit" = "Upravit";
"Sorry" = "Promiňte";
"Cancel" = "zrušení";
"Setting" = "Nastavení";
......
......@@ -2,6 +2,7 @@
"OK" = "OK";
"Back" = "Zurück";
"Done" = "Erledigt";
"Edit" = "Bearbeiten";
"Sorry" = "Es tut uns leid";
"Cancel" = "Stornieren";
"Setting" = "Rahmen";
......
......@@ -2,6 +2,7 @@
"OK" = "Εντάξει";
"Back" = "Πίσω";
"Done" = "Εγινε";
"Edit" = "επεξεργασία";
"Sorry" = "Συγνώμη";
"Cancel" = "Ματαίωση";
"Setting" = "Σύνθεση";
......
......@@ -2,6 +2,7 @@
"OK" = "DE ACUERDO";
"Back" = "Espalda";
"Done" = "Hecho";
"Edit" = "επεξεργασία";
"Sorry" = "Lo siento";
"Cancel" = "Cancelar";
"Setting" = "Ajuste";
......
......@@ -2,6 +2,7 @@
"OK" = "D'accord";
"Back" = "Retour";
"Done" = "Terminé";
"Edit" = "Éditer";
"Sorry" = "Pardon";
"Cancel" = "Annuler";
"Setting" = "Réglage";
......
......@@ -2,6 +2,7 @@
"OK" = "בסדר";
"Back" = "חזור";
"Done" = "בוצע";
"Edit" = "לַעֲרוֹך"
"Sorry" = "מצטער";
"Cancel" = "בטל";
"Setting" = "הגדרה";
......
......@@ -2,6 +2,7 @@
"OK" = "ok";
"Back" = "Indietro";
"Done" = "Fatto";
"Edit" = "modificare";
"Sorry" = "scusate";
"Cancel" = "Annulla";
"Setting" = "Ambientazione";
......
......@@ -2,6 +2,7 @@
"OK" = "OK";
"Back" = "バック";
"Done" = "完了";
"Edit" = "編集する";
"Sorry" = "ごめんなさい";
"Cancel" = "キャンセル";
"Setting" = "設定";
......
......@@ -2,6 +2,7 @@
"OK" = "그래";
"Back" = "뒤로";
"Done" = "완료";
"Edit" = "편집하다";
"Sorry" = "미안해요";
"Cancel" = "취소";
"Setting" = "설정";
......
......@@ -2,6 +2,7 @@
"OK" = "승인";
"Back" = "뒤로";
"Done" = "끝난";
"Edit" = "편집하다";
"Sorry" = "죄송합니다";
"Cancel" = "취소";
"Setting" = "환경";
......
......@@ -2,6 +2,7 @@
"OK" = "OK";
"Back" = "Terug";
"Done" = "Gedaan";
"Edit" = "Bewerk";
"Sorry" = "Sorry";
"Cancel" = "annuleren";
"Setting" = "omgeving";
......
......@@ -2,6 +2,7 @@
"OK" = "dobrze";
"Back" = "Z powrotem";
"Done" = "Gotowe";
"Edit" = "edytować";
"Sorry" = "Przepraszam";
"Cancel" = "Anuluj";
"Setting" = "Oprawa";
......
......@@ -2,6 +2,7 @@
"OK" = "Está bem";
"Back" = "De volta";
"Done" = "Feito";
"Edit" = "editar";
"Sorry" = "Desculpa";
"Cancel" = "Cancelar";
"Setting" = "Configuração";
......
......@@ -2,6 +2,7 @@
"OK" = "O.K";
"Back" = "Înapoi";
"Done" = "Terminat";
"Edit" = "Editați | ×";
"Sorry" = "scuze";
"Cancel" = "Anulare";
"Setting" = "reglaj";
......
......@@ -2,6 +2,7 @@
"OK" = "Хорошо";
"Back" = "назад";
"Done" = "Готово";
"Edit" = "редактировать";
"Sorry" = "сожалею";
"Cancel" = "отменить";
"Setting" = "настройка";
......
......@@ -2,6 +2,7 @@
"OK" = "OK";
"Back" = "späť";
"Done" = "hotový";
"Edit" = "upraviť";
"Sorry" = "Prepáč";
"Cancel" = "Zrušiť";
"Setting" = "nastavenie";
......
......@@ -2,6 +2,7 @@
"OK" = "ok";
"Back" = "Tillbaka";
"Done" = "Gjort";
"Edit" = "redigera";
"Sorry" = "Förlåt";
"Cancel" = "Annullera";
"Setting" = "Miljö";
......
......@@ -2,6 +2,7 @@
"OK" = "ตกลง";
"Back" = "กลับ";
"Done" = "เสร็จสิ้น";
"Edit" = "แก้ไข";
"Sorry" = "ขอโทษ";
"Cancel" = "ยกเลิก";
"Setting" = "การตั้งค่า";
......
......@@ -2,6 +2,7 @@
"OK" = "tamam";
"Back" = "Geri";
"Done" = "tamam";
"Edit" = "Düzenle";
"Sorry" = "Afedersiniz";
"Cancel" = "İptal etmek";
"Setting" = "Ayar";
......
......@@ -2,6 +2,7 @@
"OK" = "в порядку";
"Back" = "Назад";
"Done" = "Виконано";
"Edit" = "редагувати";
"Sorry" = "Вибачте";
"Cancel" = "Скасувати";
"Setting" = "Налаштування";
......
......@@ -2,6 +2,7 @@
"OK" = "Xác nhận";
"Back" = "Quay lại";
"Done" = "Hoàn thành";
"Edit" = "biên tập";
"Sorry" = "Xin lỗi";
"Cancel" = "Hủy";
"Setting" = "Cài đặt";
......
......@@ -78,6 +78,23 @@
/// Default is YES, if set NO, user can't picking video.
/// 默认为YES,如果设置为NO,用户将不能选择视频
@property (nonatomic, assign) BOOL allowPickingVideo;
/// Default is NO, if set YES, user can edit video.
/// 默认为NO,如果设置为YES, 用户能编辑视频
@property (nonatomic, assign) BOOL allowEditVideo;
/// Export quality of cropped video, Default is AVAssetExportPresetMediumQuality
/// 裁剪视频的导出质量,默认是 AVAssetExportPresetMediumQuality
@property (nonatomic, assign) NSString *presetName;
/// Default is 30s. If it exceeds the video duration, it is the video duration.The minimum duration of video crop is 1s.
/// 默认是30s,如果超过视频时长,则为视频时长,小于1s不裁剪
@property (nonatomic, assign) NSInteger maxCropVideoDuration;
/// Default is NO, if set YES, The edited video will be automatically saved to the album.
/// 默认为NO,如果设置为YES,编辑后的视频会自动保存到相册
@property (nonatomic, assign) BOOL saveEditedVideoToAlbum;
/// Default is NO / 默认为NO,为YES时可以多选视频/gif/图片,和照片共享最大可选张数maxImagesCount的限制
@property (nonatomic, assign) BOOL allowPickingMultipleVideo;
......@@ -176,7 +193,8 @@
/// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等
@property (nonatomic, copy) void (^photoPickerPageUIConfigBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine);
@property (nonatomic, copy) void (^photoPreviewPageUIConfigBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel);
@property (nonatomic, copy) void (^videoPreviewPageUIConfigBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton);
@property (nonatomic, copy) void (^videoPreviewPageUIConfigBlock)(UIButton *playButton, UIView *toolBar, UIButton *editBtn, UIButton *doneButton);
@property (nonatomic, copy) void (^videoEditViewPageUIConfigBlock)(UIButton *playButton,UILabel *cropVideoDurationLabel, UIButton *editButton, UIButton *doneButton);
@property (nonatomic, copy) void (^gifPreviewPageUIConfigBlock)(UIView *toolBar, UIButton *doneButton);
@property (nonatomic, copy) void (^albumPickerPageUIConfigBlock)(UITableView *tableView);
@property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
......@@ -184,7 +202,8 @@
/// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等
@property (nonatomic, copy) void (^photoPickerPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine);
@property (nonatomic, copy) void (^photoPreviewPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel);
@property (nonatomic, copy) void (^videoPreviewPageDidLayoutSubviewsBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton);
@property (nonatomic, copy) void (^videoPreviewPageDidLayoutSubviewsBlock)(UIButton *playButton, UIView *toolBar, UIButton *editButton, UIButton *doneButton);
@property (nonatomic, copy) void (^videoEditViewPageDidLayoutSubviewsBlock)(UIButton *playButton, UILabel *cropVideoDurationLabel, UIButton *cancelButton, UIButton *doneButton);
@property (nonatomic, copy) void (^gifPreviewPageDidLayoutSubviewsBlock)(UIView *toolBar, UIButton *doneButton);
@property (nonatomic, copy) void (^albumPickerPageDidLayoutSubviewsBlock)(UITableView *tableView);
@property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView);
......@@ -233,6 +252,8 @@
@property (nonatomic, copy) NSString *fullImageBtnTitleStr;
@property (nonatomic, copy) NSString *settingBtnTitleStr;
@property (nonatomic, copy) NSString *processHintStr;
@property (nonatomic, copy) NSString *editBtnTitleStr;
@property (nonatomic, copy) NSString *editViewCancelBtnTitleStr;
/// Icon theme color, default is green color like wechat, the value is r:31 g:185 b:34. Currently only support image selection icon when showSelectedIndex is YES. If you need it, please set it as soon as possible
/// icon主题色,默认是微信的绿色,值是r:31 g:185 b:34。目前仅支持showSelectedIndex为YES时的图片选中icon。如需要,请尽早设置它。
......@@ -246,6 +267,7 @@
@property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray<UIImage *> *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray<NSDictionary *> *infos);
@property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(void);
@property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,PHAsset *asset);
@property (nonatomic, copy) void (^didFinishPickingAndEditingVideoHandle)(UIImage *coverImage,NSString *outputPath,NSString *errorMsg);
@property (nonatomic, copy) void (^didFinishPickingGifImageHandle)(UIImage *animatedImage,id sourceAssets);
@property (nonatomic, weak) id<TZImagePickerControllerDelegate> pickerDelegate;
......@@ -285,6 +307,16 @@
// 如果allowPickingMultipleVideo是YES,将会调用imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(PHAsset *)asset;
// If allowEditVideo is YES and allowPickingMultipleVideo is NO, When user picking a video, this callback will be called.
// If allowPickingMultipleVideo is YES, video editing is not supported, will call imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
// 当allowEditVideo是YES且allowPickingMultipleVideo是NO是,如果用户选择了一个视频,下面的代理方法会被执行
// 如果allowPickingMultipleVideo是YES,则不支持编辑视频,将会调用imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingAndEditingVideo:(UIImage *)coverImage outputPath:(NSString *)outputPath error:(NSString *)errorMsg;
// When saving the edited video to the album fails, this callback will be called.
// 编辑后的视频自动保存到相册失败时,下面的代理方法会被执行
- (void)imagePickerController:(TZImagePickerController *)picker didFailToSaveEditedVideoWithError:(NSError *)error;
// If user picking a gif image and allowPickingMultipleVideo is NO, this callback will be called.
// If allowPickingMultipleVideo is YES, will call imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
// 如果用户选择了一个gif图片且allowPickingMultipleVideo是NO,下面的代理方法会被执行
......
......@@ -14,6 +14,7 @@
#import "TZAssetCell.h"
#import "UIView+TZLayout.h"
#import "TZImageManager.h"
#import "TZVideoCropController.h"
@interface TZImagePickerController () {
NSTimer *_timer;
......@@ -282,6 +283,8 @@
self.statusBarStyle = UIStatusBarStyleLightContent;
self.cannotSelectLayerColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8];
self.allowCameraLocation = YES;
self.presetName = AVAssetExportPresetMediumQuality;
self.maxCropVideoDuration = 30;
self.iconThemeColor = [UIColor colorWithRed:31 / 255.0 green:185 / 255.0 blue:34 / 255.0 alpha:1.0];
[self configDefaultBtnTitle];
......@@ -352,6 +355,7 @@
self.fullImageBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Full image"];
self.settingBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Setting"];
self.processHintStr = [NSBundle tz_localizedStringForKey:@"Processing..."];
self.editBtnTitleStr = [NSBundle tz_localizedStringForKey:@"Edit"];
}
- (void)setShowSelectedIndex:(BOOL)showSelectedIndex {
......@@ -708,6 +712,13 @@
}
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
if ([self.topViewController isKindOfClass:TZVideoPlayerController.class] && self.topViewController.presentedViewController) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAll;
}
@end
......
//
// TZVideoCropController.h
// TZImagePickerController
//
// Created by 肖兰月 on 2021/5/27.
// Copyright © 2021 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class TZAssetModel,TZImagePickerController;
@interface TZVideoCropController : UIViewController<UIViewControllerTransitioningDelegate>
@property (nonatomic, strong) TZAssetModel *model;
@property (nonatomic, weak) TZImagePickerController *imagePickerVc;
@end
@protocol TZVideoEditViewDelegate <NSObject>
- (void)editViewCropRectBeginChange;
- (void)editViewCropRectEndChange;
@end
@interface TZVideoEditView : UIView
@property (strong, nonatomic) UIImageView *beginImgView;
@property (strong, nonatomic) UIImageView *endImgView;
@property (strong, nonatomic) UIView *indicatorLine;
@property (assign, nonatomic) CGFloat videoDuration;
@property (assign, nonatomic) NSInteger maxCropVideoDuration;
@property (assign, nonatomic) CGRect cropRect;
@property (assign, nonatomic) CGFloat allImgWidth;
@property (assign, nonatomic) CGFloat minCropRectWidth;
@property (nonatomic, weak) id<TZVideoEditViewDelegate> delegate;
- (void)resetIndicatorLine;
- (void)indicatorLineAnimateWithDuration:(NSTimeInterval)duration cropRect:(CGRect)cropRect;
@end
@interface TZVideoPictureCell : UICollectionViewCell
@property (strong, nonatomic) UIImageView *imgView;
@end
NS_ASSUME_NONNULL_END
//
// TZVideoEditedPreviewController.h
// TZImagePickerController
//
// Created by 肖兰月 on 2021/5/29.
// Copyright © 2021 谭真. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface TZVideoEditedPreviewController : UIViewController
@property (nonatomic, copy) NSURL *videoURL;
@end
NS_ASSUME_NONNULL_END
//
// TZVideoEditedPreviewController.m
// TZImagePickerController
//
// Created by 肖兰月 on 2021/5/29.
// Copyright © 2021 谭真. All rights reserved.
//
#import "TZVideoEditedPreviewController.h"
#import <MediaPlayer/MediaPlayer.h>
#import "TZImageManager.h"
#import "TZImagePickerController.h"
#import "UIView+TZLayout.h"
@interface TZVideoEditedPreviewController () {
AVPlayer *_player;
AVPlayerLayer *_playerLayer;
UIButton *_playButton;
UIImage *_cover;
UIView *_toolBar;
UIButton *_doneButton;
UIProgressView *_progress;
UIStatusBarStyle _originStatusBarStyle;
}
@end
@implementation TZVideoEditedPreviewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self configMoviePlayer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil];
}
- (void)configMoviePlayer {
_player = [AVPlayer playerWithURL:self.videoURL];
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
[self.view.layer addSublayer:_playerLayer];
[self configPlayButton];
[self configBottomToolBar];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem];
}
- (void)configPlayButton {
_playButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
[_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted];
[_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:_playButton];
}
- (void)configBottomToolBar {
_toolBar = [[UIView alloc] initWithFrame:CGRectZero];
CGFloat rgb = 34 / 255.0;
_toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7];
_doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
_doneButton.titleLabel.font = [UIFont systemFontOfSize:16];
[_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc) {
[_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal];
[_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
} else {
[_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal];
[_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal];
}
[_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled];
[_toolBar addSubview:_doneButton];
[self.view addSubview:_toolBar];
}
#pragma mark - Layout
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
BOOL isFullScreen = self.view.tz_height == [UIScreen mainScreen].bounds.size.height;
CGFloat statusBarHeight = isFullScreen ? [TZCommonTools tz_statusBarHeight] : 0;
CGFloat statusBarAndNaviBarHeight = statusBarHeight + self.navigationController.navigationBar.tz_height;
CGFloat toolBarHeight = 44 + [TZCommonTools tz_safeAreaInsets].bottom;
_toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
_playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight);
_playerLayer.frame = self.view.bounds;
}
#pragma mark - Click Event
- (void)playButtonClick {
CMTime currentTime = _player.currentItem.currentTime;
CMTime durationTime = _player.currentItem.duration;
if (_player.rate == 0.0f) {
if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)];
[_player play];
_toolBar.hidden = YES;
[_playButton setImage:nil forState:UIControlStateNormal];
} else {
[self pausePlayerAndShowNaviBar];
}
}
- (void)doneButtonClick {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - Notification Method
- (void)pausePlayerAndShowNaviBar {
[_player pause];
_toolBar.hidden = NO;
[_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma clang diagnostic pop
@end
......@@ -13,15 +13,19 @@
#import "TZAssetModel.h"
#import "TZImagePickerController.h"
#import "TZPhotoPreviewController.h"
#import "TZVideoCropController.h"
@interface TZVideoPlayerController () {
AVPlayer *_player;
AVPlayerLayer *_playerLayer;
UIButton *_playButton;
UIImage *_cover;
NSString *_outputPath;
NSString *_errorMsg;
UIView *_toolBar;
UIButton *_doneButton;
UIButton *_editButton;
UIProgressView *_progress;
UIStatusBarStyle _originStatusBarStyle;
......@@ -71,6 +75,7 @@
if (!isDegraded && photo) {
self->_cover = photo;
self->_doneButton.enabled = YES;
self->_editButton.enabled = YES;
}
}];
[[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) {
......@@ -131,8 +136,21 @@
[_toolBar addSubview:_doneButton];
[self.view addSubview:_toolBar];
if (tzImagePickerVc && tzImagePickerVc.allowEditVideo && roundf(self.model.asset.duration) > 1) {
_editButton = [UIButton buttonWithType:UIButtonTypeCustom];
_editButton.titleLabel.font = [UIFont systemFontOfSize:16];
if (!_cover) {
_editButton.enabled = NO;
}
[_editButton addTarget:self action:@selector(editButtonClick) forControlEvents:UIControlEventTouchUpInside];
[_editButton setTitle:tzImagePickerVc.editBtnTitleStr forState:UIControlStateNormal];
[_editButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal];
[_editButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled];
[_toolBar addSubview:_editButton];
}
if (tzImagePickerVc.videoPreviewPageUIConfigBlock) {
tzImagePickerVc.videoPreviewPageUIConfigBlock(_playButton, _toolBar, _doneButton);
tzImagePickerVc.videoPreviewPageUIConfigBlock(_playButton, _toolBar, _editButton, _doneButton);
}
}
......@@ -148,6 +166,7 @@
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
BOOL isFullScreen = self.view.tz_height == [UIScreen mainScreen].bounds.size.height;
CGFloat statusBarHeight = isFullScreen ? [TZCommonTools tz_statusBarHeight] : 0;
......@@ -157,10 +176,11 @@
_toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight);
_doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44);
_playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight);
TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController;
if (tzImagePickerVc.allowEditVideo) {
_editButton.frame = CGRectMake(12, 0, 44, 44);
}
if (tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock) {
tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock(_playButton, _toolBar, _doneButton);
tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock(_playButton, _toolBar, _editButton, _doneButton);
}
}
......@@ -182,33 +202,78 @@
}
}
- (void)editButtonClick {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
TZVideoCropController *videoCropVc = [[TZVideoCropController alloc] init];
videoCropVc.model = self.model;
videoCropVc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
videoCropVc.modalPresentationStyle = UIModalPresentationFullScreen;
videoCropVc.modalPresentationCapturesStatusBarAppearance = YES;
videoCropVc.imagePickerVc = imagePickerVc;
[self presentViewController:videoCropVc animated:YES completion:nil];
}
- (void)doneButtonClick {
if ([[TZImageManager manager] isAssetCannotBeSelected:_model.asset]) {
return;
}
if (self.navigationController) {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (imagePickerVc.autoDismiss) {
[self.navigationController dismissViewControllerAnimated:YES completion:^{
[self callDelegateMethod];
}];
} else {
[self callDelegateMethod];
}
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (imagePickerVc.allowEditVideo) {
[imagePickerVc showProgressHUD];
[[TZImageManager manager] getVideoOutputPathWithAsset:_model.asset presetName:imagePickerVc.presetName success:^(NSString *outputPath) {
[imagePickerVc hideProgressHUD];
self->_outputPath = outputPath;
[self dismissAndCallDelegateMethod];
} failure:^(NSString *errorMessage, NSError *error) {
[imagePickerVc hideProgressHUD];
self->_errorMsg = errorMessage;
[self dismissAndCallDelegateMethod];
}];
} else {
[self dismissViewControllerAnimated:YES completion:^{
[self dismissAndCallDelegateMethod];
}
}
- (void)dismissAndCallDelegateMethod {
UIViewController *vc = self.navigationController;
if (!vc) {
vc = self;
}
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if (imagePickerVc.autoDismiss) {
[vc dismissViewControllerAnimated:YES completion:^{
[self callDelegateMethod];
}];
} else {
[self callDelegateMethod];
}
}
- (void)callDelegateMethod {
TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController;
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset];
}
if (imagePickerVc.didFinishPickingVideoHandle) {
imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset);
if (imagePickerVc.allowEditVideo) {
if (_outputPath) {
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingAndEditingVideo:outputPath:error:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingAndEditingVideo:self->_cover outputPath:self->_outputPath error:nil];
}
if (imagePickerVc.didFinishPickingAndEditingVideoHandle) {
imagePickerVc.didFinishPickingAndEditingVideoHandle(self->_cover, self->_outputPath, nil);
}
} else {
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingAndEditingVideo:outputPath:error:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingAndEditingVideo:nil outputPath:nil error:self->_errorMsg];
}
if (imagePickerVc.didFinishPickingAndEditingVideoHandle) {
imagePickerVc.didFinishPickingAndEditingVideoHandle(nil, nil, self->_errorMsg);
}
}
} else {
if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) {
[imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset];
}
if (imagePickerVc.didFinishPickingVideoHandle) {
imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset);
}
}
}
......
......@@ -21,11 +21,13 @@
#import <MobileCoreServices/MobileCoreServices.h>
#import "FLAnimatedImage.h"
#import "TZImageUploadOperation.h"
#import "TZVideoEditedPreviewController.h"
@interface ViewController ()<TZImagePickerControllerDelegate,UICollectionViewDataSource,UICollectionViewDelegate,UIImagePickerControllerDelegate,UINavigationControllerDelegate> {
NSMutableArray *_selectedPhotos;
NSMutableArray *_selectedAssets;
BOOL _isSelectOriginalPhoto;
BOOL _isAllowEditVideo;
CGFloat _itemWH;
CGFloat _margin;
......@@ -132,9 +134,13 @@
return _selectedPhotos.count;
}
if (!self.allowPickingMuitlpleVideoSwitch.isOn) {
for (PHAsset *asset in _selectedAssets) {
if (asset.mediaType == PHAssetMediaTypeVideo) {
return _selectedPhotos.count;
if (_isAllowEditVideo) {
return 1;
} else {
for (PHAsset *asset in _selectedAssets) {
if (asset.mediaType == PHAssetMediaTypeVideo) {
return _selectedPhotos.count;
}
}
}
}
......@@ -150,7 +156,9 @@
cell.gifLable.hidden = YES;
} else {
cell.imageView.image = _selectedPhotos[indexPath.item];
cell.asset = _selectedAssets[indexPath.item];
if (!_isAllowEditVideo) {
cell.asset = _selectedAssets[indexPath.item];
}
cell.deleteBtn.hidden = NO;
}
if (!self.allowPickingGifSwitch.isOn) {
......@@ -193,6 +201,11 @@
} else {
[self pushTZImagePickerController];
}
} else if (_isAllowEditVideo) { // preview edited video / 预览编辑后的视频
TZVideoEditedPreviewController *vc = [[TZVideoEditedPreviewController alloc] init];
vc.videoURL = _selectedAssets[indexPath.item];
vc.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:vc animated:YES completion:nil];
} else { // preview photos or video / 预览照片或者视频
PHAsset *asset = _selectedAssets[indexPath.item];
BOOL isVideo = NO;
......@@ -280,6 +293,10 @@
imagePickerVc.allowTakePicture = self.showTakePhotoBtnSwitch.isOn; // 在内部显示拍照按钮
imagePickerVc.allowTakeVideo = self.showTakeVideoBtnSwitch.isOn; // 在内部显示拍视频按
imagePickerVc.videoMaximumDuration = 10; // 视频最大拍摄时间
imagePickerVc.allowEditVideo = YES; // 允许编辑视频
// imagePickerVc.saveEditedVideoToCollection = YES; // 编辑后的视频是否自动保存到相册
// imagePickerVc.maxCropVideoDuration = 30; // 裁剪视频的最大时长
// imagePickerVc.presetName = AVAssetExportPresetMediumQuality // 编辑后的视频的导出质量
[imagePickerVc setUiImagePickerControllerSettingBlock:^(UIImagePickerController *imagePickerController) {
imagePickerController.videoQuality = UIImagePickerControllerQualityTypeHigh;
}];
......@@ -633,6 +650,31 @@
// _collectionView.contentSize = CGSizeMake(0, ((_selectedPhotos.count + 2) / 3 ) * (_margin + _itemWH));
}
// If allowEditVideo is YES and allowPickingMultipleVideo is NO, When user picking a video, this callback will be called.
// If allowPickingMultipleVideo is YES, video editing is not supported, will call imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
// 当allowEditVideo是YES且allowPickingMultipleVideo是NO是,如果用户选择了一个视频,下面的代理方法会被执行
// 如果allowPickingMultipleVideo是YES,则不支持编辑视频,将会调用imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
- (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingAndEditingVideo:(UIImage *)coverImage outputPath:(NSString *)outputPath error:(NSString *)errorMsg {
_isAllowEditVideo = YES;
self->_selectedPhotos = [NSMutableArray arrayWithArray:@[coverImage]];
self->_selectedAssets = [NSMutableArray arrayWithArray:@[[NSURL fileURLWithPath:outputPath]]];
if (outputPath) {
// NSData *data = [NSData dataWithContentsOfFile:outputPath];
NSLog(@"视频导出到本地完成,outputPath为:%@",outputPath);
// Export completed, send video here, send by outputPath or NSData
// 导出完成,在这里写上传代码,通过路径或者通过NSData上传
} else {
NSLog(@"视频导出失败:%@",errorMsg);
}
[self.collectionView reloadData];
}
// If user fail to save edited, this callback will be called.
// 如果用户保存编辑好的视频失败,将会调用
- (void)imagePickerController:(TZImagePickerController *)picker didFailToSaveEditedVideoWithError:(NSError *)error {
NSLog(@"编辑后的视频自动保存到相册失败:%@",error.description);
}
// If user picking a gif image and allowPickingMultipleVideo is NO, this callback will be called.
// If allowPickingMultipleVideo is YES, will call imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:
// 如果用户选择了一个gif图片且allowPickingMultipleVideo是NO,下面的代理方法会被执行
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment