├── ACMediaFrameExample ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── AppDelegate.h ├── UIFrameViewController.h ├── RootTableViewController.h ├── main.m ├── CoreFuncViewController.h ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.storyboard ├── UIFrameViewController.m ├── Info.plist ├── CoreFuncViewController.m ├── RootTableViewController.m ├── AppDelegate.m └── CoreFuncViewController.xib ├── Podfile ├── ACMediaFrame ├── ACMediaFrame.bundle │ ├── AddMedia@2x.png │ ├── AddMedia@3x.png │ ├── ShowVideo@2x.png │ ├── ShowVideo@3x.png │ ├── deleteButton@2x.png │ └── deleteButton@3x.png ├── Core │ ├── ACMediaModel.m │ ├── ACMediaModel.h │ ├── ACMediaTool.h │ ├── ACMediaPickerManager.h │ ├── ACMediaPickerManager.m │ └── ACMediaTool.m └── UI │ ├── ACMediaImageCell.h │ ├── ACMediaDisplayConfig.m │ ├── ACMediaDisplayConfig.h │ ├── ACMediaDisplayView.h │ ├── ACMediaImageCell.m │ └── ACMediaDisplayView.m ├── Pods ├── Target Support Files │ ├── TZImagePickerController │ │ ├── TZImagePickerController.modulemap │ │ ├── TZImagePickerController-dummy.m │ │ ├── TZImagePickerController-prefix.pch │ │ ├── TZImagePickerController.xcconfig │ │ ├── Info.plist │ │ └── TZImagePickerController-umbrella.h │ └── Pods-ACMediaFrameExample │ │ ├── Pods-ACMediaFrameExample.modulemap │ │ ├── Pods-ACMediaFrameExample-dummy.m │ │ ├── Pods-ACMediaFrameExample-umbrella.h │ │ ├── Pods-ACMediaFrameExample.debug.xcconfig │ │ ├── Pods-ACMediaFrameExample.release.xcconfig │ │ ├── Info.plist │ │ ├── Pods-ACMediaFrameExample-acknowledgements.markdown │ │ ├── Pods-ACMediaFrameExample-acknowledgements.plist │ │ ├── Pods-ACMediaFrameExample-resources.sh │ │ └── Pods-ACMediaFrameExample-frameworks.sh ├── TZImagePickerController │ ├── TZImagePickerController │ │ └── TZImagePickerController │ │ │ ├── TZImagePickerController.bundle │ │ │ ├── navi_back@2x.png │ │ │ ├── VideoSendIcon@2x.png │ │ │ ├── takePicture@2x.png │ │ │ ├── MMVideoPreviewPlay@2x.png │ │ │ ├── photo_number_icon@2x.png │ │ │ ├── photo_original_def@2x.png │ │ │ ├── photo_original_sel@2x.png │ │ │ ├── MMVideoPreviewPlayHL@2x.png │ │ │ ├── photo_def_previewVc@2x.png │ │ │ ├── photo_sel_previewVc@2x.png │ │ │ ├── preview_number_icon@2x.png │ │ │ ├── preview_original_def@2x.png │ │ │ ├── en.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── photo_def_photoPickerVc@2x.png │ │ │ ├── photo_sel_photoPickerVc@2x.png │ │ │ └── zh-Hans.lproj │ │ │ │ └── Localizable.strings │ │ │ ├── TZProgressView.h │ │ │ ├── TZVideoPlayerController.h │ │ │ ├── TZGifPhotoPreviewController.h │ │ │ ├── NSBundle+TZImagePicker.h │ │ │ ├── TZPhotoPickerController.h │ │ │ ├── TZLocationManager.h │ │ │ ├── NSBundle+TZImagePicker.m │ │ │ ├── TZImageCropManager.h │ │ │ ├── TZPhotoPreviewController.h │ │ │ ├── TZProgressView.m │ │ │ ├── TZAssetModel.h │ │ │ ├── TZAssetModel.m │ │ │ ├── TZAssetCell.h │ │ │ ├── TZPhotoPreviewCell.h │ │ │ ├── TZLocationManager.m │ │ │ ├── TZGifPhotoPreviewController.m │ │ │ ├── TZImageCropManager.m │ │ │ ├── TZImageManager.h │ │ │ ├── TZVideoPlayerController.m │ │ │ ├── TZAssetCell.m │ │ │ └── TZImagePickerController.h │ ├── LICENSE │ └── README.md └── Manifest.lock ├── ACMediaFrameExample.xcodeproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── .gitignore ├── ACMediaFrameExample.xcworkspace ├── xcshareddata │ └── IDEWorkspaceChecks.plist └── contents.xcworkspacedata ├── Podfile.lock ├── ACMediaFrame.podspec ├── LICENSE ├── README.md └── before 3.0.0 README.md /ACMediaFrameExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '8.0' 2 | use_frameworks! 3 | 4 | target "ACMediaFrameExample" do 5 | 6 | pod 'TZImagePickerController' 7 | 8 | end 9 | -------------------------------------------------------------------------------- /ACMediaFrame/ACMediaFrame.bundle/AddMedia@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/ACMediaFrame/ACMediaFrame.bundle/AddMedia@2x.png -------------------------------------------------------------------------------- /ACMediaFrame/ACMediaFrame.bundle/AddMedia@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/ACMediaFrame/ACMediaFrame.bundle/AddMedia@3x.png -------------------------------------------------------------------------------- /ACMediaFrame/ACMediaFrame.bundle/ShowVideo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/ACMediaFrame/ACMediaFrame.bundle/ShowVideo@2x.png -------------------------------------------------------------------------------- /ACMediaFrame/ACMediaFrame.bundle/ShowVideo@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/ACMediaFrame/ACMediaFrame.bundle/ShowVideo@3x.png -------------------------------------------------------------------------------- /ACMediaFrame/ACMediaFrame.bundle/deleteButton@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/ACMediaFrame/ACMediaFrame.bundle/deleteButton@2x.png -------------------------------------------------------------------------------- /ACMediaFrame/ACMediaFrame.bundle/deleteButton@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/ACMediaFrame/ACMediaFrame.bundle/deleteButton@3x.png -------------------------------------------------------------------------------- /Pods/Target Support Files/TZImagePickerController/TZImagePickerController.modulemap: -------------------------------------------------------------------------------- 1 | framework module TZImagePickerController { 2 | umbrella header "TZImagePickerController-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_ACMediaFrameExample { 2 | umbrella header "Pods-ACMediaFrameExample-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/TZImagePickerController/TZImagePickerController-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_TZImagePickerController : NSObject 3 | @end 4 | @implementation PodsDummy_TZImagePickerController 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_ACMediaFrameExample : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_ACMediaFrameExample 5 | @end 6 | -------------------------------------------------------------------------------- /ACMediaFrameExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ACMediaFrame/Core/ACMediaModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaModel.m 3 | // 4 | // Created by caoyq on 2018/11/26. 5 | // Copyright © 2018 AllenCao. All rights reserved. 6 | // 7 | 8 | #import "ACMediaModel.h" 9 | 10 | @implementation ACMediaModel 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/navi_back@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/VideoSendIcon@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/takePicture@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlay@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_number_icon@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_def@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_original_sel@2x.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/ 3 | DerivedData/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | 15 | ## Other 16 | *.moved-aside 17 | 18 | # macOS 19 | .DS_Store 20 | 21 | Pods -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/MMVideoPreviewPlayHL@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_previewVc@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_previewVc@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_number_icon@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/preview_original_def@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_def_photoPickerVc@2x.png -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/photo_sel_photoPickerVc@2x.png -------------------------------------------------------------------------------- /ACMediaFrameExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/honeycao/ACMediaFrame/HEAD/Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.bundle/zh-Hans.lproj/Localizable.strings -------------------------------------------------------------------------------- /Pods/Target Support Files/TZImagePickerController/TZImagePickerController-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /ACMediaFrameExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - TZImagePickerController (3.6.0) 3 | 4 | DEPENDENCIES: 5 | - TZImagePickerController 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - TZImagePickerController 10 | 11 | SPEC CHECKSUMS: 12 | TZImagePickerController: a37d7eec87c54436e896a67947033ad2178d498b 13 | 14 | PODFILE CHECKSUM: 59d7afde2b0a037cf7d557d11d5501b0c4071cf6 15 | 16 | COCOAPODS: 1.9.1 17 | -------------------------------------------------------------------------------- /ACMediaFrameExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2017/3/26. 6 | // Copyright © 2017年 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - TZImagePickerController (3.6.0) 3 | 4 | DEPENDENCIES: 5 | - TZImagePickerController 6 | 7 | SPEC REPOS: 8 | trunk: 9 | - TZImagePickerController 10 | 11 | SPEC CHECKSUMS: 12 | TZImagePickerController: a37d7eec87c54436e896a67947033ad2178d498b 13 | 14 | PODFILE CHECKSUM: 59d7afde2b0a037cf7d557d11d5501b0c4071cf6 15 | 16 | COCOAPODS: 1.9.1 17 | -------------------------------------------------------------------------------- /ACMediaFrameExample/UIFrameViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIFrameViewController.h 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2021/4/20. 6 | // Copyright © 2021 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UIFrameViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /ACMediaFrameExample/RootTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // RootTableViewController.h 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2021/4/20. 6 | // Copyright © 2021 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface RootTableViewController : UITableViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZProgressView.h 3 | // TZImagePickerController 4 | // 5 | // Created by ttouch on 2016/12/6. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TZProgressView : UIView 12 | 13 | @property (nonatomic, assign) double progress; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ACMediaFrameExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2017/3/26. 6 | // Copyright © 2017年 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ACMediaFrameExample/CoreFuncViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreFuncViewController.h 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2021/4/20. 6 | // Copyright © 2021 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /** 14 | * 核心功能展示:负责选取图片 15 | */ 16 | @interface CoreFuncViewController : UIViewController 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZVideoPlayerController.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 16/1/5. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TZAssetModel; 12 | @interface TZVideoPlayerController : UIViewController 13 | 14 | @property (nonatomic, strong) TZAssetModel *model; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZGifPhotoPreviewController.h 3 | // TZImagePickerController 4 | // 5 | // Created by ttouch on 2016/12/13. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TZAssetModel; 12 | @interface TZGifPhotoPreviewController : UIViewController 13 | 14 | @property (nonatomic, strong) TZAssetModel *model; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_ACMediaFrameExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_ACMediaFrameExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+TZImagePicker.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 16/08/18. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSBundle (TZImagePicker) 12 | 13 | + (NSBundle *)tz_imagePickerBundle; 14 | 15 | + (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value; 16 | + (NSString *)tz_localizedStringForKey:(NSString *)key; 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Pods/Target Support Files/TZImagePickerController/TZImagePickerController.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/TZImagePickerController 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = -framework "Photos" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/TZImagePickerController 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZPhotoPickerController.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TZAlbumModel; 12 | @interface TZPhotoPickerController : UIViewController 13 | 14 | @property (nonatomic, assign) BOOL isFirstAppear; 15 | @property (nonatomic, assign) NSInteger columnNumber; 16 | @property (nonatomic, strong) TZAlbumModel *model; 17 | @end 18 | 19 | 20 | @interface TZCollectionView : UICollectionView 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ACMediaFrame/UI/ACMediaImageCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaImageCell.h 3 | // 4 | // Created by caoyq on 2021/4/20. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface ACMediaImageCell : UICollectionViewCell 13 | 14 | /// 展示的图片 15 | @property (nonatomic, strong) UIImage *_Nullable showImage; 16 | /// video 播放标签 17 | @property (nonatomic, strong) UIImage *_Nullable videoTagImage; 18 | /// 删除按钮图片 19 | @property (nonatomic, strong) UIImage *_Nullable deleteButtonImage; 20 | 21 | /** 点击删除按钮的回调block */ 22 | @property (nonatomic, copy) void(^ACMediaClickDeleteButton)(); 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/TZImagePickerController" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/TZImagePickerController/TZImagePickerController.framework/Headers" 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_LDFLAGS = $(inherited) -framework "Photos" -framework "TZImagePickerController" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/TZImagePickerController" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/TZImagePickerController/TZImagePickerController.framework/Headers" 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_LDFLAGS = $(inherited) -framework "Photos" -framework "TZImagePickerController" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 11 | -------------------------------------------------------------------------------- /ACMediaFrame/Core/ACMediaModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaModel.h 3 | // 4 | // Created by caoyq on 2018/11/26. 5 | // Copyright © 2018 AllenCao. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | typedef NS_ENUM(NSInteger, ACMediaModelType) { 12 | ACMediaModelTypePhoto = 0, 13 | ACMediaModelTypeLivePhoto, 14 | ACMediaModelTypePhotoGif, 15 | ACMediaModelTypeVideo, 16 | ACMediaModelTypeAudio 17 | }; 18 | 19 | /** 20 | * 媒体资源模型 21 | */ 22 | @interface ACMediaModel : NSObject 23 | 24 | /// 文件名 25 | @property (nonatomic, strong) NSString *name; 26 | /// 二进制文件数据 27 | @property (nonatomic, strong) NSData *data; 28 | @property (nonatomic, strong) PHAsset *asset; 29 | 30 | /// 图片、gif以及视频的封面图 31 | @property (nonatomic, strong) UIImage *image; 32 | 33 | /// 视频URL(单选视频会有,多选的话只有data) 34 | @property (nonatomic, strong) NSURL *videoURL; 35 | 36 | /// 媒体类型 37 | @property (nonatomic, assign) ACMediaModelType mediaType; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/TZImagePickerController/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.1.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZLocationManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZLocationManager.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 2017/06/03. 6 | // Copyright © 2017年 谭真. All rights reserved. 7 | // 定位管理类 8 | 9 | 10 | #import 11 | #import 12 | 13 | @interface TZLocationManager : NSObject 14 | 15 | + (instancetype)manager NS_SWIFT_NAME(default()); 16 | 17 | /// 开始定位 18 | - (void)startLocation; 19 | - (void)startLocationWithSuccessBlock:(void (^)(NSArray *))successBlock failureBlock:(void (^)(NSError *error))failureBlock; 20 | - (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock; 21 | - (void)startLocationWithSuccessBlock:(void (^)(NSArray *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock; 22 | 23 | /// 结束定位 24 | - (void)stopUpdatingLocation; 25 | 26 | @end 27 | 28 | -------------------------------------------------------------------------------- /Pods/Target Support Files/TZImagePickerController/TZImagePickerController-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "NSBundle+TZImagePicker.h" 14 | #import "TZAssetCell.h" 15 | #import "TZAssetModel.h" 16 | #import "TZGifPhotoPreviewController.h" 17 | #import "TZImageCropManager.h" 18 | #import "TZImageManager.h" 19 | #import "TZImagePickerController.h" 20 | #import "TZImageRequestOperation.h" 21 | #import "TZLocationManager.h" 22 | #import "TZPhotoPickerController.h" 23 | #import "TZPhotoPreviewCell.h" 24 | #import "TZPhotoPreviewController.h" 25 | #import "TZProgressView.h" 26 | #import "TZVideoPlayerController.h" 27 | #import "UIView+TZLayout.h" 28 | 29 | FOUNDATION_EXPORT double TZImagePickerControllerVersionNumber; 30 | FOUNDATION_EXPORT const unsigned char TZImagePickerControllerVersionString[]; 31 | 32 | -------------------------------------------------------------------------------- /ACMediaFrame.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | 4 | s.name = "ACMediaFrame" 5 | s.version = "3.1.0" 6 | s.summary = "An easy way to display image or video form album or camera, and get more info of image or video to upload and so on." 7 | s.homepage = "https://github.com/honeycao/ACMediaFrame" 8 | s.license = "MIT" 9 | s.author = { "ArthurCao" => "honeycao9268@163.com" } 10 | s.platform = :ios, "8.0" 11 | 12 | s.source = { 13 | :git => "https://github.com/honeycao/ACMediaFrame.git", 14 | :tag => "#{s.version}" 15 | } 16 | 17 | s.default_subspec = 'UI' 18 | 19 | s.subspec 'UI' do |ss| 20 | ss.source_files = "ACMediaFrame/UI/*.{h,m}" 21 | ss.resources = "ACMediaFrame/ACMediaFrame.bundle" 22 | ss.dependency 'ACMediaFrame/Core' 23 | end 24 | 25 | s.subspec 'Core' do |ss| 26 | ss.source_files = "ACMediaFrame/Core/*.{h,m}" 27 | end 28 | 29 | s.requires_arc = true 30 | 31 | s.dependency 'TZImagePickerController' 32 | 33 | end 34 | -------------------------------------------------------------------------------- /ACMediaFrame/UI/ACMediaDisplayConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaDisplayConfig.m 3 | // 4 | // Created by caoyq on 2021/4/20. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import "ACMediaDisplayConfig.h" 9 | 10 | @implementation ACMediaDisplayConfig 11 | 12 | - (instancetype)init 13 | { 14 | self = [super init]; 15 | if (self) { 16 | self.rowImageCount = 4; 17 | self.lineSpacing = 10.0; 18 | self.interitemSpacing = 10.0; 19 | self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10); 20 | 21 | NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 22 | 23 | self.deleteImage = [UIImage imageWithContentsOfFile:[bundle pathForResource:@"ACMediaFrame.bundle/deleteButton" ofType:@"png"]]; 24 | self.addImage = [UIImage imageWithContentsOfFile:[bundle pathForResource:@"ACMediaFrame.bundle/AddMedia" ofType:@"png"]]; 25 | self.videoTagImage = [UIImage imageWithContentsOfFile:[bundle pathForResource:@"ACMediaFrame.bundle/ShowVideo" ofType:@"png"]]; 26 | } 27 | return self; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /ACMediaFrameExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "size" : "1024x1024", 46 | "scale" : "1x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Arthur Cao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Zhen Tan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /ACMediaFrame/UI/ACMediaDisplayConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaDisplayConfig.h 3 | // 4 | // Created by caoyq on 2021/4/20. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /** 13 | * UI 配置项 14 | */ 15 | @interface ACMediaDisplayConfig : NSObject 16 | 17 | /// 容器背景色 18 | @property (nonatomic, strong) UIColor *containerBgColor; 19 | 20 | /** 一行显示图片个数. default is 4. */ 21 | @property (nonatomic, assign) NSInteger rowImageCount; 22 | /** item行间距. default is 10. */ 23 | @property (nonatomic, assign) CGFloat lineSpacing; 24 | /** item列间距. default is 10. */ 25 | @property (nonatomic, assign) CGFloat interitemSpacing; 26 | /** section边距. default is (10, 10, 10, 10). */ 27 | @property (nonatomic, assign) UIEdgeInsets sectionInset; 28 | 29 | /******* 图片资源为可选,可手动传入进行自定义 *******/ 30 | 31 | /** 添加按钮的图片. 不想使用自带的图片可以自定义传入. */ 32 | @property (nonatomic, strong) UIImage *addImage; 33 | /** 删除按钮的图片. 不想使用自带的图片可以自定义传入. */ 34 | @property (nonatomic, strong) UIImage *deleteImage; 35 | /** 视频标签图片. 不想使用自带的图片可以自定义传入. */ 36 | @property (nonatomic, strong) UIImage *videoTagImage; 37 | 38 | @end 39 | 40 | NS_ASSUME_NONNULL_END 41 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/NSBundle+TZImagePicker.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+TZImagePicker.m 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 16/08/18. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import "NSBundle+TZImagePicker.h" 10 | #import "TZImagePickerController.h" 11 | 12 | @implementation NSBundle (TZImagePicker) 13 | 14 | + (NSBundle *)tz_imagePickerBundle { 15 | #ifdef SWIFT_PACKAGE 16 | NSBundle *bundle = SWIFTPM_MODULE_BUNDLE; 17 | #else 18 | NSBundle *bundle = [NSBundle bundleForClass:[TZImagePickerController class]]; 19 | #endif 20 | NSURL *url = [bundle URLForResource:@"TZImagePickerController" withExtension:@"bundle"]; 21 | bundle = [NSBundle bundleWithURL:url]; 22 | return bundle; 23 | } 24 | 25 | + (NSString *)tz_localizedStringForKey:(NSString *)key { 26 | return [self tz_localizedStringForKey:key value:@""]; 27 | } 28 | 29 | + (NSString *)tz_localizedStringForKey:(NSString *)key value:(NSString *)value { 30 | NSBundle *bundle = [TZImagePickerConfig sharedInstance].languageBundle; 31 | NSString *value1 = [bundle localizedStringForKey:key value:value table:nil]; 32 | return value1; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /ACMediaFrame/UI/ACMediaDisplayView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaDisplayView.h 3 | // 4 | // Created by caoyq on 2021/4/20. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import 9 | #import "ACMediaDisplayConfig.h" 10 | #import "ACMediaPickerManager.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** 15 | * UI 展示层 + 核心功能 16 | */ 17 | @interface ACMediaDisplayView : UIView 18 | 19 | /// 对外提供已选中的媒体资源列表. 20 | @property (nonatomic, strong, readonly) NSArray *selectedMediaList; 21 | /// 对外提供容器实时的高度 22 | @property (nonatomic, assign, readonly) CGFloat viewHeight; 23 | 24 | - (instancetype)init; 25 | - (instancetype)initWithFrame:(CGRect)frame; 26 | - (instancetype)initWithConfig: (ACMediaDisplayConfig *)config; 27 | - (instancetype)initWithFrame:(CGRect)frame config: (ACMediaDisplayConfig *)config; 28 | 29 | /// 可选:外部支持半定义 pickerManager 30 | @property (nonatomic, copy) void (^customizePickerManagerBlock)(ACMediaPickerManager *pickerMgr); 31 | /// 可选:定制图片/视频的预览功能,默认有简单预览的功能. 32 | @property (nonatomic, copy) void (^customizeMediaPreviewBlock)(NSArray *list, NSInteger currentIndex); 33 | 34 | /// 监听容器高度的改变 35 | @property (nonatomic, copy) void (^observeContainerHeightChangeBlock)(CGFloat viewHeight); 36 | 37 | @end 38 | 39 | NS_ASSUME_NONNULL_END 40 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZImageCropManager.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 2016/12/5. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 图片裁剪管理类 8 | 9 | #import 10 | #import 11 | 12 | @interface TZImageCropManager : NSObject 13 | 14 | /// 裁剪框背景的处理 15 | + (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop; 16 | 17 | /* 18 | 1.7.2 为了解决多位同学对于图片裁剪的需求,我这两天有空便在研究图片裁剪 19 | 幸好有tuyou的PhotoTweaks库做参考,裁剪的功能实现起来简单许多 20 | 该方法和其内部引用的方法基本来自于tuyou的PhotoTweaks库,我做了稍许删减和修改 21 | 感谢tuyou同学在github开源了优秀的裁剪库PhotoTweaks,表示感谢 22 | PhotoTweaks库的github链接:https://github.com/itouch2/PhotoTweaks 23 | */ 24 | /// 获得裁剪后的图片 25 | + (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView; 26 | 27 | /// 获取圆形图片 28 | + (UIImage *)circularClipImage:(UIImage *)image; 29 | 30 | @end 31 | 32 | 33 | /// 该分类的代码来自SDWebImage:https://github.com/rs/SDWebImage 34 | /// 为了防止冲突,我将分类名字和方法名字做了修改 35 | @interface UIImage (TZGif) 36 | 37 | + (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZPhotoPreviewController.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TZPhotoPreviewController : UIViewController 12 | 13 | @property (nonatomic, strong) NSMutableArray *models; ///< All photo models / 所有图片模型数组 14 | @property (nonatomic, strong) NSMutableArray *photos; ///< All photos / 所有图片数组 15 | @property (nonatomic, assign) NSInteger currentIndex; ///< Index of the photo user click / 用户点击的图片的索引 16 | @property (nonatomic, assign) BOOL isSelectOriginalPhoto; ///< If YES,return original photo / 是否返回原图 17 | @property (nonatomic, assign) BOOL isCropImage; 18 | 19 | /// Return the new selected photos / 返回最新的选中图片数组 20 | @property (nonatomic, copy) void (^backButtonClickBlock)(BOOL isSelectOriginalPhoto); 21 | @property (nonatomic, copy) void (^doneButtonClickBlock)(BOOL isSelectOriginalPhoto); 22 | @property (nonatomic, copy) void (^doneButtonClickBlockCropMode)(UIImage *cropedImage,id asset); 23 | @property (nonatomic, copy) void (^doneButtonClickBlockWithPreviewType)(NSArray *photos,NSArray *assets,BOOL isSelectOriginalPhoto); 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## TZImagePickerController 5 | 6 | The MIT License (MIT) 7 | 8 | Copyright (c) 2016 Zhen Tan 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | 29 | Generated by CocoaPods - https://cocoapods.org 30 | -------------------------------------------------------------------------------- /ACMediaFrame/Core/ACMediaTool.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaTool.h 3 | // 4 | // Created by caoyq on 2021/4/21. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | #import "ACMediaModel.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** 15 | * 工具类 16 | */ 17 | @interface ACMediaTool : NSObject 18 | 19 | /// 获取栈顶控制器 20 | + (UIViewController *)topNavigationController; 21 | 22 | /// 处理 UIImagePickerControllerDelegate 得到的数据 23 | + (ACMediaModel *)mediaInfoWithDict: (NSDictionary *)dict; 24 | /// 处理 TZImagePickerControllerDelegate 中得到的图片与gif 25 | + (ACMediaModel *)imageInfoWithAsset: (PHAsset *)asset image: (UIImage *)image; 26 | /// 处理 TZImagePickerControllerDelegate 中得到的视频 27 | + (void)videoInfoWithAsset: (PHAsset *)asset coverImage: (UIImage *)coverImage completion: (void(^)(ACMediaModel *model))completion; 28 | 29 | 30 | /// 通过 asset 获取媒体类型 31 | + (ACMediaModelType)getAssetType:(PHAsset *)asset; 32 | 33 | /// 获取图片二进制数据 34 | + (NSData *)imageDataWithImage: (UIImage *)image; 35 | /// 获取视频二进制数据 36 | + (void)videoDataWithAsset: (PHAsset *)asset completion: (void(^)(NSData *data, NSURL *videoURL))completion; 37 | 38 | /// 获取图片名 39 | + (NSString *)imageNameWithAsset: (PHAsset *)asset; 40 | /// 获取视频名 41 | + (NSString *)videoNameWithAsset: (PHAsset *)asset; 42 | 43 | /// 获取视频封面图 44 | + (UIImage *)coverImageWithVideoURL: (NSURL *)videoURL; 45 | 46 | /// 获取修正方向后的图片 47 | + (UIImage *)fixOrientation:(UIImage *)aImage; 48 | 49 | @end 50 | 51 | NS_ASSUME_NONNULL_END 52 | -------------------------------------------------------------------------------- /ACMediaFrameExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ACMediaFrameExample/UIFrameViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIFrameViewController.m 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2021/4/20. 6 | // Copyright © 2021 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import "UIFrameViewController.h" 10 | // 11 | #import "ACMediaDisplayView.h" 12 | 13 | @interface UIFrameViewController () 14 | 15 | @end 16 | 17 | @implementation UIFrameViewController 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.view.backgroundColor = [UIColor whiteColor]; 22 | 23 | UIView *bgView = [UIView new]; 24 | bgView.frame = CGRectMake(10, 100, CGRectGetWidth(self.view.frame) - 20, 0); 25 | bgView.backgroundColor = [UIColor greenColor]; 26 | bgView.layer.cornerRadius = 5.0; 27 | bgView.layer.masksToBounds = YES; 28 | [self.view addSubview:bgView]; 29 | 30 | ACMediaDisplayConfig *config = [[ACMediaDisplayConfig alloc] init]; 31 | config.containerBgColor = [UIColor lightGrayColor]; 32 | 33 | ACMediaDisplayView *displayView = [[ACMediaDisplayView alloc] initWithFrame:bgView.bounds config:config]; 34 | displayView.observeContainerHeightChangeBlock = ^(CGFloat viewHeight) { 35 | NSLog(@"高度变化 = %f",viewHeight); 36 | // 改变外部视图高度 37 | CGRect fm = bgView.frame; 38 | fm.size.height = viewHeight; 39 | bgView.frame = fm; 40 | }; 41 | [bgView addSubview:displayView]; 42 | 43 | // 设置正确的 frame 44 | CGRect bgRect = bgView.frame; 45 | bgRect.size.height = displayView.viewHeight; 46 | bgView.frame = bgRect; 47 | displayView.frame = bgView.bounds; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /ACMediaFrameExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | NSCameraUsageDescription 29 | 访问相机 30 | NSMicrophoneUsageDescription 31 | 访问麦克风 32 | NSPhotoLibraryUsageDescription 33 | 访问相册 34 | UILaunchStoryboardName 35 | LaunchScreen 36 | UIMainStoryboardFile 37 | Main 38 | UIRequiredDeviceCapabilities 39 | 40 | armv7 41 | 42 | UISupportedInterfaceOrientations 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /ACMediaFrameExample/CoreFuncViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreFuncViewController.m 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2021/4/20. 6 | // Copyright © 2021 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import "CoreFuncViewController.h" 10 | #import "ACMediaPickerManager.h" 11 | 12 | @interface CoreFuncViewController () 13 | 14 | ///需要先定义一个属性,防止临时变量被释放 15 | @property (nonatomic, strong) ACMediaPickerManager *mgr; 16 | 17 | @property (weak, nonatomic) IBOutlet UIImageView *displayImageView; 18 | 19 | @end 20 | 21 | @implementation CoreFuncViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | // add observer 26 | __weak typeof(self) weakSelf = self; 27 | self.mgr.didFinishPickingBlock = ^(NSArray * _Nonnull list) { 28 | dispatch_async(dispatch_get_main_queue(), ^{ 29 | weakSelf.displayImageView.image = list.firstObject.image; 30 | }); 31 | }; 32 | } 33 | 34 | - (IBAction)onClickCoreButtonAction:(UIButton *)sender { 35 | [self.mgr picker]; 36 | } 37 | 38 | - (ACMediaPickerManager *)mgr { 39 | if (!_mgr) { 40 | _mgr = [[ACMediaPickerManager alloc] init]; 41 | // 定制外观 42 | _mgr.naviBgColor = [UIColor whiteColor]; 43 | _mgr.naviTitleColor = [UIColor blackColor]; 44 | _mgr.naviTitleFont = [UIFont boldSystemFontOfSize:18.0f]; 45 | _mgr.barItemTextColor = [UIColor blackColor]; 46 | _mgr.barItemTextFont = [UIFont systemFontOfSize:15.0f]; 47 | _mgr.statusBarStyle = UIStatusBarStyleDefault; 48 | 49 | _mgr.allowPickingImage = YES; 50 | _mgr.allowPickingGif = YES; 51 | _mgr.maxImageSelected = 1; 52 | } 53 | return _mgr; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /ACMediaFrameExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZProgressView.m 3 | // TZImagePickerController 4 | // 5 | // Created by ttouch on 2016/12/6. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import "TZProgressView.h" 10 | 11 | @interface TZProgressView () 12 | @property (nonatomic, strong) CAShapeLayer *progressLayer; 13 | @end 14 | 15 | @implementation TZProgressView 16 | 17 | - (instancetype)init { 18 | self = [super init]; 19 | if (self) { 20 | self.backgroundColor = [UIColor clearColor]; 21 | 22 | _progressLayer = [CAShapeLayer layer]; 23 | _progressLayer.fillColor = [[UIColor clearColor] CGColor]; 24 | _progressLayer.strokeColor = [[UIColor whiteColor] CGColor]; 25 | _progressLayer.opacity = 1; 26 | _progressLayer.lineCap = kCALineCapRound; 27 | _progressLayer.lineWidth = 5; 28 | 29 | [_progressLayer setShadowColor:[UIColor blackColor].CGColor]; 30 | [_progressLayer setShadowOffset:CGSizeMake(1, 1)]; 31 | [_progressLayer setShadowOpacity:0.5]; 32 | [_progressLayer setShadowRadius:2]; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)drawRect:(CGRect)rect { 38 | CGPoint center = CGPointMake(rect.size.width / 2, rect.size.height / 2); 39 | CGFloat radius = rect.size.width / 2; 40 | CGFloat startA = - M_PI_2; 41 | CGFloat endA = - M_PI_2 + M_PI * 2 * _progress; 42 | _progressLayer.frame = self.bounds; 43 | UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; 44 | _progressLayer.path =[path CGPath]; 45 | 46 | [_progressLayer removeFromSuperlayer]; 47 | [self.layer addSublayer:_progressLayer]; 48 | } 49 | 50 | - (void)setProgress:(double)progress { 51 | _progress = progress; 52 | [self setNeedsDisplay]; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /ACMediaFrameExample/RootTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // RootTableViewController.m 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2021/4/20. 6 | // Copyright © 2021 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import "RootTableViewController.h" 10 | 11 | @interface RootTableViewController () 12 | 13 | @property (nonatomic, strong) NSArray *vcs; 14 | @property (nonatomic, strong) NSArray *titles; 15 | 16 | @end 17 | 18 | @implementation RootTableViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | self.view.backgroundColor = [UIColor whiteColor]; 23 | self.title = @"功能列表"; 24 | 25 | self.vcs = @[@"CoreFuncViewController", @"UIFrameViewController"]; 26 | self.titles = @[@"核心功能演示", @"九宫格UI-frame演示"]; 27 | } 28 | 29 | #pragma mark - Table view data source 30 | 31 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 32 | return self.titles.count; 33 | } 34 | 35 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 36 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; 37 | if (!cell) { 38 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; 39 | } 40 | cell.textLabel.text = self.titles[indexPath.row]; 41 | return cell; 42 | } 43 | 44 | - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { 45 | return 80; 46 | } 47 | 48 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 49 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 50 | NSString *vcName = self.vcs[indexPath.row]; 51 | Class cls = NSClassFromString(vcName); 52 | UIViewController *vc = [[cls alloc] init]; 53 | vc.title = self.titles[indexPath.row]; 54 | [self.navigationController pushViewController:vc animated:YES]; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZAssetModel.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | typedef enum : NSUInteger { 14 | TZAssetModelMediaTypePhoto = 0, 15 | TZAssetModelMediaTypeLivePhoto, 16 | TZAssetModelMediaTypePhotoGif, 17 | TZAssetModelMediaTypeVideo, 18 | TZAssetModelMediaTypeAudio 19 | } TZAssetModelMediaType; 20 | 21 | @class PHAsset; 22 | @interface TZAssetModel : NSObject 23 | 24 | @property (nonatomic, strong) PHAsset *asset; 25 | @property (nonatomic, assign) BOOL isSelected; ///< The select status of a photo, default is No 26 | @property (nonatomic, assign) TZAssetModelMediaType type; 27 | @property (nonatomic, copy) NSString *timeLength; 28 | @property (nonatomic, assign) BOOL iCloudFailed; 29 | 30 | /// Init a photo dataModel With a PHAsset 31 | /// 用一个PHAsset实例,初始化一个照片模型 32 | + (instancetype)modelWithAsset:(PHAsset *)asset type:(TZAssetModelMediaType)type; 33 | + (instancetype)modelWithAsset:(PHAsset *)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength; 34 | 35 | @end 36 | 37 | 38 | @class PHFetchResult; 39 | @interface TZAlbumModel : NSObject 40 | 41 | @property (nonatomic, strong) NSString *name; ///< The album name 42 | @property (nonatomic, assign) NSInteger count; ///< Count of photos the album contain 43 | @property (nonatomic, strong) PHFetchResult *result; 44 | @property (nonatomic, strong) PHAssetCollection *collection; 45 | @property (nonatomic, strong) PHFetchOptions *options; 46 | 47 | @property (nonatomic, strong) NSArray *models; 48 | @property (nonatomic, strong) NSArray *selectedModels; 49 | @property (nonatomic, assign) NSUInteger selectedCount; 50 | 51 | @property (nonatomic, assign) BOOL isCameraRoll; 52 | 53 | - (void)setResult:(PHFetchResult *)result needFetchAssets:(BOOL)needFetchAssets; 54 | - (void)refreshFetchResult; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /ACMediaFrame/UI/ACMediaImageCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaImageCell.m 3 | // 4 | // Created by caoyq on 2021/4/20. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import "ACMediaImageCell.h" 9 | 10 | static inline CGFloat deleteButtonWidth() { 11 | return 20 * [UIScreen mainScreen].bounds.size.width / 375.0; 12 | } 13 | 14 | @interface ACMediaImageCell () 15 | 16 | /// 图片 17 | @property (nonatomic, strong) UIImageView *icon; 18 | /** 删除按钮 */ 19 | @property (nonatomic, strong) UIButton *deleteButton; 20 | /** 视频标志 */ 21 | @property (nonatomic, strong) UIImageView *videoImageView; 22 | 23 | @end 24 | 25 | @implementation ACMediaImageCell 26 | 27 | - (instancetype)initWithFrame:(CGRect)frame { 28 | self = [super initWithFrame:frame]; 29 | if (self) { 30 | [self _setupViews]; 31 | } 32 | return self; 33 | } 34 | 35 | - (void)_setupViews { 36 | _icon = [[UIImageView alloc] init]; 37 | _icon.clipsToBounds = YES; 38 | _icon.contentMode = UIViewContentModeScaleAspectFill; 39 | [self.contentView addSubview:_icon]; 40 | 41 | _deleteButton = [UIButton buttonWithType:UIButtonTypeCustom]; 42 | [_deleteButton addTarget:self action:@selector(clickDeleteButton) forControlEvents:UIControlEventTouchUpInside]; 43 | [self.contentView addSubview:_deleteButton]; 44 | 45 | _videoImageView = [UIImageView new]; 46 | [self.contentView addSubview:_videoImageView]; 47 | } 48 | 49 | - (void)layoutSubviews { 50 | [super layoutSubviews]; 51 | _icon.frame = self.bounds; 52 | CGFloat btnWidth = deleteButtonWidth(); 53 | _deleteButton.frame = CGRectMake(self.bounds.size.width - btnWidth, 0, btnWidth, btnWidth); 54 | _videoImageView.frame = CGRectMake(self.bounds.size.width/4, self.bounds.size.width/4, self.bounds.size.width/2, self.bounds.size.width/2); 55 | } 56 | 57 | #pragma mark - setter 58 | 59 | - (void)setShowImage:(UIImage *)showImage { 60 | self.icon.image = showImage; 61 | } 62 | 63 | - (void)setDeleteButtonImage:(UIImage *)deleteButtonImage { 64 | [self.deleteButton setImage:deleteButtonImage forState:UIControlStateNormal]; 65 | } 66 | 67 | - (void)setVideoTagImage:(UIImage *)videoTagImage { 68 | self.videoImageView.image = videoTagImage; 69 | } 70 | 71 | #pragma mark - Action 72 | 73 | - (void)clickDeleteButton { 74 | !_ACMediaClickDeleteButton ? : _ACMediaClickDeleteButton(); 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZAssetModel.m 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import "TZAssetModel.h" 10 | #import "TZImageManager.h" 11 | 12 | @implementation TZAssetModel 13 | 14 | + (instancetype)modelWithAsset:(PHAsset *)asset type:(TZAssetModelMediaType)type{ 15 | TZAssetModel *model = [[TZAssetModel alloc] init]; 16 | model.asset = asset; 17 | model.isSelected = NO; 18 | model.type = type; 19 | return model; 20 | } 21 | 22 | + (instancetype)modelWithAsset:(PHAsset *)asset type:(TZAssetModelMediaType)type timeLength:(NSString *)timeLength { 23 | TZAssetModel *model = [self modelWithAsset:asset type:type]; 24 | model.timeLength = timeLength; 25 | return model; 26 | } 27 | 28 | @end 29 | 30 | 31 | 32 | @implementation TZAlbumModel 33 | 34 | - (void)setResult:(PHFetchResult *)result needFetchAssets:(BOOL)needFetchAssets { 35 | _result = result; 36 | if (needFetchAssets) { 37 | [[TZImageManager manager] getAssetsFromFetchResult:result completion:^(NSArray *models) { 38 | self->_models = models; 39 | if (self->_selectedModels) { 40 | [self checkSelectedModels]; 41 | } 42 | }]; 43 | } 44 | } 45 | 46 | - (void)refreshFetchResult { 47 | PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:self.collection options:self.options]; 48 | self.count = fetchResult.count; 49 | [self setResult:fetchResult]; 50 | } 51 | 52 | - (void)setSelectedModels:(NSArray *)selectedModels { 53 | _selectedModels = selectedModels; 54 | if (_models) { 55 | [self checkSelectedModels]; 56 | } 57 | } 58 | 59 | - (void)checkSelectedModels { 60 | self.selectedCount = 0; 61 | NSMutableSet *selectedAssets = [NSMutableSet setWithCapacity:_selectedModels.count]; 62 | for (TZAssetModel *model in _selectedModels) { 63 | [selectedAssets addObject:model.asset]; 64 | } 65 | for (TZAssetModel *model in _models) { 66 | if ([selectedAssets containsObject:model.asset]) { 67 | self.selectedCount ++; 68 | } 69 | } 70 | } 71 | 72 | - (NSString *)name { 73 | if (_name) { 74 | return _name; 75 | } 76 | return @""; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | The MIT License (MIT) 18 | 19 | Copyright (c) 2016 Zhen Tan 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | 40 | License 41 | MIT 42 | Title 43 | TZImagePickerController 44 | Type 45 | PSGroupSpecifier 46 | 47 | 48 | FooterText 49 | Generated by CocoaPods - https://cocoapods.org 50 | Title 51 | 52 | Type 53 | PSGroupSpecifier 54 | 55 | 56 | StringsTable 57 | Acknowledgements 58 | Title 59 | Acknowledgements 60 | 61 | 62 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZAssetCell.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef enum : NSUInteger { 13 | TZAssetCellTypePhoto = 0, 14 | TZAssetCellTypeLivePhoto, 15 | TZAssetCellTypePhotoGif, 16 | TZAssetCellTypeVideo, 17 | TZAssetCellTypeAudio, 18 | } TZAssetCellType; 19 | 20 | @class TZAssetModel; 21 | @interface TZAssetCell : UICollectionViewCell 22 | @property (weak, nonatomic) UIButton *selectPhotoButton; 23 | @property (weak, nonatomic) UIButton *cannotSelectLayerButton; 24 | @property (nonatomic, strong) TZAssetModel *model; 25 | @property (assign, nonatomic) NSInteger index; 26 | @property (nonatomic, copy) void (^didSelectPhotoBlock)(BOOL); 27 | @property (nonatomic, assign) TZAssetCellType type; 28 | @property (nonatomic, assign) BOOL allowPickingGif; 29 | @property (nonatomic, assign) BOOL allowPickingMultipleVideo; 30 | @property (nonatomic, copy) NSString *representedAssetIdentifier; 31 | @property (nonatomic, assign) int32_t imageRequestID; 32 | 33 | @property (nonatomic, strong) UIImage *photoSelImage; 34 | @property (nonatomic, strong) UIImage *photoDefImage; 35 | 36 | @property (nonatomic, assign) BOOL showSelectBtn; 37 | @property (assign, nonatomic) BOOL allowPreview; 38 | 39 | @property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView); 40 | @property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView); 41 | @end 42 | 43 | 44 | @class TZAlbumModel; 45 | @interface TZAlbumCell : UITableViewCell 46 | @property (nonatomic, strong) TZAlbumModel *model; 47 | @property (weak, nonatomic) UIButton *selectedCountButton; 48 | 49 | @property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel); 50 | @property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel); 51 | @end 52 | 53 | 54 | @interface TZAssetCameraCell : UICollectionViewCell 55 | @property (nonatomic, strong) UIImageView *imageView; 56 | @end 57 | -------------------------------------------------------------------------------- /ACMediaFrameExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ACMediaFrameExample 4 | // 5 | // Created by caoyq on 2017/3/26. 6 | // Copyright © 2017年 ArthurCao. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "RootTableViewController.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | 21 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 22 | 23 | RootTableViewController *root = [[RootTableViewController alloc] initWithStyle:UITableViewStylePlain]; 24 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:root]; 25 | 26 | [self.window setRootViewController:nav]; 27 | [self.window makeKeyAndVisible]; 28 | return YES; 29 | } 30 | 31 | 32 | - (void)applicationWillResignActive:(UIApplication *)application { 33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 35 | } 36 | 37 | 38 | - (void)applicationDidEnterBackground:(UIApplication *)application { 39 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 41 | } 42 | 43 | 44 | - (void)applicationWillEnterForeground:(UIApplication *)application { 45 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 46 | } 47 | 48 | 49 | - (void)applicationDidBecomeActive:(UIApplication *)application { 50 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 51 | } 52 | 53 | 54 | - (void)applicationWillTerminate:(UIApplication *)application { 55 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZPhotoPreviewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZPhotoPreviewCell.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TZAssetModel; 12 | @interface TZAssetPreviewCell : UICollectionViewCell 13 | @property (nonatomic, strong) TZAssetModel *model; 14 | @property (nonatomic, copy) void (^singleTapGestureBlock)(void); 15 | - (void)configSubviews; 16 | - (void)photoPreviewCollectionViewDidScroll; 17 | @end 18 | 19 | 20 | @class TZAssetModel,TZProgressView,TZPhotoPreviewView; 21 | @interface TZPhotoPreviewCell : TZAssetPreviewCell 22 | 23 | @property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress); 24 | 25 | @property (nonatomic, strong) TZPhotoPreviewView *previewView; 26 | 27 | @property (nonatomic, assign) BOOL allowCrop; 28 | @property (nonatomic, assign) CGRect cropRect; 29 | @property (nonatomic, assign) BOOL scaleAspectFillCrop; 30 | 31 | - (void)recoverSubviews; 32 | 33 | @end 34 | 35 | 36 | @interface TZPhotoPreviewView : UIView 37 | @property (nonatomic, strong) UIImageView *imageView; 38 | @property (nonatomic, strong) UIScrollView *scrollView; 39 | @property (nonatomic, strong) UIView *imageContainerView; 40 | @property (nonatomic, strong) TZProgressView *progressView; 41 | @property (nonatomic, strong) UIImageView *iCloudErrorIcon; 42 | @property (nonatomic, strong) UILabel *iCloudErrorLabel; 43 | @property (nonatomic, copy) void (^iCloudSyncFailedHandle)(id asset, BOOL isSyncFailed); 44 | 45 | 46 | @property (nonatomic, assign) BOOL allowCrop; 47 | @property (nonatomic, assign) CGRect cropRect; 48 | @property (nonatomic, assign) BOOL scaleAspectFillCrop; 49 | @property (nonatomic, strong) TZAssetModel *model; 50 | @property (nonatomic, strong) id asset; 51 | @property (nonatomic, copy) void (^singleTapGestureBlock)(void); 52 | @property (nonatomic, copy) void (^imageProgressUpdateBlock)(double progress); 53 | 54 | @property (nonatomic, assign) int32_t imageRequestID; 55 | 56 | - (void)recoverSubviews; 57 | @end 58 | 59 | 60 | @class AVPlayer, AVPlayerLayer; 61 | @interface TZVideoPreviewCell : TZAssetPreviewCell 62 | @property (strong, nonatomic) AVPlayer *player; 63 | @property (strong, nonatomic) AVPlayerLayer *playerLayer; 64 | @property (strong, nonatomic) UIButton *playButton; 65 | @property (strong, nonatomic) UIImage *cover; 66 | @property (nonatomic, strong) NSURL *videoURL; 67 | @property (nonatomic, strong) UIImageView *iCloudErrorIcon; 68 | @property (nonatomic, strong) UILabel *iCloudErrorLabel; 69 | @property (nonatomic, copy) void (^iCloudSyncFailedHandle)(id asset, BOOL isSyncFailed); 70 | - (void)pausePlayerAndShowNaviBar; 71 | @end 72 | 73 | 74 | @interface TZGifPreviewCell : TZAssetPreviewCell 75 | @property (strong, nonatomic) TZPhotoPreviewView *previewView; 76 | @end 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ACMediaFrame 2 | 3 | ## 导航 4 | * [最新版本需知](#new) 5 | * [使用](#used) 6 | * [主要功能](#func) 7 | * [版本更新](#version) 8 | * [Hope](#hope) 9 | 10 | --- 11 | 12 | ## 最新版本需知 13 | 14 | 当前版本的区分 15 | 16 | * 3.0.0 之前版本,是提供媒体库选择与展示,具体看 [before 3.0.0 README](https://github.com/honeycao/ACMediaFrame/blob/master/before%203.0.0%20README.md) 17 | * 3.0.0 之后版本,将 UI 与核心功能进行拆分,可自由选择(预览方面暂时比较简单,可自定制) 18 | 19 | 在 3.0.0 之前 存在一个 MWPhotoBrowser 第三方库,该库已不再更新所以对使用者限制很大,故从3.0.0开始直接移除无关的第三方库。 20 | 21 | 目前只有一个第三库:TZImagePickerController 22 | 23 | --- 24 | 25 | ## 使用 26 | 27 | 系统要求:`iOS 8.0 or later` 28 | 29 | 30 | ``` 31 | // 引用 UI + Core 32 | pod 'ACMediaFrame' 33 | 34 | // 单独引用 Core,不包括 UI 35 | pod 'ACMediaFrame/Core' 36 | 37 | //添加使用头文件 38 | #import 39 | #import 40 | ``` 41 | 42 | 需要之前的展示与选择功能,可以使用 2.0.5 版本,同时参考 [before 3.0.0 README](https://github.com/honeycao/ACMediaFrame/blob/master/before%203.0.0%20README.md) 进行使用。 43 | ``` 44 | pod 'ACMediaFrame', '~> 2.0.5' 45 | ``` 46 | 47 | 48 | 49 | **具体使用可参考 demo:** 50 | 51 | - `CoreFuncViewController`:核心功能 Core 的单独使用方式示例 52 | - `UIFrameViewController`:使用 Core + UI 组合的示例 53 | 54 | 55 | 56 | --- 57 | 58 | ## 主要功能 59 | 60 | * 封装系统相册、相机方法以及自定义的相册 61 | * 统一处理选择的数据;图片、gif、视频 62 | * 自定义使用系统或自定义相册等 63 | * 提供 类九宫格 + 预览 + 选取图片/视频的 UI 功能 64 | 65 | 调用者无需处理选择的媒体文件,使用本框架直接可以得到想要的数据(都封装好了) 66 | 67 | **新版本临时提交,有bug或需求等可以多多告诉我,谢谢。** 68 | 69 | ## 版本更新 70 | 71 | * `3.1.0`:新增 UI 库,同时拆分为两个文件夹 UI 与 Core,支持自由选择需要的功能 72 | * `3.0.1`:完善传参属性,更方便自定义 73 | 74 | - `3.0.0`:全面整改,当前版本已不提供视图,只有功能,重新对选择图片、视频的封装 75 | - `2.0.4`:支持自定义区域的布局、demo修改等 76 | - `2.0.3`:优化图片到达最大张数时添加图片的按钮隐藏 77 | - `2.0.2` : 支持 cocoapods 导入,当前版本 2.0.2 78 | - `2.0.0` : 修改之前选择图片、删除图片之间的一些逻辑问题。 79 | - `1.3.9` : 之前对预展示视频写的不够清楚,于是这次就对如何集成和使用预展示视频功能,添加了相关的演示范例。 80 | - `1.3.8` : 添加、开放属性,用于自定义相册界面的导航栏. 81 | - `1.3.7` : 由于会碰到无法自动获取一个主视图的情况,所以开放一个参数`rootViewController`,用于手动传入当前的主控制器,非必传的,如果自动获取失败会抛出一个异常,具体看`属性自定义`中的使用即可. 82 | - `1.3.6` : 应使用者需求,继续开放了功能接口,包括:是否允许相册中拍照、是否可以选择原图、设置录像最大持续时间。 83 | - `1.3.5` : 添加支持gif图片选择和展示功能。 84 | - `1.3.4` : 完善图片视频选择的一些逻辑问题。 85 | - `1.3.3` : 这个版本其实和上个版本一样,只不过有热心群众反馈播放视频的时候没有开启麦克风权限没有声音,所以添加了一个权限判断,但是后来自己测试的时候发现并没有这个bug,所以最终就没做什么大的调整。 86 | - `1.3.2` : 上一版本处理好之后,没有同时测试相册和相机选择图片的情况,所以出现了点问题,现在这版本就是修改这个问题,很感谢小伙伴的使用和提供的bug,由于自己能力有限,所以难免会有些许bug,不打紧,你们发现bug告诉我,我会尽快修复。。。 87 | - `1.3.1` : 对上一版本的简单改动,修改获取主控制器失败的方法,以及继续完善 88 | - `1.3.0` : 改动比较大的一次,首先是代码整体层次上变动了下,另外添加了自己写的一个底部弹出框功能,添加几个开放属性(是否在图片中可以选择视频、选择的图片下次是否可以继续选择等) 89 | - `1.2.0` : 由于上次的提交,导致一个问题(设置的隐藏添加图片按钮失效的问题),当时没有考虑完全,所以这次进行修改并修复有默认图片是显示的一些布局问题;另外继续完善几个开放接口,比如设置选择图片数量等。 90 | - `1.1.0` : 91 | - 添加了几个属性,使得框架更容易集成和修改。现在不仅可以用来选择图片等媒体资源,同时也可以只是用来展示等。 92 | - 修改了添加框架的头文件等 93 | - `1.0.1` : 添加一个媒体类型,默认媒体资源是本地图片、视频,拍摄的图片、录像等,现在可以自己选择类型,例如:当只需要图片时,就设置媒体类型属性即可。 94 | - `1.0.0` : 最初原型,封装的选择媒体以及布局的页面,把媒体资源的处理全进行封装,减少重复工作,只需添加到视图上,然后接收获取的媒体数据。 95 | 96 | ## Hope 97 | 98 | - 代码使用过程中,发现任何问题,可以随时[issues me](https://github.com/honeycao/ACMediaFrame/issues/new) 99 | - 如果有更多建议或者想法也可以直接联系我 QQ:331864805 100 | - 觉得框架对你有一点点帮助的,就请支持下,点个赞。 101 | 102 | ## Licenses 103 | 104 | All source code is licensed under the MIT License. 105 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZLocationManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZLocationManager.m 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 2017/06/03. 6 | // Copyright © 2017年 谭真. All rights reserved. 7 | // 定位管理类 8 | 9 | #import "TZLocationManager.h" 10 | #import "TZImagePickerController.h" 11 | 12 | @interface TZLocationManager () 13 | @property (nonatomic, strong) CLLocationManager *locationManager; 14 | /// 定位成功的回调block 15 | @property (nonatomic, copy) void (^successBlock)(NSArray *); 16 | /// 编码成功的回调block 17 | @property (nonatomic, copy) void (^geocodeBlock)(NSArray *geocodeArray); 18 | /// 定位失败的回调block 19 | @property (nonatomic, copy) void (^failureBlock)(NSError *error); 20 | @end 21 | 22 | @implementation TZLocationManager 23 | 24 | + (instancetype)manager { 25 | static TZLocationManager *manager; 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | manager = [[self alloc] init]; 29 | manager.locationManager = [[CLLocationManager alloc] init]; 30 | manager.locationManager.delegate = manager; 31 | [manager.locationManager requestWhenInUseAuthorization]; 32 | }); 33 | return manager; 34 | } 35 | 36 | - (void)startLocation { 37 | [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:nil]; 38 | } 39 | 40 | - (void)startLocationWithSuccessBlock:(void (^)(NSArray *))successBlock failureBlock:(void (^)(NSError *error))failureBlock { 41 | [self startLocationWithSuccessBlock:successBlock failureBlock:failureBlock geocoderBlock:nil]; 42 | } 43 | 44 | - (void)startLocationWithGeocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock { 45 | [self startLocationWithSuccessBlock:nil failureBlock:nil geocoderBlock:geocoderBlock]; 46 | } 47 | 48 | - (void)startLocationWithSuccessBlock:(void (^)(NSArray *))successBlock failureBlock:(void (^)(NSError *error))failureBlock geocoderBlock:(void (^)(NSArray *geocoderArray))geocoderBlock { 49 | [self.locationManager startUpdatingLocation]; 50 | _successBlock = successBlock; 51 | _geocodeBlock = geocoderBlock; 52 | _failureBlock = failureBlock; 53 | } 54 | 55 | - (void)stopUpdatingLocation { 56 | [self.locationManager stopUpdatingLocation]; 57 | } 58 | 59 | #pragma mark - CLLocationManagerDelegate 60 | 61 | /// 地理位置发生改变时触发 62 | - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { 63 | [manager stopUpdatingLocation]; 64 | 65 | if (_successBlock) { 66 | _successBlock(locations); 67 | } 68 | 69 | if (_geocodeBlock && locations.count) { 70 | CLGeocoder *geocoder = [[CLGeocoder alloc] init]; 71 | [geocoder reverseGeocodeLocation:[locations firstObject] completionHandler:^(NSArray *array, NSError *error) { 72 | self->_geocodeBlock(array); 73 | }]; 74 | } 75 | } 76 | 77 | /// 定位失败回调方法 78 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 79 | NSLog(@"定位失败, 错误: %@",error); 80 | switch([error code]) { 81 | case kCLErrorDenied: { // 用户禁止了定位权限 82 | 83 | } break; 84 | default: break; 85 | } 86 | if (_failureBlock) { 87 | _failureBlock(error); 88 | } 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /ACMediaFrame/Core/ACMediaPickerManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaPickerManager.h 3 | // 4 | // Created by caoyq on 2018/11/9. 5 | // Copyright © 2018 AllenCao. All rights reserved. 6 | // 7 | 8 | #import 9 | #import "ACMediaModel.h" 10 | 11 | ///来源 12 | typedef NS_ENUM(NSInteger, ACMediaPickerSource) { 13 | ACMediaPickerSourceFromAll = 0, /**< 选择相册或相机 */ 14 | ACMediaPickerSourceFromAlbum, /**< 打开相册 */ 15 | ACMediaPickerSourceFromCamera /**< 打开相机 */ 16 | }; 17 | 18 | /** 19 | * 调用相机或相册,并统一处理选中的图片、gif、视频 功能的封装。根据属性自定义功能。 20 | * 21 | * 1. 先在 @interface 下定义该属性,再用 init 初始化,避免 delegate 失效。 22 | * 23 | * 2. 设置 pickerSource 为 ACMediaPickerSourceFromAll,调用 picker 方法会弹出 UIAlertController 进行选择,如果想自定义弹框样式,那么可以不调用 picker 方法,而是手动选择 openCustomAlbum/openSystemAlbum 等方法。 24 | * 25 | * 3. 已自动对图片方向不是 UIImageOrientationUp 的进行了修正。 26 | */ 27 | @interface ACMediaPickerManager : NSObject 28 | 29 | /** 30 | * 媒体文件的来源. 31 | * 32 | * 默认为 ACMediaPickerSourceAll,会弹出一个UIAlertController进行选择;如果为其他两种则不会弹框,直接打开相册或相机。 33 | */ 34 | @property (nonatomic, assign) ACMediaPickerSource pickerSource; 35 | /** 可选择的最大个数(视频与图片). default is 9. */ 36 | @property (nonatomic, assign) NSInteger maxImageSelected; 37 | ///是否允许选择图片,default is YES. 38 | @property (nonatomic, assign) BOOL allowPickingImage; 39 | ///是否允许选择gif,gif是伴随图片一起出现的,default is NO. 40 | @property (nonatomic, assign) BOOL allowPickingGif; 41 | ///是否允许选择视频,default is NO. 42 | @property (nonatomic, assign) BOOL allowPickingVideo; 43 | 44 | /** 45 | * 打开相册时:是否允许在图片列表中出现拍照按钮. default is NO. 46 | * 47 | * 打开相机时:是否是拍照模式。 48 | */ 49 | @property (nonatomic, assign) BOOL allowTakePicture; 50 | /** 是否允许 相册中出现选择原图按钮. default is NO. */ 51 | @property (nonatomic, assign) BOOL allowPickingOriginalPhoto; 52 | /// 是否允许多选视频/gif,也受maxImageSelected限制,default is NO. 53 | @property (nonatomic, assign) BOOL allowPickingMultipleVideo; 54 | 55 | /** 56 | * 打开相册时:是否允许在视频列表中出现拍摄视频的按钮. defalut is NO。 57 | * 58 | * 打开相机时:是否是录像模式。 59 | */ 60 | @property (nonatomic, assign) BOOL allowTakeVideo; 61 | ///录像最长时间,默认60s 62 | @property (nonatomic, assign) CGFloat videoMaximumDuration; 63 | 64 | /** 65 | * 已选择的图片、视频数组。 66 | * 67 | * 如果下一次选择不需要记录上一次的结果,可以不用传值,反之就需要进行传值。 68 | * 69 | * 数组的值在 didFinishPickingBlock 返回的list范围内。 70 | */ 71 | @property (nonatomic, strong) NSArray *seletedMediaArray; 72 | /** 当前的控制器,defalut is 栈顶控制器 */ 73 | @property (nonatomic, weak) UIViewController *currentViewController; 74 | /** 选择文件结束后的回调。调用方可以进行保存,方便下次给 seletedMediaArray 赋值。*/ 75 | @property (nonatomic, copy) void(^didFinishPickingBlock)(NSArray *list); 76 | 77 | /******* 外观属性 *******/ 78 | 79 | ///默认是 UIStatusBarStyleLightContent 80 | @property (nonatomic, assign) UIStatusBarStyle statusBarStyle; 81 | @property (nonatomic, strong) UIColor *naviBgColor; 82 | @property (nonatomic, strong) UIColor *naviTitleColor; 83 | @property (nonatomic, strong) UIFont *naviTitleFont; 84 | @property (nonatomic, strong) UIColor *barItemTextColor; 85 | @property (nonatomic, strong) UIFont *barItemTextFont; 86 | 87 | #pragma mark - Methods 88 | 89 | ///调用选择控制器。相册默认调用openCustomAlbum,相机默认调用openSystemCamera 90 | - (void)picker; 91 | 92 | /// 自定义相册,支持多选,包含相册权限判定。 93 | - (void)openCustomAlbum; 94 | ///系统相册,只能单选 95 | - (void)openSystemAlbum; 96 | 97 | /** 98 | * 打开系统相机。默认拍照。 99 | * 100 | * 属性 allowTakePicture 为 YES,表示拍照,优先级最高。 101 | * 属性 allowTakeVideo 为 YES,表示录像。 102 | */ 103 | - (void)openSystemCamera; 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /ACMediaFrameExample/CoreFuncViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then 7 | # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy 8 | # resources to, so exit 0 (signalling the script phase was successful). 9 | exit 0 10 | fi 11 | 12 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 13 | 14 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 15 | > "$RESOURCES_TO_COPY" 16 | 17 | XCASSET_FILES=() 18 | 19 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 20 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 21 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 22 | 23 | case "${TARGETED_DEVICE_FAMILY:-}" in 24 | 1,2) 25 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 26 | ;; 27 | 1) 28 | TARGET_DEVICE_ARGS="--target-device iphone" 29 | ;; 30 | 2) 31 | TARGET_DEVICE_ARGS="--target-device ipad" 32 | ;; 33 | 3) 34 | TARGET_DEVICE_ARGS="--target-device tv" 35 | ;; 36 | 4) 37 | TARGET_DEVICE_ARGS="--target-device watch" 38 | ;; 39 | *) 40 | TARGET_DEVICE_ARGS="--target-device mac" 41 | ;; 42 | esac 43 | 44 | install_resource() 45 | { 46 | if [[ "$1" = /* ]] ; then 47 | RESOURCE_PATH="$1" 48 | else 49 | RESOURCE_PATH="${PODS_ROOT}/$1" 50 | fi 51 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 52 | cat << EOM 53 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 54 | EOM 55 | exit 1 56 | fi 57 | case $RESOURCE_PATH in 58 | *.storyboard) 59 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 60 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 61 | ;; 62 | *.xib) 63 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 64 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 65 | ;; 66 | *.framework) 67 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 68 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 69 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 70 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 71 | ;; 72 | *.xcdatamodel) 73 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 74 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 75 | ;; 76 | *.xcdatamodeld) 77 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 78 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 79 | ;; 80 | *.xcmappingmodel) 81 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 82 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 83 | ;; 84 | *.xcassets) 85 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 86 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 87 | ;; 88 | *) 89 | echo "$RESOURCE_PATH" || true 90 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 91 | ;; 92 | esac 93 | } 94 | 95 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 97 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 98 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 99 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 100 | fi 101 | rm -f "$RESOURCES_TO_COPY" 102 | 103 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ] 104 | then 105 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 106 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 107 | while read line; do 108 | if [[ $line != "${PODS_ROOT}*" ]]; then 109 | XCASSET_FILES+=("$line") 110 | fi 111 | done <<<"$OTHER_XCASSETS" 112 | 113 | if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then 114 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 115 | else 116 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist" 117 | fi 118 | fi 119 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZGifPhotoPreviewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZGifPhotoPreviewController.m 3 | // TZImagePickerController 4 | // 5 | // Created by ttouch on 2016/12/13. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import "TZGifPhotoPreviewController.h" 10 | #import "TZImagePickerController.h" 11 | #import "TZAssetModel.h" 12 | #import "UIView+TZLayout.h" 13 | #import "TZPhotoPreviewCell.h" 14 | #import "TZImageManager.h" 15 | 16 | #pragma clang diagnostic push 17 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 18 | 19 | @interface TZGifPhotoPreviewController () { 20 | UIView *_toolBar; 21 | UIButton *_doneButton; 22 | UIProgressView *_progress; 23 | 24 | TZPhotoPreviewView *_previewView; 25 | 26 | UIStatusBarStyle _originStatusBarStyle; 27 | } 28 | @property (assign, nonatomic) BOOL needShowStatusBar; 29 | @end 30 | 31 | @implementation TZGifPhotoPreviewController 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden; 36 | self.view.backgroundColor = [UIColor blackColor]; 37 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 38 | if (tzImagePickerVc) { 39 | self.navigationItem.title = [NSString stringWithFormat:@"GIF %@",tzImagePickerVc.previewBtnTitleStr]; 40 | } 41 | [self configPreviewView]; 42 | [self configBottomToolBar]; 43 | } 44 | 45 | - (void)viewWillAppear:(BOOL)animated { 46 | [super viewWillAppear:animated]; 47 | _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; 48 | [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; 49 | } 50 | 51 | - (void)viewWillDisappear:(BOOL)animated { 52 | [super viewWillDisappear:animated]; 53 | if (self.needShowStatusBar) { 54 | [UIApplication sharedApplication].statusBarHidden = NO; 55 | } 56 | [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; 57 | } 58 | 59 | - (void)configPreviewView { 60 | _previewView = [[TZPhotoPreviewView alloc] initWithFrame:CGRectZero]; 61 | _previewView.model = self.model; 62 | __weak typeof(self) weakSelf = self; 63 | [_previewView setSingleTapGestureBlock:^{ 64 | __strong typeof(weakSelf) strongSelf = weakSelf; 65 | [strongSelf signleTapAction]; 66 | }]; 67 | [self.view addSubview:_previewView]; 68 | } 69 | 70 | - (void)configBottomToolBar { 71 | _toolBar = [[UIView alloc] initWithFrame:CGRectZero]; 72 | CGFloat rgb = 34 / 255.0; 73 | _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; 74 | 75 | _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; 76 | _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; 77 | [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; 78 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 79 | if (tzImagePickerVc) { 80 | [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; 81 | [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; 82 | } else { 83 | [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal]; 84 | [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal]; 85 | } 86 | [_toolBar addSubview:_doneButton]; 87 | 88 | UILabel *byteLabel = [[UILabel alloc] init]; 89 | byteLabel.textColor = [UIColor whiteColor]; 90 | byteLabel.font = [UIFont systemFontOfSize:13]; 91 | byteLabel.frame = CGRectMake(10, 0, 100, 44); 92 | [[TZImageManager manager] getPhotosBytesWithArray:@[_model] completion:^(NSString *totalBytes) { 93 | byteLabel.text = totalBytes; 94 | }]; 95 | [_toolBar addSubview:byteLabel]; 96 | 97 | [self.view addSubview:_toolBar]; 98 | 99 | if (tzImagePickerVc.gifPreviewPageUIConfigBlock) { 100 | tzImagePickerVc.gifPreviewPageUIConfigBlock(_toolBar, _doneButton); 101 | } 102 | } 103 | 104 | - (UIStatusBarStyle)preferredStatusBarStyle { 105 | TZImagePickerController *tzImagePicker = (TZImagePickerController *)self.navigationController; 106 | if (tzImagePicker && [tzImagePicker isKindOfClass:[TZImagePickerController class]]) { 107 | return tzImagePicker.statusBarStyle; 108 | } 109 | return [super preferredStatusBarStyle]; 110 | } 111 | 112 | #pragma mark - Layout 113 | 114 | - (void)viewDidLayoutSubviews { 115 | [super viewDidLayoutSubviews]; 116 | 117 | _previewView.frame = self.view.bounds; 118 | _previewView.scrollView.frame = self.view.bounds; 119 | CGFloat toolBarHeight = 44 + [TZCommonTools tz_safeAreaInsets].bottom; 120 | _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight); 121 | _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); 122 | 123 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 124 | if (tzImagePickerVc.gifPreviewPageDidLayoutSubviewsBlock) { 125 | tzImagePickerVc.gifPreviewPageDidLayoutSubviewsBlock(_toolBar, _doneButton); 126 | } 127 | } 128 | 129 | #pragma mark - Click Event 130 | 131 | - (void)signleTapAction { 132 | _toolBar.hidden = !_toolBar.isHidden; 133 | [self.navigationController setNavigationBarHidden:_toolBar.isHidden]; 134 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 135 | if (_toolBar.isHidden) { 136 | [UIApplication sharedApplication].statusBarHidden = YES; 137 | } else if (tzImagePickerVc.needShowStatusBar) { 138 | [UIApplication sharedApplication].statusBarHidden = NO; 139 | } 140 | } 141 | 142 | - (void)doneButtonClick { 143 | if (self.navigationController) { 144 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; 145 | if (imagePickerVc.autoDismiss) { 146 | [self.navigationController dismissViewControllerAnimated:YES completion:^{ 147 | [self callDelegateMethod]; 148 | }]; 149 | } else { 150 | [self callDelegateMethod]; 151 | } 152 | } else { 153 | [self dismissViewControllerAnimated:YES completion:^{ 154 | [self callDelegateMethod]; 155 | }]; 156 | } 157 | } 158 | 159 | - (void)callDelegateMethod { 160 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; 161 | UIImage *animatedImage = _previewView.imageView.image; 162 | if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingGifImage:sourceAssets:)]) { 163 | [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingGifImage:animatedImage sourceAssets:_model.asset]; 164 | } 165 | if (imagePickerVc.didFinishPickingGifImageHandle) { 166 | imagePickerVc.didFinishPickingGifImageHandle(animatedImage,_model.asset); 167 | } 168 | } 169 | 170 | #pragma clang diagnostic pop 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /ACMediaFrame/UI/ACMediaDisplayView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaDisplayView.m 3 | // 4 | // Created by caoyq on 2021/4/20. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import "ACMediaDisplayView.h" 9 | // 10 | #import "ACMediaImageCell.h" 11 | // 12 | #import "TZPhotoPreviewController.h" 13 | #import "TZImagePickerController.h" 14 | #import "TZAssetModel.h" 15 | 16 | @interface ACMediaDisplayView () 17 | 18 | /// UI 配置项 19 | @property (nonatomic, strong) ACMediaDisplayConfig *config; 20 | /// 核心功能管理者 21 | @property (nonatomic, strong) ACMediaPickerManager *pickerManager; 22 | /// 容器 23 | @property (nonatomic, strong) UICollectionView *collectionView; 24 | /// 保存的媒体资源 25 | @property (nonatomic, strong) NSMutableArray *mediaArray; 26 | 27 | @end 28 | 29 | @implementation ACMediaDisplayView 30 | 31 | #pragma mark - Init 32 | 33 | - (instancetype)init { 34 | return [self initWithFrame:CGRectZero config:[ACMediaDisplayConfig new]]; 35 | } 36 | 37 | - (instancetype)initWithConfig: (ACMediaDisplayConfig *)config { 38 | return [self initWithFrame:CGRectZero config:config]; 39 | } 40 | 41 | - (instancetype)initWithFrame:(CGRect)frame { 42 | return [self initWithFrame:frame config:[ACMediaDisplayConfig new]]; 43 | } 44 | 45 | - (instancetype)initWithFrame:(CGRect)frame config: (ACMediaDisplayConfig *)config { 46 | self = [super initWithFrame:frame]; 47 | if (self) { 48 | self.config = config; 49 | self.mediaArray = @[].mutableCopy; 50 | [self settingPickerManager]; 51 | [self configureCollectionViewWithFrame:frame]; 52 | } 53 | return self; 54 | } 55 | 56 | - (void)settingPickerManager { 57 | ACMediaPickerManager *pickMgr = [[ACMediaPickerManager alloc] init]; 58 | if (self.customizePickerManagerBlock) { 59 | self.customizePickerManagerBlock(pickMgr); 60 | } 61 | __weak typeof(self) weakSelf = self; 62 | pickMgr.didFinishPickingBlock = ^(NSArray * _Nonnull list) { 63 | weakSelf.mediaArray = list.mutableCopy; 64 | [weakSelf reloadCollectionView]; 65 | }; 66 | self.pickerManager = pickMgr; 67 | } 68 | 69 | - (void)configureCollectionViewWithFrame: (CGRect)frame { 70 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 71 | layout.minimumLineSpacing = self.config.lineSpacing; 72 | layout.minimumInteritemSpacing = self.config.interitemSpacing; 73 | layout.sectionInset = self.config.sectionInset; 74 | CGFloat itemW = [self itemWidth]; 75 | layout.itemSize = CGSizeMake(itemW, itemW); 76 | _collectionView = [[UICollectionView alloc]initWithFrame:frame collectionViewLayout:layout]; 77 | [_collectionView registerClass:[ACMediaImageCell class] forCellWithReuseIdentifier:NSStringFromClass([ACMediaImageCell class])]; 78 | _collectionView.delegate = self; 79 | _collectionView.dataSource = self; 80 | _collectionView.backgroundColor = self.config.containerBgColor; 81 | [self addSubview:_collectionView]; 82 | } 83 | 84 | - (void)layoutSubviews { 85 | [super layoutSubviews]; 86 | self.collectionView.frame = self.bounds; 87 | } 88 | 89 | - (void)reloadCollectionView { 90 | [self.collectionView reloadData]; 91 | CGFloat viewH = self.viewHeight; 92 | // 内部自动更新容器高度 93 | CGRect rect = self.frame; 94 | rect.size.height = viewH; 95 | self.frame = rect; 96 | if (self.observeContainerHeightChangeBlock) { 97 | self.observeContainerHeightChangeBlock(viewH); 98 | } 99 | [self setNeedsLayout]; 100 | } 101 | 102 | #pragma mark - getter 103 | 104 | - (NSArray *)selectedMediaList { 105 | return self.mediaArray; 106 | } 107 | 108 | - (CGFloat)viewHeight { 109 | NSInteger count = [self numberOfItems]; 110 | NSInteger row = ceil(1.0 * count / self.config.rowImageCount); 111 | CGFloat itemW = [self itemWidth]; 112 | CGFloat height = self.config.sectionInset.top + self.config.sectionInset.bottom + itemW * row + self.config.interitemSpacing * (row - 1); 113 | return height; 114 | } 115 | 116 | /// collection item width 117 | - (CGFloat)itemWidth { 118 | return 1.0 * (self.bounds.size.width - self.config.sectionInset.left - self.config.sectionInset.right - (self.config.rowImageCount - 1) * self.config.interitemSpacing) / self.config.rowImageCount; 119 | } 120 | 121 | /// collection items count 122 | - (NSInteger)numberOfItems { 123 | return [self isExistAddButton] ? self.mediaArray.count + 1 : self.mediaArray.count; 124 | } 125 | 126 | /// 是否存在添加按钮 127 | - (BOOL)isExistAddButton { 128 | return self.mediaArray.count < self.pickerManager.maxImageSelected; 129 | } 130 | 131 | #pragma mark - UICollectionViewDataSource 132 | 133 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 134 | return [self numberOfItems]; 135 | } 136 | 137 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 138 | ACMediaImageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([ACMediaImageCell class]) forIndexPath:indexPath]; 139 | 140 | if ([self isExistAddButton] && indexPath.item == self.mediaArray.count) { 141 | cell.deleteButtonImage = nil; 142 | cell.showImage = self.config.addImage; 143 | cell.videoTagImage = nil; 144 | }else { 145 | ACMediaModel *model = self.mediaArray[indexPath.row]; 146 | cell.deleteButtonImage = self.config.deleteImage; 147 | 148 | if (model.mediaType == ACMediaModelTypeVideo) { 149 | cell.videoTagImage = self.config.videoTagImage; 150 | }else { 151 | cell.videoTagImage = nil; 152 | } 153 | cell.showImage = model.image; 154 | __weak typeof(self) weakSelf = self; 155 | cell.ACMediaClickDeleteButton = ^{ 156 | [weakSelf.mediaArray removeObjectAtIndex:indexPath.row]; 157 | dispatch_async(dispatch_get_main_queue(), ^{ 158 | [weakSelf reloadCollectionView]; 159 | }); 160 | }; 161 | } 162 | return cell; 163 | } 164 | 165 | #pragma mark - UICollectionViewDelegate 166 | 167 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 168 | if ([self isExistAddButton] && indexPath.item == self.mediaArray.count) { 169 | self.pickerManager.seletedMediaArray = self.mediaArray; 170 | [self.pickerManager picker]; 171 | }else { 172 | if (self.customizeMediaPreviewBlock) { 173 | self.customizeMediaPreviewBlock(self.mediaArray, indexPath.item); 174 | return; 175 | } 176 | 177 | TZPhotoPreviewController *preViewController = [[TZPhotoPreviewController alloc] init]; 178 | NSMutableArray *temp = @[].mutableCopy; 179 | for (ACMediaModel *model in self.mediaArray) { 180 | [temp addObject:[TZAssetModel modelWithAsset:model.asset type:model.mediaType]]; 181 | } 182 | preViewController.models = temp; 183 | preViewController.currentIndex = indexPath.item; 184 | TZImagePickerController *nav = [[TZImagePickerController alloc] initWithRootViewController:preViewController]; 185 | [self.pickerManager.currentViewController presentViewController:nav animated:YES completion:nil]; 186 | } 187 | } 188 | 189 | @end 190 | -------------------------------------------------------------------------------- /ACMediaFrame/Core/ACMediaPickerManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaPickerManager.m 3 | // 4 | // Created by caoyq on 2018/11/9. 5 | // Copyright © 2018 AllenCao. All rights reserved. 6 | // 7 | 8 | #import "ACMediaPickerManager.h" 9 | #import "TZImagePickerController.h" 10 | #import "ACMediaTool.h" 11 | 12 | static NSString *const str_openAlbum = @"打开本地相册"; 13 | static NSString *const str_openCamera = @"打开相机"; 14 | static NSString *const str_cancel = @"取消"; 15 | static NSString *const str_openCamera_error = @"设备不能打开相机"; 16 | 17 | @interface ACMediaPickerManager() 18 | 19 | @end 20 | 21 | @implementation ACMediaPickerManager 22 | 23 | #pragma mark - init 24 | 25 | - (instancetype)init { 26 | self = [super init]; 27 | if (self) { 28 | self.currentViewController = [UIApplication sharedApplication].keyWindow.rootViewController; 29 | self.statusBarStyle = UIStatusBarStyleLightContent; 30 | self.maxImageSelected = 9; 31 | self.videoMaximumDuration = 60.0; 32 | self.allowPickingImage = YES; 33 | self.currentViewController = [ACMediaTool topNavigationController]; 34 | } 35 | return self; 36 | } 37 | 38 | #pragma mark - public 39 | 40 | - (void)picker { 41 | switch (self.pickerSource) { 42 | case ACMediaPickerSourceFromAlbum: 43 | [self openCustomAlbum]; 44 | break; 45 | case ACMediaPickerSourceFromCamera: 46 | [self openSystemCamera]; 47 | break; 48 | default: 49 | { 50 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; 51 | UIAlertAction *album = [UIAlertAction actionWithTitle:str_openAlbum style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 52 | [self openCustomAlbum]; 53 | }]; 54 | UIAlertAction *camera = [UIAlertAction actionWithTitle:str_openCamera style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 55 | [self openSystemCamera]; 56 | }]; 57 | UIAlertAction *cancel = [UIAlertAction actionWithTitle:str_cancel style:UIAlertActionStyleCancel handler:nil]; 58 | [alert addAction:album]; 59 | [alert addAction:camera]; 60 | [alert addAction:cancel]; 61 | [self.currentViewController presentViewController:alert animated:YES completion:nil]; 62 | } 63 | break; 64 | } 65 | } 66 | 67 | - (void)openCustomAlbum { 68 | //组装所有已选的asset 69 | NSMutableArray *seletedAssets = [NSMutableArray array]; 70 | for (ACMediaModel *model in self.seletedMediaArray) { 71 | if (model.asset) { 72 | [seletedAssets addObject:model.asset]; 73 | } 74 | } 75 | 76 | TZImagePickerController *imagePickController = [[TZImagePickerController alloc] initWithMaxImagesCount:self.maxImageSelected delegate:self]; 77 | imagePickController.selectedAssets = seletedAssets; 78 | [self configureTZImagePicker:imagePickController]; 79 | [self.currentViewController presentViewController:imagePickController animated:YES completion:nil]; 80 | } 81 | 82 | - (void)openSystemCamera { 83 | UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; 84 | 85 | if ([UIImagePickerController isSourceTypeAvailable: sourceType]){ 86 | UIImagePickerController *picker = [[UIImagePickerController alloc] init]; 87 | picker.delegate = self; 88 | picker.sourceType = sourceType; 89 | [self configureCameraPicker:picker]; 90 | [self.currentViewController presentViewController:picker animated:YES completion:nil]; 91 | }else{ 92 | NSLog(str_openCamera_error); 93 | } 94 | } 95 | 96 | - (void)openSystemAlbum { 97 | UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 98 | if ([UIImagePickerController isSourceTypeAvailable:sourceType]) { 99 | UIImagePickerController *picker = [[UIImagePickerController alloc] init]; 100 | picker.delegate = self; 101 | picker.allowsEditing = YES; 102 | picker.sourceType = sourceType; 103 | [self.currentViewController presentViewController:picker animated:YES completion:nil]; 104 | } 105 | } 106 | 107 | #pragma mark - private 108 | 109 | - (void)configureCameraPicker: (UIImagePickerController *)picker { 110 | if (self.allowTakeVideo && !self.allowTakePicture) { //录像 111 | NSArray * mediaTypes =[UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]; 112 | picker.mediaTypes = mediaTypes; 113 | picker.videoMaximumDuration = self.videoMaximumDuration; 114 | picker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo; 115 | }else { //拍照 116 | picker.allowsEditing = YES; 117 | } 118 | } 119 | 120 | - (void)configureTZImagePicker: (TZImagePickerController *)imagePicker { 121 | imagePicker.allowPickingImage = self.allowPickingImage; 122 | imagePicker.allowPickingVideo = self.allowPickingVideo; 123 | imagePicker.allowPickingGif = self.allowPickingGif; 124 | 125 | imagePicker.allowTakePicture = self.allowTakePicture; 126 | imagePicker.allowTakeVideo = self.allowTakeVideo; 127 | imagePicker.allowPickingOriginalPhoto = self.allowPickingOriginalPhoto; 128 | imagePicker.allowPickingMultipleVideo = self.allowPickingMultipleVideo; 129 | imagePicker.videoMaximumDuration = self.videoMaximumDuration; 130 | 131 | //外观 132 | if (self.naviBgColor) imagePicker.naviBgColor = self.naviBgColor; 133 | if (self.naviTitleColor) imagePicker.naviTitleColor = self.naviTitleColor; 134 | if (self.naviTitleFont) imagePicker.naviTitleFont = self.naviTitleFont; 135 | if (self.barItemTextColor) imagePicker.barItemTextColor = self.barItemTextColor; 136 | if (self.barItemTextFont) imagePicker.barItemTextFont = self.barItemTextFont; 137 | imagePicker.statusBarStyle = self.statusBarStyle; 138 | } 139 | 140 | #pragma mark - UIImagePickerControllerDelegate 141 | 142 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 143 | ACMediaModel *model = [ACMediaTool mediaInfoWithDict:info]; 144 | if (self.didFinishPickingBlock) { 145 | self.didFinishPickingBlock(@[model]); 146 | } 147 | [picker dismissViewControllerAnimated:YES completion:nil]; 148 | } 149 | 150 | #pragma mark - TZImagePickerControllerDelegate 151 | 152 | // 单个/多个图片、多个gif、多个视频、三者混合选取的回调 153 | - (void)imagePickerController:(TZImagePickerController *)picker 154 | didFinishPickingPhotos:(NSArray *)photos 155 | sourceAssets:(NSArray *)assets 156 | isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto { 157 | NSMutableArray *list = [NSMutableArray array]; 158 | for (NSInteger idx = 0; idx < photos.count; idx++) { 159 | ACMediaModel *model = [ACMediaTool imageInfoWithAsset:assets[idx] image:photos[idx]]; 160 | [list addObject:model]; 161 | } 162 | if (self.didFinishPickingBlock) { 163 | self.didFinishPickingBlock(list); 164 | } 165 | } 166 | 167 | // 单个视频选取回调 168 | - (void)imagePickerController:(TZImagePickerController *)picker 169 | didFinishPickingVideo:(UIImage *)coverImage 170 | sourceAssets:(id)asset { 171 | [ACMediaTool videoInfoWithAsset:asset coverImage:coverImage completion:^(ACMediaModel * _Nonnull model) { 172 | if (self.didFinishPickingBlock) { 173 | self.didFinishPickingBlock(@[model]); 174 | } 175 | }]; 176 | } 177 | 178 | // 单个gif选取回调 179 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(PHAsset *)asset { 180 | ACMediaModel *model = [ACMediaTool imageInfoWithAsset:asset image:animatedImage]; 181 | if (self.didFinishPickingBlock) { 182 | self.didFinishPickingBlock(@[model]); 183 | } 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /before 3.0.0 README.md: -------------------------------------------------------------------------------- 1 | # ACMediaFrame before 3.0.0 2 | 最完整、最全面的媒体库选择和展示的框架。包括图片、视频选取、拍照、自定义录像等的展示,自动帮你处理得到可用于上传的数据类型,不用你作任何操作。 3 | 4 | ![ACMediaFrameExample.gif](https://gitlab.com/ImageLibrary/githubImage/raw/master/ACMediaFrame/ACMediaFrame.gif) 5 | 6 | ## 导航 7 | * [基本要求](#Requirements) 8 | * [实现功能](#function) 9 | * [结构层次](#Architecture) 10 | * [如何添加](#add) 11 | * [使用详情](#detail) 12 | * [属性自定义](#custom) 13 | * [版本更新](#version) 14 | * [Hope](#hope) 15 | 16 | 17 | 18 | 19 | iOS11上`MWPhotoBrowser`出现一点问题,第三方库作者并未更新,所以需要使用者自己修改源代码。 20 | 21 | 具体问题以及解决:[iOS 11 display multiple images swipe issue](https://github.com/mwaterfall/MWPhotoBrowser/issues/620) 22 | 23 | 如果上面的看不懂,也可以按照下面我的模板修改即可: 24 | 25 | 修改`MWPhotoBrowser`文件夹下的 `MWPhotoBrowser.m`文件 26 | 27 | ``` 28 | - (void)viewWillLayoutSubviews { 29 | [super viewWillLayoutSubviews]; 30 | if (@available(iOS 11.0, *)) { 31 | // do nothing 32 | } else { 33 | [self layoutVisiblePages]; 34 | } 35 | } 36 | 37 | - (void)viewWillAppear:(BOOL)animated { 38 | ... 39 | //前面的不变,只是下面这部分有改动 40 | // Layout 41 | if (@available(iOS 11.0, *)) { 42 | [self layoutVisiblePages]; 43 | } 44 | [self.view setNeedsLayout]; 45 | } 46 | ``` 47 | 48 | 49 | 50 | 51 | 52 | ## 基本要求 53 | 54 | * iOS 8.0 or later 55 | 56 | * Xcode 7.0 or later 57 | 58 | * 用到github上第三方:[TZImagePickerController](https://github.com/banchichen/TZImagePickerController)和[MWPhotoBrowser](https://github.com/mwaterfall/MWPhotoBrowser)和 [ACAlertController](https://github.com/honeycao/ACAlertController) 59 | 60 | 61 | ## 实现功能 62 | * 本地图片(包括gif)、视频单选多选、界面展示等,直接返回数据类型,可用于上传。 63 | * 拍照、自定义录像、界面展示,直接返回数据类型,可用于上传。 64 | * 单独对网络图片、本地图片、视频等直接进行界面展示。 65 | * 自定义媒体model,返回图片、视频上传数据类型,如:NSData或视频路径。不用为了得到上传的数据类型做任何处理了。 66 | * 框架主体是一个view,已经实现高度配置,不用再去做任何处理 67 | * 框架主体形势支持:添加媒体、预览展示媒体、混合编辑(添加和预览展示一起实现) 68 | * 选择媒体上支持:删除、限定最大选择数数量、同个媒体资源是否多次选择等多种自定义功能。 69 | * 从本地相册选择图片用到了`TZImagePickerController`;查看图片视频用到了`MWPhotoBrowser`;底部弹出框用到`ACAlertController`替代系统弹框 70 | 71 | ## 结构层次 72 | 73 | ### 如何添加 74 | 75 | * 使用 `CocoaPods` 76 | - `pod 'ACMediaFrame'` 77 | * 手动添加 78 | - 把`ACMediaFrame`文件拉到项目中 79 | - 添加头文件`#import "ACMediaFrame.h"` 80 | 81 | ### 使用详情(具体看 `ACMediaFrameExample` 示例) 82 | *demo目录分析* 83 | * `AddTableViewController` 添加媒体的演示 84 | * `DisplayTableViewController` 预览媒体的演示 85 | * `EditTableViewController` 添加和预览混合编排的演示 86 | **作为tableHeaderView使用** 87 | 88 | ``` 89 | 90 | // 初始化 91 | ACSelectMediaView *mediaView = [[ACSelectMediaView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 1)]; 92 | 93 | // 需要展示的媒体的资源类型,当前是仅本地图库 94 | mediaView.type = ACMediaTypePhoto; 95 | 96 | // 是否允许 同个图片或视频进行多次选择 97 | mediaView.allowMultipleSelection = NO; 98 | 99 | //视情况看是否需要改变高度,目前单独使用且作为tableview的header,并不用监控并改变高度 100 | [mediaView observeViewHeight:^(CGFloat mediaHeight) { 101 | // 102 | }]; 103 | 104 | // 随时获取选择好媒体文件 105 | [mediaView observeSelectedMediaArray:^(NSArray *list) { 106 | // do something 107 | for (ACMediaModel *model in list) { 108 | //遍历得到模型中想要的数据 e.g. 109 | // id uplodaType = model.uploadType; 110 | // NSString *name = model.name; 111 | } 112 | NSLog(@"list.count = %lu",(unsigned long)list.count); 113 | }]; 114 | 115 | //刷新方法 在 observeViewHeight 存在时可忽略 116 | [mediaView reload]; 117 | 118 | // 添加到控件上 119 | self.tableView.tableHeaderView = mediaView; 120 | ``` 121 | 122 | 123 | **注意:作为`tableFooterView`的时候,有一点不同就是设置`tableFooterView`方法写入`observeViewHeight`方法中,具体可以查看`demo1`写法。** 124 | 125 | ------- 126 | 127 | ### 属性自定义 128 | 129 | >demo中有些属性可能没用上,不同属性的设置可以达成不同的效果 130 | 131 | * `type` 132 | >需要展示的媒体的资源类型:如仅显示图片等,默认是 ACMediaTypePhotoAndCamera 133 | ``` 134 | e.g. 点击加号按钮,自定义所想要的媒体资源选项 135 | mediaView.type = ACMediaTypePhoto 136 | ``` 137 | 138 | * `preShowMedias` 139 | >预先展示的媒体数组。如果一开始有需要显示媒体资源,可以先传入进行显示,没有的话可以不赋值。 140 | >传入的如果是图片类型,则可以是:UIImage,NSString,至于其他的都可以传入 ACMediaModel类型 141 | >包括网络图片和gif图片、视频。 142 | 143 | ``` 144 | e.g. 在预览或者之前已经有图片的情况下,需要传入进行预先展示(其中包括预展示视频、gif等) 145 | 146 | //视频必须是传入这样一个model参数 147 | ACMediaModel *md = [ACMediaModel new]; 148 | md.mediaURL = [NSURL URLWithString:@"http://baobab.wdjcdn.com/1451897812703c.mp4"]; 149 | md.isVideo = YES; 150 | md.image = [UIImage imageNamed:@"memory"]; //封面图 151 | 152 | mediaView.preShowMedias = @[@"bg_1", @"bg_2", @"bug.gif", @"http://c.hiphotos.baidu.com/image/h%3D200/sign=ad1c53cd0355b31983f9857573ab8286/279759ee3d6d55fbb02469ea64224f4a21a4dd1f.jpg"]; 153 | ``` 154 | 155 | * `maxImageSelected` 156 | >最大图片、视频选择个数,包括 `preShowMedias`的数量. default is 9 157 | ``` 158 | e.g. 自定义从本地相册中所选取的最大数量 159 | mediaView.maxImageSelected = 5; 160 | ``` 161 | 162 | * `showDelete` 163 | >是否显示删除按钮. Defaults is YES 164 | ``` 165 | e.g. 一般在预览情况下设置为 NO 166 | mediaView.showDelete = NO; 167 | ``` 168 | 169 | * `showAddButton` 170 | >是否需要显示添加按钮. Defaults is YES 171 | ``` 172 | e.g. 一般在预览情况下设置为 NO 173 | mediaView.showAddButton = NO; 174 | ``` 175 | 176 | * `allowPickingVideo` 177 | >是否允许 在选择图片的同时可以选择视频文件. default is NO 178 | >选择的本地视频只是简单加载显示,当需要立刻播放选择的本地视频时,会有一个转码加载的过程,请等待(注意) 179 | ``` 180 | e.g. 如果希望在选择图片的时候,出现视频资源,那么可以设置为 YES 181 | mediaView.allowPickingVideo = NO; 182 | ``` 183 | 184 | * `allowMultipleSelection` 185 | >是否允许 同个图片或视频进行多次选择. default is YES 186 | >如果设置为 NO,那么在已经选择了一张以上图片之后,就不能同时选择视频了(注意) 187 | ``` 188 | e.g. 如果不希望已经选择的图片或视频,再次被选择,那么可以设置为 NO 189 | mediaView.allowMultipleSelection = NO; 190 | ``` 191 | 192 | * `allowTakePicture` 193 | >是否允许 在相册中出现拍照选择. default is NO 194 | >设置为YES,那么在相册最后一格会出现一格拍照按钮,点击可以打开相机拍照,拍照成功之后会保存到相册并选中状态 195 | ``` 196 | e.g. 如果希望出现拍照按钮,可以设置为YES 197 | mediaView.allowTakePicture = YES; 198 | ``` 199 | 200 | * `allowPickingOriginalPhoto` 201 | >是否允许 相册中出现选择原图. default is NO 202 | >设置为 YES,那么相册底部会出现一格原图选项,可以保证选中的图片是原图,原图可能就比较大点,所以一般没这个必要。 203 | ``` 204 | e.g. 如果希望选择原图,那么可以设置为YES 205 | mediaView.allowPickingOriginalPhoto = YES; 206 | ``` 207 | 208 | * `videoMaximumDuration` 209 | >设置录像的一个最大持续时间(以秒为单位). default is 60 210 | ``` 211 | e.g. 设置录像最大时长为10秒 212 | mediaView.videoMaximumDuration = 10.0; 213 | ``` 214 | 215 | * `rootViewController` 216 | >当前的主控制器(非必传) 217 | >但是有时候碰到无法自动获取的时候会抛出异常(rootViewController must not be nil),那么就必须手动传入 218 | 219 | * `backgroundColor` 220 | >底部collectionView的背景颜色,有特殊颜色要求的可以单独去设置 221 | 222 | ***一系列自定义导航栏属性*** 223 | 224 | * `naviBarBgColor` 225 | >navigationbar background color. 226 | 227 | * `naviBarTitleColor` 228 | >navigationBar title color 229 | 230 | * `naviBarTitleFont` 231 | >navigationBar title font 232 | 233 | * `barItemTextColor` 234 | >navigationItem right/left barButtonItem text color 235 | 236 | * `barItemTextFont` 237 | >navigationItem right/left barButtonItem text font 238 | 239 | ------ 240 | 241 | ## 版本更新 242 | * `2.0.4`:支持自定义区域的布局、demo修改等 243 | * `2.0.3`:优化图片到达最大张数时添加图片的按钮隐藏 244 | * `2.0.2` : 支持 cocoapods 导入,当前版本 2.0.2 245 | * `2.0.0` : 修改之前选择图片、删除图片之间的一些逻辑问题。 246 | * `1.3.9` : 之前对预展示视频写的不够清楚,于是这次就对如何集成和使用预展示视频功能,添加了相关的演示范例。 247 | * `1.3.8` : 添加、开放属性,用于自定义相册界面的导航栏. 248 | * `1.3.7` : 由于会碰到无法自动获取一个主视图的情况,所以开放一个参数`rootViewController`,用于手动传入当前的主控制器,非必传的,如果自动获取失败会抛出一个异常,具体看`属性自定义`中的使用即可. 249 | * `1.3.6` : 应使用者需求,继续开放了功能接口,包括:是否允许相册中拍照、是否可以选择原图、设置录像最大持续时间。 250 | * `1.3.5` : 添加支持gif图片选择和展示功能。 251 | * `1.3.4` : 完善图片视频选择的一些逻辑问题。 252 | * `1.3.3` : 这个版本其实和上个版本一样,只不过有热心群众反馈播放视频的时候没有开启麦克风权限没有声音,所以添加了一个权限判断,但是后来自己测试的时候发现并没有这个bug,所以最终就没做什么大的调整。 253 | * `1.3.2` : 上一版本处理好之后,没有同时测试相册和相机选择图片的情况,所以出现了点问题,现在这版本就是修改这个问题,很感谢小伙伴的使用和提供的bug,由于自己能力有限,所以难免会有些许bug,不打紧,你们发现bug告诉我,我会尽快修复。。。 254 | * `1.3.1` : 对上一版本的简单改动,修改获取主控制器失败的方法,以及继续完善 255 | * `1.3.0` : 改动比较大的一次,首先是代码整体层次上变动了下,另外添加了自己写的一个底部弹出框功能,添加几个开放属性(是否在图片中可以选择视频、选择的图片下次是否可以继续选择等) 256 | * `1.2.0` : 由于上次的提交,导致一个问题(设置的隐藏添加图片按钮失效的问题),当时没有考虑完全,所以这次进行修改并修复有默认图片是显示的一些布局问题;另外继续完善几个开放接口,比如设置选择图片数量等。 257 | * `1.1.0` : 258 | * 添加了几个属性,使得框架更容易集成和修改。现在不仅可以用来选择图片等媒体资源,同时也可以只是用来展示等。 259 | * 修改了添加框架的头文件等 260 | * `1.0.1` : 添加一个媒体类型,默认媒体资源是本地图片、视频,拍摄的图片、录像等,现在可以自己选择类型,例如:当只需要图片时,就设置媒体类型属性即可。 261 | * `1.0.0` : 最初原型,封装的选择媒体以及布局的页面,把媒体资源的处理全进行封装,减少重复工作,只需添加到视图上,然后接收获取的媒体数据。 262 | 263 | ## Hope 264 | * 代码使用过程中,发现任何问题,可以随时[issues me](https://github.com/honeycao/ACMediaFrame/issues/new) 265 | * 如果有更多建议或者想法也可以直接联系我 QQ:331864805 266 | * 觉得框架对你有一点点帮助的,就请支持下,点个赞。 267 | 268 | ## Licenses 269 | All source code is licensed under the MIT License. 270 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/README.md: -------------------------------------------------------------------------------- 1 | # TZImagePickerController 2 | [![CocoaPods](https://img.shields.io/cocoapods/v/TZImagePickerController.svg?style=flat)](https://github.com/banchichen/TZImagePickerController) 3 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 4 | 5 | 6 | A clone of UIImagePickerController, support picking multiple photos、original photo、video, also allow preview photo and video, support iOS6+. 7 | 一个支持多选、选原图和视频的图片选择器,同时有预览功能,支持iOS6+。 8 | 9 | ## 重要提示1:提issue前,请先对照Demo、常见问题自查!Demo正常说明你可以升级下新版试试。 10 | 11 | ## 重要提示2:3.5.2版本适配了iOS14、iPhone12,修复2个严重问题,强烈建议尽快更新 12 | 关于iOS14模拟器的问题 13 | PHAuthorizationStatusLimited授权模式下,iOS14模拟器有bug,未授权照片无法显示,真机正常,暂可忽略:https://github.com/banchichen/TZImagePickerController/issues/1347 14 | 15 | 关于升级iOS10和Xcdoe8的提示: 16 | 在Xcode8环境下将项目运行在iOS10的设备/模拟器中,访问相册和相机需要额外配置info.plist文件。分别是Privacy - Photo Library Usage Description和Privacy - Camera Usage Description字段,详见Demo中info.plist中的设置。 17 | 18 | 项目截图 1.Demo首页 2.照片列表页 3.照片预览页 4.视频预览页 19 | 20 | 21 | 22 | ## 一. Installation 安装 23 | 24 | #### CocoaPods 25 | > pod 'TZImagePickerController' #iOS8 and later 26 | > pod 'TZImagePickerController', '2.2.6' #iOS6、iOS7 27 | 28 | #### Carthage 29 | > github "banchichen/TZImagePickerController" 30 | 31 | #### 手动安装 32 | > 将TZImagePickerController文件夹拽入项目中,导入头文件:#import "TZImagePickerController.h" 33 | 34 | ## 二. Example 例子 35 | 36 | TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self]; 37 | 38 | // You can get the photos by block, the same as by delegate. 39 | // 你可以通过block或者代理,来得到用户选择的照片. 40 | [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray *photos, NSArray *assets, BOOL isSelectOriginalPhoto) { 41 | 42 | }]; 43 | [self presentViewController:imagePickerVc animated:YES completion:nil]; 44 | 45 | ## 三. Requirements 要求 46 | iOS 6 or later. Requires ARC 47 | iOS6及以上系统可使用. ARC环境. 48 | 49 | When system version is iOS6 or iOS7, Using AssetsLibrary. 50 | When system version is iOS8 or later, Using PhotoKit. 51 | 如果运行在iOS6或7系统上,用的是AssetsLibrary库获取照片资源。 52 | 如果运行在iOS8及以上系统上,用的是PhotoKit库获取照片资源。 53 | 54 | TZImagePickerController uses Camera、Location、Microphone、Photo Library,you need add these properties to info.plist like Demo: 55 | TZImagePickerController使用了相机、定位、麦克风、相册,请参考Demo添加下列属性到info.plist文件: 56 | `Privacy - Camera Usage Description` 57 | `Privacy - Location Usage Description` 58 | `Privacy - Location When In Use Usage Description` 59 | `Privacy - Microphone Usage Description` 60 | `Privacy - Photo Library Usage Description` 61 | 62 | ## 四. More 更多 63 | 64 | If you find a bug, please create a issue. 65 | More information please view code. 66 | 如果你发现了bug,请提一个issue。 67 | 更多信息详见代码,也可查看我的博客: [我的博客](http://www.jianshu.com/p/1975411a31bb "半尺尘 - 简书") 68 | 69 | 关于issue: 70 | 请尽可能详细地描述**系统版本**、**手机型号**、**库的版本**、**崩溃日志**和**复现步骤**,**请先更新到最新版再测试一下**,如果新版还存在再提~如果已有开启的类似issue,请直接在该issue下评论说出你的问题 71 | 72 | ## 五. FAQ 常见问题 73 | 74 | **Q:pod search TZImagePickerController 搜索出来的不是最新版本** 75 | A:需要在终端执行cd转换文件路径命令退回到Desktop,然后执行pod setup命令更新本地spec缓存(可能需要几分钟),然后再搜索就可以了 76 | 77 | **Q:拍照后照片保存失败** 78 | A:请参考issue481:https://github.com/banchichen/TZImagePickerController/issues/481 的信息排查,若还有问题请直接在issue内评论 79 | 80 | **Q:photos数组图片不是原图,如何获取原图?** 81 | A:请参考issue457的解释:https://github.com/banchichen/TZImagePickerController/issues/457 82 | 83 | **Q:系统语言是中文/英文,界面上却有部分相册名字、返回按钮显示成了英文/中文?** 84 | A:请参考 https://github.com/banchichen/TZImagePickerController/issues/443 和 https://github.com/banchichen/TZImagePickerController/issues/929 85 | 86 | **Q:预览界面能否支持传入NSURL、UIImage对象?** 87 | A:3.0.1版本已支持,需新接一个库:[TZImagePreviewController](https://github.com/banchichen/TZImagePreviewController),请参考里面的Demo使用。 88 | 89 | **Q:设置可选视频的最大/最小时长?照片的最小/最大尺寸?不符合要求的不显示** 90 | A:可以的,参照Demo的isAssetCanBeDisplayed方法实现。我会返回asset出来,显示与否你来决定,注意这个是一个同步方法,对于需要根据asset去异步获取的信息如视频的大小、视频是否存在iCloud里来过滤的,无法做到。如果真要这样做,相册打开速度会变慢,你需要改我源码。 91 | 如果需要显示,选择时才提醒用户不可选,则实现isAssetCanBeSelected,用户选择时会调用它 92 | 93 | **Q:预览页面出现了导航栏?** 94 | A:https://github.com/banchichen/TZImagePickerController/issues/652 95 | 96 | **Q:可否增加微信编辑图片的功能?** 97 | A:考虑下,优先级低 98 | 99 | **Q:是否有QQ/微信群?** 100 | A:有QQ群:778723997 101 | 102 | **Q:想提交一个Pull Request?** 103 | A:请先加下面钉钉群说下方案,和我确认下,避免同时改动同一处内容。**一个PR请只修复1个问题,变动内容越少越好**。 104 | 105 | 106 | **Q:demo在真机上跑不起来?** 107 | A:1、team选你自己的;2、bundleId也改成你自己的或改成一个不会和别人重复的。可参考[简书的这篇博客](https://www.jianshu.com/p/cbe59138fca6) 108 | 109 | **Q:设置导航栏颜色无效?导航栏颜色总是白色?** 110 | A:是否有集成WRNavigationBar?如有,参考其readme调一下它的wr_setBlackList,把TZImagePickerController相关的控制器放到黑名单里,使得不受WRNavigationBar的影响。如果没有集成,可在issues列表里搜一下看看类似的issue参考下,如实在没头绪,可加群提供个能复现该问题的demo,0~2天给你解决。最近发现WRNavigationBar的黑名单会有不生效的情况,临时解决方案大家可参考:[https://github.com/wangrui460/WRNavigationBar/issues/145](https://github.com/wangrui460/WRNavigationBar/issues/145) 111 | 112 | **Q:导航栏没了?** 113 | A:是否有集成GKNavigationBarViewController?需要升级到2.0.4及以上版本,详见issue:[https://github.com/QuintGao/GKNavigationBarViewController/issues/7](https://github.com/QuintGao/GKNavigationBarViewController/issues/7)。 114 | 115 | **Q:有的视频导出失败?** 116 | A:升级到2.2.6及以上版本试试,发现是修正视频转向导致的,2.2.6开始默认不再主动修正。如需打开,可设置needFixComposition为YES,但有几率导致安卓拍的视频导出失败。此外也可参考这个issue:https://github.com/banchichen/TZImagePickerController/issues/1073 117 | 118 | **Q:视频导出慢?** 119 | A:视频导出分两步,第一步是通过PHAsset获取AVURLAsset,如是iCloud视频则涉及到网络请求,耗时容易不可控,第二步是通过AVURLAsset把视频保存到沙盒,耗时不算多。但第一步耗时不可控,你可以拷贝我源码出来拿到第一步的进度给用户一个进度提示... 120 | 121 | **Q:有的图片info里没有PHImageFileURLKey?** 122 | A:不要去拿PHImageFileURLKey,没用的,只有通过Photos框架才能访问相册照片,光拿一个路径没用。 123 | 如果需要通过路径上传照片,请先把UIImage保存到沙盒,**用沙盒路径**。 124 | 如果你上传照片需要一个名字参数,请参考Demo**直接用照片名字**。 125 | 126 | ## 六. Release Notes 最近更新 127 | 128 | 3.6.0 修复iOS14下iCloud视频导出失败问题 129 | **3.5.2 适配iPhone12系列设备** 130 | 3.4.4 支持Dark Mode 131 | **3.4.2 适配iOS14,若干问题修复** 132 | 3.3.2 适配iOS13,若干问题修复 133 | 3.2.1 新增裁剪用scaleAspectFillCrop属性,设置为YES后,照片尺寸小于裁剪框时会自动放大撑满 134 | 3.2.0 加入用NSOperationQueue控制获取原图并发数降低内存的示例 135 | 3.1.8 批量获取图片时加入队列控制,尝试优化大批量选择图片时CPU和内存占用过高的问题(仍然危险,maxImagesCount谨慎设置过大...) 136 | 3.1.5 相册内无照片时给出提示,修复快速滑动时内存一直增加的问题 137 | 3.1.3 适配阿拉伯等语言下从右往左布局的特性 138 | 3.0.8 新增gifImagePlayBlock允许使用FLAnimatedImage等替换内部的GIF播放方案 139 | 3.0.7 适配iPhoneXR、XS、XS Max 140 | 3.0.6 优化保存照片、视频的方法 141 | 3.0.1 新增对[TZImagePreviewController](https://github.com/banchichen/TZImagePreviewController)库的支持,允许预览UIImage、NSURL、PHAsset对象 142 | **3.0.0 去除iOS6和7的适配代码,更轻量,最低支持iOS8** 143 | 2.2.6 新增needFixComposition属性,默认为NO,不再主动修正视频转向,防止部分安卓拍的视频导出失败(**最后一个支持iOS6和7的版本**) 144 | 2.1.5 修复开启showSelectedIndex后照片列表页iCloud图片进度条紊乱的bug 145 | 2.1.4 新增多个页面和组件的样式自定义block,允许自定义绝大多数UI样式 146 | 2.1.2 新增showPhotoCannotSelectLayer属性,当已选照片张数达到最大可选张数时,可像微信一样让其它照片显示一个提示不可选的浮层 147 | 2.1.1 新增是否显示图片选中序号的属性,优化一些细节 148 | 2.1.0.3 新增拍摄视频功能,优化一些细节 149 | 2.0.0.6 优化自定义languageBundle的支持,加入使用示例 150 | 2.0.0.5 优化性能,提高选择器打开速度,新增越南语支持 151 | 2.0.0.2 新增繁体语言,可设置首选语言,国际化支持更强大;优化一些细节 152 | 1.9.8 支持Carthage,优化一些细节 153 | 1.9.6 优化视频预览和gif预览页toolbar在iPhoneX上的样式 154 | ... 155 | 1.8.4 加入横竖屏适配;支持视频/gif多选;支持视频和照片一起选 156 | 1.8.1 新增2个代理方法,支持由上层来决定相册/照片的显示与否 157 | ... 158 | 1.7.7 支持GIF图片的播放和选择 159 | 1.7.6 支持对共享相册和同步相册的显示 160 | 1.7.5 允许不进入预览页面直接选择照片 161 | 1.7.4 支持单选模式下裁剪照片,支持任意矩形和圆形裁剪框 162 | 1.7.3 优化iCloud照片的显示与选择 163 | ... 164 | 1.5.0 可把拍照按钮放在外面;可自定义照片排序方式;Demo页的UI大改版,新增若干开关; 165 | ... 166 | 1.4.5 性能大幅提升(性能测试截图请去博客查看);可在照片列表页拍照;Demo大幅优化; 167 | ... 168 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageCropManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZImageCropManager.m 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 2016/12/5. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import "TZImageCropManager.h" 10 | #import "UIView+TZLayout.h" 11 | #import 12 | #import "TZImageManager.h" 13 | #import "TZImagePickerController.h" 14 | 15 | @implementation TZImageCropManager 16 | 17 | /// 裁剪框背景的处理 18 | + (void)overlayClippingWithView:(UIView *)view cropRect:(CGRect)cropRect containerView:(UIView *)containerView needCircleCrop:(BOOL)needCircleCrop { 19 | UIBezierPath *path= [UIBezierPath bezierPathWithRect:[UIScreen mainScreen].bounds]; 20 | CAShapeLayer *layer = [CAShapeLayer layer]; 21 | if (needCircleCrop) { // 圆形裁剪框 22 | [path appendPath:[UIBezierPath bezierPathWithArcCenter:containerView.center radius:cropRect.size.width / 2 startAngle:0 endAngle: 2 * M_PI clockwise:NO]]; 23 | } else { // 矩形裁剪框 24 | [path appendPath:[UIBezierPath bezierPathWithRect:cropRect]]; 25 | } 26 | layer.path = path.CGPath; 27 | layer.fillRule = kCAFillRuleEvenOdd; 28 | layer.fillColor = [[UIColor blackColor] CGColor]; 29 | layer.opacity = 0.5; 30 | [view.layer addSublayer:layer]; 31 | } 32 | 33 | /// 获得裁剪后的图片 34 | + (UIImage *)cropImageView:(UIImageView *)imageView toRect:(CGRect)rect zoomScale:(double)zoomScale containerView:(UIView *)containerView { 35 | CGAffineTransform transform = CGAffineTransformIdentity; 36 | // 平移的处理 37 | CGRect imageViewRect = [imageView convertRect:imageView.bounds toView:containerView]; 38 | CGPoint point = CGPointMake(imageViewRect.origin.x + imageViewRect.size.width / 2, imageViewRect.origin.y + imageViewRect.size.height / 2); 39 | CGFloat xMargin = containerView.tz_width - CGRectGetMaxX(rect) - rect.origin.x; 40 | CGPoint zeroPoint = CGPointMake((CGRectGetWidth(containerView.frame) - xMargin) / 2, containerView.center.y); 41 | CGPoint translation = CGPointMake(point.x - zeroPoint.x, point.y - zeroPoint.y); 42 | transform = CGAffineTransformTranslate(transform, translation.x, translation.y); 43 | // 缩放的处理 44 | transform = CGAffineTransformScale(transform, zoomScale, zoomScale); 45 | 46 | CGImageRef imageRef = [self newTransformedImage:transform 47 | sourceImage:imageView.image.CGImage 48 | sourceSize:imageView.image.size 49 | outputWidth:rect.size.width * [UIScreen mainScreen].scale 50 | cropSize:rect.size 51 | imageViewSize:imageView.frame.size]; 52 | UIImage *cropedImage = [UIImage imageWithCGImage:imageRef]; 53 | cropedImage = [[TZImageManager manager] fixOrientation:cropedImage]; 54 | CGImageRelease(imageRef); 55 | return cropedImage; 56 | } 57 | 58 | + (CGImageRef)newTransformedImage:(CGAffineTransform)transform sourceImage:(CGImageRef)sourceImage sourceSize:(CGSize)sourceSize outputWidth:(CGFloat)outputWidth cropSize:(CGSize)cropSize imageViewSize:(CGSize)imageViewSize { 59 | CGImageRef source = [self newScaledImage:sourceImage toSize:sourceSize]; 60 | 61 | CGFloat aspect = cropSize.height/cropSize.width; 62 | CGSize outputSize = CGSizeMake(outputWidth, outputWidth*aspect); 63 | 64 | CGContextRef context = CGBitmapContextCreate(NULL, outputSize.width, outputSize.height, CGImageGetBitsPerComponent(source), 0, CGImageGetColorSpace(source), CGImageGetBitmapInfo(source)); 65 | CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]); 66 | CGContextFillRect(context, CGRectMake(0, 0, outputSize.width, outputSize.height)); 67 | 68 | CGAffineTransform uiCoords = CGAffineTransformMakeScale(outputSize.width / cropSize.width, outputSize.height / cropSize.height); 69 | uiCoords = CGAffineTransformTranslate(uiCoords, cropSize.width/2.0, cropSize.height / 2.0); 70 | uiCoords = CGAffineTransformScale(uiCoords, 1.0, -1.0); 71 | CGContextConcatCTM(context, uiCoords); 72 | 73 | CGContextConcatCTM(context, transform); 74 | CGContextScaleCTM(context, 1.0, -1.0); 75 | 76 | CGContextDrawImage(context, CGRectMake(-imageViewSize.width/2, -imageViewSize.height/2.0, imageViewSize.width, imageViewSize.height), source); 77 | CGImageRef resultRef = CGBitmapContextCreateImage(context); 78 | CGContextRelease(context); 79 | CGImageRelease(source); 80 | return resultRef; 81 | } 82 | 83 | + (CGImageRef)newScaledImage:(CGImageRef)source toSize:(CGSize)size { 84 | CGSize srcSize = size; 85 | CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB(); 86 | CGContextRef context = CGBitmapContextCreate(NULL, size.width, size.height, 8, 0, rgbColorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 87 | CGColorSpaceRelease(rgbColorSpace); 88 | 89 | CGContextSetInterpolationQuality(context, kCGInterpolationNone); 90 | CGContextTranslateCTM(context, size.width/2, size.height/2); 91 | 92 | CGContextDrawImage(context, CGRectMake(-srcSize.width/2, -srcSize.height/2, srcSize.width, srcSize.height), source); 93 | 94 | CGImageRef resultRef = CGBitmapContextCreateImage(context); 95 | CGContextRelease(context); 96 | return resultRef; 97 | } 98 | 99 | /// 获取圆形图片 100 | + (UIImage *)circularClipImage:(UIImage *)image { 101 | UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale); 102 | 103 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 104 | CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); 105 | CGContextAddEllipseInRect(ctx, rect); 106 | CGContextClip(ctx); 107 | 108 | [image drawInRect:rect]; 109 | UIImage *circleImage = UIGraphicsGetImageFromCurrentImageContext(); 110 | 111 | UIGraphicsEndImageContext(); 112 | return circleImage; 113 | } 114 | 115 | @end 116 | 117 | 118 | @implementation UIImage (TZGif) 119 | 120 | + (UIImage *)sd_tz_animatedGIFWithData:(NSData *)data { 121 | if (!data) { 122 | return nil; 123 | } 124 | 125 | CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); 126 | 127 | size_t count = CGImageSourceGetCount(source); 128 | 129 | UIImage *animatedImage; 130 | 131 | if (count <= 1) { 132 | animatedImage = [[UIImage alloc] initWithData:data]; 133 | } 134 | else { 135 | // images数组过大时内存会飙升,在这里限制下最大count 136 | NSInteger maxCount = [TZImagePickerConfig sharedInstance].gifPreviewMaxImagesCount ?: 50; 137 | NSInteger interval = MAX((count + maxCount / 2) / maxCount, 1); 138 | 139 | NSMutableArray *images = [NSMutableArray array]; 140 | 141 | NSTimeInterval duration = 0.0f; 142 | 143 | for (size_t i = 0; i < count; i+=interval) { 144 | CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); 145 | if (!image) { 146 | continue; 147 | } 148 | 149 | duration += [self sd_frameDurationAtIndex:i source:source] * MIN(interval, 3); 150 | 151 | [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; 152 | 153 | CGImageRelease(image); 154 | } 155 | 156 | if (!duration) { 157 | duration = (1.0f / 10.0f) * count; 158 | } 159 | 160 | animatedImage = [UIImage animatedImageWithImages:images duration:duration]; 161 | } 162 | 163 | CFRelease(source); 164 | 165 | return animatedImage; 166 | } 167 | 168 | + (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { 169 | float frameDuration = 0.1f; 170 | CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); 171 | NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; 172 | NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; 173 | 174 | NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; 175 | if (delayTimeUnclampedProp) { 176 | frameDuration = [delayTimeUnclampedProp floatValue]; 177 | } 178 | else { 179 | 180 | NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; 181 | if (delayTimeProp) { 182 | frameDuration = [delayTimeProp floatValue]; 183 | } 184 | } 185 | 186 | // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. 187 | // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify 188 | // a duration of <= 10 ms. See and 189 | // for more information. 190 | 191 | if (frameDuration < 0.011f) { 192 | frameDuration = 0.100f; 193 | } 194 | 195 | CFRelease(cfFrameProperties); 196 | return frameDuration; 197 | } 198 | 199 | @end 200 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImageManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZImageManager.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 16/1/4. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 图片资源获取管理类 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import "TZAssetModel.h" 14 | 15 | @class TZAlbumModel,TZAssetModel; 16 | @protocol TZImagePickerControllerDelegate; 17 | @interface TZImageManager : NSObject 18 | 19 | @property (nonatomic, strong) PHCachingImageManager *cachingImageManager; 20 | 21 | + (instancetype)manager NS_SWIFT_NAME(default()); 22 | + (void)deallocManager; 23 | 24 | @property (weak, nonatomic) id pickerDelegate; 25 | 26 | @property (nonatomic, assign) BOOL shouldFixOrientation; 27 | 28 | @property (nonatomic, assign) BOOL isPreviewNetworkImage; 29 | 30 | /// Default is 600px / 默认600像素宽 31 | @property (nonatomic, assign) CGFloat photoPreviewMaxWidth; 32 | /// The pixel width of output image, Default is 828px / 导出图片的宽度,默认828像素宽 33 | @property (nonatomic, assign) CGFloat photoWidth; 34 | 35 | /// Default is 4, Use in photos collectionView in TZPhotoPickerController 36 | /// 默认4列, TZPhotoPickerController中的照片collectionView 37 | @property (nonatomic, assign) NSInteger columnNumber; 38 | 39 | /// Sort photos ascending by modificationDate,Default is YES 40 | /// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个 41 | @property (nonatomic, assign) BOOL sortAscendingByModificationDate; 42 | 43 | /// Minimum selectable photo width, Default is 0 44 | /// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中 45 | @property (nonatomic, assign) NSInteger minPhotoWidthSelectable; 46 | @property (nonatomic, assign) NSInteger minPhotoHeightSelectable; 47 | @property (nonatomic, assign) BOOL hideWhenCanNotSelect; 48 | 49 | /// Return YES if Authorized 返回YES如果得到了授权 50 | - (BOOL)authorizationStatusAuthorized; 51 | - (void)requestAuthorizationWithCompletion:(void (^)(void))completion; 52 | 53 | /// Get Album 获得相册/相册数组 54 | - (void)getCameraRollAlbumWithFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion; 55 | - (void)getCameraRollAlbum:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(TZAlbumModel *model))completion __attribute__((deprecated("Use -getCameraRollAlbumWithFetchAssets:completion:. You can config allowPickingImage、allowPickingVideo by TZImagePickerConfig"))); 56 | - (void)getAllAlbums:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage needFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray *models))completion __attribute__((deprecated("Use -getAllAlbumsWithFetchAssets:completion:. You can config allowPickingImage、allowPickingVideo by TZImagePickerConfig"))); 57 | - (void)getAllAlbumsWithFetchAssets:(BOOL)needFetchAssets completion:(void (^)(NSArray *models))completion; 58 | 59 | /// Get Assets 获得Asset数组 60 | - (void)getAssetsFromFetchResult:(PHFetchResult *)result completion:(void (^)(NSArray *models))completion; 61 | - (void)getAssetsFromFetchResult:(PHFetchResult *)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray *models))completion __attribute__((deprecated("Use -getAssetsFromFetchResult:completion:. You can config allowPickingImage、allowPickingVideo by TZImagePickerConfig"))); 62 | - (void)getAssetFromFetchResult:(PHFetchResult *)result atIndex:(NSInteger)index allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(TZAssetModel *model))completion __attribute__((deprecated("Use -getAssetFromFetchResult:atIndex:completion:. You can config allowPickingImage、allowPickingVideo by TZImagePickerConfig"))); 63 | - (void)getAssetFromFetchResult:(PHFetchResult *)result atIndex:(NSInteger)index completion:(void (^)(TZAssetModel *model))completion; 64 | 65 | /// Get photo 获得照片 66 | - (PHImageRequestID)getPostImageWithAlbumModel:(TZAlbumModel *)model completion:(void (^)(UIImage *postImage))completion; 67 | 68 | - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; 69 | - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; 70 | - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed; 71 | - (PHImageRequestID)getPhotoWithAsset:(PHAsset *)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler networkAccessAllowed:(BOOL)networkAccessAllowed; 72 | - (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset completion:(void (^)(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info))completion progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler; 73 | 74 | /// Get full Image 获取原图 75 | /// 如下两个方法completion一般会调多次,一般会先返回缩略图,再返回原图(详见方法内部使用的系统API的说明),如果info[PHImageResultIsDegradedKey] 为 YES,则表明当前返回的是缩略图,否则是原图。 76 | - (PHImageRequestID)getOriginalPhotoWithAsset:(PHAsset *)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion; 77 | - (PHImageRequestID)getOriginalPhotoWithAsset:(PHAsset *)asset newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; 78 | - (PHImageRequestID)getOriginalPhotoWithAsset:(PHAsset *)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler newCompletion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; 79 | // 该方法中,completion只会走一次 80 | - (PHImageRequestID)getOriginalPhotoDataWithAsset:(PHAsset *)asset completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion; 81 | - (PHImageRequestID)getOriginalPhotoDataWithAsset:(PHAsset *)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(NSData *data,NSDictionary *info,BOOL isDegraded))completion; 82 | 83 | /// Save photo 保存照片 84 | - (void)savePhotoWithImage:(UIImage *)image completion:(void (^)(PHAsset *asset, NSError *error))completion; 85 | - (void)savePhotoWithImage:(UIImage *)image location:(CLLocation *)location completion:(void (^)(PHAsset *asset, NSError *error))completion; 86 | - (void)savePhotoWithImage:(UIImage *)image meta:(NSDictionary *)meta location:(CLLocation *)location completion:(void (^)(PHAsset *asset, NSError *error))completion; 87 | 88 | /// Save video 保存视频 89 | - (void)saveVideoWithUrl:(NSURL *)url completion:(void (^)(PHAsset *asset, NSError *error))completion; 90 | - (void)saveVideoWithUrl:(NSURL *)url location:(CLLocation *)location completion:(void (^)(PHAsset *asset, NSError *error))completion; 91 | 92 | /// Get video 获得视频 93 | - (void)getVideoWithAsset:(PHAsset *)asset completion:(void (^)(AVPlayerItem * playerItem, NSDictionary * info))completion; 94 | - (void)getVideoWithAsset:(PHAsset *)asset progressHandler:(void (^)(double progress, NSError *error, BOOL *stop, NSDictionary *info))progressHandler completion:(void (^)(AVPlayerItem *, NSDictionary *))completion; 95 | 96 | /// Export video 导出视频 presetName: 预设名字,默认值是AVAssetExportPreset640x480 97 | - (void)getVideoOutputPathWithAsset:(PHAsset *)asset success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure; 98 | - (void)getVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure; 99 | /// 新的导出视频API,解决iOS14 iCloud视频导出失败的问题,未大量测试,请大家多多测试,有问题群里反馈 100 | - (void)requestVideoOutputPathWithAsset:(PHAsset *)asset presetName:(NSString *)presetName success:(void (^)(NSString *outputPath))success failure:(void (^)(NSString *errorMessage, NSError *error))failure; 101 | /// 得到视频原始文件地址 102 | - (void)requestVideoURLWithAsset:(PHAsset *)asset success:(void (^)(NSURL *videoURL))success failure:(void (^)(NSDictionary* info))failure; 103 | 104 | /// Get photo bytes 获得一组照片的大小 105 | - (void)getPhotosBytesWithArray:(NSArray *)photos completion:(void (^)(NSString *totalBytes))completion; 106 | 107 | - (BOOL)isCameraRollAlbum:(PHAssetCollection *)metadata; 108 | 109 | /// 检查照片大小是否满足最小要求 110 | - (BOOL)isPhotoSelectableWithAsset:(PHAsset *)asset; 111 | 112 | /// 检查照片能否被选中 113 | - (BOOL)isAssetCannotBeSelected:(PHAsset *)asset; 114 | 115 | /// 修正图片转向 116 | - (UIImage *)fixOrientation:(UIImage *)aImage; 117 | 118 | /// 获取asset的资源类型 119 | - (TZAssetModelMediaType)getAssetType:(PHAsset *)asset; 120 | /// 缩放图片至新尺寸 121 | - (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size; 122 | 123 | /// 判断asset是否是视频 124 | - (BOOL)isVideo:(PHAsset *)asset; 125 | 126 | /// for TZImagePreviewController 127 | - (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration; 128 | 129 | - (TZAssetModel *)createModelWithAsset:(PHAsset *)asset; 130 | 131 | @end 132 | 133 | //@interface TZSortDescriptor : NSSortDescriptor 134 | // 135 | //@end 136 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-ACMediaFrameExample/Pods-ACMediaFrameExample-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -u 4 | set -o pipefail 5 | 6 | function on_error { 7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" 8 | } 9 | trap 'on_error $LINENO' ERR 10 | 11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then 12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy 13 | # frameworks to, so exit 0 (signalling the script phase was successful). 14 | exit 0 15 | fi 16 | 17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 19 | 20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}" 21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 22 | 23 | # Used as a return value for each invocation of `strip_invalid_archs` function. 24 | STRIP_BINARY_RETVAL=0 25 | 26 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 27 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 28 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 29 | 30 | # Copies and strips a vendored framework 31 | install_framework() 32 | { 33 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 34 | local source="${BUILT_PRODUCTS_DIR}/$1" 35 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 36 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 37 | elif [ -r "$1" ]; then 38 | local source="$1" 39 | fi 40 | 41 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 42 | 43 | if [ -L "${source}" ]; then 44 | echo "Symlinked..." 45 | source="$(readlink "${source}")" 46 | fi 47 | 48 | # Use filter instead of exclude so missing patterns don't throw errors. 49 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 50 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 51 | 52 | local basename 53 | basename="$(basename -s .framework "$1")" 54 | binary="${destination}/${basename}.framework/${basename}" 55 | 56 | if ! [ -r "$binary" ]; then 57 | binary="${destination}/${basename}" 58 | elif [ -L "${binary}" ]; then 59 | echo "Destination binary is symlinked..." 60 | dirname="$(dirname "${binary}")" 61 | binary="${dirname}/$(readlink "${binary}")" 62 | fi 63 | 64 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 65 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 66 | strip_invalid_archs "$binary" 67 | fi 68 | 69 | # Resign the code if required by the build settings to avoid unstable apps 70 | code_sign_if_enabled "${destination}/$(basename "$1")" 71 | 72 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 73 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 74 | local swift_runtime_libs 75 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u) 76 | for lib in $swift_runtime_libs; do 77 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 78 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 79 | code_sign_if_enabled "${destination}/${lib}" 80 | done 81 | fi 82 | } 83 | 84 | # Copies and strips a vendored dSYM 85 | install_dsym() { 86 | local source="$1" 87 | warn_missing_arch=${2:-true} 88 | if [ -r "$source" ]; then 89 | # Copy the dSYM into the targets temp dir. 90 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\"" 91 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}" 92 | 93 | local basename 94 | basename="$(basename -s .dSYM "$source")" 95 | binary_name="$(ls "$source/Contents/Resources/DWARF")" 96 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}" 97 | 98 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 99 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then 100 | strip_invalid_archs "$binary" "$warn_missing_arch" 101 | fi 102 | 103 | if [[ $STRIP_BINARY_RETVAL == 1 ]]; then 104 | # Move the stripped file into its final destination. 105 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\"" 106 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}" 107 | else 108 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing. 109 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM" 110 | fi 111 | fi 112 | } 113 | 114 | # Copies the bcsymbolmap files of a vendored framework 115 | install_bcsymbolmap() { 116 | local bcsymbolmap_path="$1" 117 | local destination="${BUILT_PRODUCTS_DIR}" 118 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"" 119 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}" 120 | } 121 | 122 | # Signs a framework with the provided identity 123 | code_sign_if_enabled() { 124 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 125 | # Use the current code_sign_identity 126 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 127 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'" 128 | 129 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 130 | code_sign_cmd="$code_sign_cmd &" 131 | fi 132 | echo "$code_sign_cmd" 133 | eval "$code_sign_cmd" 134 | fi 135 | } 136 | 137 | # Strip invalid architectures 138 | strip_invalid_archs() { 139 | binary="$1" 140 | warn_missing_arch=${2:-true} 141 | # Get architectures for current target binary 142 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)" 143 | # Intersect them with the architectures we are building for 144 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)" 145 | # If there are no archs supported by this binary then warn the user 146 | if [[ -z "$intersected_archs" ]]; then 147 | if [[ "$warn_missing_arch" == "true" ]]; then 148 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)." 149 | fi 150 | STRIP_BINARY_RETVAL=0 151 | return 152 | fi 153 | stripped="" 154 | for arch in $binary_archs; do 155 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 156 | # Strip non-valid architectures in-place 157 | lipo -remove "$arch" -output "$binary" "$binary" 158 | stripped="$stripped $arch" 159 | fi 160 | done 161 | if [[ "$stripped" ]]; then 162 | echo "Stripped $binary of architectures:$stripped" 163 | fi 164 | STRIP_BINARY_RETVAL=1 165 | } 166 | 167 | install_artifact() { 168 | artifact="$1" 169 | base="$(basename "$artifact")" 170 | case $base in 171 | *.framework) 172 | install_framework "$artifact" 173 | ;; 174 | *.dSYM) 175 | # Suppress arch warnings since XCFrameworks will include many dSYM files 176 | install_dsym "$artifact" "false" 177 | ;; 178 | *.bcsymbolmap) 179 | install_bcsymbolmap "$artifact" 180 | ;; 181 | *) 182 | echo "error: Unrecognized artifact "$artifact"" 183 | ;; 184 | esac 185 | } 186 | 187 | copy_artifacts() { 188 | file_list="$1" 189 | while read artifact; do 190 | install_artifact "$artifact" 191 | done <$file_list 192 | } 193 | 194 | ARTIFACT_LIST_FILE="${BUILT_PRODUCTS_DIR}/cocoapods-artifacts-${CONFIGURATION}.txt" 195 | if [ -r "${ARTIFACT_LIST_FILE}" ]; then 196 | copy_artifacts "${ARTIFACT_LIST_FILE}" 197 | fi 198 | 199 | if [[ "$CONFIGURATION" == "Debug" ]]; then 200 | install_framework "${BUILT_PRODUCTS_DIR}/TZImagePickerController/TZImagePickerController.framework" 201 | fi 202 | if [[ "$CONFIGURATION" == "Release" ]]; then 203 | install_framework "${BUILT_PRODUCTS_DIR}/TZImagePickerController/TZImagePickerController.framework" 204 | fi 205 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 206 | wait 207 | fi 208 | -------------------------------------------------------------------------------- /ACMediaFrame/Core/ACMediaTool.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACMediaTool.m 3 | // 4 | // Created by caoyq on 2021/4/21. 5 | // Copyright © 2021 ArthurCao. All rights reserved. 6 | // 7 | 8 | #import "ACMediaTool.h" 9 | 10 | @implementation ACMediaTool 11 | 12 | + (UIViewController *)topNavigationController { 13 | UIViewController *topVc = [UIApplication sharedApplication].keyWindow.rootViewController; 14 | if ([topVc isKindOfClass:[UITabBarController class]]) { 15 | topVc = ((UITabBarController *)topVc).selectedViewController; 16 | } 17 | NSArray *vcs = nil; 18 | if ([topVc isKindOfClass:[UINavigationController class]]) { 19 | vcs = ((UINavigationController *)topVc).viewControllers; 20 | }else { 21 | vcs = topVc.navigationController.viewControllers; 22 | } 23 | return vcs ? vcs.lastObject : nil; 24 | } 25 | 26 | // dict -> model 27 | + (ACMediaModel *)mediaInfoWithDict: (NSDictionary *)dict { 28 | ACMediaModel *model = [[ACMediaModel alloc] init]; 29 | 30 | NSString *mediaType = [dict objectForKey:UIImagePickerControllerMediaType]; //UIImagePickerControllerPHAsset 31 | NSURL *referenceURL = [dict objectForKey:UIImagePickerControllerReferenceURL]; 32 | PHAsset *asset; 33 | //录像与拍照没有引用地址 所以 referenceURL 为nil 34 | if (referenceURL) { 35 | PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[referenceURL] options:nil]; 36 | asset = [result firstObject]; 37 | } 38 | model.asset = asset; 39 | model.mediaType = [self getAssetType:asset]; 40 | 41 | if ([mediaType isEqualToString:@"public.movie"]) { 42 | NSURL *videoURL = [dict objectForKey:UIImagePickerControllerMediaURL]; 43 | model.name = [self videoNameWithAsset:asset]; 44 | model.data = [NSData dataWithContentsOfURL:videoURL]; 45 | model.videoURL = videoURL; 46 | model.image = [self coverImageWithVideoURL:videoURL]; 47 | }else if ([mediaType isEqualToString:@"public.image"]) { 48 | UIImage * image = [dict objectForKey:UIImagePickerControllerEditedImage]; 49 | //如果 picker 没有设置可编辑,那么image 为 nil 50 | if (image == nil) { 51 | image = [dict objectForKey:UIImagePickerControllerOriginalImage]; 52 | } 53 | model.name = [self imageNameWithAsset:asset]; 54 | model.image = [self fixOrientation:image]; 55 | model.data = [self imageDataWithImage:model.image]; 56 | } 57 | 58 | return model; 59 | } 60 | 61 | // asset -> model 62 | + (ACMediaModel *)imageInfoWithAsset: (PHAsset *)asset image: (UIImage *)image { 63 | ACMediaModel *model = [[ACMediaModel alloc] init]; 64 | model.asset = asset; 65 | model.mediaType = [self getAssetType:asset]; 66 | model.data = [self imageDataWithImage:image]; 67 | model.name = [self imageNameWithAsset:asset]; 68 | model.image = image; 69 | return model; 70 | } 71 | 72 | + (void)videoInfoWithAsset: (PHAsset *)asset coverImage: (UIImage *)coverImage completion: (void(^)(ACMediaModel *model))completion { 73 | ACMediaModel *model = [[ACMediaModel alloc] init]; 74 | model.asset = asset; 75 | model.name = [self videoNameWithAsset:asset]; 76 | model.image = coverImage; 77 | model.mediaType = ACMediaModelTypeVideo; 78 | 79 | [self videoDataWithAsset:asset completion:^(NSData * _Nonnull data, NSURL * _Nonnull videoURL) { 80 | model.data = data; 81 | model.videoURL = videoURL; 82 | if (completion) completion(model); 83 | }]; 84 | } 85 | 86 | + (ACMediaModelType)getAssetType:(PHAsset *)asset { 87 | ACMediaModelType type = ACMediaModelTypePhoto; 88 | PHAsset *phAsset = (PHAsset *)asset; 89 | if (phAsset.mediaType == PHAssetMediaTypeVideo) type = ACMediaModelTypeVideo; 90 | else if (phAsset.mediaType == PHAssetMediaTypeAudio) type = ACMediaModelTypeAudio; 91 | else if (phAsset.mediaType == PHAssetMediaTypeImage) { 92 | if (@available(iOS 9.1, *)) { 93 | // if (asset.mediaSubtypes == PHAssetMediaSubtypePhotoLive) type = TZAssetModelMediaTypeLivePhoto; 94 | } 95 | // Gif 96 | if ([[phAsset valueForKey:@"filename"] hasSuffix:@"GIF"]) { 97 | type = ACMediaModelTypePhotoGif; 98 | } 99 | } 100 | return type; 101 | } 102 | 103 | #pragma mark - data 104 | 105 | + (NSData *)imageDataWithImage: (UIImage *)image { 106 | NSData *imageData = nil; 107 | if (UIImagePNGRepresentation(image) == nil) 108 | { 109 | imageData = UIImageJPEGRepresentation(image, 1); 110 | } else 111 | { 112 | imageData = UIImagePNGRepresentation(image); 113 | } 114 | return imageData; 115 | } 116 | 117 | + (void)videoDataWithAsset: (PHAsset *)asset completion: (void(^)(NSData *data, NSURL *videoURL))completion { 118 | PHVideoRequestOptions *option = [[PHVideoRequestOptions alloc] init]; 119 | option.networkAccessAllowed = YES; 120 | [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:option resultHandler:^(AVPlayerItem *playerItem, NSDictionary *info) { 121 | NSString *key = info[@"PHImageFileSandboxExtensionTokenKey"]; 122 | NSString *path = [key componentsSeparatedByString:@";"].lastObject; 123 | NSURL *url = [NSURL fileURLWithPath:path]; 124 | NSData *data = [NSData dataWithContentsOfURL:url]; 125 | if (completion) completion(data,url); 126 | }]; 127 | } 128 | 129 | #pragma mark - name 130 | 131 | + (NSString *)imageNameWithAsset: (PHAsset *)asset { 132 | return [self mediaNameWithAsset:asset suffixName:@"IMG.PNG"]; 133 | } 134 | 135 | + (NSString *)videoNameWithAsset: (PHAsset *)asset { 136 | return [self mediaNameWithAsset:asset suffixName:@"Video.MOV"]; 137 | } 138 | 139 | + (NSString *)mediaNameWithAsset: (PHAsset *)asset suffixName: (NSString *)suffixName { 140 | //default user current time as name. 141 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 142 | [formatter setDateFormat:@"yyyyMMddHHmmss"]; 143 | NSString *normalName = [formatter stringFromDate:[NSDate date]]; 144 | normalName = [normalName stringByAppendingString:suffixName]; 145 | 146 | if (asset) { 147 | PHAssetResource *resource = [[PHAssetResource assetResourcesForAsset:asset] firstObject]; 148 | //获取本地原图的名称 149 | if (resource.originalFilename) { 150 | normalName = resource.originalFilename; 151 | } 152 | } 153 | return normalName; 154 | } 155 | 156 | #pragma mark - image 157 | 158 | + (UIImage *)coverImageWithVideoURL: (NSURL *)videoURL { 159 | AVURLAsset *urlAsset = [AVURLAsset assetWithURL:videoURL]; 160 | AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:urlAsset]; 161 | imageGenerator.appliesPreferredTrackTransform = YES; 162 | 163 | //视频总时长 164 | Float64 duration = CMTimeGetSeconds([urlAsset duration]); 165 | //取某个帧的时间,参数一表示哪个时间(秒),参数二表示每秒多少帧 166 | CMTime midPoint = CMTimeMake(duration * 0.5, 600); 167 | 168 | NSError *error = nil; 169 | //缩略图实际生成的时间 170 | CMTime actucalTime; 171 | 172 | //中间帧图片 173 | CGImageRef centerFrameImage = [imageGenerator copyCGImageAtTime:midPoint actualTime:&actucalTime error:&error]; 174 | 175 | UIImage *image = nil; 176 | if (centerFrameImage) { 177 | image = [UIImage imageWithCGImage:centerFrameImage]; 178 | CGImageRelease(centerFrameImage); 179 | } 180 | return image; 181 | } 182 | 183 | + (UIImage *)fixOrientation:(UIImage *)aImage { 184 | if (aImage.imageOrientation == UIImageOrientationUp) 185 | return aImage; 186 | 187 | // We need to calculate the proper transformation to make the image upright. 188 | // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. 189 | CGAffineTransform transform = CGAffineTransformIdentity; 190 | 191 | switch (aImage.imageOrientation) { 192 | case UIImageOrientationDown: 193 | case UIImageOrientationDownMirrored: 194 | transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height); 195 | transform = CGAffineTransformRotate(transform, M_PI); 196 | break; 197 | 198 | case UIImageOrientationLeft: 199 | case UIImageOrientationLeftMirrored: 200 | transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); 201 | transform = CGAffineTransformRotate(transform, M_PI_2); 202 | break; 203 | 204 | case UIImageOrientationRight: 205 | case UIImageOrientationRightMirrored: 206 | transform = CGAffineTransformTranslate(transform, 0, aImage.size.height); 207 | transform = CGAffineTransformRotate(transform, -M_PI_2); 208 | break; 209 | default: 210 | break; 211 | } 212 | 213 | switch (aImage.imageOrientation) { 214 | case UIImageOrientationUpMirrored: 215 | case UIImageOrientationDownMirrored: 216 | transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); 217 | transform = CGAffineTransformScale(transform, -1, 1); 218 | break; 219 | 220 | case UIImageOrientationLeftMirrored: 221 | case UIImageOrientationRightMirrored: 222 | transform = CGAffineTransformTranslate(transform, aImage.size.height, 0); 223 | transform = CGAffineTransformScale(transform, -1, 1); 224 | break; 225 | default: 226 | break; 227 | } 228 | 229 | // Now we draw the underlying CGImage into a new context, applying the transform 230 | // calculated above. 231 | CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, 232 | CGImageGetBitsPerComponent(aImage.CGImage), 0, 233 | CGImageGetColorSpace(aImage.CGImage), 234 | CGImageGetBitmapInfo(aImage.CGImage)); 235 | CGContextConcatCTM(ctx, transform); 236 | switch (aImage.imageOrientation) { 237 | case UIImageOrientationLeft: 238 | case UIImageOrientationLeftMirrored: 239 | case UIImageOrientationRight: 240 | case UIImageOrientationRightMirrored: 241 | // Grr... 242 | CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage); 243 | break; 244 | 245 | default: 246 | CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage); 247 | break; 248 | } 249 | 250 | // And now we just create a new UIImage from the drawing context 251 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 252 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 253 | CGContextRelease(ctx); 254 | CGImageRelease(cgimg); 255 | return img; 256 | } 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZVideoPlayerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZVideoPlayerController.m 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 16/1/5. 6 | // Copyright © 2016年 谭真. All rights reserved. 7 | // 8 | 9 | #import "TZVideoPlayerController.h" 10 | #import 11 | #import "UIView+TZLayout.h" 12 | #import "TZImageManager.h" 13 | #import "TZAssetModel.h" 14 | #import "TZImagePickerController.h" 15 | #import "TZPhotoPreviewController.h" 16 | 17 | @interface TZVideoPlayerController () { 18 | AVPlayer *_player; 19 | AVPlayerLayer *_playerLayer; 20 | UIButton *_playButton; 21 | UIImage *_cover; 22 | 23 | UIView *_toolBar; 24 | UIButton *_doneButton; 25 | UIProgressView *_progress; 26 | 27 | UIStatusBarStyle _originStatusBarStyle; 28 | } 29 | @property (assign, nonatomic) BOOL needShowStatusBar; 30 | 31 | // iCloud无法同步提示UI 32 | @property (nonatomic, strong) UIView *iCloudErrorView; 33 | 34 | @end 35 | 36 | #pragma clang diagnostic push 37 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 38 | 39 | @implementation TZVideoPlayerController 40 | 41 | - (void)viewDidLoad { 42 | [super viewDidLoad]; 43 | self.needShowStatusBar = ![UIApplication sharedApplication].statusBarHidden; 44 | self.view.backgroundColor = [UIColor blackColor]; 45 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 46 | if (tzImagePickerVc) { 47 | self.navigationItem.title = tzImagePickerVc.previewBtnTitleStr; 48 | } 49 | [self configMoviePlayer]; 50 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:UIApplicationWillResignActiveNotification object:nil]; 51 | } 52 | 53 | - (void)viewWillAppear:(BOOL)animated { 54 | [super viewWillAppear:animated]; 55 | _originStatusBarStyle = [UIApplication sharedApplication].statusBarStyle; 56 | [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; 57 | } 58 | 59 | - (void)viewWillDisappear:(BOOL)animated { 60 | [super viewWillDisappear:animated]; 61 | if (self.needShowStatusBar) { 62 | [UIApplication sharedApplication].statusBarHidden = NO; 63 | } 64 | [UIApplication sharedApplication].statusBarStyle = _originStatusBarStyle; 65 | } 66 | 67 | - (void)configMoviePlayer { 68 | [[TZImageManager manager] getPhotoWithAsset:_model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { 69 | BOOL iCloudSyncFailed = !photo && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]]; 70 | self.iCloudErrorView.hidden = !iCloudSyncFailed; 71 | if (!isDegraded && photo) { 72 | self->_cover = photo; 73 | self->_doneButton.enabled = YES; 74 | } 75 | }]; 76 | [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) { 77 | dispatch_async(dispatch_get_main_queue(), ^{ 78 | self->_player = [AVPlayer playerWithPlayerItem:playerItem]; 79 | self->_playerLayer = [AVPlayerLayer playerLayerWithPlayer:self->_player]; 80 | self->_playerLayer.frame = self.view.bounds; 81 | [self.view.layer addSublayer:self->_playerLayer]; 82 | [self addProgressObserver]; 83 | [self configPlayButton]; 84 | [self configBottomToolBar]; 85 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(pausePlayerAndShowNaviBar) name:AVPlayerItemDidPlayToEndTimeNotification object:self->_player.currentItem]; 86 | }); 87 | }]; 88 | } 89 | 90 | /// Show progress,do it next time / 给播放器添加进度更新,下次加上 91 | - (void)addProgressObserver{ 92 | AVPlayerItem *playerItem = _player.currentItem; 93 | UIProgressView *progress = _progress; 94 | [_player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) { 95 | float current = CMTimeGetSeconds(time); 96 | float total = CMTimeGetSeconds([playerItem duration]); 97 | if (current) { 98 | [progress setProgress:(current/total) animated:YES]; 99 | } 100 | }]; 101 | } 102 | 103 | - (void)configPlayButton { 104 | _playButton = [UIButton buttonWithType:UIButtonTypeCustom]; 105 | [_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal]; 106 | [_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlayHL"] forState:UIControlStateHighlighted]; 107 | [_playButton addTarget:self action:@selector(playButtonClick) forControlEvents:UIControlEventTouchUpInside]; 108 | [self.view addSubview:_playButton]; 109 | } 110 | 111 | - (void)configBottomToolBar { 112 | _toolBar = [[UIView alloc] initWithFrame:CGRectZero]; 113 | CGFloat rgb = 34 / 255.0; 114 | _toolBar.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.7]; 115 | 116 | _doneButton = [UIButton buttonWithType:UIButtonTypeCustom]; 117 | _doneButton.titleLabel.font = [UIFont systemFontOfSize:16]; 118 | if (!_cover) { 119 | _doneButton.enabled = NO; 120 | } 121 | [_doneButton addTarget:self action:@selector(doneButtonClick) forControlEvents:UIControlEventTouchUpInside]; 122 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 123 | if (tzImagePickerVc) { 124 | [_doneButton setTitle:tzImagePickerVc.doneBtnTitleStr forState:UIControlStateNormal]; 125 | [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorNormal forState:UIControlStateNormal]; 126 | } else { 127 | [_doneButton setTitle:[NSBundle tz_localizedStringForKey:@"Done"] forState:UIControlStateNormal]; 128 | [_doneButton setTitleColor:[UIColor colorWithRed:(83/255.0) green:(179/255.0) blue:(17/255.0) alpha:1.0] forState:UIControlStateNormal]; 129 | } 130 | [_doneButton setTitleColor:tzImagePickerVc.oKButtonTitleColorDisabled forState:UIControlStateDisabled]; 131 | [_toolBar addSubview:_doneButton]; 132 | [self.view addSubview:_toolBar]; 133 | 134 | if (tzImagePickerVc.videoPreviewPageUIConfigBlock) { 135 | tzImagePickerVc.videoPreviewPageUIConfigBlock(_playButton, _toolBar, _doneButton); 136 | } 137 | } 138 | 139 | - (UIStatusBarStyle)preferredStatusBarStyle { 140 | TZImagePickerController *tzImagePicker = (TZImagePickerController *)self.navigationController; 141 | if (tzImagePicker && [tzImagePicker isKindOfClass:[TZImagePickerController class]]) { 142 | return tzImagePicker.statusBarStyle; 143 | } 144 | return [super preferredStatusBarStyle]; 145 | } 146 | 147 | #pragma mark - Layout 148 | 149 | - (void)viewDidLayoutSubviews { 150 | [super viewDidLayoutSubviews]; 151 | 152 | BOOL isFullScreen = self.view.tz_height == [UIScreen mainScreen].bounds.size.height; 153 | CGFloat statusBarHeight = isFullScreen ? [TZCommonTools tz_statusBarHeight] : 0; 154 | CGFloat statusBarAndNaviBarHeight = statusBarHeight + self.navigationController.navigationBar.tz_height; 155 | _playerLayer.frame = self.view.bounds; 156 | CGFloat toolBarHeight = 44 + [TZCommonTools tz_safeAreaInsets].bottom; 157 | _toolBar.frame = CGRectMake(0, self.view.tz_height - toolBarHeight, self.view.tz_width, toolBarHeight); 158 | _doneButton.frame = CGRectMake(self.view.tz_width - 44 - 12, 0, 44, 44); 159 | _playButton.frame = CGRectMake(0, statusBarAndNaviBarHeight, self.view.tz_width, self.view.tz_height - statusBarAndNaviBarHeight - toolBarHeight); 160 | 161 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)self.navigationController; 162 | if (tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock) { 163 | tzImagePickerVc.videoPreviewPageDidLayoutSubviewsBlock(_playButton, _toolBar, _doneButton); 164 | } 165 | } 166 | 167 | #pragma mark - Click Event 168 | 169 | - (void)playButtonClick { 170 | CMTime currentTime = _player.currentItem.currentTime; 171 | CMTime durationTime = _player.currentItem.duration; 172 | if (_player.rate == 0.0f) { 173 | [[NSNotificationCenter defaultCenter] postNotificationName:@"TZ_VIDEO_PLAY_NOTIFICATION" object:_player]; 174 | if (currentTime.value == durationTime.value) [_player.currentItem seekToTime:CMTimeMake(0, 1)]; 175 | [_player play]; 176 | [self.navigationController setNavigationBarHidden:YES]; 177 | _toolBar.hidden = YES; 178 | [_playButton setImage:nil forState:UIControlStateNormal]; 179 | [UIApplication sharedApplication].statusBarHidden = YES; 180 | } else { 181 | [self pausePlayerAndShowNaviBar]; 182 | } 183 | } 184 | 185 | - (void)doneButtonClick { 186 | if ([[TZImageManager manager] isAssetCannotBeSelected:_model.asset]) { 187 | return; 188 | } 189 | if (self.navigationController) { 190 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; 191 | if (imagePickerVc.autoDismiss) { 192 | [self.navigationController dismissViewControllerAnimated:YES completion:^{ 193 | [self callDelegateMethod]; 194 | }]; 195 | } else { 196 | [self callDelegateMethod]; 197 | } 198 | } else { 199 | [self dismissViewControllerAnimated:YES completion:^{ 200 | [self callDelegateMethod]; 201 | }]; 202 | } 203 | } 204 | 205 | - (void)callDelegateMethod { 206 | TZImagePickerController *imagePickerVc = (TZImagePickerController *)self.navigationController; 207 | if ([imagePickerVc.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingVideo:sourceAssets:)]) { 208 | [imagePickerVc.pickerDelegate imagePickerController:imagePickerVc didFinishPickingVideo:_cover sourceAssets:_model.asset]; 209 | } 210 | if (imagePickerVc.didFinishPickingVideoHandle) { 211 | imagePickerVc.didFinishPickingVideoHandle(_cover,_model.asset); 212 | } 213 | } 214 | 215 | #pragma mark - Notification Method 216 | 217 | - (void)pausePlayerAndShowNaviBar { 218 | [_player pause]; 219 | _toolBar.hidden = NO; 220 | [self.navigationController setNavigationBarHidden:NO]; 221 | [_playButton setImage:[UIImage tz_imageNamedFromMyBundle:@"MMVideoPreviewPlay"] forState:UIControlStateNormal]; 222 | 223 | if (self.needShowStatusBar) { 224 | [UIApplication sharedApplication].statusBarHidden = NO; 225 | } 226 | } 227 | 228 | #pragma mark - lazy 229 | - (UIView *)iCloudErrorView{ 230 | if (!_iCloudErrorView) { 231 | _iCloudErrorView = [[UIView alloc] initWithFrame:CGRectMake(0, [TZCommonTools tz_statusBarHeight] + 44 + 10, self.view.tz_width, 28)]; 232 | UIImageView *icloud = [[UIImageView alloc] init]; 233 | icloud.image = [UIImage tz_imageNamedFromMyBundle:@"iCloudError"]; 234 | icloud.frame = CGRectMake(20, 0, 28, 28); 235 | [_iCloudErrorView addSubview:icloud]; 236 | UILabel *label = [[UILabel alloc] init]; 237 | label.frame = CGRectMake(53, 0, self.view.tz_width - 63, 28); 238 | label.font = [UIFont systemFontOfSize:10]; 239 | label.textColor = [UIColor whiteColor]; 240 | label.text = [NSBundle tz_localizedStringForKey:@"iCloud sync failed"]; 241 | [_iCloudErrorView addSubview:label]; 242 | [self.view addSubview:_iCloudErrorView]; 243 | _iCloudErrorView.hidden = YES; 244 | } 245 | return _iCloudErrorView; 246 | } 247 | 248 | - (void)dealloc { 249 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 250 | } 251 | 252 | #pragma clang diagnostic pop 253 | 254 | @end 255 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZAssetCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // TZAssetCell.m 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // 8 | 9 | #import "TZAssetCell.h" 10 | #import "TZAssetModel.h" 11 | #import "UIView+TZLayout.h" 12 | #import "TZImageManager.h" 13 | #import "TZImagePickerController.h" 14 | #import "TZProgressView.h" 15 | 16 | @interface TZAssetCell () 17 | @property (weak, nonatomic) UIImageView *imageView; // The photo / 照片 18 | @property (weak, nonatomic) UIImageView *selectImageView; 19 | @property (weak, nonatomic) UILabel *indexLabel; 20 | @property (weak, nonatomic) UIView *bottomView; 21 | @property (weak, nonatomic) UILabel *timeLength; 22 | @property (strong, nonatomic) UITapGestureRecognizer *tapGesture; 23 | 24 | @property (nonatomic, weak) UIImageView *videoImgView; 25 | @property (nonatomic, strong) TZProgressView *progressView; 26 | @property (nonatomic, assign) int32_t bigImageRequestID; 27 | @end 28 | 29 | @implementation TZAssetCell 30 | 31 | - (instancetype)initWithFrame:(CGRect)frame { 32 | self = [super initWithFrame:frame]; 33 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reload:) name:@"TZ_PHOTO_PICKER_RELOAD_NOTIFICATION" object:nil]; 34 | return self; 35 | } 36 | 37 | - (void)setModel:(TZAssetModel *)model { 38 | _model = model; 39 | self.representedAssetIdentifier = model.asset.localIdentifier; 40 | int32_t imageRequestID = [[TZImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.tz_width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { 41 | // Set the cell's thumbnail image if it's still showing the same asset. 42 | if ([self.representedAssetIdentifier isEqualToString:model.asset.localIdentifier]) { 43 | self.imageView.image = photo; 44 | [self setNeedsLayout]; 45 | } else { 46 | // NSLog(@"this cell is showing other asset"); 47 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; 48 | } 49 | if (!isDegraded) { 50 | [self hideProgressView]; 51 | self.imageRequestID = 0; 52 | } 53 | } progressHandler:nil networkAccessAllowed:NO]; 54 | if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) { 55 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; 56 | // NSLog(@"cancelImageRequest %d",self.imageRequestID); 57 | } 58 | self.imageRequestID = imageRequestID; 59 | self.selectPhotoButton.selected = model.isSelected; 60 | self.selectImageView.image = self.selectPhotoButton.isSelected ? self.photoSelImage : self.photoDefImage; 61 | self.indexLabel.hidden = !self.selectPhotoButton.isSelected; 62 | 63 | self.type = (NSInteger)model.type; 64 | // 让宽度/高度小于 最小可选照片尺寸 的图片不能选中 65 | if (![[TZImageManager manager] isPhotoSelectableWithAsset:model.asset]) { 66 | if (_selectImageView.hidden == NO) { 67 | self.selectPhotoButton.hidden = YES; 68 | _selectImageView.hidden = YES; 69 | } 70 | } 71 | // 如果用户选中了该图片,提前获取一下大图 72 | if (model.isSelected) { 73 | [self requestBigImage]; 74 | } else { 75 | [self cancelBigImageRequest]; 76 | } 77 | [self setNeedsLayout]; 78 | 79 | if (self.assetCellDidSetModelBlock) { 80 | self.assetCellDidSetModelBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView); 81 | } 82 | } 83 | 84 | - (void)setIndex:(NSInteger)index { 85 | _index = index; 86 | self.indexLabel.text = [NSString stringWithFormat:@"%zd", index]; 87 | [self.contentView bringSubviewToFront:self.indexLabel]; 88 | } 89 | 90 | - (void)setShowSelectBtn:(BOOL)showSelectBtn { 91 | _showSelectBtn = showSelectBtn; 92 | BOOL selectable = [[TZImageManager manager] isPhotoSelectableWithAsset:self.model.asset]; 93 | if (!self.selectPhotoButton.hidden) { 94 | self.selectPhotoButton.hidden = !showSelectBtn || !selectable; 95 | } 96 | if (!self.selectImageView.hidden) { 97 | self.selectImageView.hidden = !showSelectBtn || !selectable; 98 | } 99 | } 100 | 101 | - (void)setType:(TZAssetCellType)type { 102 | _type = type; 103 | if (type == TZAssetCellTypePhoto || type == TZAssetCellTypeLivePhoto || (type == TZAssetCellTypePhotoGif && !self.allowPickingGif) || self.allowPickingMultipleVideo) { 104 | _selectImageView.hidden = NO; 105 | _selectPhotoButton.hidden = NO; 106 | _bottomView.hidden = YES; 107 | } else { // Video of Gif 108 | _selectImageView.hidden = YES; 109 | _selectPhotoButton.hidden = YES; 110 | } 111 | 112 | if (type == TZAssetCellTypeVideo) { 113 | self.bottomView.hidden = NO; 114 | self.timeLength.text = _model.timeLength; 115 | self.videoImgView.hidden = NO; 116 | _timeLength.tz_left = self.videoImgView.tz_right; 117 | _timeLength.textAlignment = NSTextAlignmentRight; 118 | } else if (type == TZAssetCellTypePhotoGif && self.allowPickingGif) { 119 | self.bottomView.hidden = NO; 120 | self.timeLength.text = @"GIF"; 121 | self.videoImgView.hidden = YES; 122 | _timeLength.tz_left = 5; 123 | _timeLength.textAlignment = NSTextAlignmentLeft; 124 | } 125 | } 126 | 127 | - (void)setAllowPreview:(BOOL)allowPreview { 128 | _allowPreview = allowPreview; 129 | if (allowPreview) { 130 | _imageView.userInteractionEnabled = NO; 131 | _tapGesture.enabled = NO; 132 | } else { 133 | _imageView.userInteractionEnabled = YES; 134 | _tapGesture.enabled = YES; 135 | } 136 | } 137 | 138 | - (void)selectPhotoButtonClick:(UIButton *)sender { 139 | if (self.didSelectPhotoBlock) { 140 | self.didSelectPhotoBlock(sender.isSelected); 141 | } 142 | self.selectImageView.image = sender.isSelected ? self.photoSelImage : self.photoDefImage; 143 | if (sender.isSelected) { 144 | [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:TZOscillatoryAnimationToBigger]; 145 | // 用户选中了该图片,提前获取一下大图 146 | [self requestBigImage]; 147 | } else { // 取消选中,取消大图的获取 148 | [self cancelBigImageRequest]; 149 | } 150 | } 151 | 152 | /// 只在单选状态且allowPreview为NO时会有该事件 153 | - (void)didTapImageView { 154 | if (self.didSelectPhotoBlock) { 155 | self.didSelectPhotoBlock(NO); 156 | } 157 | } 158 | 159 | - (void)hideProgressView { 160 | if (_progressView) { 161 | self.progressView.hidden = YES; 162 | self.imageView.alpha = 1.0; 163 | } 164 | } 165 | 166 | - (void)requestBigImage { 167 | if (_bigImageRequestID) { 168 | [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID]; 169 | } 170 | 171 | _bigImageRequestID = [[TZImageManager manager] requestImageDataForAsset:_model.asset completion:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { 172 | BOOL iCloudSyncFailed = !imageData && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]]; 173 | self.model.iCloudFailed = iCloudSyncFailed; 174 | if (iCloudSyncFailed && self.didSelectPhotoBlock) { 175 | self.didSelectPhotoBlock(YES); 176 | self.selectImageView.image = self.photoDefImage; 177 | } 178 | [self hideProgressView]; 179 | } progressHandler:^(double progress, NSError *error, BOOL *stop, NSDictionary *info) { 180 | if (self.model.isSelected) { 181 | progress = progress > 0.02 ? progress : 0.02;; 182 | self.progressView.progress = progress; 183 | self.progressView.hidden = NO; 184 | self.imageView.alpha = 0.4; 185 | if (progress >= 1) { 186 | [self hideProgressView]; 187 | } 188 | } else { 189 | // 快速连续点几次,会EXC_BAD_ACCESS... 190 | // *stop = YES; 191 | [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 192 | [self cancelBigImageRequest]; 193 | } 194 | }]; 195 | if (_model.type == TZAssetCellTypeVideo) { 196 | [[TZImageManager manager] getVideoWithAsset:_model.asset completion:^(AVPlayerItem *playerItem, NSDictionary *info) { 197 | BOOL iCloudSyncFailed = !playerItem && [TZCommonTools isICloudSyncError:info[PHImageErrorKey]]; 198 | self.model.iCloudFailed = iCloudSyncFailed; 199 | if (iCloudSyncFailed && self.didSelectPhotoBlock) { 200 | dispatch_async(dispatch_get_main_queue(), ^{ 201 | self.didSelectPhotoBlock(YES); 202 | self.selectImageView.image = self.photoDefImage; 203 | }); 204 | } 205 | }]; 206 | } 207 | } 208 | 209 | - (void)cancelBigImageRequest { 210 | if (_bigImageRequestID) { 211 | [[PHImageManager defaultManager] cancelImageRequest:_bigImageRequestID]; 212 | } 213 | [self hideProgressView]; 214 | } 215 | 216 | #pragma mark - Notification 217 | 218 | - (void)reload:(NSNotification *)noti { 219 | TZImagePickerController *tzImagePickerVc = (TZImagePickerController *)noti.object; 220 | 221 | UIViewController *parentViewController = nil; 222 | UIResponder *responder = self.nextResponder; 223 | do { 224 | if ([responder isKindOfClass:[UIViewController class]]) { 225 | parentViewController = (UIViewController *)responder; 226 | break; 227 | } 228 | responder = responder.nextResponder; 229 | } while (responder); 230 | 231 | if (parentViewController.navigationController != tzImagePickerVc) { 232 | return; 233 | } 234 | 235 | if (self.model.isSelected && tzImagePickerVc.showSelectedIndex) { 236 | self.index = [tzImagePickerVc.selectedAssetIds indexOfObject:self.model.asset.localIdentifier] + 1; 237 | } 238 | self.indexLabel.hidden = !self.selectPhotoButton.isSelected; 239 | if (tzImagePickerVc.selectedModels.count >= tzImagePickerVc.maxImagesCount && tzImagePickerVc.showPhotoCannotSelectLayer && !self.model.isSelected) { 240 | self.cannotSelectLayerButton.backgroundColor = tzImagePickerVc.cannotSelectLayerColor; 241 | self.cannotSelectLayerButton.hidden = NO; 242 | } else { 243 | self.cannotSelectLayerButton.hidden = YES; 244 | } 245 | } 246 | 247 | #pragma mark - Lazy load 248 | 249 | - (UIButton *)selectPhotoButton { 250 | if (_selectPhotoButton == nil) { 251 | UIButton *selectPhotoButton = [[UIButton alloc] init]; 252 | [selectPhotoButton addTarget:self action:@selector(selectPhotoButtonClick:) forControlEvents:UIControlEventTouchUpInside]; 253 | [self.contentView addSubview:selectPhotoButton]; 254 | _selectPhotoButton = selectPhotoButton; 255 | } 256 | return _selectPhotoButton; 257 | } 258 | 259 | - (UIImageView *)imageView { 260 | if (_imageView == nil) { 261 | UIImageView *imageView = [[UIImageView alloc] init]; 262 | imageView.contentMode = UIViewContentModeScaleAspectFill; 263 | imageView.clipsToBounds = YES; 264 | [self.contentView addSubview:imageView]; 265 | _imageView = imageView; 266 | 267 | _tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapImageView)]; 268 | [_imageView addGestureRecognizer:_tapGesture]; 269 | self.allowPreview = self.allowPreview; 270 | } 271 | return _imageView; 272 | } 273 | 274 | - (UIImageView *)selectImageView { 275 | if (_selectImageView == nil) { 276 | UIImageView *selectImageView = [[UIImageView alloc] init]; 277 | selectImageView.contentMode = UIViewContentModeCenter; 278 | selectImageView.clipsToBounds = YES; 279 | [self.contentView addSubview:selectImageView]; 280 | _selectImageView = selectImageView; 281 | } 282 | return _selectImageView; 283 | } 284 | 285 | - (UIView *)bottomView { 286 | if (_bottomView == nil) { 287 | UIView *bottomView = [[UIView alloc] init]; 288 | static NSInteger rgb = 0; 289 | bottomView.userInteractionEnabled = NO; 290 | bottomView.backgroundColor = [UIColor colorWithRed:rgb green:rgb blue:rgb alpha:0.8]; 291 | [self.contentView addSubview:bottomView]; 292 | _bottomView = bottomView; 293 | } 294 | return _bottomView; 295 | } 296 | 297 | - (UIButton *)cannotSelectLayerButton { 298 | if (_cannotSelectLayerButton == nil) { 299 | UIButton *cannotSelectLayerButton = [[UIButton alloc] init]; 300 | [self.contentView addSubview:cannotSelectLayerButton]; 301 | _cannotSelectLayerButton = cannotSelectLayerButton; 302 | } 303 | return _cannotSelectLayerButton; 304 | } 305 | 306 | - (UIImageView *)videoImgView { 307 | if (_videoImgView == nil) { 308 | UIImageView *videoImgView = [[UIImageView alloc] init]; 309 | [videoImgView setImage:[UIImage tz_imageNamedFromMyBundle:@"VideoSendIcon"]]; 310 | [self.bottomView addSubview:videoImgView]; 311 | _videoImgView = videoImgView; 312 | } 313 | return _videoImgView; 314 | } 315 | 316 | - (UILabel *)timeLength { 317 | if (_timeLength == nil) { 318 | UILabel *timeLength = [[UILabel alloc] init]; 319 | timeLength.font = [UIFont boldSystemFontOfSize:11]; 320 | timeLength.textColor = [UIColor whiteColor]; 321 | timeLength.textAlignment = NSTextAlignmentRight; 322 | [self.bottomView addSubview:timeLength]; 323 | _timeLength = timeLength; 324 | } 325 | return _timeLength; 326 | } 327 | 328 | - (UILabel *)indexLabel { 329 | if (_indexLabel == nil) { 330 | UILabel *indexLabel = [[UILabel alloc] init]; 331 | indexLabel.font = [UIFont systemFontOfSize:14]; 332 | indexLabel.adjustsFontSizeToFitWidth = YES; 333 | indexLabel.textColor = [UIColor whiteColor]; 334 | indexLabel.textAlignment = NSTextAlignmentCenter; 335 | [self.contentView addSubview:indexLabel]; 336 | _indexLabel = indexLabel; 337 | } 338 | return _indexLabel; 339 | } 340 | 341 | - (TZProgressView *)progressView { 342 | if (_progressView == nil) { 343 | _progressView = [[TZProgressView alloc] init]; 344 | _progressView.hidden = YES; 345 | [self addSubview:_progressView]; 346 | } 347 | return _progressView; 348 | } 349 | 350 | - (void)layoutSubviews { 351 | [super layoutSubviews]; 352 | _cannotSelectLayerButton.frame = self.bounds; 353 | if (self.allowPreview) { 354 | _selectPhotoButton.frame = CGRectMake(self.tz_width - 44, 0, 44, 44); 355 | } else { 356 | _selectPhotoButton.frame = self.bounds; 357 | } 358 | _selectImageView.frame = CGRectMake(self.tz_width - 27, 3, 24, 24); 359 | if (_selectImageView.image.size.width <= 27) { 360 | _selectImageView.contentMode = UIViewContentModeCenter; 361 | } else { 362 | _selectImageView.contentMode = UIViewContentModeScaleAspectFit; 363 | } 364 | _indexLabel.frame = _selectImageView.frame; 365 | _imageView.frame = self.bounds; 366 | 367 | static CGFloat progressWH = 20; 368 | CGFloat progressXY = (self.tz_width - progressWH) / 2; 369 | _progressView.frame = CGRectMake(progressXY, progressXY, progressWH, progressWH); 370 | 371 | _bottomView.frame = CGRectMake(0, self.tz_height - 17, self.tz_width, 17); 372 | _videoImgView.frame = CGRectMake(8, 0, 17, 17); 373 | _timeLength.frame = CGRectMake(self.videoImgView.tz_right, 0, self.tz_width - self.videoImgView.tz_right - 5, 17); 374 | 375 | self.type = (NSInteger)self.model.type; 376 | self.showSelectBtn = self.showSelectBtn; 377 | 378 | [self.contentView bringSubviewToFront:_bottomView]; 379 | [self.contentView bringSubviewToFront:_cannotSelectLayerButton]; 380 | [self.contentView bringSubviewToFront:_selectPhotoButton]; 381 | [self.contentView bringSubviewToFront:_selectImageView]; 382 | [self.contentView bringSubviewToFront:_indexLabel]; 383 | 384 | if (self.assetCellDidLayoutSubviewsBlock) { 385 | self.assetCellDidLayoutSubviewsBlock(self, _imageView, _selectImageView, _indexLabel, _bottomView, _timeLength, _videoImgView); 386 | } 387 | } 388 | 389 | - (void)dealloc { 390 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 391 | } 392 | 393 | @end 394 | 395 | @interface TZAlbumCell () 396 | @property (weak, nonatomic) UIImageView *posterImageView; 397 | @property (weak, nonatomic) UILabel *titleLabel; 398 | @end 399 | 400 | @implementation TZAlbumCell 401 | 402 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 403 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 404 | self.backgroundColor = [UIColor whiteColor]; 405 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 406 | return self; 407 | } 408 | 409 | - (void)setModel:(TZAlbumModel *)model { 410 | _model = model; 411 | 412 | UIColor *nameColor = UIColor.blackColor; 413 | if (@available(iOS 13.0, *)) { 414 | nameColor = UIColor.labelColor; 415 | } 416 | NSMutableAttributedString *nameString = [[NSMutableAttributedString alloc] initWithString:model.name attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:nameColor}]; 417 | NSAttributedString *countString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:@" (%zd)",model.count] attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:16],NSForegroundColorAttributeName:[UIColor lightGrayColor]}]; 418 | [nameString appendAttributedString:countString]; 419 | self.titleLabel.attributedText = nameString; 420 | [[TZImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) { 421 | self.posterImageView.image = postImage; 422 | [self setNeedsLayout]; 423 | }]; 424 | if (model.selectedCount) { 425 | self.selectedCountButton.hidden = NO; 426 | [self.selectedCountButton setTitle:[NSString stringWithFormat:@"%zd",model.selectedCount] forState:UIControlStateNormal]; 427 | } else { 428 | self.selectedCountButton.hidden = YES; 429 | } 430 | 431 | if (self.albumCellDidSetModelBlock) { 432 | self.albumCellDidSetModelBlock(self, _posterImageView, _titleLabel); 433 | } 434 | } 435 | 436 | - (void)layoutSubviews { 437 | [super layoutSubviews]; 438 | _selectedCountButton.frame = CGRectMake(self.contentView.tz_width - 24, 23, 24, 24); 439 | NSInteger titleHeight = ceil(self.titleLabel.font.lineHeight); 440 | self.titleLabel.frame = CGRectMake(80, (self.tz_height - titleHeight) / 2, self.tz_width - 80 - 50, titleHeight); 441 | self.posterImageView.frame = CGRectMake(0, 0, 70, 70); 442 | 443 | if (self.albumCellDidLayoutSubviewsBlock) { 444 | self.albumCellDidLayoutSubviewsBlock(self, _posterImageView, _titleLabel); 445 | } 446 | } 447 | 448 | - (void)layoutSublayersOfLayer:(CALayer *)layer { 449 | [super layoutSublayersOfLayer:layer]; 450 | } 451 | 452 | #pragma mark - Lazy load 453 | 454 | - (UIImageView *)posterImageView { 455 | if (_posterImageView == nil) { 456 | UIImageView *posterImageView = [[UIImageView alloc] init]; 457 | posterImageView.contentMode = UIViewContentModeScaleAspectFill; 458 | posterImageView.clipsToBounds = YES; 459 | [self.contentView addSubview:posterImageView]; 460 | _posterImageView = posterImageView; 461 | } 462 | return _posterImageView; 463 | } 464 | 465 | - (UILabel *)titleLabel { 466 | if (_titleLabel == nil) { 467 | UILabel *titleLabel = [[UILabel alloc] init]; 468 | titleLabel.font = [UIFont boldSystemFontOfSize:17]; 469 | if (@available(iOS 13.0, *)) { 470 | titleLabel.textColor = UIColor.labelColor; 471 | } else { 472 | titleLabel.textColor = [UIColor blackColor]; 473 | } 474 | titleLabel.textAlignment = NSTextAlignmentLeft; 475 | [self.contentView addSubview:titleLabel]; 476 | _titleLabel = titleLabel; 477 | } 478 | return _titleLabel; 479 | } 480 | 481 | - (UIButton *)selectedCountButton { 482 | if (_selectedCountButton == nil) { 483 | UIButton *selectedCountButton = [[UIButton alloc] init]; 484 | selectedCountButton.titleLabel.adjustsFontSizeToFitWidth = YES; 485 | selectedCountButton.layer.cornerRadius = 12; 486 | selectedCountButton.clipsToBounds = YES; 487 | selectedCountButton.backgroundColor = [UIColor redColor]; 488 | [selectedCountButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 489 | selectedCountButton.titleLabel.font = [UIFont systemFontOfSize:15]; 490 | [self.contentView addSubview:selectedCountButton]; 491 | _selectedCountButton = selectedCountButton; 492 | } 493 | return _selectedCountButton; 494 | } 495 | 496 | @end 497 | 498 | 499 | 500 | @implementation TZAssetCameraCell 501 | 502 | - (instancetype)initWithFrame:(CGRect)frame { 503 | self = [super initWithFrame:frame]; 504 | if (self) { 505 | self.backgroundColor = [UIColor whiteColor]; 506 | _imageView = [[UIImageView alloc] init]; 507 | _imageView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; 508 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 509 | [self.contentView addSubview:_imageView]; 510 | self.clipsToBounds = YES; 511 | } 512 | return self; 513 | } 514 | 515 | - (void)layoutSubviews { 516 | [super layoutSubviews]; 517 | _imageView.frame = self.bounds; 518 | } 519 | 520 | @end 521 | -------------------------------------------------------------------------------- /Pods/TZImagePickerController/TZImagePickerController/TZImagePickerController/TZImagePickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TZImagePickerController.h 3 | // TZImagePickerController 4 | // 5 | // Created by 谭真 on 15/12/24. 6 | // Copyright © 2015年 谭真. All rights reserved. 7 | // version 3.6.0 - 2021.04.02 8 | // 更多信息,请前往项目的github地址:https://github.com/banchichen/TZImagePickerController 9 | 10 | /* 11 | 经过测试,比起xib的方式,把TZAssetCell改用纯代码的方式来写,滑动帧数明显提高了(约提高10帧左右) 12 | 13 | 最初发现这个问题并修复的是@小鱼周凌宇同学,她的博客地址: http://zhoulingyu.com/ 14 | 表示感谢~ 15 | 16 | 原来xib确实会导致性能问题啊...大家也要注意了... 17 | */ 18 | 19 | #import 20 | #import "TZAssetModel.h" 21 | #import "NSBundle+TZImagePicker.h" 22 | #import "TZImageManager.h" 23 | #import "TZVideoPlayerController.h" 24 | #import "TZGifPhotoPreviewController.h" 25 | #import "TZLocationManager.h" 26 | #import "TZPhotoPreviewController.h" 27 | #import "TZPhotoPreviewCell.h" 28 | 29 | @class TZAlbumCell, TZAssetCell; 30 | @protocol TZImagePickerControllerDelegate; 31 | @interface TZImagePickerController : UINavigationController 32 | 33 | #pragma mark - 34 | /// Use this init method / 用这个初始化方法 35 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount delegate:(id)delegate; 36 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id)delegate; 37 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id)delegate pushPhotoPickerVc:(BOOL)pushPhotoPickerVc; 38 | /// This init method just for previewing photos / 用这个初始化方法以预览图片 39 | - (instancetype)initWithSelectedAssets:(NSMutableArray *)selectedAssets selectedPhotos:(NSMutableArray *)selectedPhotos index:(NSInteger)index; 40 | /// This init method for crop photo / 用这个初始化方法以裁剪图片 41 | - (instancetype)initCropTypeWithAsset:(PHAsset *)asset photo:(UIImage *)photo completion:(void (^)(UIImage *cropImage,PHAsset *asset))completion; 42 | 43 | #pragma mark - 44 | /// Default is 9 / 默认最大可选9张图片 45 | @property (nonatomic, assign) NSInteger maxImagesCount; 46 | 47 | /// The minimum count photos user must pick, Default is 0 48 | /// 最小照片必选张数,默认是0 49 | @property (nonatomic, assign) NSInteger minImagesCount; 50 | 51 | /// If the user does not select any pictures, the current picture is automatically selected when the Finish button is clicked, Default is YES 52 | /// 如果用户未选择任何图片,在点击完成按钮时自动选中当前图片,默认YES 53 | @property (nonatomic, assign) BOOL autoSelectCurrentWhenDone; 54 | 55 | /// Always enale the done button, not require minimum 1 photo be picked 56 | /// 让完成按钮一直可以点击,无须最少选择一张图片 57 | @property (nonatomic, assign) BOOL alwaysEnableDoneBtn; 58 | 59 | /// Sort photos ascending by modificationDate,Default is YES 60 | /// 对照片排序,按修改时间升序,默认是YES。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个 61 | @property (nonatomic, assign) BOOL sortAscendingByModificationDate; 62 | 63 | /// The pixel width of output image, Default is 828px,you need to set photoPreviewMaxWidth at the same time 64 | /// 导出图片的宽度,默认828像素宽,你需要同时设置photoPreviewMaxWidth的值 65 | @property (nonatomic, assign) CGFloat photoWidth; 66 | 67 | /// Default is 600px / 默认600像素宽 68 | @property (nonatomic, assign) CGFloat photoPreviewMaxWidth; 69 | 70 | /// Default is 30, While fetching photo, HUD will dismiss automatic if timeout; 71 | /// 超时时间,默认为30秒,当取图片时间超过30秒还没有取成功时,会自动dismiss HUD; 72 | @property (nonatomic, assign) NSInteger timeout; 73 | 74 | /// Default is YES, if set NO, the original photo button will hide. user can't picking original photo. 75 | /// 默认为YES,如果设置为NO,原图按钮将隐藏,用户不能选择发送原图 76 | @property (nonatomic, assign) BOOL allowPickingOriginalPhoto; 77 | 78 | /// Default is YES, if set NO, user can't picking video. 79 | /// 默认为YES,如果设置为NO,用户将不能选择视频 80 | @property (nonatomic, assign) BOOL allowPickingVideo; 81 | /// Default is NO / 默认为NO,为YES时可以多选视频/gif/图片,和照片共享最大可选张数maxImagesCount的限制 82 | @property (nonatomic, assign) BOOL allowPickingMultipleVideo; 83 | 84 | /// Default is NO, if set YES, user can picking gif image. 85 | /// 默认为NO,如果设置为YES,用户可以选择gif图片 86 | @property (nonatomic, assign) BOOL allowPickingGif; 87 | 88 | /// Default is YES, if set NO, user can't picking image. 89 | /// 默认为YES,如果设置为NO,用户将不能选择发送图片 90 | @property (nonatomic, assign) BOOL allowPickingImage; 91 | 92 | /// Default is YES, if set NO, user can't take picture. 93 | /// 默认为YES,如果设置为NO, 用户将不能拍摄照片 94 | @property (nonatomic, assign) BOOL allowTakePicture; 95 | @property (nonatomic, assign) BOOL allowCameraLocation; 96 | 97 | /// Default is YES, if set NO, user can't take video. 98 | /// 默认为YES,如果设置为NO, 用户将不能拍摄视频 99 | @property(nonatomic, assign) BOOL allowTakeVideo; 100 | /// Default value is 10 minutes / 视频最大拍摄时间,默认是10分钟,单位是秒 101 | @property (assign, nonatomic) NSTimeInterval videoMaximumDuration; 102 | /// Customizing UIImagePickerController's other properties, such as videoQuality / 定制UIImagePickerController的其它属性,比如视频拍摄质量videoQuality 103 | @property (nonatomic, copy) void(^uiImagePickerControllerSettingBlock)(UIImagePickerController *imagePickerController); 104 | 105 | /// 首选语言,如果设置了就用该语言,不设则取当前系统语言。 106 | /// 支持zh-Hans、zh-Hant、en、vi等值,详见TZImagePickerController.bundle内的语言资源 107 | @property (copy, nonatomic) NSString *preferredLanguage; 108 | 109 | /// 语言bundle,preferredLanguage变化时languageBundle会变化 110 | /// 可通过手动设置bundle,让选择器支持新的的语言(需要在设置preferredLanguage后设置languageBundle)。欢迎提交PR把语言文件提交上来~ 111 | @property (strong, nonatomic) NSBundle *languageBundle; 112 | 113 | /// Default is YES, if set NO, user can't preview photo. 114 | /// 默认为YES,如果设置为NO,预览按钮将隐藏,用户将不能去预览照片 115 | @property (nonatomic, assign) BOOL allowPreview; 116 | 117 | /// Default is YES, if set NO, the picker don't dismiss itself. 118 | /// 默认为YES,如果设置为NO, 选择器将不会自己dismiss 119 | @property(nonatomic, assign) BOOL autoDismiss; 120 | 121 | /// Default is NO, if set YES, in the delegate method the photos and infos will be nil, only assets hava value. 122 | /// 默认为NO,如果设置为YES,代理方法里photos和infos会是nil,只返回assets 123 | @property (assign, nonatomic) BOOL onlyReturnAsset; 124 | 125 | /// Default is NO, if set YES, will show the image's selected index. 126 | /// 默认为NO,如果设置为YES,会显示照片的选中序号 127 | @property (assign, nonatomic) BOOL showSelectedIndex; 128 | 129 | /// Default is NO, if set YES, when selected photos's count up to maxImagesCount, other photo will show float layer what's color is cannotSelectLayerColor. 130 | /// 默认是NO,如果设置为YES,当照片选择张数达到maxImagesCount时,其它照片会显示颜色为cannotSelectLayerColor的浮层 131 | @property (assign, nonatomic) BOOL showPhotoCannotSelectLayer; 132 | /// Default is white color with 0.8 alpha; 133 | @property (strong, nonatomic) UIColor *cannotSelectLayerColor; 134 | 135 | /// Default is YES, if set NO, the result photo will be scaled to photoWidth pixel width. The photoWidth default is 828px 136 | /// 默认是YES,如果设置为NO,内部会缩放图片到photoWidth像素宽 137 | @property (assign, nonatomic) BOOL notScaleImage; 138 | 139 | /// 默认是NO,如果设置为YES,导出视频时会修正转向(慎重设为YES,可能导致部分安卓下拍的视频导出失败) 140 | @property (assign, nonatomic) BOOL needFixComposition; 141 | 142 | /// The photos user have selected 143 | /// 用户选中过的图片数组 144 | @property (nonatomic, strong) NSMutableArray *selectedAssets; 145 | @property (nonatomic, strong) NSMutableArray *selectedModels; 146 | @property (nonatomic, strong) NSMutableArray *selectedAssetIds; 147 | - (void)addSelectedModel:(TZAssetModel *)model; 148 | - (void)removeSelectedModel:(TZAssetModel *)model; 149 | 150 | /// Minimum selectable photo width, Default is 0 151 | /// 最小可选中的图片宽度,默认是0,小于这个宽度的图片不可选中 152 | @property (nonatomic, assign) NSInteger minPhotoWidthSelectable; 153 | @property (nonatomic, assign) NSInteger minPhotoHeightSelectable; 154 | /// Hide the photo what can not be selected, Default is NO 155 | /// 隐藏不可以选中的图片,默认是NO,不推荐将其设置为YES 156 | @property (nonatomic, assign) BOOL hideWhenCanNotSelect; 157 | /// Deprecated, Use statusBarStyle (顶部statusBar 是否为系统默认的黑色,默认为NO) 158 | @property (nonatomic, assign) BOOL isStatusBarDefault __attribute__((deprecated("Use -statusBarStyle."))); 159 | /// statusBar的样式,默认为UIStatusBarStyleLightContent 160 | @property (assign, nonatomic) UIStatusBarStyle statusBarStyle; 161 | 162 | #pragma mark - 163 | /// Single selection mode, valid when maxImagesCount = 1 164 | /// 单选模式,maxImagesCount为1时才生效 165 | @property (nonatomic, assign) BOOL showSelectBtn; ///< 在单选模式下,照片列表页中,显示选择按钮,默认为NO 166 | @property (nonatomic, assign) BOOL allowCrop; ///< 允许裁剪,默认为YES,showSelectBtn为NO才生效 167 | @property (nonatomic, assign) BOOL scaleAspectFillCrop; ///< 是否图片等比缩放填充cropRect区域,开启后预览页面无法左右滑动切换图片 168 | @property (nonatomic, assign) CGRect cropRect; ///< 裁剪框的尺寸 169 | @property (nonatomic, assign) CGRect cropRectPortrait; ///< 裁剪框的尺寸(竖屏) 170 | @property (nonatomic, assign) CGRect cropRectLandscape; ///< 裁剪框的尺寸(横屏) 171 | @property (nonatomic, assign) BOOL needCircleCrop; ///< 需要圆形裁剪框 172 | @property (nonatomic, assign) NSInteger circleCropRadius; ///< 圆形裁剪框半径大小 173 | @property (nonatomic, copy) void (^cropViewSettingBlock)(UIView *cropView); ///< 自定义裁剪框的其他属性 174 | @property (nonatomic, copy) void (^navLeftBarButtonSettingBlock)(UIButton *leftButton); ///< 自定义返回按钮样式及其属性 175 | 176 | /// 【自定义各页面/组件的样式】在界面初始化/组件setModel完成后调用,允许外界修改样式等 177 | @property (nonatomic, copy) void (^photoPickerPageUIConfigBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine); 178 | @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); 179 | @property (nonatomic, copy) void (^videoPreviewPageUIConfigBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton); 180 | @property (nonatomic, copy) void (^gifPreviewPageUIConfigBlock)(UIView *toolBar, UIButton *doneButton); 181 | @property (nonatomic, copy) void (^albumPickerPageUIConfigBlock)(UITableView *tableView); 182 | @property (nonatomic, copy) void (^assetCellDidSetModelBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView); 183 | @property (nonatomic, copy) void (^albumCellDidSetModelBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel); 184 | /// 【自定义各页面/组件的frame】在界面viewDidLayoutSubviews/组件layoutSubviews后调用,允许外界修改frame等 185 | @property (nonatomic, copy) void (^photoPickerPageDidLayoutSubviewsBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine); 186 | @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); 187 | @property (nonatomic, copy) void (^videoPreviewPageDidLayoutSubviewsBlock)(UIButton *playButton, UIView *toolBar, UIButton *doneButton); 188 | @property (nonatomic, copy) void (^gifPreviewPageDidLayoutSubviewsBlock)(UIView *toolBar, UIButton *doneButton); 189 | @property (nonatomic, copy) void (^albumPickerPageDidLayoutSubviewsBlock)(UITableView *tableView); 190 | @property (nonatomic, copy) void (^assetCellDidLayoutSubviewsBlock)(TZAssetCell *cell, UIImageView *imageView, UIImageView *selectImageView, UILabel *indexLabel, UIView *bottomView, UILabel *timeLength, UIImageView *videoImgView); 191 | @property (nonatomic, copy) void (^albumCellDidLayoutSubviewsBlock)(TZAlbumCell *cell, UIImageView *posterImageView, UILabel *titleLabel); 192 | /// 自定义各页面/组件的frame】刷新底部状态(refreshNaviBarAndBottomBarState)使用的 193 | @property (nonatomic, copy) void (^photoPickerPageDidRefreshStateBlock)(UICollectionView *collectionView, UIView *bottomToolBar, UIButton *previewButton, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel, UIView *divideLine); 194 | 195 | @property (nonatomic, copy) void (^photoPreviewPageDidRefreshStateBlock)(UICollectionView *collectionView, UIView *naviBar, UIButton *backButton, UIButton *selectButton, UILabel *indexLabel, UIView *toolBar, UIButton *originalPhotoButton, UILabel *originalPhotoLabel, UIButton *doneButton, UIImageView *numberImageView, UILabel *numberLabel); 196 | 197 | #pragma mark - 198 | - (UIAlertController *)showAlertWithTitle:(NSString *)title; 199 | - (void)showProgressHUD; 200 | - (void)hideProgressHUD; 201 | @property (nonatomic, assign) BOOL isSelectOriginalPhoto; 202 | @property (assign, nonatomic) BOOL needShowStatusBar; 203 | 204 | #pragma mark - 205 | @property (nonatomic, copy) NSString *takePictureImageName __attribute__((deprecated("Use -takePictureImage."))); 206 | @property (nonatomic, copy) NSString *photoSelImageName __attribute__((deprecated("Use -photoSelImage."))); 207 | @property (nonatomic, copy) NSString *photoDefImageName __attribute__((deprecated("Use -photoDefImage."))); 208 | @property (nonatomic, copy) NSString *photoOriginSelImageName __attribute__((deprecated("Use -photoOriginSelImage."))); 209 | @property (nonatomic, copy) NSString *photoOriginDefImageName __attribute__((deprecated("Use -photoOriginDefImage."))); 210 | @property (nonatomic, copy) NSString *photoPreviewOriginDefImageName __attribute__((deprecated("Use -photoPreviewOriginDefImage."))); 211 | @property (nonatomic, copy) NSString *photoNumberIconImageName __attribute__((deprecated("Use -photoNumberIconImage."))); 212 | @property (nonatomic, strong) UIImage *takePictureImage; 213 | @property (nonatomic, strong) UIImage *photoSelImage; 214 | @property (nonatomic, strong) UIImage *photoDefImage; 215 | @property (nonatomic, strong) UIImage *photoOriginSelImage; 216 | @property (nonatomic, strong) UIImage *photoOriginDefImage; 217 | @property (nonatomic, strong) UIImage *photoPreviewOriginDefImage; 218 | @property (nonatomic, strong) UIImage *photoNumberIconImage; 219 | 220 | #pragma mark - 221 | /// Appearance / 外观颜色 + 按钮文字 222 | @property (nonatomic, strong) UIColor *oKButtonTitleColorNormal; 223 | @property (nonatomic, strong) UIColor *oKButtonTitleColorDisabled; 224 | @property (nonatomic, strong) UIColor *naviBgColor; 225 | @property (nonatomic, strong) UIColor *naviTitleColor; 226 | @property (nonatomic, strong) UIFont *naviTitleFont; 227 | @property (nonatomic, strong) UIColor *barItemTextColor; 228 | @property (nonatomic, strong) UIFont *barItemTextFont; 229 | 230 | @property (nonatomic, copy) NSString *doneBtnTitleStr; 231 | @property (nonatomic, copy) NSString *cancelBtnTitleStr; 232 | @property (nonatomic, copy) NSString *previewBtnTitleStr; 233 | @property (nonatomic, copy) NSString *fullImageBtnTitleStr; 234 | @property (nonatomic, copy) NSString *settingBtnTitleStr; 235 | @property (nonatomic, copy) NSString *processHintStr; 236 | 237 | /// 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 238 | /// icon主题色,默认是微信的绿色,值是r:31 g:185 b:34。目前仅支持showSelectedIndex为YES时的图片选中icon。如需要,请尽早设置它。 239 | @property (strong, nonatomic) UIColor *iconThemeColor; 240 | 241 | #pragma mark - 242 | - (void)cancelButtonClick; 243 | 244 | // For method annotations, see the corresponding method in TZImagePickerControllerDelegate / 方法注释见TZImagePickerControllerDelegate中对应方法 245 | @property (nonatomic, copy) void (^didFinishPickingPhotosHandle)(NSArray *photos,NSArray *assets,BOOL isSelectOriginalPhoto); 246 | @property (nonatomic, copy) void (^didFinishPickingPhotosWithInfosHandle)(NSArray *photos,NSArray *assets,BOOL isSelectOriginalPhoto,NSArray *infos); 247 | @property (nonatomic, copy) void (^imagePickerControllerDidCancelHandle)(void); 248 | @property (nonatomic, copy) void (^didFinishPickingVideoHandle)(UIImage *coverImage,PHAsset *asset); 249 | @property (nonatomic, copy) void (^didFinishPickingGifImageHandle)(UIImage *animatedImage,id sourceAssets); 250 | 251 | @property (nonatomic, weak) id pickerDelegate; 252 | 253 | @end 254 | 255 | 256 | @protocol TZImagePickerControllerDelegate 257 | @optional 258 | // The picker should dismiss itself; when it dismissed these callback will be called. 259 | // You can also set autoDismiss to NO, then the picker don't dismiss itself. 260 | // If isOriginalPhoto is YES, user picked the original photo. 261 | // You can get original photo with asset, by the method [[TZImageManager manager] getOriginalPhotoWithAsset:completion:]. 262 | // The UIImage Object in photos default width is 828px, you can set it by photoWidth property. 263 | // 这个照片选择器会自己dismiss,当选择器dismiss的时候,会执行下面的代理方法 264 | // 你也可以设置autoDismiss属性为NO,选择器就不会自己dismis了 265 | // 如果isSelectOriginalPhoto为YES,表明用户选择了原图 266 | // 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] 267 | // photos数组里的UIImage对象,默认是828像素宽,你可以通过设置photoWidth属性的值来改变它 268 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto; 269 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto infos:(NSArray *)infos; 270 | - (void)tz_imagePickerControllerDidCancel:(TZImagePickerController *)picker; 271 | 272 | /// 如果用户选择了某张照片下面的代理方法会被执行 273 | /// 如果isSelectOriginalPhoto为YES,表明用户选择了原图 274 | /// 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] 275 | - (void)imagePickerController:(TZImagePickerController *)picker didSelectAsset:(PHAsset *)asset photo:(UIImage *)photo isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto; 276 | 277 | /// 如果用户取消选择了某张照片下面的代理方法会被执行 278 | /// 如果isSelectOriginalPhoto为YES,表明用户选择了原图 279 | /// 你可以通过一个asset获得原图,通过这个方法:[[TZImageManager manager] getOriginalPhotoWithAsset:completion:] 280 | - (void)imagePickerController:(TZImagePickerController *)picker didDeselectAsset:(PHAsset *)asset photo:(UIImage *)photo isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto; 281 | 282 | // If user picking a video and allowPickingMultipleVideo is NO, this callback will be called. 283 | // If allowPickingMultipleVideo is YES, will call imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto: 284 | // 如果用户选择了一个视频且allowPickingMultipleVideo是NO,下面的代理方法会被执行 285 | // 如果allowPickingMultipleVideo是YES,将会调用imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto: 286 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingVideo:(UIImage *)coverImage sourceAssets:(PHAsset *)asset; 287 | 288 | // If user picking a gif image and allowPickingMultipleVideo is NO, this callback will be called. 289 | // If allowPickingMultipleVideo is YES, will call imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto: 290 | // 如果用户选择了一个gif图片且allowPickingMultipleVideo是NO,下面的代理方法会被执行 291 | // 如果allowPickingMultipleVideo是YES,将会调用imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto: 292 | - (void)imagePickerController:(TZImagePickerController *)picker didFinishPickingGifImage:(UIImage *)animatedImage sourceAssets:(PHAsset *)asset; 293 | 294 | // Decide album show or not't 295 | // 决定相册显示与否 albumName:相册名字 result:相册原始数据 296 | - (BOOL)isAlbumCanSelect:(NSString *)albumName result:(PHFetchResult *)result; 297 | 298 | // Decide asset show or not't 299 | // 决定照片显示与否 300 | - (BOOL)isAssetCanSelect:(PHAsset *)asset __attribute__((deprecated("Use -isAssetCanBeDisplayed:."))); 301 | - (BOOL)isAssetCanBeDisplayed:(PHAsset *)asset; 302 | 303 | // Decide asset can be selected 304 | // 决定照片能否被选中 305 | - (BOOL)isAssetCanBeSelected:(PHAsset *)asset; 306 | @end 307 | 308 | 309 | @interface TZAlbumPickerController : UIViewController 310 | @property (nonatomic, assign) NSInteger columnNumber; 311 | @property (assign, nonatomic) BOOL isFirstAppear; 312 | - (void)configTableView; 313 | @end 314 | 315 | 316 | @interface UIImage (MyBundle) 317 | + (UIImage *)tz_imageNamedFromMyBundle:(NSString *)name; 318 | @end 319 | 320 | 321 | @interface TZCommonTools : NSObject 322 | + (UIEdgeInsets)tz_safeAreaInsets; 323 | + (BOOL)tz_isIPhoneX; 324 | + (CGFloat)tz_statusBarHeight; 325 | // 获得Info.plist数据字典 326 | + (NSDictionary *)tz_getInfoDictionary; 327 | + (BOOL)tz_isRightToLeftLayout; 328 | + (void)configBarButtonItem:(UIBarButtonItem *)item tzImagePickerVc:(TZImagePickerController *)tzImagePickerVc; 329 | + (BOOL)isICloudSyncError:(NSError *)error; 330 | @end 331 | 332 | 333 | @interface TZImagePickerConfig : NSObject 334 | + (instancetype)sharedInstance; 335 | @property (copy, nonatomic) NSString *preferredLanguage; 336 | @property(nonatomic, assign) BOOL allowPickingImage; 337 | @property (nonatomic, assign) BOOL allowPickingVideo; 338 | @property (strong, nonatomic) NSBundle *languageBundle; 339 | @property (assign, nonatomic) BOOL showSelectedIndex; 340 | @property (assign, nonatomic) BOOL showPhotoCannotSelectLayer; 341 | @property (assign, nonatomic) BOOL notScaleImage; 342 | @property (assign, nonatomic) BOOL needFixComposition; 343 | 344 | /// 默认是50,如果一个GIF过大,里面图片个数可能超过1000,会导致内存飙升而崩溃 345 | @property (assign, nonatomic) NSInteger gifPreviewMaxImagesCount; 346 | /// 【自定义GIF播放方案】为了避免内存过大,内部默认限制只播放50帧(平均取),可通过gifPreviewMaxImagesCount属性调整,若对GIF预览有更好的效果要求,可实现这个block采用FLAnimatedImage等三方库来播放,但注意FLAnimatedImage有播放速度较慢问题,自行取舍下。 347 | @property (nonatomic, copy) void (^gifImagePlayBlock)(TZPhotoPreviewView *view, UIImageView *imageView, NSData *gifData, NSDictionary *info); 348 | @end 349 | --------------------------------------------------------------------------------