├── .gitignore └── TestPhotoKit ├── Direction.h ├── TestPhotoKit.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── TestPhotoKit.xcscmblueprint ├── TestPhotoKit ├── AlbumCell.h ├── AlbumCell.m ├── AlbumCell.xib ├── AlbumController.h ├── AlbumController.m ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── asset_selectedOrigion_normal.imageset │ │ ├── Contents.json │ │ ├── asset_selectedOrigion_normal@2x.png │ │ └── asset_selectedOrigion_normal@3x.png │ ├── asset_selectedOrigion_selected.imageset │ │ ├── Contents.json │ │ ├── asset_selectedOrigion_selected@2x.png │ │ └── asset_selectedOrigion_selected@3x.png │ ├── imagesBrowse_back.imageset │ │ ├── Contents.json │ │ ├── imagesBrowse_back@2x.png │ │ └── imagesBrowse_back@3x.png │ ├── message_oeuvre_btn_normal.imageset │ │ ├── Contents.json │ │ ├── message_oeuvre_btn_normal@2x.png │ │ └── message_oeuvre_btn_normal@3x.png │ └── message_oeuvre_btn_selected.imageset │ │ ├── Contents.json │ │ ├── message_oeuvre_btn_selected@2x.png │ │ └── message_oeuvre_btn_selected@3x.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ContainView.h ├── ContainView.m ├── E8DE84D6-A559-4081-8EFC-BA4542890307.png ├── Info.plist ├── ShowAlbumViewController.h ├── ShowAlbumViewController.m ├── ShowSmartAblumTableViewController.h ├── ShowSmartAblumTableViewController.m ├── ViewController.h ├── ViewController.m ├── imagesShow │ ├── WZMediaFetcher │ │ ├── NSObject+WZCommon.h │ │ ├── NSObject+WZCommon.m │ │ ├── WZMediaFetcher.h │ │ ├── WZMediaFetcher.m │ │ ├── WZToast.h │ │ └── WZToast.m │ ├── WZPhotoBrowser │ │ ├── WZAssetBrowseController │ │ │ ├── WZAssetBrowseController.h │ │ │ ├── WZAssetBrowseController.m │ │ │ ├── WZAssetBrowseNavigationView.h │ │ │ ├── WZAssetBrowseNavigationView.m │ │ │ ├── WZAssetBrowseToolView.h │ │ │ └── WZAssetBrowseToolView.m │ │ ├── WZImageBrowseController.h │ │ ├── WZImageBrowseController.m │ │ ├── WZImageContainerController.h │ │ ├── WZImageContainerController.m │ │ ├── WZImageScrollView.h │ │ ├── WZImageScrollView.m │ │ ├── WZRemoteImagesBrowseController │ │ │ ├── WZRemoteImageBrowseController.h │ │ │ ├── WZRemoteImageBrowseController.m │ │ │ ├── WZRemoteImageNavigationView.h │ │ │ └── WZRemoteImageNavigationView.m │ │ ├── WZRoundRenderLayer.h │ │ └── WZRoundRenderLayer.m │ └── WZPhotoPicker │ │ ├── WZMediaAssetBaseCell.h │ │ ├── WZMediaAssetBaseCell.m │ │ ├── WZPhotoCatalogueController.h │ │ ├── WZPhotoCatalogueController.m │ │ ├── WZPhotoPickerController.h │ │ └── WZPhotoPickerController.m └── main.m ├── TestPhotoKitUITests ├── Info.plist └── TestPhotoKitUITests.m └── ThirdLibrary └── SDWebImage ├── NSData+ImageContentType.h ├── NSData+ImageContentType.m ├── SDImageCache.h ├── SDImageCache.m ├── SDWebImageCompat.h ├── SDWebImageCompat.m ├── SDWebImageDecoder.h ├── SDWebImageDecoder.m ├── SDWebImageDownloader.h ├── SDWebImageDownloader.m ├── SDWebImageDownloaderOperation.h ├── SDWebImageDownloaderOperation.m ├── SDWebImageManager.h ├── SDWebImageManager.m ├── SDWebImageOperation.h ├── SDWebImagePrefetcher.h ├── SDWebImagePrefetcher.m ├── UIButton+WebCache.h ├── UIButton+WebCache.m ├── UIImage+GIF.h ├── UIImage+GIF.m ├── UIImage+MultiFormat.h ├── UIImage+MultiFormat.m ├── UIImageView+HighlightedWebCache.h ├── UIImageView+HighlightedWebCache.m ├── UIImageView+WebCache.h ├── UIImageView+WebCache.m ├── UIView+WebCacheOperation.h └── UIView+WebCacheOperation.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /TestPhotoKit/Direction.h: -------------------------------------------------------------------------------- 1 | // 2 | // Direction.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 13/10/17. 6 | // Copyright © 2017年 admin. All rights reserved. 7 | // 8 | 9 | #ifndef Direction_h 10 | #define Direction_h 11 | 12 | 13 | /* 14 | fetch : image、video、audio、gif 15 | image : editing 16 | video : cliping mixture 17 | gif : mixture split 18 | auido : transform into words、clip、mix 19 | 20 | network: 21 | iCloud 部分 22 | 23 | */ 24 | 25 | 26 | #endif /* Direction_h */ 27 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit.xcodeproj/project.xcworkspace/xcshareddata/TestPhotoKit.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 3 | "824315d4-9642-4b1d-9f8f-75b6ef73f7b3" : { 4 | 5 | } 6 | }, 7 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 8 | "824315d4-9642-4b1d-9f8f-75b6ef73f7b3" : 0 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "72138AA8-62E7-4DB1-89EB-2FA71FCDF10A", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "824315d4-9642-4b1d-9f8f-75b6ef73f7b3" : "..\/.." 13 | }, 14 | "DVTSourceControlWorkspaceBlueprintNameKey" : "TestPhotoKit", 15 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 16 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "TestPhotoKit.xcodeproj", 17 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 18 | { 19 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "http:\/\/14.18.242.139:8088\/repos\/yueyueApp", 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "824315d4-9642-4b1d-9f8f-75b6ef73f7b3" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AlbumCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlbumCell.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AlbumCell : UICollectionViewCell 12 | @property (weak, nonatomic) IBOutlet UIImageView *photoImageView; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AlbumCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlbumCell.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import "AlbumCell.h" 10 | 11 | @implementation AlbumCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | // Initialization code 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AlbumCell.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 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AlbumController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlbumController.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AlbumController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AlbumController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlbumController.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import "AlbumController.h" 10 | #import "ContainView.h" 11 | #import 12 | #import 13 | 14 | @interface AlbumController () 15 | @property (nonatomic, strong) ContainView *containView; 16 | @property (nonatomic, strong) PHImageRequestOptions *options; 17 | @property (nonatomic, strong) PHFetchResult *assets; 18 | 19 | @end 20 | 21 | @implementation AlbumController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | [self setupViews]; 26 | [self getAllPhotosFromAlbum]; 27 | 28 | #pragma mark - 获取video 这段代码这个VC没有使用 29 | PHFetchResult *assetsResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeVideo options:nil]; 30 | PHVideoRequestOptions *options2 = [[PHVideoRequestOptions alloc] init]; 31 | options2.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic; 32 | [options2 setNetworkAccessAllowed:true]; 33 | for (PHAsset *a in assetsResult) { 34 | [[PHImageManager defaultManager] requestAVAssetForVideo:a options:options2 resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { 35 | NSLog(@"%@",info); 36 | NSLog(@"%@",audioMix); 37 | NSLog(@"%@",((AVURLAsset*)asset).URL);//asset为AVURLAsset类型 可直接获取相应视频的相对地址 38 | // NSString *path = ((AVURLAsset*)asset).URL.path;// 39 | }]; 40 | } 41 | } 42 | 43 | - (void)setupViews { 44 | self.view.backgroundColor = [UIColor whiteColor]; 45 | self.containView =[[ContainView alloc] initWithFrame:self.view.bounds delegate:self]; 46 | [self.view addSubview:self.containView]; 47 | } 48 | 49 | //从系统中捕获所有相片 50 | - (void)getAllPhotosFromAlbum { 51 | self.options = [[PHImageRequestOptions alloc] init];//请求选项设置 52 | self.options.resizeMode = PHImageRequestOptionsResizeModeExact;//自定义图片大小的加载模式 53 | self.options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; 54 | self.options.synchronous = YES;//是否同步加载 55 | 56 | //容器类 57 | self.assets = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil]; //得到所有图片 58 | /* 59 | PHAssetMediaType: 60 | PHAssetMediaTypeUnknown = 0,//在这个配置下,请求不会返回任何东西 61 | PHAssetMediaTypeImage = 1,//图片 62 | PHAssetMediaTypeVideo = 2,//视频 63 | PHAssetMediaTypeAudio = 3,//音频 64 | */ 65 | [self.containView.collectionView reloadData]; 66 | } 67 | 68 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 69 | return self.assets.count; 70 | } 71 | 72 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 73 | AlbumCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:ALBUMCELLID forIndexPath:indexPath]; 74 | // cell.backgroundColor= [UIColor redColor]; 75 | 76 | //9.0可用 77 | CGSizeMake(self.assets[indexPath.row].pixelWidth, self.assets[indexPath.row].pixelHeight); 78 | 79 | [self adjustGIFWithAsset2:self.assets[indexPath.row]]; 80 | [[PHImageManager defaultManager] requestImageForAsset:self.assets[indexPath.row] targetSize: CGSizeMake(110, 110) contentMode:PHImageContentModeDefault options:self.options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 81 | cell.photoImageView.contentMode = UIViewContentModeScaleAspectFit; 82 | cell.photoImageView.image = result; 83 | //// NSLog(@"%@",result); 84 | // NSLog(@"%ld",self.num); 85 | // NSLog(@"%@",info.allKeys); 86 | // NSLog(@"---------------------------------------------------------------"); 87 | }]; 88 | return cell; 89 | } 90 | 91 | 92 | /** 关于localIdentifier: 93 | * 我们可以在第一次获取到相册中的 GIF 的时候,将其获取到的所有 GIF 的 localIdentifier 记录下来。这样,下次启动的时候,就可以通过这些 localIdentifier 来直接获取 GIF 资源 94 | * PHAsset fetchAssetsWithLocalIdentifiers:<#(nonnull NSArray *)#> options:<#(nullable PHFetchOptions *)#> 95 | */ 96 | #pragma mark - 判断资源是不是GIF :(资源类型判别可以为UI提供一些图片类型的指示) 97 | ////方法1 iOS 9.0 98 | - (BOOL)adjustGIFWithAsset:(PHAsset *)asset { 99 | if ([asset isKindOfClass:[PHAsset class]]) { 100 | //每个asset 都有一个或者多个PHAssetResource(如:被编辑保存过的aseet会有若干个resource, 且被修改后的GIF类型的asset得uniformTypeIdentifier 会发生改变变成了public.jpeg 类型,所以修改多地GIF的就不再是GIF了,所以要对比最后一个resource的类型) 101 | NSArray* tmpArr = [PHAssetResource assetResourcesForAsset:asset]; 102 | if (tmpArr.count) { 103 | PHAssetResource *resource = tmpArr.lastObject; 104 | if (resource.uniformTypeIdentifier.length) { 105 | return UTTypeConformsTo( (__bridge CFStringRef)resource.uniformTypeIdentifier, kUTTypeGIF); 106 | } 107 | } 108 | } 109 | return false; 110 | } 111 | 112 | //方法2 113 | - (BOOL)adjustGIFWithAsset2:(PHAsset *)asset { 114 | PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; 115 | options.deliveryMode = PHImageRequestOptionsDeliveryModeFastFormat; 116 | options.resizeMode = PHImageRequestOptionsResizeModeFast; 117 | [options setSynchronous:true];//同步 118 | __block NSString *dataUTIStr = nil; 119 | if ([asset isKindOfClass:[PHAsset class]]) { 120 | [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { 121 | dataUTIStr = dataUTI; 122 | }]; 123 | } 124 | if (dataUTIStr.length) { 125 | return UTTypeConformsTo( (__bridge CFStringRef)dataUTIStr, kUTTypeGIF); 126 | } 127 | return false; 128 | } 129 | 130 | /**mov转mp4格式 最好设一个block 转完码之后的回调*/ 131 | -(void)convertMovWithSourceURL:(NSURL *)sourceUrl fileName:(NSString *)fileName saveExportFilePath:(NSString *)path 132 | { 133 | if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { 134 | [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; 135 | } 136 | AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:sourceUrl options:nil]; 137 | NSArray *compatiblePresets=[AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];//输出模式标识符的集合 138 | if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality]) { 139 | 140 | AVAssetExportSession *exportSession=[[AVAssetExportSession alloc] initWithAsset:avAsset presetName:AVAssetExportPresetMediumQuality]; 141 | NSString *resultPath = [path stringByAppendingFormat:@"/%@.mp4",fileName]; 142 | exportSession.outputURL=[NSURL fileURLWithPath:resultPath];//输出路径 143 | exportSession.outputFileType = AVFileTypeMPEG4;//输出类型 144 | exportSession.shouldOptimizeForNetworkUse = YES;//为网络使用时做出最佳调整 145 | 146 | [exportSession exportAsynchronouslyWithCompletionHandler:^(void){//异步输出转码视频 147 | switch (exportSession.status) { 148 | case AVAssetExportSessionStatusCancelled: 149 | NSLog(@"转码状态:取消转码"); 150 | break; 151 | case AVAssetExportSessionStatusUnknown: 152 | NSLog(@"转码状态:未知"); 153 | break; 154 | case AVAssetExportSessionStatusWaiting: 155 | NSLog(@"转码状态:等待转码"); 156 | break; 157 | case AVAssetExportSessionStatusExporting: 158 | NSLog(@"转码状态:正在转码"); 159 | break; 160 | case AVAssetExportSessionStatusCompleted: 161 | { 162 | NSLog(@"转码状态:完成转码"); 163 | NSArray *files=[[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:nil]; 164 | for (NSString *fn in files) { 165 | if ([resultPath isEqualToString:fn]) { 166 | NSLog(@"转码状态:完成转码 文件存在"); 167 | } 168 | } 169 | break; 170 | } 171 | case AVAssetExportSessionStatusFailed: 172 | NSLog(@"转码状态:转码失败"); 173 | NSLog(@"%@",exportSession.error.description); 174 | break; 175 | } 176 | }]; 177 | } 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. 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 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "asset_selectedOrigion_normal@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "asset_selectedOrigion_normal@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_normal.imageset/asset_selectedOrigion_normal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_normal.imageset/asset_selectedOrigion_normal@2x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_normal.imageset/asset_selectedOrigion_normal@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_normal.imageset/asset_selectedOrigion_normal@3x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "asset_selectedOrigion_selected@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "asset_selectedOrigion_selected@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_selected.imageset/asset_selectedOrigion_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_selected.imageset/asset_selectedOrigion_selected@2x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_selected.imageset/asset_selectedOrigion_selected@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/asset_selectedOrigion_selected.imageset/asset_selectedOrigion_selected@3x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/imagesBrowse_back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "imagesBrowse_back@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "imagesBrowse_back@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/imagesBrowse_back.imageset/imagesBrowse_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/imagesBrowse_back.imageset/imagesBrowse_back@2x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/imagesBrowse_back.imageset/imagesBrowse_back@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/imagesBrowse_back.imageset/imagesBrowse_back@3x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "message_oeuvre_btn_normal@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "message_oeuvre_btn_normal@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_normal.imageset/message_oeuvre_btn_normal@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_normal.imageset/message_oeuvre_btn_normal@2x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_normal.imageset/message_oeuvre_btn_normal@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_normal.imageset/message_oeuvre_btn_normal@3x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "message_oeuvre_btn_selected@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "message_oeuvre_btn_selected@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_selected.imageset/message_oeuvre_btn_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_selected.imageset/message_oeuvre_btn_selected@2x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_selected.imageset/message_oeuvre_btn_selected@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/Assets.xcassets/message_oeuvre_btn_selected.imageset/message_oeuvre_btn_selected@3x.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/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 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/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 | 30 | 37 | 44 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ContainView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ContainView.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AlbumCell.h" 11 | #define ALBUMCELLID @"AlbumCellIdentifier" 12 | @interface ContainView : UIView 13 | @property (nonatomic, strong) UICollectionView *collectionView; 14 | - (instancetype)initWithFrame:(CGRect)frame delegate:(id)delegate; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ContainView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ContainView.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import "ContainView.h" 10 | @interface ContainView() 11 | 12 | @property (nonatomic, weak) id delegate; 13 | @end 14 | 15 | @implementation ContainView 16 | 17 | - (instancetype)initWithFrame:(CGRect)frame delegate:(id)delegate { 18 | if (self = [super initWithFrame:frame]) { 19 | self.delegate = delegate; 20 | [self setupViews]; 21 | 22 | } 23 | return self; 24 | } 25 | - (UICollectionView *)collectionView { 26 | if (!_collectionView) { 27 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 28 | layout.minimumInteritemSpacing = 0; 29 | _collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:layout]; 30 | _collectionView.delegate = _delegate; 31 | _collectionView.dataSource = _delegate; 32 | [_collectionView registerNib:[UINib nibWithNibName:@"AlbumCell" bundle:[NSBundle mainBundle]] forCellWithReuseIdentifier:ALBUMCELLID]; 33 | _collectionView.backgroundColor = [UIColor whiteColor]; 34 | } 35 | return _collectionView; 36 | } 37 | 38 | - (void)setupViews { 39 | [self addSubview:self.collectionView]; 40 | } 41 | @end 42 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/E8DE84D6-A559-4081-8EFC-BA4542890307.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wizetLee/TestPhotoKit/8a2404f78b381559fb8003ff2f23ebdbad156a77/TestPhotoKit/TestPhotoKit/E8DE84D6-A559-4081-8EFC-BA4542890307.png -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleAllowMixedLocalizations 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSAllowsArbitraryLoads 30 | 31 | 32 | NSPhotoLibraryUsageDescription 33 | available 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 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ShowAlbumViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShowAlbumViewController.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | @interface ShowAlbumViewController : UICollectionViewController 12 | @property (nonatomic, strong) PHFetchResult *assets; 13 | @end 14 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ShowAlbumViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShowAlbumViewController.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import "ShowAlbumViewController.h" 10 | 11 | @interface ShowAlbumViewController () 12 | 13 | @end 14 | 15 | @implementation ShowAlbumViewController 16 | 17 | static NSString * const reuseIdentifier = @"Cell"; 18 | 19 | - (void)viewDidLoad { 20 | [super viewDidLoad]; 21 | self.collectionView.backgroundColor = [UIColor whiteColor]; 22 | self.collectionView.delegate = self; 23 | self.collectionView.dataSource = self; 24 | [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier]; 25 | } 26 | 27 | 28 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { 29 | return 1; 30 | } 31 | 32 | 33 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 34 | return self.assets.count; 35 | } 36 | 37 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 38 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; 39 | for (UIView *view in cell.subviews ) { 40 | [view removeFromSuperview]; 41 | } 42 | 43 | UIImageView *imageView = [[UIImageView alloc] initWithFrame:cell.contentView.frame]; 44 | imageView.contentMode = UIViewContentModeScaleToFill; 45 | [cell addSubview:imageView]; 46 | 47 | 48 | 49 | PHImageRequestOptions *imageOptions = [[PHImageRequestOptions alloc] init]; 50 | imageOptions.synchronous = NO;//YES 一定是同步 NO不一定是异步 51 | imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact; 52 | /* 53 | PHImageRequestOptionsResizeModeNone // 不调整大小 54 | PHImageRequestOptionsResizeModeFast // 由系统去安排,情况不定:有时你设置的size比较低,会根据你设的size,有时又会比 55 | PHImageRequestOptionsResizeModeExact// 保证精确到自定义size :此处精确的前提得用PHImageContentModeAspectFill 56 | */ 57 | 58 | //simageOptions.version = PHImageRequestOptionsVersionCurrent;//版本 iOS8.0之后出的图片编辑extension,可以根据次枚举获取原图或者是经编辑过的图片, 59 | /*PHImageRequestOptionsVersion: 60 | PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图:原图) 61 | PHImageRequestOptionsVersionUnadjusted, //经过编辑的图 62 | PHImageRequestOptionsVersionOriginal //原始图片 63 | */ 64 | 65 | // imageOptions.networkAccessAllowed = YES;//用于开启iClould中下载图片 66 | // imageOptions.progressHandler //iClould下载进度的回调 67 | 68 | imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;//imageOptions.synchronous = NO的情况下最终决定是否是异步 69 | NSLog(@"%ld",indexPath.row); 70 | 71 | //返回一个 PHImageRequestID 72 | //在异步请求时可以根据这个ID去取消请求,同步就没办法了.. 73 | [[PHImageManager defaultManager] requestImageForAsset:self.assets[indexPath.row] targetSize:CGSizeMake(120,120) contentMode:PHImageContentModeAspectFit options:imageOptions resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 74 | /* 75 | 最终产生图片的size是有 imageOptions.resizeMode(即PHImageRequestOptions) 以及 PHImageContentMode 决定的,当然也有我们设定的size 76 | 优先级而言 77 | PHImageRequestOptions > PHImageContentMode 78 | */ 79 | 80 | //这个handler 并非在主线程上执行,所以如果有UI的更新操作就得手动添加到主线程中 81 | // dispatch_async(dispatch_get_main_queue(), ^{ //update UI }); 82 | imageView.image = result; 83 | NSLog(@"%@",result); 84 | NSLog(@"%@",info); 85 | }]; 86 | 87 | /*注意这个info字典 有时这个info甚至为null 慎用 88 | 里面的key是比较奇怪的 89 | 尽量不要用里面的key 90 | 因为这个key 会变动: 当我们最终获取到的图片的size的高/宽 没有一个达到能原有的图片size的高/宽时 91 | 部分key 会消失 如 PHImageFileSandboxExtensionTokenKey , PHImageFileURLKey 92 | */ 93 | 94 | 95 | /* 96 | 在PHImageContentModeAspectFill 下 图片size 有一个分水岭 {125,125} {126,126} 97 | 当imageOptions.resizeMode = PHImageRequestOptionsResizeModeExact; 98 | 时: 设置size 小于{125,125}时,你得到的图片size 将会是设置的1/2 99 | 100 | 而在PHImageContentModeAspectFit 分水岭 {120,120} {121,121} 101 | */ 102 | return cell; 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ShowSmartAblumTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ShowSmartAblumTableViewController.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 17/6/12. 6 | // Copyright © 2017年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ShowSmartAblumTableViewController : UITableViewController 12 | 13 | @property (nonatomic, assign) NSInteger albumCount; 14 | @property (nonatomic, strong) NSMutableArray *albumNameArr; 15 | @property (nonatomic, strong) NSMutableArray *albumAssetsArr; 16 | - (instancetype)initWithAlbumCount:(NSInteger)albumCount; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ShowSmartAblumTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ShowSmartAblumTableViewController.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 17/6/12. 6 | // Copyright © 2017年 admin. All rights reserved. 7 | // 8 | 9 | #import "ShowSmartAblumTableViewController.h" 10 | #import 11 | #import "ShowAlbumViewController.h" 12 | 13 | #define CELLID @"cellID" 14 | 15 | @interface ShowSmartAblumTableViewController () 16 | 17 | @end 18 | 19 | @implementation ShowSmartAblumTableViewController 20 | 21 | #pragma mark - Initialize 22 | 23 | - (instancetype)initWithAlbumCount:(NSInteger)albumCount { 24 | if (self =[super initWithStyle:UITableViewStylePlain]) { 25 | self.albumCount = albumCount; 26 | } 27 | return self; 28 | } 29 | 30 | #pragma mark - Lifecycle 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | self.view.backgroundColor = [UIColor whiteColor]; 35 | [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CELLID]; 36 | } 37 | 38 | #pragma mark - - Table view data source 39 | 40 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 41 | return 1; 42 | } 43 | 44 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 45 | return self.self.albumNameArr.count; 46 | } 47 | 48 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 49 | 50 | UITableViewCell * cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CELLID]; 51 | cell.textLabel.text = self.albumNameArr[indexPath.row]; 52 | cell.detailTextLabel.text = [NSString stringWithFormat:@"%ld张",((PHFetchResult *)self.albumAssetsArr[indexPath.row]).count]; 53 | 54 | return cell; 55 | } 56 | 57 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 58 | if (self.albumAssetsArr[indexPath.row] && ((PHFetchResult *)self.albumAssetsArr[indexPath.row]).count >0) { 59 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 60 | layout.minimumInteritemSpacing = 0; 61 | ShowAlbumViewController *SAVC = [[ShowAlbumViewController alloc] initWithCollectionViewLayout:layout]; 62 | SAVC.assets = self.albumAssetsArr[indexPath.row]; 63 | [self.navigationController pushViewController:SAVC animated:YES]; 64 | } 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ShowSmartAblumTableViewController.h" 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZMediaFetcher/NSObject+WZCommon.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+WZCommon.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/19. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | /** 14 | * 作用于系统的权限 设置等 15 | */ 16 | @interface NSObject (WZCommon) 17 | 18 | 19 | /** 20 | 获取相册权限 21 | @param handler 获取权限结果 22 | */ 23 | + (void)requestPhotosLibraryAuthorization:(void(^)(BOOL ownAuthorization))handler; 24 | 25 | 26 | /** 27 | 进入app设置页面 28 | */ 29 | + (void)openAppSettings; 30 | 31 | 32 | /** 33 | 颜色转图片 34 | 35 | @param color 颜色 36 | @return 图片 37 | */ 38 | + (UIImage *)imageWithColor:(UIColor *)color; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZMediaFetcher/NSObject+WZCommon.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+WZCommon.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/19. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "NSObject+WZCommon.h" 10 | 11 | @implementation NSObject (WZCommon) 12 | 13 | /** 14 | 获取相册权限 15 | @param handler 获取权限结果 16 | */ 17 | + (void)requestPhotosLibraryAuthorization:(void(^)(BOOL ownAuthorization))handler { 18 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 19 | if (handler) { 20 | BOOL boolean = false; 21 | if (status == PHAuthorizationStatusAuthorized) { 22 | boolean = true; 23 | } 24 | handler(boolean); 25 | } 26 | }]; 27 | } 28 | 29 | /** 30 | 进入app设置页面 31 | */ 32 | + (void)openAppSettings { 33 | NSURL * url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; 34 | if([[UIApplication sharedApplication] canOpenURL:url]) { 35 | NSURL*url =[NSURL URLWithString:UIApplicationOpenSettingsURLString]; 36 | [[UIApplication sharedApplication] openURL:url]; 37 | } else { 38 | NSLog(@"无法打开设置"); 39 | } 40 | } 41 | 42 | /************************************************/ 43 | //颜色转图 44 | + (UIImage *)imageWithColor:(UIColor *)color 45 | { 46 | CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); 47 | UIGraphicsBeginImageContext(rect.size); 48 | CGContextRef context = UIGraphicsGetCurrentContext(); 49 | 50 | CGContextSetFillColorWithColor(context, [color CGColor]); 51 | CGContextFillRect(context, rect); 52 | 53 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 54 | UIGraphicsEndImageContext(); 55 | 56 | return image; 57 | } 58 | @end 59 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZMediaFetcher/WZMediaFetcher.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZMediaFetcher.h 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/7. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "NSObject+WZCommon.h" 12 | #define WZMEDIAASSET_CUSTOMSIZE CGSizeMake(2000, 2000) //大图限定的尺寸 13 | 14 | #define WZMEDIAASSET_THUMBNAILSIZE CGSizeMake(250, 250) //缩略图限定的尺寸 15 | 16 | #define MACRO_COLOR_HEX_ALPHA(hexValue, alpha) [UIColor colorWithRed:((float)((hexValue & 0xFF0000) >> 16))/255.0 green:((float)((hexValue & 0xFF00) >> 8))/255.0 blue:((float)(hexValue & 0xFF))/255.0 alpha:alpha] 17 | #define MACRO_COLOR_HEX(hexValue) MACRO_COLOR_HEX_ALPHA(hexValue, 1.0) 18 | 19 | @class WZMediaAsset; 20 | @protocol WZProtocolMediaAsset 21 | 22 | @optional 23 | 24 | /** 25 | * 选中图片的自定义资源集合的回调 26 | * 27 | * @param assets 自定义资源集合 28 | */ 29 | - (void)fetchAssets:(NSArray *)assets; 30 | 31 | //同步获取图片数据 images + loading + end + callback 32 | /** 33 | * 选中图片集合的回调 34 | * 35 | * @param images 图片集合 36 | */ 37 | - (void)fetchImages:(NSArray *)images; 38 | 39 | @end 40 | 41 | /** 42 | * media类型枚举 43 | */ 44 | typedef NS_ENUM(NSUInteger, WZMediaType) { 45 | /** 46 | * 未知类型(默认) 47 | */ 48 | WZMediaTypeUnknow = 0, 49 | /** 50 | * 图片类型 51 | */ 52 | WZMediaTypePhoto = 1, 53 | /** 54 | * 视频类型 55 | */ 56 | WZMediaTypeVideo = 2, 57 | /** 58 | * 音频类型 59 | */ 60 | WZMediaTypeAudio = 3, 61 | }; 62 | 63 | #pragma mark - WZMediaAsset 64 | @interface WZMediaAsset : NSObject 65 | 66 | @property (nonatomic, assign) BOOL selected;//是否已被选中 67 | @property (nonatomic, assign) BOOL origion;//是否应显示原尺寸图片 68 | 69 | @property (nonatomic, strong) PHAsset *asset;//元数据资源 70 | @property (nonatomic, assign) WZMediaType mediaType;//meida 类型 video image 等 71 | 72 | ///大小由宏定义 73 | @property (nonatomic, strong) UIImage *imageClear;//清晰图(原尺寸图片或者是大图{2000, 200s0}) 74 | @property (nonatomic, strong) UIImage *imageThumbnail;//缩略图{250, 250} 75 | 76 | @property (nonatomic, strong) NSURL *remoteMediaURL;//用于获取远程资源的URL 77 | @property (nonatomic, strong) NSString *clearPath;//保存到本地的清晰图的路径 78 | 79 | /** 80 | * 获取缩略图 81 | * 82 | * @param synchronous 是否同步 83 | * @param handler 图片回调 84 | */ 85 | - (void)fetchThumbnailImageSynchronous:(BOOL)synchronous handler:(void (^)(UIImage *image))handler; 86 | 87 | /** 88 | * 获取原尺寸图 89 | * 90 | * @param synchronous 是否同步 91 | * @param handler 图片回调 92 | */ 93 | - (void)fetchOrigionImageSynchronous:(BOOL)synchronous handler:(void (^)(UIImage *image))handler; 94 | 95 | @end 96 | 97 | #pragma mark - WZMediaAssetCollection 98 | @interface WZMediaAssetCollection : NSObject 99 | 100 | @property (nonatomic, strong) NSArray * mediaAssetArray;//数据载体 101 | @property (nonatomic, strong) PHAssetCollection *assetCollection;//相册的载体 102 | @property (nonatomic, strong) NSString *title;//相册的title 103 | @property (nonatomic, strong) WZMediaAsset *coverAssset;//封面资源 默认是 assetMArray 首个元素 104 | 105 | /** 106 | * 自定义封面资源 107 | * 108 | * @param mediaAsset 自定义的封面资源 109 | * @param handler 回调所得到的封面图 110 | */ 111 | - (void)customCoverWithMediaAsset:(WZMediaAsset *)mediaAsset withCoverHandler:(void(^)(UIImage *image))handler; 112 | 113 | /** 114 | * 封面图的回调 115 | * 116 | * @param handler 回调所得到的封面图 117 | */ 118 | - (void)coverHandler:(void(^)(UIImage *image))handler; 119 | 120 | @end 121 | 122 | #pragma mark - WZMediaFetcher 123 | @interface WZMediaFetcher : NSObject 124 | 125 | //扩展 获取视频 以及 特定音频的资源组合 126 | //获取所需要的资源集合的集合 127 | 128 | //获取最普通的资源集合 129 | + (NSMutableArray *)fetchAssetCollection; 130 | 131 | //获取拥有所有图片的胶卷集合 132 | + (NSArray *)allImagesAssets; 133 | 134 | //获取拥有所有视频的集合 135 | + (NSArray *)allVideosAssets; 136 | 137 | 138 | 139 | //获取个人自定义创建的相册(也就是我的相簿)的集合<只有图片类型> 140 | + (NSArray *)customMediaAssetCollectionOnlyImageAsset; 141 | //获取个人自定义创建的相册(也就是我的相簿)的集合<只有视频类型> 142 | + (NSArray *)customMediaAssetCollectionOnlyVideoAsset; 143 | //获取个人自定义创建的相册(也就是我的相簿)的集合<也有视频/图片类型> 144 | + (NSArray *)customMediaAssetCollectionOnlyImageHybirdVideoAsset; 145 | 146 | 147 | #pragma mark - Fetch Picture 148 | 149 | /** 150 | * 获取目标资源的缩略图 size为WZMEDIAASSET_THUMBNAILSIZE 151 | * 152 | * @param mediaAsset 目标资源 153 | * @param synchronous 是否同步获取 154 | * @param handler 返回图片的block 155 | * 156 | * @return 资源ID 157 | */ 158 | + (int32_t)fetchThumbnailWithAsset:(PHAsset *)mediaAsset synchronous:(BOOL)synchronous handler:(void(^)(UIImage *thumbnail))handler ; 159 | 160 | /** 161 | * 获取目标资源的原尺寸图 162 | * 163 | * @param mediaAsset 目标资源 164 | * @param synchronous 是否同步获取 165 | * @param handler 返回图片的block 166 | * 167 | * @return 资源ID 168 | */ 169 | + (int32_t)fetchOrigionWith:(PHAsset *)mediaAsset synchronous:(BOOL)synchronous handler:(void(^)(UIImage *origion))handler; 170 | 171 | /** 172 | * 获取目标资源的图 自定义size 173 | * 174 | * @param mediaAsset 目标资源 175 | * @param costumSize 自定义size 176 | * @param synchronous 是否同步获取 177 | * @param handler 返回图片的block 178 | * 179 | * @return 资源ID 180 | */ 181 | + (int32_t)fetchImageWithAsset:(PHAsset *)mediaAsset costumSize:(CGSize)customSize synchronous:(BOOL)synchronous handler:(void(^)(UIImage *origion))handler; 182 | 183 | /** 184 | * 获取目标资源的原尺寸图 185 | * 186 | * @param asset 目标资源 187 | * @param synchronous 是否同步获取 188 | * @param handler data形式 图片方向 图片的详情info 189 | * 190 | * @return 资源ID 191 | */ 192 | + (int32_t)fetchImageWithAsset:(PHAsset *)asset synchronous:(BOOL)synchronous handler:(void (^)(NSData * imageData, NSString * dataUTI, UIImageOrientation orientation, NSDictionary * info))handler; 193 | 194 | #pragma mark - Fetch Video 195 | //+ (int32_t)fetchVideoWith:(PHAsset *)asset 196 | 197 | 198 | #pragma mark - Fetch Audio 199 | 200 | @end 201 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZMediaFetcher/WZToast.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZToast.h 3 | 4 | 5 | 6 | #import 7 | typedef NS_ENUM(NSUInteger, WZToastPositionType) { 8 | WZToastPositionTypeMiddle = 0, 9 | WZToastPositionTypeTop = 1, 10 | WZToastPositionTypeBottom = 2, 11 | }; 12 | 13 | @interface WZToast : UIView 14 | 15 | 16 | + (void)toastWithContent:(NSString *)content; 17 | 18 | + (void)toastWithContent:(NSString *)content duration:(NSTimeInterval)duration; 19 | 20 | + (void)toastWithContent:(NSString *)content position:(WZToastPositionType)position; 21 | 22 | + (void)toastWithContent:(NSString *)content 23 | position:(WZToastPositionType)position 24 | duration:(NSTimeInterval)duration; 25 | 26 | + (void)toastWithContent:(NSString *)content 27 | position:(WZToastPositionType)position 28 | customOriginY:(CGFloat)customOriginY; 29 | 30 | + (void)toastWithContent:(NSString *)content 31 | position:(WZToastPositionType)position 32 | customOrigin:(CGPoint)customOrigin; 33 | @end 34 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZMediaFetcher/WZToast.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZToast.m 3 | 4 | 5 | #import "WZToast.h" 6 | 7 | @implementation WZToast 8 | 9 | + (void)toastWithContent:(NSString *)content { 10 | [WZToast toastWithContent:content position:WZToastPositionTypeMiddle]; 11 | } 12 | 13 | + (void)toastWithContent:(NSString *)content duration:(NSTimeInterval)duration { 14 | [WZToast toastWithContent:content position:WZToastPositionTypeMiddle duration:duration]; 15 | } 16 | 17 | + (void)toastWithContent:(NSString *)content position:(WZToastPositionType)position { 18 | [WZToast toastWithContent:content position:position duration:1.5]; 19 | } 20 | 21 | + (void)toastWithContent:(NSString *)content 22 | position:(WZToastPositionType)position 23 | duration:(NSTimeInterval)duration { 24 | [WZToast toastWithContent:content position:position duration:duration customOriginY:false customOriginYMake:0 customOrigin:false customOriginMake:CGPointZero]; 25 | } 26 | 27 | + (void)toastWithContent:(NSString *)content 28 | position:(WZToastPositionType)position 29 | customOriginY:(CGFloat)customOriginY { 30 | [WZToast toastWithContent:content position:position duration:1.5 customOriginY:true customOriginYMake:customOriginY customOrigin:false customOriginMake:CGPointZero]; 31 | } 32 | 33 | + (void)toastWithContent:(NSString *)content 34 | position:(WZToastPositionType)position 35 | customOrigin:(CGPoint)customOrigin { 36 | [WZToast toastWithContent:content position:position duration:1.5 customOriginY:false customOriginYMake:0 customOrigin:true customOriginMake:customOrigin]; 37 | } 38 | 39 | + (void)toastWithContent:(NSString *)content 40 | position:(WZToastPositionType)position 41 | duration:(NSTimeInterval)duration 42 | customOriginY:(BOOL)customOriginY 43 | customOriginYMake:(CGFloat)customOriginYMake 44 | customOrigin:(BOOL)customOrigin 45 | customOriginMake:(CGPoint)customOriginMake 46 | { 47 | WZToast *toastView = [[WZToast alloc] init]; 48 | toastView.alpha = 0.0; 49 | toastView.layer.cornerRadius = 10.0; 50 | toastView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7]; 51 | 52 | //structure layout 53 | if ([content isKindOfClass:[NSString class]] && ![content isEqualToString:@""]) { 54 | 55 | UILabel *toastLabel = [[UILabel alloc] init]; 56 | toastLabel.textColor = [UIColor whiteColor]; 57 | toastLabel.backgroundColor = [UIColor clearColor]; 58 | toastLabel.font = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]]; 59 | toastLabel.text = content; 60 | toastLabel.textAlignment = NSTextAlignmentCenter; 61 | toastLabel.numberOfLines = 0; 62 | UIWindow *forefrontWindow = [WZToast getFrontWindow]; 63 | [toastView addSubview:toastLabel]; 64 | [forefrontWindow addSubview:toastView]; 65 | 66 | 67 | //structure detail 68 | CGFloat labelLRSpacingSum = 30; 69 | CGFloat labelTBSpacingSum = 30; 70 | CGFloat labelH = [toastLabel sizeThatFits:CGSizeZero].height + 30; 71 | CGFloat labelW = [toastLabel sizeThatFits:CGSizeZero].width; 72 | CGFloat boundingSpacing = 40.0; 73 | 74 | CGFloat toastRestrictW = [UIScreen mainScreen].bounds.size.width - boundingSpacing * 2.0; 75 | 76 | if (labelW > toastRestrictW) { 77 | CGFloat calculatelabelW = toastRestrictW - labelLRSpacingSum; 78 | labelH = [toastLabel sizeThatFits:CGSizeMake(calculatelabelW - labelLRSpacingSum, 0)].height 79 | + labelTBSpacingSum 80 | - 4.0; 81 | labelW = [toastLabel sizeThatFits:CGSizeMake(calculatelabelW - labelLRSpacingSum, 0)].width; 82 | } 83 | toastLabel.frame = CGRectMake(labelLRSpacingSum / 2.0 84 | , 0.0 85 | , labelW 86 | , labelH); 87 | CGFloat toastW = labelW + labelLRSpacingSum; 88 | CGFloat toastH = labelH; 89 | CGFloat toastX = ([UIScreen mainScreen].bounds.size.width - toastW) / 2.0; 90 | CGFloat toastY = ([UIScreen mainScreen].bounds.size.height - toastH) / 2.0; 91 | 92 | //Y坐标的计算 93 | switch (position) { 94 | break; 95 | case WZToastPositionTypeTop: 96 | { 97 | toastY = 100.0; 98 | } 99 | break; 100 | 101 | case WZToastPositionTypeBottom: 102 | { 103 | toastY = [UIScreen mainScreen].bounds.size.height - toastH - 100.0; 104 | } 105 | break; 106 | default/*WZToastPositionTypeMiddle*/: 107 | break; 108 | } 109 | 110 | 111 | if (customOriginY) { 112 | toastY = customOriginYMake; 113 | } 114 | 115 | if (customOrigin) { 116 | toastX = customOriginMake.x; 117 | toastY = customOriginMake.y; 118 | } 119 | 120 | // style normal middle 121 | toastView.frame = CGRectMake(toastX 122 | ,toastY 123 | , toastW 124 | , toastH); 125 | 126 | //part of effect 127 | [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{ 128 | toastView.alpha = 1.0; 129 | } completion:^(BOOL finished) { 130 | [UIView animateWithDuration:0.8 delay:0.5 + 0.25 options:UIViewAnimationOptionAllowUserInteraction animations:^{ 131 | toastView.alpha = 0.0; 132 | } completion:^(BOOL finished) { 133 | [toastView removeFromSuperview]; 134 | }]; 135 | }]; 136 | } 137 | } 138 | 139 | + (UIWindow *)getFrontWindow { 140 | UIWindow *frontWindow = nil; 141 | NSEnumerator *frontToBackWindows = [[UIApplication sharedApplication].windows reverseObjectEnumerator]; 142 | for (UIWindow *window in frontToBackWindows) { 143 | BOOL isWindowOnMainScreen = (window.screen == [UIScreen mainScreen]); //当前屏幕 144 | BOOL isWindowVisible = (!window.hidden && window.alpha > 0.001); //透明度 145 | BOOL isWindowNormalLevel = (window.windowLevel == UIWindowLevelNormal); // 146 | if (isWindowOnMainScreen && isWindowVisible && isWindowNormalLevel) { 147 | frontWindow = window; 148 | } 149 | } 150 | 151 | if (!frontWindow) { 152 | frontWindow = [UIApplication sharedApplication].windows.lastObject; 153 | } 154 | 155 | return frontWindow; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZAssetBrowseController/WZAssetBrowseController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZAssetBrowseController.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZImageBrowseController.h" 10 | 11 | 12 | @interface WZAssetBrowseController : WZImageBrowseController 13 | 14 | @property (nonatomic, assign) PHImageRequestID imageRequestID;//请求图片的请求ID 15 | @property (nonatomic, assign) PHImageRequestID imageDataRequestID;//请求图片(data)的请求ID 16 | 17 | /** 18 | * 用于判断滑动的图片是否越界 19 | * 20 | * @return 是否越界 21 | */ 22 | - (BOOL)overloadJudgement; 23 | 24 | /** 25 | * 用于计算当前选中的图片数目的接口 26 | */ 27 | - (void)caculateSelected; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZAssetBrowseController/WZAssetBrowseController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZAssetBrowseController.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZAssetBrowseController.h" 10 | #import "WZAssetBrowseNavigationView.h" 11 | #import "WZAssetBrowseToolView.h" 12 | 13 | @interface WZAssetBrowseController () 14 | 15 | @property (nonatomic, strong) WZAssetBrowseNavigationView *navigationView;//顶部导航条 16 | @property (nonatomic, strong) WZAssetBrowseToolView *toolView;//底部工具条 17 | 18 | @end 19 | 20 | @implementation WZAssetBrowseController 21 | 22 | #pragma mark - Lifecycle 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | } 26 | 27 | - (void)dealloc { 28 | NSLog(@"%s", __func__); 29 | } 30 | 31 | #pragma mark - CreateViews 32 | - (void)createViews { 33 | [self.view addSubview:self.navigationView]; 34 | [self.view addSubview:self.toolView]; 35 | [self caculateSelected]; 36 | self.view.backgroundColor = [UIColor blackColor]; 37 | 38 | } 39 | 40 | 41 | #pragma mark - WZProtocolAssetBrowseNaviagtion 42 | - (void)backAction { 43 | if ([self.imagesBrowseDelegate respondsToSelector:@selector(backAction)]) { 44 | [self.imagesBrowseDelegate backAction]; 45 | } 46 | [self dismissViewControllerAnimated:true completion:^{}]; 47 | } 48 | 49 | - (void)selectedAction { 50 | if ([self overloadJudgement] && !self.currentMediaAsset.selected) { 51 | return; 52 | } 53 | 54 | self.currentMediaAsset.selected = !self.currentMediaAsset.selected; 55 | _navigationView.selectedButton.selected = self.currentMediaAsset.selected; 56 | [self caculateSelected]; 57 | } 58 | 59 | #pragma mark - WZProtocolAssetBrowseTool 60 | - (void)selectedOrigionAction { 61 | self.currentMediaAsset.origion = !self.currentMediaAsset.origion; 62 | self.toolView.selectedButtonClear.selected = self.currentMediaAsset.origion; 63 | [self fetchOrigion]; 64 | } 65 | 66 | - (void)completeAction { 67 | [self dismissViewControllerAnimated:false completion:^{ 68 | if ([self.imagesBrowseDelegate respondsToSelector:@selector(send)]) { 69 | [self.imagesBrowseDelegate send]; 70 | } 71 | }]; 72 | } 73 | 74 | #pragma mark - Match image 75 | - (void)matchThumnailImageWith:(WZImageContainerController *)VC { 76 | [super matchThumnailImageWith:VC]; 77 | 78 | NSUInteger index = VC.index; 79 | if (index < self.mediaAssetArray.count ) { 80 | WZMediaAsset *asset = self.mediaAssetArray[index]; 81 | if (asset.imageThumbnail) { 82 | [VC matchingPicture:asset.imageThumbnail]; 83 | } else { 84 | [WZMediaFetcher fetchThumbnailWithAsset:asset.asset synchronous:false handler:^(UIImage *thumbnail) { 85 | asset.imageThumbnail = thumbnail; 86 | [VC matchingPicture:asset.imageThumbnail]; 87 | }]; 88 | } 89 | } 90 | } 91 | 92 | - (void)matchClearImageWith:(WZImageContainerController *)VC { 93 | [super matchClearImageWith:VC]; 94 | 95 | NSUInteger index = VC.index; 96 | WZMediaAsset *asset = nil; 97 | if (index < self.mediaAssetArray.count ) { 98 | asset = self.mediaAssetArray[index]; 99 | 100 | if (asset.clearPath || asset.imageClear) { 101 | if (asset.imageClear) { 102 | [VC matchingPicture:asset.imageClear]; 103 | [self caculateImageDataWithImage:asset.imageClear]; 104 | } else { 105 | UIImage *image = [UIImage imageWithContentsOfFile:asset.clearPath]; 106 | [VC matchingPicture:image]; 107 | [self caculateImageDataWithImage:image]; 108 | } 109 | 110 | } else if (asset.asset) { 111 | //根据 PHAsset callback 112 | //block回调可能会引起图片紊乱(重用) 请求前先将之前的request cancel掉 113 | 114 | [[PHImageManager defaultManager] cancelImageRequest:_imageRequestID]; 115 | [[PHImageManager defaultManager] cancelImageRequest:_imageDataRequestID]; 116 | 117 | if (asset.origion) { 118 | _imageRequestID = [WZMediaFetcher fetchOrigionWith:asset.asset synchronous:false handler:^(UIImage *origion) { 119 | [VC matchingPicture:origion]; 120 | }]; 121 | } else { 122 | //渲染成本太高 不选源图 123 | _imageRequestID = [WZMediaFetcher fetchImageWithAsset:asset.asset costumSize:WZMEDIAASSET_CUSTOMSIZE synchronous:false handler:^(UIImage *image) { 124 | [VC matchingPicture:image]; 125 | }]; 126 | } 127 | 128 | //数据计算 129 | _imageDataRequestID = [WZMediaFetcher fetchImageWithAsset:asset.asset synchronous:false handler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { 130 | [self caculateImageDataWithData:imageData]; 131 | }]; 132 | } 133 | } 134 | 135 | { 136 | //配置其他的属性 137 | self.currentMediaAsset = asset; 138 | self.currentContainerVC = VC; 139 | self.navigationView.selectedButton.selected = self.currentMediaAsset.selected; 140 | self.toolView.selectedButtonClear.selected = self.currentMediaAsset.origion; 141 | self.navigationView.titleLabel.text = [NSString stringWithFormat:@"当前页面ID:%ld", index]; 142 | 143 | } 144 | } 145 | 146 | 147 | 148 | #pragma mark - private method 149 | - (void)caculateSelected { 150 | NSUInteger restrictNumber = 0; 151 | for (WZMediaAsset *asset in self.mediaAssetArray) { 152 | if (asset.selected == true) { 153 | restrictNumber = restrictNumber + 1; 154 | } 155 | } 156 | self.toolView.restrictNumber(restrictNumber); 157 | } 158 | 159 | - (BOOL)overloadJudgement { 160 | if (self.restrictNumber == 0) { 161 | return false; 162 | } 163 | 164 | NSUInteger restrictNumber = 0; 165 | for (WZMediaAsset *asset in self.mediaAssetArray) { 166 | if (asset.selected == true) { 167 | restrictNumber = restrictNumber + 1; 168 | } 169 | } 170 | 171 | if (self.restrictNumber <= restrictNumber) { 172 | return true; 173 | } 174 | 175 | return false; 176 | } 177 | 178 | - (void)caculateImageDataWithImage:(UIImage *)image { 179 | if (!image) { 180 | return; 181 | } 182 | NSData *data = UIImagePNGRepresentation(image); 183 | [self caculateImageDataWithData:data]; 184 | } 185 | 186 | - (void)caculateImageDataWithData:(NSData *)data { 187 | self.toolView.fetchClearInfo([NSString stringWithFormat:@"%.3lf M", data.length / 1000.0 / 1000.0]); 188 | } 189 | 190 | - (void)fetchOrigion { 191 | if (self.currentMediaAsset.origion) { 192 | [WZMediaFetcher fetchOrigionWith:self.currentMediaAsset.asset synchronous:true handler:^(UIImage *origion) { 193 | [self.currentContainerVC matchingPicture:origion]; 194 | }]; 195 | } 196 | } 197 | 198 | #pragma mark - Accessor 199 | - (WZAssetBrowseNavigationView *)navigationView { 200 | if (!_navigationView) { 201 | _navigationView = [WZAssetBrowseNavigationView customAssetBrowseNavigationWithDelegate:(id)self]; 202 | } 203 | return _navigationView; 204 | } 205 | 206 | - (WZAssetBrowseToolView *)toolView { 207 | if (!_toolView) { 208 | _toolView = [WZAssetBrowseToolView customAssetBrowseToolWithDelegate:(id)self]; 209 | } 210 | return _toolView; 211 | } 212 | 213 | @end 214 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZAssetBrowseController/WZAssetBrowseNavigationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZAssetBrowseNavigationView.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol WZProtocolAssetBrowseNaviagtion 12 | 13 | - (void)backAction;//返回代理事件 14 | - (void)selectedAction;//选中代理事件 15 | 16 | @end 17 | 18 | @interface WZAssetBrowseNavigationView : UIView 19 | 20 | @property (nonatomic, weak) id delegate; 21 | @property (nonatomic, strong) UIButton *backButton; 22 | @property (nonatomic, strong) UIButton *selectedButton; 23 | @property (nonatomic, strong) UILabel *titleLabel; 24 | 25 | + (instancetype)customAssetBrowseNavigationWithDelegate:(id)delegate; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZAssetBrowseController/WZAssetBrowseNavigationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZAssetBrowseNavigationView.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZAssetBrowseNavigationView.h" 10 | 11 | @implementation WZAssetBrowseNavigationView 12 | 13 | + (instancetype)customAssetBrowseNavigationWithDelegate:(id)delegate { 14 | WZAssetBrowseNavigationView *navigation = [[WZAssetBrowseNavigationView alloc] initWithFrame:CGRectMake(0.0, 0.0, [UIScreen mainScreen].bounds.size.width, 64.0)]; 15 | navigation.delegate = delegate; 16 | navigation.backgroundColor = [UIColor colorWithRed:51.0 / 255 green:51.0 / 255 blue:51.0 / 255 alpha:0.4]; 17 | 18 | CGFloat buttonHW = 44.0; 19 | navigation.backButton = [[UIButton alloc] initWithFrame:CGRectMake(5, 20.0, buttonHW, buttonHW)]; 20 | navigation.selectedButton = [[UIButton alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - buttonHW, 20.0, buttonHW, buttonHW)]; 21 | navigation.titleLabel.textAlignment = NSTextAlignmentCenter; 22 | navigation.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(buttonHW, 20.0, [UIScreen mainScreen].bounds.size.width - buttonHW * 2.0, buttonHW)]; 23 | navigation.titleLabel.textAlignment = NSTextAlignmentCenter; 24 | navigation.titleLabel.textColor = [UIColor whiteColor]; 25 | 26 | [navigation addSubview:navigation.titleLabel]; 27 | [navigation addSubview:navigation.selectedButton]; 28 | [navigation addSubview:navigation.backButton]; 29 | 30 | [navigation.backButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 31 | [navigation.selectedButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 32 | 33 | [navigation.backButton setImage:[UIImage imageNamed:@"imagesBrowse_back"] forState:UIControlStateNormal]; 34 | [navigation.selectedButton setImage:[UIImage imageNamed:@"message_oeuvre_btn_normal"] forState:UIControlStateNormal]; 35 | [navigation.selectedButton setImage:[UIImage imageNamed:@"message_oeuvre_btn_selected"] forState:UIControlStateSelected]; 36 | 37 | navigation.titleLabel.text = @"图片"; 38 | [navigation.selectedButton addTarget:navigation action:@selector(clickedBtn:) forControlEvents:UIControlEventTouchUpInside]; 39 | [navigation.backButton addTarget:navigation action:@selector(clickedBtn:) forControlEvents:UIControlEventTouchUpInside]; 40 | 41 | return navigation; 42 | } 43 | 44 | - (void)clickedBtn:(UIButton *)sender { 45 | if (sender == self.backButton) { 46 | if ([_delegate respondsToSelector:@selector(backAction)]) { 47 | [_delegate backAction]; 48 | } 49 | } else if (sender == self.selectedButton) { 50 | if ([_delegate respondsToSelector:@selector(selectedAction)]) { 51 | [_delegate selectedAction]; 52 | } 53 | } 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZAssetBrowseController/WZAssetBrowseToolView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZAssetBrowseToolView.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol WZProtocolAssetBrowseTool 12 | 13 | - (void)selectedOrigionAction;//选择原尺寸图片的代理事件 14 | - (void)completeAction;//发送代理事件 15 | 16 | @end 17 | 18 | @interface WZAssetBrowseToolView : UIView 19 | 20 | @property (nonatomic, weak) id delegate; 21 | @property (nonatomic, strong) void (^fetchClearInfo)(NSString *info); 22 | @property (nonatomic, strong) void (^restrictNumber)(NSUInteger restrictNumber); 23 | @property (nonatomic, strong) UIButton *selectedButtonClear; 24 | @property (nonatomic, strong) UILabel *clearInfoLabel; 25 | @property (nonatomic, strong) UIButton *completeButton; 26 | @property (nonatomic, strong) UILabel *countLabel; 27 | 28 | + (instancetype)customAssetBrowseToolWithDelegate:(id)delegate; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZAssetBrowseController/WZAssetBrowseToolView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZAssetBrowseToolView.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZAssetBrowseToolView.h" 10 | 11 | @implementation WZAssetBrowseToolView 12 | 13 | + (instancetype)customAssetBrowseToolWithDelegate:(id)delegate { 14 | WZAssetBrowseToolView *tool = [[WZAssetBrowseToolView alloc] init]; 15 | tool.delegate = delegate; 16 | CGFloat toolH = 49.0; 17 | tool.frame = CGRectMake(0.0, [UIScreen mainScreen].bounds.size.height - toolH, [UIScreen mainScreen].bounds.size.width, toolH); 18 | tool.backgroundColor = [UIColor colorWithRed:51.0 / 255 green:51.0 / 255 blue:51.0 / 255 alpha:0.4]; 19 | 20 | tool.selectedButtonClear = [UIButton buttonWithType:UIButtonTypeCustom]; 21 | CGFloat button_origionHW = 72 / 2.0; 22 | tool.selectedButtonClear.frame = CGRectMake(5.0, (toolH - button_origionHW)/2.0 , button_origionHW, button_origionHW); 23 | 24 | [tool.selectedButtonClear setImage:[UIImage imageNamed:@"asset_selectedOrigion_normal"] forState:UIControlStateNormal]; 25 | [tool.selectedButtonClear setImage:[UIImage imageNamed:@"asset_selectedOrigion_selected"] forState:UIControlStateSelected]; 26 | 27 | tool.clearInfoLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(tool.selectedButtonClear.frame), 0.0, [UIScreen mainScreen].bounds.size.width / 2.0, toolH)]; 28 | tool.clearInfoLabel.text = @"选择原图"; 29 | tool.clearInfoLabel.textColor = [UIColor whiteColor]; 30 | 31 | __weak typeof(tool) weakTool = tool; 32 | tool.fetchClearInfo = ^(NSString *info){ 33 | weakTool.clearInfoLabel.text = [NSString stringWithFormat:@"选择原图(%@)", info]; 34 | }; 35 | 36 | tool.completeButton = [UIButton buttonWithType:UIButtonTypeCustom]; 37 | CGFloat completeButtonHW = 45.0; 38 | tool.completeButton.frame = CGRectMake([UIScreen mainScreen].bounds.size.width - completeButtonHW - 15.0, (toolH - completeButtonHW)/2.0, completeButtonHW, completeButtonHW); 39 | [tool.completeButton setTitle:@"发送" forState:UIControlStateNormal]; 40 | tool.completeButton.titleLabel.font = [UIFont systemFontOfSize:16.0]; 41 | [tool.completeButton setTitleColor:[UIColor colorWithRed:254.0 / 255 green:191.0 / 255 blue:39.0 / 255 alpha:1.0] forState:UIControlStateNormal]; 42 | [tool.completeButton setTitleColor:[UIColor colorWithRed:254.0 / 255 green:191.0 / 255 blue:39.0 / 255 alpha:1.0] forState:UIControlStateHighlighted]; 43 | CGFloat label_HW = 20.0; 44 | 45 | tool.countLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMinX(tool.completeButton.frame) -label_HW, (toolH - label_HW)/2.0, label_HW, label_HW)]; 46 | tool.countLabel.backgroundColor = [UIColor colorWithRed:254.0 / 255 green:191.0 / 255 blue:39.0 / 255 alpha:1.0]; 47 | tool.countLabel.text = @"0"; 48 | tool.restrictNumber = ^(NSUInteger restrictNumber){ 49 | weakTool.countLabel.text = [NSString stringWithFormat:@"%ld", restrictNumber]; 50 | }; 51 | tool.countLabel.layer.cornerRadius = label_HW / 2.0; 52 | tool.countLabel.layer.masksToBounds = true; 53 | tool.countLabel.textAlignment = NSTextAlignmentCenter; 54 | tool.countLabel.textColor = [UIColor whiteColor]; 55 | 56 | [tool addSubview:tool.selectedButtonClear]; 57 | [tool addSubview:tool.completeButton]; 58 | [tool addSubview:tool.clearInfoLabel]; 59 | [tool addSubview:tool.countLabel]; 60 | 61 | [tool.completeButton addTarget:tool action:@selector(clickedBtn:) forControlEvents:UIControlEventTouchUpInside]; 62 | [tool.selectedButtonClear addTarget:tool action:@selector(clickedBtn:) forControlEvents:UIControlEventTouchUpInside]; 63 | return tool; 64 | } 65 | 66 | - (void)clickedBtn:(UIButton *)sender { 67 | if (sender == self.selectedButtonClear) { 68 | if ([_delegate respondsToSelector:@selector(selectedOrigionAction)]) { 69 | [_delegate selectedOrigionAction]; 70 | } 71 | } else if (sender == self.completeButton) { 72 | if ([_delegate respondsToSelector:@selector(completeAction)]) { 73 | [_delegate completeAction]; 74 | } 75 | } 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZImageBrowseController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZImageBrowseController.h 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WZImageContainerController.h" 11 | #import "UIImageView+WebCache.h" 12 | 13 | @protocol WZProtocolImageBrowse 14 | 15 | - (void)backAction;//返回代理事件 16 | - (void)send;//发送代理事件 17 | 18 | @end 19 | 20 | //图片浏览容器控制器 21 | @interface WZImageBrowseController : UIPageViewController 22 | 23 | @property (nonatomic, strong) id imagesBrowseDelegate;//代理 24 | @property (nonatomic, strong) NSArray *mediaAssetArray;//选中的mdeiaAsset集合 25 | @property (nonatomic, strong) NSArray *imageContainersReuseableArray;//图片容器(复用) 26 | @property (nonatomic, strong) WZImageContainerController *currentContainerVC;//当前的图片容器 27 | @property (nonatomic, assign) NSInteger currentIndex;//当前图片的角标 28 | @property (nonatomic, assign) NSInteger numberOfIndexs;//图片的角标极值 29 | @property (nonatomic, assign) NSUInteger restrictNumber;//限制选图数目 =0时无选图限制 30 | @property (nonatomic, strong) WZMediaAsset *currentMediaAsset;//当前集合 31 | 32 | - (void)showInIndex:(NSInteger)index animated:(BOOL)animated;//控制器定位 33 | - (void)matchThumnailImageWith:(WZImageContainerController *)VC;//控制器缩略图匹配 34 | - (void)matchClearImageWith:(WZImageContainerController *)VC;//控制器上清晰图匹配 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZImageBrowseController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZImageBrowseController.m 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZImageBrowseController.h" 10 | 11 | #pragma mark - WZImageBrowseController 12 | @interface WZImageBrowseController () 18 | 19 | @end 20 | 21 | @implementation WZImageBrowseController 22 | 23 | #pragma mark - Initialize 24 | - (instancetype)initWithTransitionStyle:(UIPageViewControllerTransitionStyle)style navigationOrientation:(UIPageViewControllerNavigationOrientation)navigationOrientation options:(NSDictionary *)options { 25 | NSMutableDictionary *configOptions = [NSMutableDictionary dictionaryWithDictionary:options?:@{}]; 26 | //页面间隔设置 27 | configOptions[UIPageViewControllerOptionInterPageSpacingKey] = @(10); 28 | if (self = [super initWithTransitionStyle:UIPageViewControllerTransitionStyleScroll navigationOrientation:navigationOrientation options:configOptions]) { 29 | //自定义模态跳转模式 30 | // self.modalPresentationStyle = UIModalPresentationCustom; 31 | //模态过渡模式 32 | self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; 33 | /* 34 | UIModalTransitionStyleCoverVertical:画面从下向上徐徐弹出,关闭时向下隐 藏(默认方式)。 35 | UIModalTransitionStyleFlipHorizontal:从前一个画面的后方,以水平旋转的方式显示后一画面。 36 | UIModalTransitionStyleCrossDissolve:前一画面逐渐消失的同时,后一画面逐渐显示。 37 | */ 38 | //自定义跳转代理 39 | // self.transitioningDelegate = self; 40 | 41 | _currentIndex = 0; 42 | } 43 | return self; 44 | } 45 | 46 | #pragma mark - Lifecycle 47 | - (void)viewDidLoad { 48 | [super viewDidLoad]; 49 | self.view.backgroundColor = [UIColor whiteColor]; 50 | self.automaticallyAdjustsScrollViewInsets = false; 51 | self.dataSource = self; 52 | self.delegate = self; 53 | [self createViews]; 54 | 55 | for (UIView *view in self.view.subviews) { 56 | if ([view isKindOfClass:[UIScrollView class]]) { 57 | UIScrollView *scroll = (UIScrollView *)view; 58 | // NSLog(@"___%@", scroll.delegate);//打印得知代理为null 59 | scroll.delegate = self; 60 | for (UIGestureRecognizer *gesture in scroll.gestureRecognizers) { 61 | if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) { 62 | ((UIPanGestureRecognizer *)gesture).maximumNumberOfTouches = 1; //不能双手pan 能够解决pageView中的一个BUG 63 | break; 64 | } 65 | } 66 | break; 67 | } 68 | } 69 | } 70 | 71 | 72 | 73 | 74 | - (void)createViews { 75 | } 76 | 77 | #pragma mark - WZProtocolImageBrowseNavigationView 78 | - (void)leftButtunAction { 79 | [self dismissViewControllerAnimated:true completion:^{}]; 80 | } 81 | - (void)rightButtunAction { 82 | } 83 | 84 | #pragma mark - Match VC use index 85 | - (WZImageContainerController *)matchControllerIndexWithIndex:(NSInteger)index { 86 | 87 | if (index < 0 88 | || index > _numberOfIndexs) { 89 | return nil; 90 | } 91 | 92 | WZImageContainerController *VC = self.imageContainersReuseableArray[index % self.imageContainersReuseableArray.count]; 93 | VC.index = index; 94 | [self matchThumnailImageWith:VC]; 95 | return VC; 96 | } 97 | 98 | #pragma mark - Show VC in index 99 | - (void)showInIndex:(NSInteger)index animated:(BOOL)animated { 100 | 101 | if (index <= 0) {index = 0;} 102 | if (index > _numberOfIndexs) {index = _numberOfIndexs;} 103 | _currentIndex = index; 104 | 105 | WZImageContainerController *VC = [self matchControllerIndexWithIndex:_currentIndex]; 106 | [self matchClearImageWith:VC]; 107 | [self setViewControllers:@[VC] direction:UIPageViewControllerNavigationDirectionForward animated:animated completion:^(BOOL finished) {}]; 108 | self.currentContainerVC = VC; 109 | } 110 | 111 | 112 | #pragma mark - Match image 113 | - (void)matchThumnailImageWith:(WZImageContainerController *)VC { 114 | if (!VC) { 115 | return; 116 | } 117 | NSUInteger index = VC.index; 118 | if (index >= _mediaAssetArray.count) { 119 | return; 120 | } 121 | } 122 | 123 | - (void)matchClearImageWith:(WZImageContainerController *)VC { 124 | if (!VC) { 125 | return; 126 | } 127 | NSUInteger index = VC.index; 128 | if (index >= _mediaAssetArray.count) { 129 | return; 130 | } 131 | } 132 | 133 | #pragma mark - WZProtocolImageScrollView 134 | - (void)singleTap:(UIGestureRecognizer *)gesture { 135 | //单击 136 | } 137 | 138 | - (void)doubleTap:(UIGestureRecognizer *)gesture { 139 | //变焦动画 140 | [self.currentContainerVC focusingWithGesture:gesture]; 141 | } 142 | 143 | - (void)longPress:(UIGestureRecognizer *)gesture { 144 | //保存图片 145 | 146 | } 147 | 148 | #pragma mark - WZProtocolImageContainer 149 | 150 | #pragma mark - UIPageViewControllerDelegate 151 | - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { 152 | WZImageContainerController *VC = pageViewController.viewControllers.firstObject; 153 | if (self.currentContainerVC != VC) { 154 | [self matchClearImageWith:VC]; 155 | } 156 | } 157 | 158 | #pragma mark - UIPageViewControllerDataSource 159 | - (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(WZImageContainerController *)viewController { 160 | return [self matchControllerIndexWithIndex:viewController.index - 1]; 161 | } 162 | 163 | - (nullable UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(WZImageContainerController *)viewController { 164 | return [self matchControllerIndexWithIndex:viewController.index + 1]; 165 | } 166 | 167 | #pragma mark - UIViewControllerTransitioningDelegate 168 | - (nullable id )animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { 169 | return nil; 170 | } 171 | 172 | - (nullable id )animationControllerForDismissedController:(UIViewController *)dismissed { 173 | return nil; 174 | } 175 | 176 | #pragma mark - Accessor 177 | - (NSArray *)imageContainersReuseableArray { 178 | if (!_imageContainersReuseableArray) { 179 | NSMutableArray *tmpMArr = [NSMutableArray array]; 180 | NSUInteger reuseCount = 5;//重用控制器数目 181 | for (NSUInteger i = 0; i < reuseCount; i++) { 182 | WZImageContainerController *VC = [[WZImageContainerController alloc] init]; 183 | VC.index = i; 184 | VC.delegate = (id)self; 185 | VC.mainVC = self; 186 | [tmpMArr addObject:VC]; 187 | } 188 | _imageContainersReuseableArray = [NSArray arrayWithArray:tmpMArr]; 189 | } 190 | return _imageContainersReuseableArray; 191 | } 192 | 193 | - (void)setMediaAssetArray:(NSArray *)mediaAssetArray { 194 | if ([mediaAssetArray isKindOfClass:[NSArray class]]) { 195 | _mediaAssetArray = mediaAssetArray; 196 | _numberOfIndexs = _mediaAssetArray.count - 1; 197 | if (_numberOfIndexs < 0) { 198 | _numberOfIndexs = 0; 199 | } 200 | } 201 | } 202 | 203 | @end 204 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZImageContainerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZImageContainerController.h 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/5/24. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WZImageScrollView.h" 11 | #import "WZRoundRenderLayer.h" 12 | 13 | @interface WZRemoteImgaeProgressView : UIView 14 | 15 | @property (nonatomic, strong) WZRoundRenderLayer *downloadProgressLayer;//layer进度条 16 | 17 | /** 18 | * 自定义进度条 19 | * 20 | * @return 自定义进度条 21 | */ 22 | + (instancetype)customProgress; 23 | 24 | /** 25 | * 进度比例 26 | * 27 | * @param rate 0 <= rate <= 1 28 | */ 29 | - (void)setProgressRate:(float)rate; 30 | 31 | @end 32 | 33 | @class WZImageContainerController; 34 | @protocol WZProtocolImageContainer 35 | 36 | @end 37 | 38 | /** 39 | * 图片容器控制器 40 | */ 41 | @interface WZImageContainerController : UIViewController 42 | 43 | @property (nonatomic, weak) UIViewController *mainVC;//手势代理对象 44 | @property (nonatomic, weak) id delegate;// 45 | @property (nonatomic, assign) NSInteger index;//当前图片角标 46 | 47 | //进度显示(for remote) 48 | @property (nonatomic, strong) WZRemoteImgaeProgressView *progress; 49 | 50 | /** 51 | * 匹配图片接口 52 | * 53 | * @param image 需要匹配的图片 54 | */ 55 | - (void)matchingPicture:(UIImage *)image; 56 | 57 | /** 58 | * 匹配经过缩放的图片接口 59 | * 60 | * @param gesture 缩放手势 61 | */ 62 | - (void)focusingWithGesture:(UIGestureRecognizer *)gesture; 63 | @end 64 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZImageContainerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZImageContainerController.m 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/5/24. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZImageContainerController.h" 10 | 11 | @implementation WZRemoteImgaeProgressView 12 | 13 | #pragma mark - Initialize 14 | + (instancetype)customProgress { 15 | 16 | //进度的图的设置 17 | WZRemoteImgaeProgressView *progress = [[WZRemoteImgaeProgressView alloc] init]; 18 | CGFloat viewHW = 50; 19 | progress.downloadProgressLayer = [[WZRoundRenderLayer alloc] initWithCircleRadius:viewHW / 2.0 layerLineWidth:5]; 20 | progress.frame = CGRectMake(0.0, 0.0, viewHW, viewHW); 21 | [progress.layer addSublayer:progress.downloadProgressLayer]; 22 | return progress; 23 | } 24 | 25 | #pragma mark - Public 26 | - (void)setProgressRate:(float)rate { 27 | if (rate > 1) {rate = 1.0;}; 28 | if (self.downloadProgressLayer) { 29 | self.downloadProgressLayer.renderAngle = (M_PI * 2.0) * rate; 30 | } 31 | 32 | } 33 | 34 | #pragma mark - Override 35 | - (void)setFrame:(CGRect)frame { 36 | [super setFrame:CGRectMake(([UIScreen mainScreen].bounds.size.width - frame.size.width) / 2.0, ([UIScreen mainScreen].bounds.size.height - frame.size.height) / 2.0, frame.size.width, frame.size.height)]; 37 | } 38 | 39 | @end 40 | 41 | @interface WZImageContainerController() 42 | 43 | @property (nonatomic, strong) WZImageScrollView *scrollPictureView; 44 | 45 | @end 46 | 47 | @implementation WZImageContainerController 48 | 49 | - (instancetype)init 50 | { 51 | self = [super init]; 52 | if (self) { 53 | _scrollPictureView = [[WZImageScrollView alloc] init]; 54 | [self.view addSubview:_scrollPictureView]; 55 | [self.view addSubview:self.progress]; 56 | } 57 | return self; 58 | } 59 | 60 | - (void)setMainVC:(UIViewController *)mainVC { 61 | if ([mainVC isKindOfClass:[UIViewController class]]) { 62 | _mainVC = mainVC; 63 | _scrollPictureView.imageScrollDelegate = (id)_mainVC; 64 | } 65 | } 66 | 67 | #pragma mark - Life cycle 68 | - (void)viewDidLoad { 69 | [super viewDidLoad]; 70 | } 71 | 72 | - (void)viewWillAppear:(BOOL)animated { 73 | [super viewWillAppear:animated]; 74 | } 75 | 76 | #pragma mark - Public 77 | - (void)matchingPicture:(UIImage *)image { 78 | [_scrollPictureView matchingPicture:image]; 79 | } 80 | - (void)focusingWithGesture:(UIGestureRecognizer *)gesture { 81 | [_scrollPictureView matchZoomWithGesture:gesture]; 82 | } 83 | 84 | 85 | #pragma mark - Accessor 86 | - (WZRemoteImgaeProgressView *)progress { 87 | if (!_progress) { 88 | _progress = [WZRemoteImgaeProgressView customProgress]; 89 | _progress.hidden = true; 90 | } 91 | return _progress; 92 | } 93 | @end 94 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZImageScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZImageScrollView.h 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/5/22. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WZMediaFetcher.h" 11 | 12 | @protocol WZProtocolImageScrollView 13 | 14 | - (void)singleTap:(UIGestureRecognizer *)gesture; 15 | - (void)doubleTap:(UIGestureRecognizer *)gesture; 16 | - (void)longPress:(UIGestureRecognizer *)gesture; 17 | 18 | @end 19 | 20 | @interface WZImageScrollView : UIScrollView 21 | 22 | @property (nonatomic, weak) id imageScrollDelegate; 23 | @property (nonatomic, strong) UITapGestureRecognizer *singleTap; 24 | @property (nonatomic, strong) UITapGestureRecognizer *doubleTap; 25 | @property (nonatomic, strong) UILongPressGestureRecognizer *longPress; 26 | 27 | /** 28 | * 匹配图片接口 29 | * 30 | * @param image 需要匹配的图片 31 | */ 32 | - (void)matchingPicture:(UIImage *)image; 33 | 34 | /** 35 | * 匹配经过缩放的图片接口 36 | * 37 | * @param gesture 缩放手势 38 | */ 39 | - (void)matchZoomWithGesture:(UIGestureRecognizer *)gesture; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZImageScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZImageScrollView.m 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/5/22. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZImageScrollView.h" 10 | 11 | #define WZ_MAX_ZOOMSCALE 3.0 //最大缩放比例 12 | @interface WZImageScrollView () 13 | 14 | @property (nonatomic, strong) UIImageView *pictureImageView; 15 | 16 | @end 17 | 18 | @implementation WZImageScrollView 19 | 20 | #pragma mark - Life Cycle 21 | - (instancetype)init 22 | { 23 | self = [super init]; 24 | if (self) { 25 | self.frame = CGRectZero; 26 | self.frame = [UIScreen mainScreen].bounds; 27 | self.multipleTouchEnabled = true; 28 | self.showsVerticalScrollIndicator = false; 29 | self.showsHorizontalScrollIndicator = false; 30 | self.alwaysBounceVertical = true; 31 | self.minimumZoomScale = 1.0; 32 | self.maximumZoomScale = 1.0; 33 | self.delegate = self; 34 | 35 | _pictureImageView = [[UIImageView alloc] init]; 36 | _pictureImageView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.5]; 37 | _pictureImageView.frame = self.bounds; 38 | _pictureImageView.clipsToBounds = true; 39 | _pictureImageView.contentMode = UIViewContentModeScaleAspectFill; 40 | [self addSubview:_pictureImageView]; 41 | 42 | _singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gesture:)]; 43 | _doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gesture:)]; 44 | _doubleTap.numberOfTapsRequired = 2; 45 | [_singleTap requireGestureRecognizerToFail:_doubleTap]; 46 | _longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(gesture:)]; 47 | [self addGestureRecognizer:_singleTap]; 48 | [self addGestureRecognizer:_doubleTap]; 49 | [self addGestureRecognizer:_longPress]; 50 | } 51 | return self; 52 | } 53 | 54 | #pragma mark - public 55 | - (void)matchingPicture:(UIImage *)image { 56 | if ([image isKindOfClass:[UIImage class]]) { 57 | _pictureImageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; 58 | 59 | if (_pictureImageView.image) { 60 | [self standardConfig]; 61 | } 62 | } else { 63 | _pictureImageView.image = nil; 64 | } 65 | } 66 | 67 | - (void)matchZoomWithGesture:(UIGestureRecognizer *)gesture { 68 | if ([gesture isKindOfClass:[UITapGestureRecognizer class]]) { 69 | CGPoint point = [gesture locationInView:self]; 70 | [self matchZoomWithPoint:point]; 71 | } 72 | } 73 | 74 | #pragma mark - Common 75 | - (void)gesture:(UIGestureRecognizer *)sender { 76 | if (sender == _singleTap) { 77 | if ([_imageScrollDelegate respondsToSelector:@selector(singleTap:)]) { 78 | [_imageScrollDelegate singleTap:sender]; 79 | } 80 | } else if (sender == _doubleTap) { 81 | if ([_imageScrollDelegate respondsToSelector:@selector(doubleTap:)]) { 82 | [_imageScrollDelegate doubleTap:sender]; 83 | } 84 | } else if (sender == _longPress) { 85 | if (sender.state == UIGestureRecognizerStateBegan) { 86 | if ([_imageScrollDelegate respondsToSelector:@selector(longPress:)]) { 87 | [_imageScrollDelegate longPress:sender]; 88 | } 89 | } 90 | } 91 | } 92 | 93 | - (void)setFrame:(CGRect)frame { 94 | [super setFrame:[UIScreen mainScreen].bounds]; 95 | } 96 | 97 | - (void)matchZoomWithPoint:(CGPoint)point { 98 | CGPoint touchPoint = [self convertPoint:point toView:_pictureImageView]; 99 | if (self.zoomScale > 1) { 100 | //比例复原 101 | [self setZoomScale:1 animated:true]; 102 | } else if (self.maximumZoomScale > 1) { 103 | // 104 | CGFloat currentZoomScale = self.maximumZoomScale; 105 | CGFloat horizontalSize = CGRectGetWidth(self.bounds) / currentZoomScale; 106 | CGFloat verticalSize = CGRectGetHeight(self.bounds) / currentZoomScale; 107 | //设置浏览窗口位置 108 | CGRect rect = CGRectMake(touchPoint.x - horizontalSize / 2.0, touchPoint.y - verticalSize / 2.0, horizontalSize, verticalSize); 109 | [self zoomToRect:rect animated:true]; 110 | } 111 | } 112 | 113 | - (void)matchImageViewSize { 114 | //更新imageView位置 115 | if (_pictureImageView.image) { 116 | CGFloat ratio = CGRectGetWidth(self.bounds) / _pictureImageView.image.size.width; 117 | //固定了imageView的宽度 高度随比例 118 | _pictureImageView.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(self.bounds), ceil(ratio * _pictureImageView.image.size.height)); 119 | //配置contentSize 120 | self.contentSize = _pictureImageView.frame.size; 121 | } 122 | } 123 | 124 | //配置imageView 的中心位置: 初始化、变焦前后分别调用 125 | - (void)matchImageViewCenter { 126 | CGFloat contentWidth = self.contentSize.width; 127 | CGFloat horizontalDiff = CGRectGetWidth(self.bounds) - contentWidth;//水平方向偏差 总是0 128 | CGFloat horizontalAddition = horizontalDiff > 0.0 ? horizontalDiff : 0.0;//设置偏差量 129 | 130 | CGFloat contentHeight = self.contentSize.height; 131 | CGFloat verticalDiff = CGRectGetHeight(self.bounds) - contentHeight;//垂直方向偏差 132 | 133 | //设置偏差量 当图片的高宽比大于屏幕的高宽比时,imageView的Y轴为0 134 | CGFloat verticalAdditon = verticalDiff > 0.0 ? verticalDiff : 0.0; 135 | //校正图片中心 136 | _pictureImageView.center = CGPointMake((contentWidth + horizontalAddition) / 2.0, (contentHeight + verticalAdditon) / 2.0); 137 | } 138 | 139 | - (void)matchZoomScale { 140 | //恢复处理 141 | self.maximumZoomScale = 1.0; 142 | [self setZoomScale:1 animated:true]; 143 | 144 | CGSize imageSize = _pictureImageView.image.size; 145 | 146 | CGFloat restrictW = CGRectGetWidth(self.bounds); 147 | CGFloat restrictH = CGRectGetHeight(self.bounds); 148 | 149 | // if (imageSize.width <= restrictW && imageSize.height <= restrictH) { 150 | // //不作放大 151 | // self.maximumZoomScale = 1.0; 152 | // } else { 153 | // //比例为3倍 154 | self.maximumZoomScale = MAX(MIN(imageSize.width / restrictW, imageSize.height / restrictH), WZ_MAX_ZOOMSCALE); 155 | // } 156 | 157 | } 158 | 159 | //适配屏幕旋转 160 | - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { 161 | [super traitCollectionDidChange:previousTraitCollection]; 162 | if (_pictureImageView.image) { 163 | [self standardConfig]; 164 | } 165 | } 166 | 167 | - (void)standardConfig { 168 | [self matchZoomScale]; 169 | [self matchImageViewSize]; 170 | [self matchImageViewCenter]; 171 | } 172 | 173 | #pragma mark - UIScrollViewDelegate 174 | 175 | //产生了变焦 镜头发生变化的时候 contentSize 也会发生改变 要同步imageView的位置 176 | - (void)scrollViewDidZoom:(UIScrollView *)scrollView NS_AVAILABLE_IOS(3_2) { 177 | [self matchImageViewCenter]; 178 | } 179 | 180 | //设置变焦View 181 | - (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { 182 | return _pictureImageView; 183 | } 184 | 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZRemoteImagesBrowseController/WZRemoteImageBrowseController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZRemoteImageBrowseController.h 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZAssetBrowseController.h" 10 | #import "WZRemoteImageNavigationView.h" 11 | 12 | @interface WZRemoteImageBrowseController : WZAssetBrowseController 13 | 14 | @property (nonatomic, strong) UIImageView *mediumImageView; 15 | 16 | + (void)showRemoteImagesWithURLArray:(NSArray *)urlArray loactedVC:(UIViewController *)locatedVC; 17 | 18 | + (NSArray *)fetchUrlArrayAccordingStringArray:(NSArray *)stringArray; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZRemoteImagesBrowseController/WZRemoteImageBrowseController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZRemoteImageBrowseController.m 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZRemoteImageBrowseController.h" 10 | #import "WZToast.h" 11 | 12 | @interface WZRemoteImageBrowseController () 13 | 14 | @property (nonatomic, strong) WZRemoteImageNavigationView *navigationView; 15 | 16 | @end 17 | 18 | @implementation WZRemoteImageBrowseController 19 | 20 | //会过滤部分字符串 21 | + (NSArray *)fetchUrlArrayAccordingStringArray:(NSArray *)stringArray { 22 | NSMutableArray *urlMArray = [NSMutableArray array]; 23 | for (NSString *urlStr in stringArray) { 24 | if ([urlStr isKindOfClass:[NSString class]] && urlStr.length) { 25 | NSURL *url = [NSURL URLWithString:urlStr]; 26 | if ([url isKindOfClass:[NSURL class]]) { 27 | [urlMArray addObject:url]; 28 | } 29 | } 30 | } 31 | return urlMArray; 32 | } 33 | 34 | #pragma mark - Initialize 35 | + (void)showRemoteImagesWithURLArray:(NSArray *)urlArray loactedVC:(UIViewController *)locatedVC { 36 | if (!urlArray 37 | || !locatedVC 38 | || ![urlArray isKindOfClass:[NSArray class]] 39 | || ![locatedVC isKindOfClass:[UIViewController class]]) { 40 | return; 41 | } 42 | 43 | NSMutableArray *imagesMArray = [NSMutableArray array]; 44 | 45 | SDWebImageDownloader *sdDownloader = [SDWebImageDownloader sharedDownloader]; 46 | [sdDownloader setValue:@"" forHTTPHeaderField:@"Accept-Encoding"]; 47 | 48 | for (int i = 0; i < urlArray.count; i++) { 49 | WZMediaAsset *asset = [[WZMediaAsset alloc] init]; 50 | asset.remoteMediaURL = urlArray[i]; 51 | asset.imageThumbnail = [UIImage imageWithColor:[[UIColor blackColor] colorWithAlphaComponent:0.5]]; 52 | [imagesMArray addObject:asset]; 53 | 54 | //使用了url缓存 55 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:asset.remoteMediaURL]; 56 | if (key) { 57 | UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key]; 58 | if (cacheImage) { 59 | asset.imageClear = cacheImage; 60 | asset.imageThumbnail = cacheImage; 61 | } 62 | NSLog(@"远程图片缓存Path:%@", [[SDImageCache sharedImageCache] defaultCachePathForKey:key]); 63 | NSData *data = [NSData dataWithContentsOfFile:[[SDImageCache sharedImageCache] defaultCachePathForKey:key]]; 64 | NSLog(@"文件大小:%ld", data.length); 65 | } 66 | } 67 | 68 | if (imagesMArray.count) { 69 | WZRemoteImageBrowseController *VC = [[WZRemoteImageBrowseController alloc] init]; 70 | VC.imagesBrowseDelegate = (id)locatedVC; 71 | VC.mediaAssetArray = imagesMArray; 72 | 73 | VC.restrictNumber = 9;//控制选中图片的数目 74 | [VC showInIndex:0 animated:true]; 75 | [locatedVC presentViewController:VC animated:true completion:^{}]; 76 | } 77 | } 78 | 79 | #pragma mark - Lifecycle 80 | - (void)viewDidLoad { 81 | [super viewDidLoad]; 82 | self.view.backgroundColor = [UIColor blackColor]; 83 | } 84 | 85 | - (void)createViews { 86 | [self.view addSubview:self.navigationView]; 87 | [self caculateSelected]; 88 | } 89 | 90 | #pragma mark - Match image 91 | - (void)matchThumnailImageWith:(WZImageContainerController *)VC { 92 | if (!VC) { 93 | return; 94 | } 95 | NSUInteger index = VC.index; 96 | if (index >= self.mediaAssetArray.count) { 97 | return; 98 | } 99 | 100 | VC.progress.hidden = true;//隐藏加载视图 101 | if (index < self.mediaAssetArray.count) { 102 | WZMediaAsset *asset = self.mediaAssetArray[index]; 103 | NSAssert(asset.imageThumbnail, @"请配置默认图!"); 104 | if (asset.imageThumbnail) { 105 | [VC matchingPicture:asset.imageThumbnail]; 106 | } 107 | } 108 | } 109 | 110 | - (void)matchClearImageWith:(WZImageContainerController *)VC { 111 | if (!VC) { 112 | return; 113 | } 114 | NSUInteger index = VC.index; 115 | if (index >= self.mediaAssetArray.count) { 116 | return; 117 | } 118 | VC.progress.hidden = true; 119 | WZMediaAsset *asset = nil; 120 | if (index < self.mediaAssetArray.count ) { 121 | asset = self.mediaAssetArray[index]; 122 | NSAssert(asset.remoteMediaURL, @"却少媒体URL!"); 123 | 124 | if (asset.clearPath) { 125 | UIImage *image = [UIImage imageWithContentsOfFile:asset.clearPath]; 126 | if (image) { 127 | [VC matchingPicture:image]; 128 | return; 129 | } 130 | } 131 | if (asset.imageClear) { 132 | [VC matchingPicture:asset.imageClear]; 133 | } else if (asset.remoteMediaURL) { 134 | 135 | [self.mediumImageView sd_cancelCurrentImageLoad]; 136 | //复位状态 137 | [VC.progress setProgressRate:0]; 138 | VC.progress.hidden = false; 139 | if ([asset.remoteMediaURL isKindOfClass:[NSURL class]]) { 140 | 141 | [self.mediumImageView sd_setImageWithPreviousCachedImageWithURL:asset.remoteMediaURL andPlaceholderImage:nil options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { 142 | /* 143 | 这个因为NSHTTPURLResponse中 144 | Accept-Encoding为gzip造成的 145 | 当遇到Accept-Encoding为gzip时,expectedsize会变为-1不确定的大小 146 | 此时在sdwebimage中expectedsize判断小于0,就会赋值为0 147 | 所以如果确定文件的大小时,可以将Accept-Encoding修改成非gzip的就可以获取需要的文件大小了 148 | */ 149 | if (expectedSize > 0) { 150 | [VC.progress setProgressRate:receivedSize / (expectedSize * 1.0)]; 151 | } 152 | } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 153 | VC.progress.hidden = true; 154 | if (error) { 155 | //显示下载失败的图片 156 | [WZToast toastWithContent:[NSString stringWithFormat:@"图片下载失败:页面id为 %ld", VC.index]]; 157 | } else { 158 | if (image) { 159 | asset.imageThumbnail = image; 160 | asset.imageClear = image; 161 | [VC matchingPicture:image]; 162 | } 163 | } 164 | }]; 165 | } else { 166 | [WZToast toastWithContent:@"图片url错误"]; 167 | } 168 | } else { 169 | [WZToast toastWithContent:@"匹配不到图片资源"]; 170 | } 171 | } 172 | 173 | self.currentMediaAsset = asset; 174 | self.currentContainerVC = VC; 175 | self.navigationView.titleLabel.text = [NSString stringWithFormat:@"当前页面ID:%ld", index]; 176 | } 177 | 178 | /* 179 | HTTP Header中 180 | Accept-Encoding 是浏览器发给服务器,声明浏览器支持的编码类型的 181 | 常见的有 182 | Accept-Encoding: compress, gzip             //支持compress 和gzip类型 183 | Accept-Encoding:                    //默认是identity 184 | Accept-Encoding: *                     //支持所有类型 185 | Accept-Encoding: compress;q=0.5, gzip;q=1.0 //按顺序支持 gzip , compress 186 | Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0 // 按顺序支持 gzip , identity 187 | 188 | 服务器返回的对应的类型编码header是 content-encoding 189 | 服务器处理accept-encoding的规则如下所示 190 |   1. 如果服务器可以返回定义在Accept-Encoding 中的任何一种Encoding类型, 那么处理成功(除非q的值等于0, 等于0代表不可接受) 191 |   2. * 代表任意一种Encoding类型 (除了在Accept-Encoding中显示定义的类型) 192 |   3.如果有多个Encoding同时匹配, 按照q值顺序排列 193 |   4. identity总是可被接受的encoding类型(除非显示的标记这个类型q=0) , 如果Accept-Encoding的值是空 那么只有identity是会被接受的类型 194 | 如果Accept-Encoding中的所有类型服务器都没发返回, 那么应该返回406错误给客户端 195 | 如果request中没有Accept-Encoding 那么服务器会假设所有的Encoding都是可以被接受的, 196 | 如果Accept-Encoding中有identity 那么应该优先返回identity (除非有q值的定义,或者你认为另外一种类型是更有意义的) 197 | 注意: 198 | 如果服务器不支持identity 并且浏览器没有发送Accept-Encoding,那么服务器应该倾向于使用HTTP1.0中的 "gzip" and "compress" , 服务器可能按照客户端类型 发送更适合的encoding类型 199 | 大部分HTTP1.0的客户端无法处理q值 200 | */ 201 | 202 | #pragma mark - Accessor 203 | - (UIImageView *)mediumImageView { 204 | if (!_mediumImageView) { 205 | _mediumImageView = [[UIImageView alloc] init]; 206 | } 207 | return _mediumImageView; 208 | } 209 | 210 | - (WZRemoteImageNavigationView *)navigationView { 211 | if (!_navigationView) { 212 | _navigationView = [WZRemoteImageNavigationView customAssetBrowseNavigationWithDelegate:(id)self]; 213 | } 214 | return _navigationView; 215 | } 216 | @end 217 | 218 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZRemoteImagesBrowseController/WZRemoteImageNavigationView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZRemoteImageNavigationView.h 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZAssetBrowseNavigationView.h" 10 | 11 | @interface WZRemoteImageNavigationView : WZAssetBrowseNavigationView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZRemoteImagesBrowseController/WZRemoteImageNavigationView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZRemoteImageNavigationView.m 3 | // WZPhotoPicker 4 | // 5 | // Created by admin on 17/6/9. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZRemoteImageNavigationView.h" 10 | 11 | @implementation WZRemoteImageNavigationView 12 | 13 | + (instancetype)customAssetBrowseNavigationWithDelegate:(id)delegate { 14 | WZRemoteImageNavigationView *navigation = [super customAssetBrowseNavigationWithDelegate:delegate]; 15 | navigation.selectedButton.hidden = true; 16 | return navigation; 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZRoundRenderLayer.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZRoundRenderLayer.h 3 | // WZBaseRoundSelector 4 | // 5 | // Created by admin on 17/3/28. 6 | // Copyright © 2017年 WZ. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @protocol WZRoundRenderLayerDelegate 13 | 14 | /** 15 | * 16 | * @param currentPoint : bezier path current point 17 | */ 18 | - (void)renderPathCurrentPoint:(CGPoint)currentPoint; 19 | 20 | @end 21 | 22 | 23 | /** 24 | * 始终在-PI / 2.0 处绘制 只负责绘制 25 | */ 26 | @interface WZRoundRenderLayer : CALayer 27 | 28 | /** 29 | * 设置进行绘制弧 30 | */ 31 | @property (nonatomic, assign) float renderAngle;//范围 0 ~ M_PI * 2.0 32 | 33 | @property (nonatomic, weak) id renderLayerDelegate; 34 | 35 | - (instancetype)initWithCircleRadius:(CGFloat)circleRadius layerLineWidth:(CGFloat)layerLineWidth; 36 | 37 | /** 38 | * 渲染表层的颜色 39 | */ 40 | - (void)setSurfaceTrackColor:(UIColor *)color; 41 | 42 | /** 43 | * 渲染底层的颜色 44 | */ 45 | - (void)setBottomTrackColor:(UIColor *)color; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoBrowser/WZRoundRenderLayer.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZRoundRenderLayer.m 3 | // WZBaseRoundSelector 4 | // 5 | // Created by admin on 17/3/28. 6 | // Copyright © 2017年 WZ. All rights reserved. 7 | // 8 | 9 | #import "WZRoundRenderLayer.h" 10 | 11 | @interface WZRoundRenderLayer () 12 | 13 | @property (nonatomic, strong) CAShapeLayer *surfaceLayer; 14 | @property (nonatomic, strong) CAShapeLayer *bottomLayer; 15 | @property (nonatomic, strong) CAShapeLayer *maskLayer; 16 | @property (nonatomic, strong) UIBezierPath *renderBezierPath; 17 | 18 | @property (nonatomic, assign) CGFloat circleRadius; 19 | @property (nonatomic, assign) CGFloat layerLineWidth; 20 | 21 | @end 22 | 23 | 24 | @implementation WZRoundRenderLayer 25 | 26 | #pragma mark - Initalize 27 | - (instancetype)initWithCircleRadius:(CGFloat)circleRadius layerLineWidth:(CGFloat)layerLineWidth { 28 | if (self = [super init]) { 29 | _circleRadius = circleRadius; 30 | _layerLineWidth = layerLineWidth; 31 | self.frame = CGRectZero; 32 | 33 | UIBezierPath *tmpBezierPath = [UIBezierPath bezierPath]; 34 | CGFloat circleWH = _circleRadius - _layerLineWidth / 2.0; 35 | [tmpBezierPath addArcWithCenter:CGPointMake(_circleRadius, _circleRadius) 36 | radius:circleWH 37 | startAngle:-M_PI_2 38 | endAngle:M_PI_2 * 3.0 39 | clockwise:true]; 40 | 41 | self.bottomLayer.path = tmpBezierPath.CGPath; 42 | self.surfaceLayer.path = tmpBezierPath.CGPath; 43 | self.surfaceLayer.mask = self.maskLayer; 44 | [self addSublayer:self.bottomLayer]; 45 | [self addSublayer:self.surfaceLayer]; 46 | 47 | } 48 | return self; 49 | } 50 | 51 | //frame 的size 由 _circleRadius 决定 52 | - (void)setFrame:(CGRect)frame { 53 | [super setFrame:CGRectMake(frame.origin.x, frame.origin.y, _circleRadius * 2.0, _circleRadius * 2.0)]; 54 | } 55 | 56 | 57 | - (void)setSurfaceTrackColor:(UIColor *)color { 58 | if ([color isKindOfClass:[UIColor class]]) { 59 | self.surfaceLayer.strokeColor = color.CGColor; 60 | } 61 | } 62 | 63 | - (void)setBottomTrackColor:(UIColor *)color { 64 | if ([color isKindOfClass:[UIColor class]]) { 65 | self.bottomLayer.strokeColor = color.CGColor; 66 | } 67 | } 68 | 69 | #pragma mark - setter & getter 70 | 71 | - (CAShapeLayer *)surfaceLayer { 72 | if (!_surfaceLayer) { 73 | _surfaceLayer = [CAShapeLayer layer]; 74 | _surfaceLayer.strokeColor = [UIColor colorWithRed:255.0 / 255.0 green:197.0 / 255.0 blue:41.0 / 255.0 alpha:1.0].CGColor; 75 | _surfaceLayer.fillColor = [UIColor clearColor].CGColor; 76 | _surfaceLayer.lineWidth = _layerLineWidth; 77 | _surfaceLayer.lineCap = @"round"; 78 | } 79 | return _surfaceLayer; 80 | } 81 | 82 | 83 | - (CAShapeLayer *)bottomLayer { 84 | if (!_bottomLayer) { 85 | _bottomLayer = [CAShapeLayer layer]; 86 | _bottomLayer.strokeColor = [UIColor colorWithRed:255.0 / 255.0 green:248.0 / 255.0 blue:234.0 / 255.0 alpha:1.0].CGColor; 87 | _bottomLayer.fillColor = [UIColor clearColor].CGColor; 88 | _bottomLayer.lineWidth = _layerLineWidth; 89 | _bottomLayer.lineCap = @"round"; 90 | } 91 | return _bottomLayer; 92 | } 93 | 94 | 95 | - (CAShapeLayer *)maskLayer { 96 | if (!_maskLayer) { 97 | _maskLayer = [CAShapeLayer layer]; 98 | _maskLayer.strokeColor = [UIColor whiteColor].CGColor; 99 | _maskLayer.fillColor = [UIColor clearColor].CGColor; 100 | _maskLayer.lineWidth = _layerLineWidth; 101 | _maskLayer.lineCap = @"round"; 102 | } 103 | return _maskLayer; 104 | } 105 | 106 | 107 | - (UIBezierPath *)renderBezierPath { 108 | if (!_renderBezierPath) { 109 | _renderBezierPath = [UIBezierPath bezierPath]; 110 | } 111 | return _renderBezierPath; 112 | } 113 | 114 | - (void)setRenderAngle:(float)renderAngle { 115 | if (renderAngle < 0) { 116 | renderAngle = 0; 117 | } 118 | if (renderAngle > M_PI * 2.0) { 119 | renderAngle = M_PI * 2.0; 120 | } 121 | renderAngle = renderAngle - M_PI_2; 122 | _renderAngle = renderAngle; 123 | 124 | CGFloat circleWH = _circleRadius - _layerLineWidth / 2.0; 125 | [self.renderBezierPath removeAllPoints]; 126 | [_renderBezierPath addArcWithCenter:CGPointMake(_circleRadius, _circleRadius) 127 | radius:circleWH 128 | startAngle:- M_PI_2 129 | endAngle:_renderAngle 130 | clockwise:1]; 131 | self.maskLayer.path = _renderBezierPath.CGPath; 132 | if ([self.renderLayerDelegate respondsToSelector:@selector(renderPathCurrentPoint:)]) { 133 | [self.renderLayerDelegate renderPathCurrentPoint:_renderBezierPath.currentPoint]; 134 | } 135 | } 136 | 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoPicker/WZMediaAssetBaseCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZMediaAssetBaseCell.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/21. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | @class WZMediaFetcher; 11 | @class WZMediaAsset; 12 | 13 | @interface WZMediaAssetBaseCell : UICollectionViewCell 14 | 15 | @property (nonatomic, strong) UIImageView *imageView; 16 | @property (nonatomic, strong) UIButton *selectButton; 17 | @property (nonatomic, strong) void (^selectedBlock)(BOOL selected); 18 | @property (nonatomic, strong) WZMediaAsset *asset; 19 | 20 | //网络加载 写进度 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoPicker/WZMediaAssetBaseCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZMediaAssetBaseCell.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/21. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZMediaAssetBaseCell.h" 10 | #import "WZMediaFetcher.h" 11 | 12 | @implementation WZMediaAssetBaseCell 13 | 14 | - (void)prepareForReuse { 15 | self.imageView.image = nil; 16 | } 17 | 18 | - (instancetype)initWithFrame:(CGRect)frame 19 | { 20 | self = [super initWithFrame:frame]; 21 | if (self) { 22 | // self.contentView.layer.borderWidth = 1.0; 23 | // self.contentView.layer.borderColor = [UIColor blackColor].CGColor; 24 | _imageView = [[UIImageView alloc] initWithFrame:self.bounds]; 25 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 26 | _imageView.backgroundColor = [UIColor lightGrayColor]; 27 | _imageView.layer.masksToBounds = true; 28 | [self.contentView addSubview:_imageView]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)clickedBtn:(UIButton *)sender { 34 | if (_asset) { 35 | if (_selectedBlock) { 36 | _selectedBlock(_asset.selected); 37 | } 38 | } 39 | } 40 | 41 | - (void)setAsset:(WZMediaAsset *)asset { 42 | if ([asset isKindOfClass:[WZMediaAsset class]]) { 43 | _asset = asset; 44 | self.selectButton.selected = _asset.selected; 45 | if (_asset.imageThumbnail) { 46 | self.imageView.image = _asset.imageThumbnail; 47 | } else { 48 | __weak typeof(self) weakSelf = self; 49 | [_asset fetchThumbnailImageSynchronous:false handler:^(UIImage *image) { 50 | weakSelf.imageView.image = image; 51 | }]; 52 | } 53 | } 54 | } 55 | 56 | #pragma mark - Accessor 57 | - (UIButton *)selectButton { 58 | if (!_selectButton) { 59 | CGFloat selectedBtnHW = 33; 60 | _selectButton = [[UIButton alloc] initWithFrame:CGRectMake(self.frame.size.width - selectedBtnHW , 0, selectedBtnHW, selectedBtnHW)]; 61 | [self.contentView addSubview:_selectButton]; 62 | [_selectButton setImage:[UIImage imageNamed:@"message_oeuvre_btn_normal"] forState:UIControlStateNormal]; 63 | [_selectButton setImage:[UIImage imageNamed:@"message_oeuvre_btn_selected"] forState:UIControlStateSelected]; 64 | [_selectButton addTarget:self action:@selector(clickedBtn:) forControlEvents:UIControlEventTouchUpInside]; 65 | _selectButton.titleLabel.font = [UIFont boldSystemFontOfSize:16.0]; 66 | } 67 | return _selectButton; 68 | } 69 | 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoPicker/WZPhotoCatalogueController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZPhotoCatalogueController.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/21. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WZMediaAssetBaseCell.h" 11 | @class WZMediaAssetCollection; 12 | @protocol WZProtocolMediaAsset; 13 | 14 | /** 15 | * 图片目录 16 | */ 17 | @interface WZPhotoCatalogueCell : WZMediaAssetBaseCell 18 | 19 | @property (nonatomic, strong) UILabel *titleLabel; 20 | @property (nonatomic, strong) UIButton *button; 21 | @property (nonatomic, strong) WZMediaAssetCollection *mediaAssetCollection; 22 | @property (nonatomic, strong) void (^clickedBlock)(); 23 | 24 | @end 25 | 26 | @interface WZPhotoCatalogueController : UIViewController 27 | 28 | + (void)showPickerWithPresentedController:(UIViewController *)presentedController; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoPicker/WZPhotoCatalogueController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZPhotoCatalogueController.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/21. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZPhotoCatalogueController.h" 10 | #import "WZPhotoPickerController.h" 11 | 12 | #pragma mark - WZPhotoCatalogueController 13 | @interface WZPhotoCatalogueController() 14 | 15 | @property (nonatomic, strong) WZPhotoPickerController *pickerVC; 16 | 17 | @end 18 | 19 | @implementation WZPhotoCatalogueCell 20 | 21 | - (instancetype)initWithFrame:(CGRect)frame 22 | { 23 | self = [super initWithFrame:frame]; 24 | if (self) { 25 | [self createViews]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)createViews { 31 | self.imageView.frame = CGRectMake(self.frame.size.width - self.frame.size.height + 10, 10, self.frame.size.height - 20, self.frame.size.height - 20); 32 | _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(10.0, 0.0, self.frame.size.width - self.frame.size.height, self.frame.size.height)]; 33 | [self.contentView addSubview:_titleLabel]; 34 | self.backgroundColor = [UIColor lightGrayColor]; 35 | 36 | _button = [[UIButton alloc] initWithFrame:self.bounds]; 37 | [_button addTarget:self action:@selector(clickedBtn:) forControlEvents:UIControlEventTouchUpInside]; 38 | [self.contentView addSubview:_button]; 39 | [self.contentView sendSubviewToBack:_button]; 40 | [_button setBackgroundImage:[[self class] imageWithColor:[UIColor colorWithRed:205.0 / 255 green:205.0 / 255 blue:205.0 / 255 alpha:1.0]] forState:UIControlStateNormal]; 41 | [_button setBackgroundImage:[[self class] imageWithColor:[UIColor colorWithRed:238.0 / 255 green:238.0 / 255 blue:238.0 / 255 alpha:1.0]] forState:UIControlStateHighlighted]; 42 | 43 | } 44 | 45 | - (void)clickedBtn:(UIButton *)sender { 46 | if (_clickedBlock) { 47 | _clickedBlock(); 48 | } 49 | } 50 | 51 | - (void)setMediaAssetCollection:(WZMediaAssetCollection *)mediaAssetCollection { 52 | if ([mediaAssetCollection isKindOfClass:[WZMediaAssetCollection class]]) { 53 | _mediaAssetCollection = mediaAssetCollection; 54 | self.titleLabel.text = mediaAssetCollection.title; 55 | [_mediaAssetCollection coverHandler:^(UIImage *image) { 56 | self.imageView.image = image; 57 | }]; 58 | } 59 | } 60 | 61 | @end 62 | 63 | #pragma mark - WZPhotoCatalogueController 64 | @interface WZPhotoCatalogueController () 65 | 66 | 69 | 70 | @property (nonatomic, strong) UICollectionView *collection; 71 | @property (nonatomic, strong) NSArray * mediaAssetArrayCollection; 72 | 73 | @end 74 | 75 | @implementation WZPhotoCatalogueController 76 | 77 | #pragma mark - initialize 78 | + (void)showPickerWithPresentedController:(UIViewController *)presentedController { 79 | WZPhotoCatalogueController *VC = [[WZPhotoCatalogueController alloc] init]; 80 | VC.pickerVC.delegate = (id)presentedController; 81 | UINavigationController *navigationVC = [[UINavigationController alloc] initWithRootViewController:VC]; 82 | [presentedController presentViewController:navigationVC animated:true completion:^{}]; 83 | } 84 | 85 | #pragma mark - Lifecycle 86 | - (instancetype) init { 87 | if (self = [super init]) { 88 | _pickerVC = [[WZPhotoPickerController alloc] init]; 89 | _pickerVC.restrictNumber = 9;//选图限制 90 | _mediaAssetArrayCollection = [NSArray array]; 91 | } 92 | return self; 93 | } 94 | 95 | 96 | 97 | - (void)viewDidLoad { 98 | [super viewDidLoad]; 99 | self.view.backgroundColor = [UIColor whiteColor]; 100 | self.title = NSStringFromClass([self class]); 101 | self.automaticallyAdjustsScrollViewInsets = false; 102 | [self getAuthorization]; 103 | [self createViews]; 104 | 105 | // NSLog(@"%@", NSStringFromUIEdgeInsets(self.additionalSafeAreaInsets)); 106 | // NSLog(@"%@", NSStringFromUIEdgeInsets(self.view.safeAreaInsets)); 107 | 108 | } 109 | 110 | - (void)didReceiveMemoryWarning { 111 | [super didReceiveMemoryWarning]; 112 | } 113 | 114 | - (void)dealloc { 115 | NSLog(@"%s", __func__); 116 | } 117 | 118 | #pragma mark - CreateViews 119 | - (void)createViews { 120 | [self.view addSubview:self.collection]; 121 | 122 | UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:self action:@selector(back)]; 123 | if (self.navigationController) { 124 | self.navigationItem.leftBarButtonItem = left; 125 | } 126 | } 127 | 128 | -(void)back { 129 | [self dismissViewControllerAnimated:true completion:^{}]; 130 | } 131 | 132 | #pragma mark - fetchAuthorization 133 | - (void)getAuthorization { 134 | [NSObject requestPhotosLibraryAuthorization:^(BOOL ownAuthorization) { 135 | if (ownAuthorization) { 136 | //action 137 | dispatch_async(dispatch_get_main_queue(), ^{ 138 | _mediaAssetArrayCollection = [WZMediaFetcher fetchAssetCollection]; 139 | [_collection reloadData]; 140 | }); 141 | } else { 142 | //提示可到设置页面获取权限 143 | [self showAlter]; 144 | } 145 | }]; 146 | } 147 | 148 | - (void)showAlter { 149 | UIAlertController *alter = [UIAlertController alertControllerWithTitle:@"尚未获取到相册权限" message:@"是否到设置处进行权限设置" preferredStyle:UIAlertControllerStyleAlert]; 150 | UIAlertAction *actionSure = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { 151 | [NSObject openAppSettings]; 152 | }]; 153 | UIAlertAction *actionCancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { 154 | [alter dismissViewControllerAnimated:true completion:nil]; 155 | }]; 156 | [alter addAction:actionSure]; 157 | [alter addAction:actionCancel]; 158 | [self presentViewController:alter animated:true completion:nil]; 159 | } 160 | 161 | #pragma mark - UICollectionViewDataSource 162 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 163 | return _mediaAssetArrayCollection.count; 164 | } 165 | 166 | - (__kindof WZPhotoCatalogueCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 167 | __block WZPhotoCatalogueCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([WZPhotoCatalogueCell class]) forIndexPath:indexPath]; 168 | @try { 169 | if ([_mediaAssetArrayCollection[indexPath.row] isKindOfClass:[WZMediaAssetCollection class]]) { 170 | 171 | cell.mediaAssetCollection = _mediaAssetArrayCollection[indexPath.row]; 172 | 173 | __weak typeof(self) weakSelf = self; 174 | cell.clickedBlock = ^(){ 175 | //点击目录 进入章节 176 | weakSelf.pickerVC.mediaAssetArray = weakSelf.mediaAssetArrayCollection[indexPath.row].mediaAssetArray; 177 | if (weakSelf.navigationController) { 178 | [weakSelf.navigationController pushViewController:weakSelf.pickerVC animated:true]; 179 | } 180 | }; 181 | } 182 | } @catch (NSException *exception) { 183 | NSLog(@"%@",exception.debugDescription); 184 | } 185 | return cell; 186 | } 187 | 188 | #pragma mark - Accessor 189 | - (UICollectionView *)collection { 190 | if (!_collection) { 191 | CGRect rect = self.navigationController?CGRectMake(0.0, 64.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64.0):self.view.bounds; 192 | 193 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 194 | CGFloat gap = 10.0; 195 | layout.minimumLineSpacing = gap; 196 | layout.minimumInteritemSpacing = gap; 197 | CGFloat itemW = ([UIScreen mainScreen].bounds.size.width); 198 | CGFloat itemH = 44 + gap * 2.0; 199 | layout.itemSize = CGSizeMake(itemW, itemH); 200 | 201 | _collection = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:layout]; 202 | _collection.backgroundColor = [UIColor whiteColor]; 203 | _collection.delaysContentTouches = false; 204 | _collection.dataSource = self; 205 | _collection.delegate = self; 206 | [_collection registerClass:[WZPhotoCatalogueCell class] forCellWithReuseIdentifier:NSStringFromClass([WZPhotoCatalogueCell class])]; 207 | } 208 | return _collection; 209 | } 210 | 211 | @end 212 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoPicker/WZPhotoPickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WZPhotoPickerController.h 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/19. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WZMediaFetcher.h" 11 | 12 | /** 13 | * 图片挑选 14 | */ 15 | @interface WZPhotoPickerController : UIViewController 16 | 17 | @property (nonatomic, weak) id delegate; 18 | @property (nonatomic, strong) NSArray * mediaAssetArray; 19 | @property (nonatomic, assign) NSUInteger restrictNumber; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/imagesShow/WZPhotoPicker/WZPhotoPickerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WZPhotoPickerController.m 3 | // WZPhotoPicker 4 | // 5 | // Created by wizet on 2017/5/19. 6 | // Copyright © 2017年 wizet. All rights reserved. 7 | // 8 | 9 | #import "WZPhotoPickerController.h" 10 | #import "WZMediaAssetBaseCell.h" 11 | 12 | #import "WZImageBrowseController.h" 13 | #import "WZAssetBrowseController.h" 14 | #import "WZRemoteImageBrowseController.h" 15 | 16 | #pragma mark - WZPhotoPickerController 17 | @interface WZPhotoPickerController () 18 | 21 | 22 | @property (nonatomic, strong) UICollectionView *collection; 23 | 24 | @end 25 | 26 | @implementation WZPhotoPickerController 27 | 28 | #pragma mark - initialize 29 | 30 | #pragma mark - ViewController Lifecycle 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | self.view.backgroundColor = [UIColor whiteColor]; 34 | self.title = NSStringFromClass([self class]); 35 | self.automaticallyAdjustsScrollViewInsets = false; 36 | if (!_mediaAssetArray) { 37 | _mediaAssetArray = [NSArray array]; 38 | } 39 | 40 | [self createViews]; 41 | } 42 | 43 | - (void)didReceiveMemoryWarning { 44 | [super didReceiveMemoryWarning]; 45 | } 46 | 47 | - (void)dealloc { 48 | NSLog(@"%s", __func__); 49 | } 50 | 51 | #pragma mark - create views 52 | - (void)createViews { 53 | [self.view addSubview:self.collection]; 54 | UIBarButtonItem *left = [[UIBarButtonItem alloc] initWithTitle:@"返回目录" style:UIBarButtonItemStyleDone target:self action:@selector(back)]; 55 | UIBarButtonItem *right = [[UIBarButtonItem alloc] initWithTitle:@"选择完成" style:UIBarButtonItemStyleDone target:self action:@selector(finish)]; 56 | 57 | if (self.navigationController) { 58 | self.navigationItem.leftBarButtonItem = left; 59 | self.navigationItem.rightBarButtonItem = right; 60 | } 61 | } 62 | 63 | - (void)finish { 64 | //如果实现了代理 65 | if ([_delegate respondsToSelector:@selector(fetchImages:)]) { 66 | //获取选中目标 同步取出大小图 67 | NSLock *lock = [[NSLock alloc] init]; 68 | [lock tryLock]; 69 | NSMutableArray *mArray_images = [NSMutableArray array]; 70 | for (WZMediaAsset *mediaAsset in self.mediaAssetArray) { 71 | if (mediaAsset.selected) { 72 | if (mediaAsset.origion) { 73 | [mediaAsset fetchOrigionImageSynchronous:true handler:^(UIImage *image) { 74 | [mArray_images addObject:image]; 75 | }]; 76 | } else { 77 | [WZMediaFetcher fetchImageWithAsset:mediaAsset.asset costumSize:WZMEDIAASSET_CUSTOMSIZE synchronous:true handler:^(UIImage *image) { 78 | [mArray_images addObject:image]; 79 | }]; 80 | } 81 | } 82 | } 83 | 84 | [lock unlock]; 85 | [_delegate fetchImages:mArray_images]; 86 | //同步完 87 | [self dismiss]; 88 | } else { 89 | [self dismiss]; 90 | } 91 | } 92 | 93 | - (void)dismiss { 94 | [self dismissViewControllerAnimated:true completion:^{ 95 | if ([_delegate respondsToSelector:@selector(fetchAssets:)]) { 96 | NSMutableArray *mmediaAssetArray_callback = [NSMutableArray array]; 97 | for (WZMediaAsset *mediaAsset in self.mediaAssetArray) { 98 | if (mediaAsset.selected) { 99 | [mmediaAssetArray_callback addObject:mediaAsset]; 100 | } 101 | } 102 | [_delegate fetchAssets:[NSArray arrayWithArray:mmediaAssetArray_callback]]; 103 | } 104 | }]; 105 | } 106 | 107 | -(void)back { 108 | //复原选择数据 109 | for (WZMediaAsset *asset in self.mediaAssetArray) { 110 | asset.selected = false; 111 | asset.origion = false; 112 | } 113 | if (self.navigationController) { 114 | [self.navigationController popViewControllerAnimated:true]; 115 | } else { 116 | [self dismissViewControllerAnimated:true completion:^{}]; 117 | } 118 | } 119 | 120 | #pragma mark - UICollectionViewDataSource 121 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 122 | return _mediaAssetArray.count; 123 | } 124 | 125 | - (__kindof WZMediaAssetBaseCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 126 | WZMediaAssetBaseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([WZMediaAssetBaseCell class]) forIndexPath:indexPath]; 127 | 128 | @try { 129 | cell.asset = _mediaAssetArray[indexPath.row]; 130 | __weak typeof(cell) weakCell = cell; 131 | __weak typeof(self) weakSelf = self; 132 | cell.selectedBlock = ^(BOOL selected) { 133 | if ([weakSelf overloadJudgement] && !weakCell.asset.selected) { 134 | 135 | } else { 136 | weakCell.asset.selected = !weakCell.asset.selected; 137 | weakCell.selectButton.selected = weakCell.asset.selected; 138 | } 139 | }; 140 | } @catch (NSException *exception) { 141 | 142 | } 143 | return cell; 144 | } 145 | 146 | - (BOOL)overloadJudgement { 147 | if (self.restrictNumber == 0) { 148 | return false; 149 | } 150 | 151 | NSUInteger restrictNumber = 0; 152 | for (WZMediaAsset *asset in self.mediaAssetArray) { 153 | if (asset.selected == true) { 154 | restrictNumber = restrictNumber + 1; 155 | } 156 | } 157 | if (self.restrictNumber <= restrictNumber) { 158 | return true; 159 | } 160 | 161 | return false; 162 | } 163 | 164 | 165 | #pragma mark - UICollectionViewDelegate 166 | - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 167 | // WZMediaAssetBaseCell *cell = (WZMediaAssetBaseCell *)[collectionView cellForItemAtIndexPath:indexPath]; 168 | 169 | //浏览大图 170 | if (self.mediaAssetArray.count) { 171 | WZAssetBrowseController *VC = [[WZAssetBrowseController alloc] init]; 172 | VC.imagesBrowseDelegate = (id)self; 173 | VC.mediaAssetArray = self.mediaAssetArray; 174 | VC.restrictNumber = self.restrictNumber; 175 | [VC showInIndex:indexPath.row animated:true]; 176 | [self presentViewController:VC animated:true completion:^{}]; 177 | } 178 | } 179 | 180 | #pragma mark - WZProtocolImageBrowse 181 | - (void)backAction { 182 | [self.collection reloadData]; 183 | } 184 | 185 | - (void)send { 186 | [self finish]; 187 | } 188 | 189 | #pragma mark - WZProtocolMediaAsset 190 | - (void)fetchAssets:(NSArray *)assets { 191 | if (assets) { 192 | } 193 | } 194 | 195 | #pragma mark - Accessor 196 | - (void)setMediaAssetArray:(NSArray *)mediaAssetArray { 197 | _mediaAssetArray = [mediaAssetArray isKindOfClass:[NSArray class]]?mediaAssetArray:nil; 198 | if (_collection) { 199 | [_collection reloadData]; 200 | } 201 | } 202 | 203 | - (UICollectionView *)collection { 204 | if (!_collection) { 205 | CGRect rect = self.navigationController?CGRectMake(0.0, 64.0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64.0):self.view.bounds; 206 | 207 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 208 | CGFloat gap = 10.0; 209 | layout.minimumLineSpacing = gap; 210 | layout.minimumInteritemSpacing = gap; 211 | layout.sectionInset = UIEdgeInsetsMake(gap, gap, gap, gap); 212 | CGFloat itemWH = ([UIScreen mainScreen].bounds.size.width - gap * 5) / 4; 213 | layout.itemSize = CGSizeMake(itemWH, itemWH); 214 | 215 | _collection = [[UICollectionView alloc] initWithFrame:rect collectionViewLayout:layout]; 216 | _collection.backgroundColor = [UIColor whiteColor]; 217 | _collection.dataSource = self; 218 | _collection.delegate = self; 219 | [_collection registerClass:[WZMediaAssetBaseCell class] forCellWithReuseIdentifier:NSStringFromClass([WZMediaAssetBaseCell class])]; 220 | } 221 | return _collection; 222 | } 223 | 224 | 225 | @end 226 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKit/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TestPhotoKit 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. 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 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKitUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /TestPhotoKit/TestPhotoKitUITests/TestPhotoKitUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // TestPhotoKitUITests.m 3 | // TestPhotoKitUITests 4 | // 5 | // Created by admin on 16/7/8. 6 | // Copyright © 2016年 admin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TestPhotoKitUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation TestPhotoKitUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/NSData+ImageContentType.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Fabrice Aneche on 06/01/14. 3 | // Copyright (c) 2014 Dailymotion. All rights reserved. 4 | // 5 | 6 | #import 7 | 8 | @interface NSData (ImageContentType) 9 | 10 | /** 11 | * Compute the content type for an image data 12 | * 13 | * @param data the input data 14 | * 15 | * @return the content type as string (i.e. image/jpeg, image/gif) 16 | */ 17 | + (NSString *)sd_contentTypeForImageData:(NSData *)data; 18 | 19 | @end 20 | 21 | 22 | @interface NSData (ImageContentTypeDeprecated) 23 | 24 | + (NSString *)contentTypeForImageData:(NSData *)data __deprecated_msg("Use `sd_contentTypeForImageData:`"); 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/NSData+ImageContentType.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Fabrice Aneche on 06/01/14. 3 | // Copyright (c) 2014 Dailymotion. All rights reserved. 4 | // 5 | 6 | #import "NSData+ImageContentType.h" 7 | 8 | 9 | @implementation NSData (ImageContentType) 10 | 11 | + (NSString *)sd_contentTypeForImageData:(NSData *)data { 12 | uint8_t c; 13 | [data getBytes:&c length:1]; 14 | switch (c) { 15 | case 0xFF: 16 | return @"image/jpeg"; 17 | case 0x89: 18 | return @"image/png"; 19 | case 0x47: 20 | return @"image/gif"; 21 | case 0x49: 22 | case 0x4D: 23 | return @"image/tiff"; 24 | case 0x52: 25 | // R as RIFF for WEBP 26 | if ([data length] < 12) { 27 | return nil; 28 | } 29 | 30 | NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; 31 | if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { 32 | return @"image/webp"; 33 | } 34 | 35 | return nil; 36 | } 37 | return nil; 38 | } 39 | 40 | @end 41 | 42 | 43 | @implementation NSData (ImageContentTypeDeprecated) 44 | 45 | + (NSString *)contentTypeForImageData:(NSData *)data { 46 | return [self sd_contentTypeForImageData:data]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDImageCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | 12 | typedef NS_ENUM(NSInteger, SDImageCacheType) { 13 | /** 14 | * The image wasn't available the SDWebImage caches, but was downloaded from the web. 15 | */ 16 | SDImageCacheTypeNone, 17 | /** 18 | * The image was obtained from the disk cache. 19 | */ 20 | SDImageCacheTypeDisk, 21 | /** 22 | * The image was obtained from the memory cache. 23 | */ 24 | SDImageCacheTypeMemory 25 | }; 26 | 27 | typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType cacheType); 28 | 29 | typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); 30 | 31 | typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); 32 | 33 | /** 34 | * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed 35 | * asynchronous so it doesn’t add unnecessary latency to the UI. 36 | */ 37 | @interface SDImageCache : NSObject 38 | 39 | /** 40 | * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. 41 | * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. 42 | */ 43 | @property (assign, nonatomic) BOOL shouldDecompressImages; 44 | 45 | /** 46 | * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. 47 | */ 48 | @property (assign, nonatomic) NSUInteger maxMemoryCost; 49 | 50 | /** 51 | * The maximum number of objects the cache should hold. 52 | */ 53 | @property (assign, nonatomic) NSUInteger maxMemoryCountLimit; 54 | 55 | /** 56 | * The maximum length of time to keep an image in the cache, in seconds 57 | */ 58 | @property (assign, nonatomic) NSInteger maxCacheAge; 59 | 60 | /** 61 | * The maximum size of the cache, in bytes. 62 | */ 63 | @property (assign, nonatomic) NSUInteger maxCacheSize; 64 | 65 | /** 66 | * Returns global shared cache instance 67 | * 68 | * @return SDImageCache global instance 69 | */ 70 | + (SDImageCache *)sharedImageCache; 71 | 72 | /** 73 | * Init a new cache store with a specific namespace 74 | * 75 | * @param ns The namespace to use for this cache store 76 | */ 77 | - (id)initWithNamespace:(NSString *)ns; 78 | 79 | /** 80 | * Init a new cache store with a specific namespace and directory 81 | * 82 | * @param ns The namespace to use for this cache store 83 | * @param directory Directory to cache disk images in 84 | */ 85 | - (id)initWithNamespace:(NSString *)ns diskCacheDirectory:(NSString *)directory; 86 | 87 | -(NSString *)makeDiskCachePath:(NSString*)fullNamespace; 88 | 89 | /** 90 | * Add a read-only cache path to search for images pre-cached by SDImageCache 91 | * Useful if you want to bundle pre-loaded images with your app 92 | * 93 | * @param path The path to use for this read-only cache path 94 | */ 95 | - (void)addReadOnlyCachePath:(NSString *)path; 96 | 97 | /** 98 | * Store an image into memory and disk cache at the given key. 99 | * 100 | * @param image The image to store 101 | * @param key The unique image cache key, usually it's image absolute URL 102 | */ 103 | - (void)storeImage:(UIImage *)image forKey:(NSString *)key; 104 | 105 | /** 106 | * Store an image into memory and optionally disk cache at the given key. 107 | * 108 | * @param image The image to store 109 | * @param key The unique image cache key, usually it's image absolute URL 110 | * @param toDisk Store the image to disk cache if YES 111 | */ 112 | - (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk; 113 | 114 | /** 115 | * Store an image into memory and optionally disk cache at the given key. 116 | * 117 | * @param image The image to store 118 | * @param recalculate BOOL indicates if imageData can be used or a new data should be constructed from the UIImage 119 | * @param imageData The image data as returned by the server, this representation will be used for disk storage 120 | * instead of converting the given image object into a storable/compressed image format in order 121 | * to save quality and CPU 122 | * @param key The unique image cache key, usually it's image absolute URL 123 | * @param toDisk Store the image to disk cache if YES 124 | */ 125 | - (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk; 126 | 127 | /** 128 | * Query the disk cache asynchronously. 129 | * 130 | * @param key The unique key used to store the wanted image 131 | */ 132 | - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock; 133 | 134 | /** 135 | * Query the memory cache synchronously. 136 | * 137 | * @param key The unique key used to store the wanted image 138 | */ 139 | - (UIImage *)imageFromMemoryCacheForKey:(NSString *)key; 140 | 141 | /** 142 | * Query the disk cache synchronously after checking the memory cache. 143 | * 144 | * @param key The unique key used to store the wanted image 145 | */ 146 | - (UIImage *)imageFromDiskCacheForKey:(NSString *)key; 147 | 148 | /** 149 | * Remove the image from memory and disk cache synchronously 150 | * 151 | * @param key The unique image cache key 152 | */ 153 | - (void)removeImageForKey:(NSString *)key; 154 | 155 | 156 | /** 157 | * Remove the image from memory and disk cache asynchronously 158 | * 159 | * @param key The unique image cache key 160 | * @param completion An block that should be executed after the image has been removed (optional) 161 | */ 162 | - (void)removeImageForKey:(NSString *)key withCompletion:(SDWebImageNoParamsBlock)completion; 163 | 164 | /** 165 | * Remove the image from memory and optionally disk cache asynchronously 166 | * 167 | * @param key The unique image cache key 168 | * @param fromDisk Also remove cache entry from disk if YES 169 | */ 170 | - (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk; 171 | 172 | /** 173 | * Remove the image from memory and optionally disk cache asynchronously 174 | * 175 | * @param key The unique image cache key 176 | * @param fromDisk Also remove cache entry from disk if YES 177 | * @param completion An block that should be executed after the image has been removed (optional) 178 | */ 179 | - (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion; 180 | 181 | /** 182 | * Clear all memory cached images 183 | */ 184 | - (void)clearMemory; 185 | 186 | /** 187 | * Clear all disk cached images. Non-blocking method - returns immediately. 188 | * @param completion An block that should be executed after cache expiration completes (optional) 189 | */ 190 | - (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion; 191 | 192 | /** 193 | * Clear all disk cached images 194 | * @see clearDiskOnCompletion: 195 | */ 196 | - (void)clearDisk; 197 | 198 | /** 199 | * Remove all expired cached image from disk. Non-blocking method - returns immediately. 200 | * @param completionBlock An block that should be executed after cache expiration completes (optional) 201 | */ 202 | - (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock; 203 | 204 | /** 205 | * Remove all expired cached image from disk 206 | * @see cleanDiskWithCompletionBlock: 207 | */ 208 | - (void)cleanDisk; 209 | 210 | /** 211 | * Get the size used by the disk cache 212 | */ 213 | - (NSUInteger)getSize; 214 | 215 | /** 216 | * Get the number of images in the disk cache 217 | */ 218 | - (NSUInteger)getDiskCount; 219 | 220 | /** 221 | * Asynchronously calculate the disk cache's size. 222 | */ 223 | - (void)calculateSizeWithCompletionBlock:(SDWebImageCalculateSizeBlock)completionBlock; 224 | 225 | /** 226 | * Async check if image exists in disk cache already (does not load the image) 227 | * 228 | * @param key the key describing the url 229 | * @param completionBlock the block to be executed when the check is done. 230 | * @note the completion block will be always executed on the main queue 231 | */ 232 | - (void)diskImageExistsWithKey:(NSString *)key completion:(SDWebImageCheckCacheCompletionBlock)completionBlock; 233 | 234 | /** 235 | * Check if image exists in disk cache already (does not load the image) 236 | * 237 | * @param key the key describing the url 238 | * 239 | * @return YES if an image exists for the given key 240 | */ 241 | - (BOOL)diskImageExistsWithKey:(NSString *)key; 242 | 243 | /** 244 | * Get the cache path for a certain key (needs the cache path root folder) 245 | * 246 | * @param key the key (can be obtained from url using cacheKeyForURL) 247 | * @param path the cach path root folder 248 | * 249 | * @return the cache path 250 | */ 251 | - (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path; 252 | 253 | /** 254 | * Get the default cache path for a certain key 255 | * 256 | * @param key the key (can be obtained from url using cacheKeyForURL) 257 | * 258 | * @return the default cache path 259 | */ 260 | - (NSString *)defaultCachePathForKey:(NSString *)key; 261 | 262 | @end 263 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageCompat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * (c) Jamie Pinkham 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | #import 11 | 12 | #ifdef __OBJC_GC__ 13 | #error SDWebImage does not support Objective-C Garbage Collection 14 | #endif 15 | 16 | #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 17 | #error SDWebImage doesn't support Deployement Target version < 5.0 18 | #endif 19 | 20 | #if !TARGET_OS_IPHONE 21 | #import 22 | #ifndef UIImage 23 | #define UIImage NSImage 24 | #endif 25 | #ifndef UIImageView 26 | #define UIImageView NSImageView 27 | #endif 28 | #else 29 | 30 | #import 31 | 32 | #endif 33 | 34 | #ifndef NS_ENUM 35 | #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type 36 | #endif 37 | 38 | #ifndef NS_OPTIONS 39 | #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type 40 | #endif 41 | 42 | #if OS_OBJECT_USE_OBJC 43 | #undef SDDispatchQueueRelease 44 | #undef SDDispatchQueueSetterSementics 45 | #define SDDispatchQueueRelease(q) 46 | #define SDDispatchQueueSetterSementics strong 47 | #else 48 | #undef SDDispatchQueueRelease 49 | #undef SDDispatchQueueSetterSementics 50 | #define SDDispatchQueueRelease(q) (dispatch_release(q)) 51 | #define SDDispatchQueueSetterSementics assign 52 | #endif 53 | 54 | extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image); 55 | 56 | typedef void(^SDWebImageNoParamsBlock)(); 57 | 58 | extern NSString *const SDWebImageErrorDomain; 59 | 60 | #define dispatch_main_sync_safe(block)\ 61 | if ([NSThread isMainThread]) {\ 62 | block();\ 63 | } else {\ 64 | dispatch_sync(dispatch_get_main_queue(), block);\ 65 | } 66 | 67 | #define dispatch_main_async_safe(block)\ 68 | if ([NSThread isMainThread]) {\ 69 | block();\ 70 | } else {\ 71 | dispatch_async(dispatch_get_main_queue(), block);\ 72 | } 73 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageCompat.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDWebImageCompat.m 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 11/12/12. 6 | // Copyright (c) 2012 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import "SDWebImageCompat.h" 10 | 11 | #if !__has_feature(objc_arc) 12 | #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag 13 | #endif 14 | 15 | inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) { 16 | if (!image) { 17 | return nil; 18 | } 19 | 20 | if ([image.images count] > 0) { 21 | NSMutableArray *scaledImages = [NSMutableArray array]; 22 | 23 | for (UIImage *tempImage in image.images) { 24 | [scaledImages addObject:SDScaledImageForKey(key, tempImage)]; 25 | } 26 | 27 | return [UIImage animatedImageWithImages:scaledImages duration:image.duration]; 28 | } 29 | else { 30 | if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { 31 | CGFloat scale = 1.0; 32 | if (key.length >= 8) { 33 | NSRange range = [key rangeOfString:@"@2x."]; 34 | if (range.location != NSNotFound) { 35 | scale = 2.0; 36 | } 37 | 38 | range = [key rangeOfString:@"@3x."]; 39 | if (range.location != NSNotFound) { 40 | scale = 3.0; 41 | } 42 | } 43 | 44 | UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; 45 | image = scaledImage; 46 | } 47 | return image; 48 | } 49 | } 50 | 51 | NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; 52 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageDecoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * Created by james on 9/28/11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | #import 12 | #import "SDWebImageCompat.h" 13 | 14 | @interface UIImage (ForceDecode) 15 | 16 | + (UIImage *)decodedImageWithImage:(UIImage *)image; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageDecoder.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * Created by james on 9/28/11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | #import "SDWebImageDecoder.h" 12 | 13 | @implementation UIImage (ForceDecode) 14 | 15 | + (UIImage *)decodedImageWithImage:(UIImage *)image { 16 | if (image.images) { 17 | // Do not decode animated images 18 | return image; 19 | } 20 | 21 | CGImageRef imageRef = image.CGImage; 22 | CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); 23 | CGRect imageRect = (CGRect){.origin = CGPointZero, .size = imageSize}; 24 | 25 | CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 26 | CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); 27 | 28 | int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask); 29 | BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone || 30 | infoMask == kCGImageAlphaNoneSkipFirst || 31 | infoMask == kCGImageAlphaNoneSkipLast); 32 | 33 | // CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB. 34 | // https://developer.apple.com/library/mac/#qa/qa1037/_index.html 35 | if (infoMask == kCGImageAlphaNone && CGColorSpaceGetNumberOfComponents(colorSpace) > 1) { 36 | // Unset the old alpha info. 37 | bitmapInfo &= ~kCGBitmapAlphaInfoMask; 38 | 39 | // Set noneSkipFirst. 40 | bitmapInfo |= kCGImageAlphaNoneSkipFirst; 41 | } 42 | // Some PNGs tell us they have alpha but only 3 components. Odd. 43 | else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace) == 3) { 44 | // Unset the old alpha info. 45 | bitmapInfo &= ~kCGBitmapAlphaInfoMask; 46 | bitmapInfo |= kCGImageAlphaPremultipliedFirst; 47 | } 48 | 49 | // It calculates the bytes-per-row based on the bitsPerComponent and width arguments. 50 | CGContextRef context = CGBitmapContextCreate(NULL, 51 | imageSize.width, 52 | imageSize.height, 53 | CGImageGetBitsPerComponent(imageRef), 54 | 0, 55 | colorSpace, 56 | bitmapInfo); 57 | CGColorSpaceRelease(colorSpace); 58 | 59 | // If failed, return undecompressed image 60 | if (!context) return image; 61 | 62 | CGContextDrawImage(context, imageRect, imageRef); 63 | CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context); 64 | 65 | CGContextRelease(context); 66 | 67 | UIImage *decompressedImage = [UIImage imageWithCGImage:decompressedImageRef scale:image.scale orientation:image.imageOrientation]; 68 | CGImageRelease(decompressedImageRef); 69 | return decompressedImage; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageDownloader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | #import "SDWebImageOperation.h" 12 | 13 | typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { 14 | SDWebImageDownloaderLowPriority = 1 << 0, 15 | SDWebImageDownloaderProgressiveDownload = 1 << 1, 16 | 17 | /** 18 | * By default, request prevent the of NSURLCache. With this flag, NSURLCache 19 | * is used with default policies. 20 | */ 21 | SDWebImageDownloaderUseNSURLCache = 1 << 2, 22 | 23 | /** 24 | * Call completion block with nil image/imageData if the image was read from NSURLCache 25 | * (to be combined with `SDWebImageDownloaderUseNSURLCache`). 26 | */ 27 | 28 | SDWebImageDownloaderIgnoreCachedResponse = 1 << 3, 29 | /** 30 | * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for 31 | * extra time in background to let the request finish. If the background task expires the operation will be cancelled. 32 | */ 33 | 34 | SDWebImageDownloaderContinueInBackground = 1 << 4, 35 | 36 | /** 37 | * Handles cookies stored in NSHTTPCookieStore by setting 38 | * NSMutableURLRequest.HTTPShouldHandleCookies = YES; 39 | */ 40 | SDWebImageDownloaderHandleCookies = 1 << 5, 41 | 42 | /** 43 | * Enable to allow untrusted SSL ceriticates. 44 | * Useful for testing purposes. Use with caution in production. 45 | */ 46 | SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6, 47 | 48 | /** 49 | * Put the image in the high priority queue. 50 | */ 51 | SDWebImageDownloaderHighPriority = 1 << 7, 52 | }; 53 | 54 | typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { 55 | /** 56 | * Default value. All download operations will execute in queue style (first-in-first-out). 57 | */ 58 | SDWebImageDownloaderFIFOExecutionOrder, 59 | 60 | /** 61 | * All download operations will execute in stack style (last-in-first-out). 62 | */ 63 | SDWebImageDownloaderLIFOExecutionOrder 64 | }; 65 | 66 | extern NSString *const SDWebImageDownloadStartNotification; 67 | extern NSString *const SDWebImageDownloadStopNotification; 68 | 69 | typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize); 70 | 71 | typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished); 72 | 73 | typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDictionary *headers); 74 | 75 | /** 76 | * Asynchronous downloader dedicated and optimized for image loading. 77 | */ 78 | @interface SDWebImageDownloader : NSObject 79 | 80 | /** 81 | * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. 82 | * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. 83 | */ 84 | @property (assign, nonatomic) BOOL shouldDecompressImages; 85 | 86 | @property (assign, nonatomic) NSInteger maxConcurrentDownloads; 87 | 88 | /** 89 | * Shows the current amount of downloads that still need to be downloaded 90 | */ 91 | @property (readonly, nonatomic) NSUInteger currentDownloadCount; 92 | 93 | 94 | /** 95 | * The timeout value (in seconds) for the download operation. Default: 15.0. 96 | */ 97 | @property (assign, nonatomic) NSTimeInterval downloadTimeout; 98 | 99 | 100 | /** 101 | * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. 102 | */ 103 | @property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; 104 | 105 | /** 106 | * Singleton method, returns the shared instance 107 | * 108 | * @return global shared instance of downloader class 109 | */ 110 | + (SDWebImageDownloader *)sharedDownloader; 111 | 112 | /** 113 | * Set username 114 | */ 115 | @property (strong, nonatomic) NSString *username; 116 | 117 | /** 118 | * Set password 119 | */ 120 | @property (strong, nonatomic) NSString *password; 121 | 122 | /** 123 | * Set filter to pick headers for downloading image HTTP request. 124 | * 125 | * This block will be invoked for each downloading image request, returned 126 | * NSDictionary will be used as headers in corresponding HTTP request. 127 | */ 128 | @property (nonatomic, copy) SDWebImageDownloaderHeadersFilterBlock headersFilter; 129 | 130 | /** 131 | * Set a value for a HTTP header to be appended to each download HTTP request. 132 | * 133 | * @param value The value for the header field. Use `nil` value to remove the header. 134 | * @param field The name of the header field to set. 135 | */ 136 | - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; 137 | 138 | /** 139 | * Returns the value of the specified HTTP header field. 140 | * 141 | * @return The value associated with the header field field, or `nil` if there is no corresponding header field. 142 | */ 143 | - (NSString *)valueForHTTPHeaderField:(NSString *)field; 144 | 145 | /** 146 | * Sets a subclass of `SDWebImageDownloaderOperation` as the default 147 | * `NSOperation` to be used each time SDWebImage constructs a request 148 | * operation to download an image. 149 | * 150 | * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set 151 | * as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. 152 | */ 153 | - (void)setOperationClass:(Class)operationClass; 154 | 155 | /** 156 | * Creates a SDWebImageDownloader async downloader instance with a given URL 157 | * 158 | * The delegate will be informed when the image is finish downloaded or an error has happen. 159 | * 160 | * @see SDWebImageDownloaderDelegate 161 | * 162 | * @param url The URL to the image to download 163 | * @param options The options to be used for this download 164 | * @param progressBlock A block called repeatedly while the image is downloading 165 | * @param completedBlock A block called once the download is completed. 166 | * If the download succeeded, the image parameter is set, in case of error, 167 | * error parameter is set with the error. The last parameter is always YES 168 | * if SDWebImageDownloaderProgressiveDownload isn't use. With the 169 | * SDWebImageDownloaderProgressiveDownload option, this block is called 170 | * repeatedly with the partial image object and the finished argument set to NO 171 | * before to be called a last time with the full image and finished argument 172 | * set to YES. In case of error, the finished argument is always YES. 173 | * 174 | * @return A cancellable SDWebImageOperation 175 | */ 176 | - (id )downloadImageWithURL:(NSURL *)url 177 | options:(SDWebImageDownloaderOptions)options 178 | progress:(SDWebImageDownloaderProgressBlock)progressBlock 179 | completed:(SDWebImageDownloaderCompletedBlock)completedBlock; 180 | 181 | /** 182 | * Sets the download queue suspension state 183 | */ 184 | - (void)setSuspended:(BOOL)suspended; 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageDownloaderOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageDownloader.h" 11 | #import "SDWebImageOperation.h" 12 | 13 | extern NSString *const SDWebImageDownloadStartNotification; 14 | extern NSString *const SDWebImageDownloadReceiveResponseNotification; 15 | extern NSString *const SDWebImageDownloadStopNotification; 16 | extern NSString *const SDWebImageDownloadFinishNotification; 17 | 18 | @interface SDWebImageDownloaderOperation : NSOperation 19 | 20 | /** 21 | * The request used by the operation's connection. 22 | */ 23 | @property (strong, nonatomic, readonly) NSURLRequest *request; 24 | 25 | 26 | @property (assign, nonatomic) BOOL shouldDecompressImages; 27 | 28 | /** 29 | * Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. 30 | * 31 | * This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. 32 | */ 33 | @property (nonatomic, assign) BOOL shouldUseCredentialStorage; 34 | 35 | /** 36 | * The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. 37 | * 38 | * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. 39 | */ 40 | @property (nonatomic, strong) NSURLCredential *credential; 41 | 42 | /** 43 | * The SDWebImageDownloaderOptions for the receiver. 44 | */ 45 | @property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; 46 | 47 | /** 48 | * The expected size of data. 49 | */ 50 | @property (assign, nonatomic) NSInteger expectedSize; 51 | 52 | /** 53 | * The response returned by the operation's connection. 54 | */ 55 | @property (strong, nonatomic) NSURLResponse *response; 56 | 57 | /** 58 | * Initializes a `SDWebImageDownloaderOperation` object 59 | * 60 | * @see SDWebImageDownloaderOperation 61 | * 62 | * @param request the URL request 63 | * @param options downloader options 64 | * @param progressBlock the block executed when a new chunk of data arrives. 65 | * @note the progress block is executed on a background queue 66 | * @param completedBlock the block executed when the download is done. 67 | * @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue 68 | * @param cancelBlock the block executed if the download (operation) is cancelled 69 | * 70 | * @return the initialized instance 71 | */ 72 | - (id)initWithRequest:(NSURLRequest *)request 73 | options:(SDWebImageDownloaderOptions)options 74 | progress:(SDWebImageDownloaderProgressBlock)progressBlock 75 | completed:(SDWebImageDownloaderCompletedBlock)completedBlock 76 | cancelled:(SDWebImageNoParamsBlock)cancelBlock; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImageOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | 11 | @protocol SDWebImageOperation 12 | 13 | - (void)cancel; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImagePrefetcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageManager.h" 11 | 12 | @class SDWebImagePrefetcher; 13 | 14 | @protocol SDWebImagePrefetcherDelegate 15 | 16 | @optional 17 | 18 | /** 19 | * Called when an image was prefetched. 20 | * 21 | * @param imagePrefetcher The current image prefetcher 22 | * @param imageURL The image url that was prefetched 23 | * @param finishedCount The total number of images that were prefetched (successful or not) 24 | * @param totalCount The total number of images that were to be prefetched 25 | */ 26 | - (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount; 27 | 28 | /** 29 | * Called when all images are prefetched. 30 | * @param imagePrefetcher The current image prefetcher 31 | * @param totalCount The total number of images that were prefetched (whether successful or not) 32 | * @param skippedCount The total number of images that were skipped 33 | */ 34 | - (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount; 35 | 36 | @end 37 | 38 | typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls); 39 | typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls); 40 | 41 | /** 42 | * Prefetch some URLs in the cache for future use. Images are downloaded in low priority. 43 | */ 44 | @interface SDWebImagePrefetcher : NSObject 45 | 46 | /** 47 | * The web image manager 48 | */ 49 | @property (strong, nonatomic, readonly) SDWebImageManager *manager; 50 | 51 | /** 52 | * Maximum number of URLs to prefetch at the same time. Defaults to 3. 53 | */ 54 | @property (nonatomic, assign) NSUInteger maxConcurrentDownloads; 55 | 56 | /** 57 | * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority. 58 | */ 59 | @property (nonatomic, assign) SDWebImageOptions options; 60 | 61 | /** 62 | * Queue options for Prefetcher. Defaults to Main Queue. 63 | */ 64 | @property (nonatomic, assign) dispatch_queue_t prefetcherQueue; 65 | 66 | @property (weak, nonatomic) id delegate; 67 | 68 | /** 69 | * Return the global image prefetcher instance. 70 | */ 71 | + (SDWebImagePrefetcher *)sharedImagePrefetcher; 72 | 73 | /** 74 | * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, 75 | * currently one image is downloaded at a time, 76 | * and skips images for failed downloads and proceed to the next image in the list 77 | * 78 | * @param urls list of URLs to prefetch 79 | */ 80 | - (void)prefetchURLs:(NSArray *)urls; 81 | 82 | /** 83 | * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, 84 | * currently one image is downloaded at a time, 85 | * and skips images for failed downloads and proceed to the next image in the list 86 | * 87 | * @param urls list of URLs to prefetch 88 | * @param progressBlock block to be called when progress updates; 89 | * first parameter is the number of completed (successful or not) requests, 90 | * second parameter is the total number of images originally requested to be prefetched 91 | * @param completionBlock block to be called when prefetching is completed 92 | * first param is the number of completed (successful or not) requests, 93 | * second parameter is the number of skipped requests 94 | */ 95 | - (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock; 96 | 97 | /** 98 | * Remove and cancel queued list 99 | */ 100 | - (void)cancelPrefetching; 101 | 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/SDWebImagePrefetcher.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDWebImagePrefetcher.h" 10 | 11 | #if (!defined(DEBUG) && !defined (SD_VERBOSE)) || defined(SD_LOG_NONE) 12 | #define NSLog(...) 13 | #endif 14 | 15 | @interface SDWebImagePrefetcher () 16 | 17 | @property (strong, nonatomic) SDWebImageManager *manager; 18 | @property (strong, nonatomic) NSArray *prefetchURLs; 19 | @property (assign, nonatomic) NSUInteger requestedCount; 20 | @property (assign, nonatomic) NSUInteger skippedCount; 21 | @property (assign, nonatomic) NSUInteger finishedCount; 22 | @property (assign, nonatomic) NSTimeInterval startedTime; 23 | @property (copy, nonatomic) SDWebImagePrefetcherCompletionBlock completionBlock; 24 | @property (copy, nonatomic) SDWebImagePrefetcherProgressBlock progressBlock; 25 | 26 | @end 27 | 28 | @implementation SDWebImagePrefetcher 29 | 30 | + (SDWebImagePrefetcher *)sharedImagePrefetcher { 31 | static dispatch_once_t once; 32 | static id instance; 33 | dispatch_once(&once, ^{ 34 | instance = [self new]; 35 | }); 36 | return instance; 37 | } 38 | 39 | - (id)init { 40 | if ((self = [super init])) { 41 | _manager = [SDWebImageManager new]; 42 | _options = SDWebImageLowPriority; 43 | _prefetcherQueue = dispatch_get_main_queue(); 44 | self.maxConcurrentDownloads = 3; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { 50 | self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads; 51 | } 52 | 53 | - (NSUInteger)maxConcurrentDownloads { 54 | return self.manager.imageDownloader.maxConcurrentDownloads; 55 | } 56 | 57 | - (void)startPrefetchingAtIndex:(NSUInteger)index { 58 | if (index >= self.prefetchURLs.count) return; 59 | self.requestedCount++; 60 | [self.manager downloadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 61 | if (!finished) return; 62 | self.finishedCount++; 63 | 64 | if (image) { 65 | if (self.progressBlock) { 66 | self.progressBlock(self.finishedCount,[self.prefetchURLs count]); 67 | } 68 | NSLog(@"Prefetched %@ out of %@", @(self.finishedCount), @(self.prefetchURLs.count)); 69 | } 70 | else { 71 | if (self.progressBlock) { 72 | self.progressBlock(self.finishedCount,[self.prefetchURLs count]); 73 | } 74 | NSLog(@"Prefetched %@ out of %@ (Failed)", @(self.finishedCount), @(self.prefetchURLs.count)); 75 | 76 | // Add last failed 77 | self.skippedCount++; 78 | } 79 | if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) { 80 | [self.delegate imagePrefetcher:self 81 | didPrefetchURL:self.prefetchURLs[index] 82 | finishedCount:self.finishedCount 83 | totalCount:self.prefetchURLs.count 84 | ]; 85 | } 86 | if (self.prefetchURLs.count > self.requestedCount) { 87 | dispatch_async(self.prefetcherQueue, ^{ 88 | [self startPrefetchingAtIndex:self.requestedCount]; 89 | }); 90 | } 91 | else if (self.finishedCount == self.requestedCount) { 92 | [self reportStatus]; 93 | if (self.completionBlock) { 94 | self.completionBlock(self.finishedCount, self.skippedCount); 95 | self.completionBlock = nil; 96 | } 97 | self.progressBlock = nil; 98 | } 99 | }]; 100 | } 101 | 102 | - (void)reportStatus { 103 | NSUInteger total = [self.prefetchURLs count]; 104 | NSLog(@"Finished prefetching (%@ successful, %@ skipped, timeElasped %.2f)", @(total - self.skippedCount), @(self.skippedCount), CFAbsoluteTimeGetCurrent() - self.startedTime); 105 | if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) { 106 | [self.delegate imagePrefetcher:self 107 | didFinishWithTotalCount:(total - self.skippedCount) 108 | skippedCount:self.skippedCount 109 | ]; 110 | } 111 | } 112 | 113 | - (void)prefetchURLs:(NSArray *)urls { 114 | [self prefetchURLs:urls progress:nil completed:nil]; 115 | } 116 | 117 | - (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock { 118 | [self cancelPrefetching]; // Prevent duplicate prefetch request 119 | self.startedTime = CFAbsoluteTimeGetCurrent(); 120 | self.prefetchURLs = urls; 121 | self.completionBlock = completionBlock; 122 | self.progressBlock = progressBlock; 123 | 124 | if(urls.count == 0){ 125 | if(completionBlock){ 126 | completionBlock(0,0); 127 | } 128 | }else{ 129 | // Starts prefetching from the very first image on the list with the max allowed concurrency 130 | NSUInteger listCount = self.prefetchURLs.count; 131 | for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { 132 | [self startPrefetchingAtIndex:i]; 133 | } 134 | } 135 | } 136 | 137 | - (void)cancelPrefetching { 138 | self.prefetchURLs = nil; 139 | self.skippedCount = 0; 140 | self.requestedCount = 0; 141 | self.finishedCount = 0; 142 | [self.manager cancelAll]; 143 | } 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImage+GIF.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+GIF.h 3 | // LBGIFImage 4 | // 5 | // Created by Laurin Brandner on 06.01.12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (GIF) 12 | 13 | + (UIImage *)sd_animatedGIFNamed:(NSString *)name; 14 | 15 | + (UIImage *)sd_animatedGIFWithData:(NSData *)data; 16 | 17 | - (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImage+GIF.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+GIF.m 3 | // LBGIFImage 4 | // 5 | // Created by Laurin Brandner on 06.01.12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "UIImage+GIF.h" 10 | #import 11 | 12 | @implementation UIImage (GIF) 13 | 14 | + (UIImage *)sd_animatedGIFWithData:(NSData *)data { 15 | if (!data) { 16 | return nil; 17 | } 18 | 19 | CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); 20 | 21 | size_t count = CGImageSourceGetCount(source); 22 | 23 | UIImage *animatedImage; 24 | 25 | if (count <= 1) { 26 | animatedImage = [[UIImage alloc] initWithData:data]; 27 | } 28 | else { 29 | NSMutableArray *images = [NSMutableArray array]; 30 | 31 | NSTimeInterval duration = 0.0f; 32 | 33 | for (size_t i = 0; i < count; i++) { 34 | CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); 35 | 36 | duration += [self sd_frameDurationAtIndex:i source:source]; 37 | 38 | [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; 39 | 40 | CGImageRelease(image); 41 | } 42 | 43 | if (!duration) { 44 | duration = (1.0f / 10.0f) * count; 45 | } 46 | 47 | animatedImage = [UIImage animatedImageWithImages:images duration:duration]; 48 | } 49 | 50 | CFRelease(source); 51 | 52 | return animatedImage; 53 | } 54 | 55 | + (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { 56 | float frameDuration = 0.1f; 57 | CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); 58 | NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; 59 | NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; 60 | 61 | NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; 62 | if (delayTimeUnclampedProp) { 63 | frameDuration = [delayTimeUnclampedProp floatValue]; 64 | } 65 | else { 66 | 67 | NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; 68 | if (delayTimeProp) { 69 | frameDuration = [delayTimeProp floatValue]; 70 | } 71 | } 72 | 73 | // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. 74 | // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify 75 | // a duration of <= 10 ms. See and 76 | // for more information. 77 | 78 | if (frameDuration < 0.011f) { 79 | frameDuration = 0.100f; 80 | } 81 | 82 | CFRelease(cfFrameProperties); 83 | return frameDuration; 84 | } 85 | 86 | + (UIImage *)sd_animatedGIFNamed:(NSString *)name { 87 | CGFloat scale = [UIScreen mainScreen].scale; 88 | 89 | if (scale > 1.0f) { 90 | NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"]; 91 | 92 | NSData *data = [NSData dataWithContentsOfFile:retinaPath]; 93 | 94 | if (data) { 95 | return [UIImage sd_animatedGIFWithData:data]; 96 | } 97 | 98 | NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; 99 | 100 | data = [NSData dataWithContentsOfFile:path]; 101 | 102 | if (data) { 103 | return [UIImage sd_animatedGIFWithData:data]; 104 | } 105 | 106 | return [UIImage imageNamed:name]; 107 | } 108 | else { 109 | NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; 110 | 111 | NSData *data = [NSData dataWithContentsOfFile:path]; 112 | 113 | if (data) { 114 | return [UIImage sd_animatedGIFWithData:data]; 115 | } 116 | 117 | return [UIImage imageNamed:name]; 118 | } 119 | } 120 | 121 | - (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size { 122 | if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) { 123 | return self; 124 | } 125 | 126 | CGSize scaledSize = size; 127 | CGPoint thumbnailPoint = CGPointZero; 128 | 129 | CGFloat widthFactor = size.width / self.size.width; 130 | CGFloat heightFactor = size.height / self.size.height; 131 | CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor; 132 | scaledSize.width = self.size.width * scaleFactor; 133 | scaledSize.height = self.size.height * scaleFactor; 134 | 135 | if (widthFactor > heightFactor) { 136 | thumbnailPoint.y = (size.height - scaledSize.height) * 0.5; 137 | } 138 | else if (widthFactor < heightFactor) { 139 | thumbnailPoint.x = (size.width - scaledSize.width) * 0.5; 140 | } 141 | 142 | NSMutableArray *scaledImages = [NSMutableArray array]; 143 | 144 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); 145 | 146 | for (UIImage *image in self.images) { 147 | [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)]; 148 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 149 | 150 | [scaledImages addObject:newImage]; 151 | } 152 | 153 | UIGraphicsEndImageContext(); 154 | 155 | return [UIImage animatedImageWithImages:scaledImages duration:self.duration]; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImage+MultiFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+MultiFormat.h 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 07/06/13. 6 | // Copyright (c) 2013 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (MultiFormat) 12 | 13 | + (UIImage *)sd_imageWithData:(NSData *)data; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImage+MultiFormat.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+MultiFormat.m 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 07/06/13. 6 | // Copyright (c) 2013 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import "UIImage+MultiFormat.h" 10 | #import "UIImage+GIF.h" 11 | #import "NSData+ImageContentType.h" 12 | #import 13 | 14 | #ifdef SD_WEBP 15 | #import "UIImage+WebP.h" 16 | #endif 17 | 18 | @implementation UIImage (MultiFormat) 19 | 20 | + (UIImage *)sd_imageWithData:(NSData *)data { 21 | if (!data) { 22 | return nil; 23 | } 24 | 25 | UIImage *image; 26 | NSString *imageContentType = [NSData sd_contentTypeForImageData:data]; 27 | if ([imageContentType isEqualToString:@"image/gif"]) { 28 | image = [UIImage sd_animatedGIFWithData:data]; 29 | } 30 | #ifdef SD_WEBP 31 | else if ([imageContentType isEqualToString:@"image/webp"]) 32 | { 33 | image = [UIImage sd_imageWithWebPData:data]; 34 | } 35 | #endif 36 | else { 37 | image = [[UIImage alloc] initWithData:data]; 38 | UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data]; 39 | if (orientation != UIImageOrientationUp) { 40 | image = [UIImage imageWithCGImage:image.CGImage 41 | scale:image.scale 42 | orientation:orientation]; 43 | } 44 | } 45 | 46 | 47 | return image; 48 | } 49 | 50 | 51 | +(UIImageOrientation)sd_imageOrientationFromImageData:(NSData *)imageData { 52 | UIImageOrientation result = UIImageOrientationUp; 53 | CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); 54 | if (imageSource) { 55 | CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); 56 | if (properties) { 57 | CFTypeRef val; 58 | int exifOrientation; 59 | val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); 60 | if (val) { 61 | CFNumberGetValue(val, kCFNumberIntType, &exifOrientation); 62 | result = [self sd_exifOrientationToiOSOrientation:exifOrientation]; 63 | } // else - if it's not set it remains at up 64 | CFRelease((CFTypeRef) properties); 65 | } else { 66 | //NSLog(@"NO PROPERTIES, FAIL"); 67 | } 68 | CFRelease(imageSource); 69 | } 70 | return result; 71 | } 72 | 73 | #pragma mark EXIF orientation tag converter 74 | // Convert an EXIF image orientation to an iOS one. 75 | // reference see here: http://sylvana.net/jpegcrop/exif_orientation.html 76 | + (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation { 77 | UIImageOrientation orientation = UIImageOrientationUp; 78 | switch (exifOrientation) { 79 | case 1: 80 | orientation = UIImageOrientationUp; 81 | break; 82 | 83 | case 3: 84 | orientation = UIImageOrientationDown; 85 | break; 86 | 87 | case 8: 88 | orientation = UIImageOrientationLeft; 89 | break; 90 | 91 | case 6: 92 | orientation = UIImageOrientationRight; 93 | break; 94 | 95 | case 2: 96 | orientation = UIImageOrientationUpMirrored; 97 | break; 98 | 99 | case 4: 100 | orientation = UIImageOrientationDownMirrored; 101 | break; 102 | 103 | case 5: 104 | orientation = UIImageOrientationLeftMirrored; 105 | break; 106 | 107 | case 7: 108 | orientation = UIImageOrientationRightMirrored; 109 | break; 110 | default: 111 | break; 112 | } 113 | return orientation; 114 | } 115 | 116 | 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImageView+HighlightedWebCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | #import "SDWebImageManager.h" 12 | 13 | /** 14 | * Integrates SDWebImage async downloading and caching of remote images with UIImageView for highlighted state. 15 | */ 16 | @interface UIImageView (HighlightedWebCache) 17 | 18 | /** 19 | * Set the imageView `highlightedImage` with an `url`. 20 | * 21 | * The download is asynchronous and cached. 22 | * 23 | * @param url The url for the image. 24 | */ 25 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url; 26 | 27 | /** 28 | * Set the imageView `highlightedImage` with an `url` and custom options. 29 | * 30 | * The download is asynchronous and cached. 31 | * 32 | * @param url The url for the image. 33 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 34 | */ 35 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options; 36 | 37 | /** 38 | * Set the imageView `highlightedImage` with an `url`. 39 | * 40 | * The download is asynchronous and cached. 41 | * 42 | * @param url The url for the image. 43 | * @param completedBlock A block called when operation has been completed. This block has no return value 44 | * and takes the requested UIImage as first parameter. In case of error the image parameter 45 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 46 | * indicating if the image was retrived from the local cache or from the network. 47 | * The fourth parameter is the original image url. 48 | */ 49 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock; 50 | 51 | /** 52 | * Set the imageView `highlightedImage` with an `url` and custom options. 53 | * 54 | * The download is asynchronous and cached. 55 | * 56 | * @param url The url for the image. 57 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 58 | * @param completedBlock A block called when operation has been completed. This block has no return value 59 | * and takes the requested UIImage as first parameter. In case of error the image parameter 60 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 61 | * indicating if the image was retrived from the local cache or from the network. 62 | * The fourth parameter is the original image url. 63 | */ 64 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; 65 | 66 | /** 67 | * Set the imageView `highlightedImage` with an `url` and custom options. 68 | * 69 | * The download is asynchronous and cached. 70 | * 71 | * @param url The url for the image. 72 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 73 | * @param progressBlock A block called while image is downloading 74 | * @param completedBlock A block called when operation has been completed. This block has no return value 75 | * and takes the requested UIImage as first parameter. In case of error the image parameter 76 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 77 | * indicating if the image was retrived from the local cache or from the network. 78 | * The fourth parameter is the original image url. 79 | */ 80 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; 81 | 82 | /** 83 | * Cancel the current download 84 | */ 85 | - (void)sd_cancelCurrentHighlightedImageLoad; 86 | 87 | @end 88 | 89 | 90 | @interface UIImageView (HighlightedWebCacheDeprecated) 91 | 92 | - (void)setHighlightedImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:`"); 93 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:`"); 94 | - (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:completed:`"); 95 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:completed:`"); 96 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:progress:completed:`"); 97 | 98 | - (void)cancelCurrentHighlightedImageLoad __deprecated_msg("Use `sd_cancelCurrentHighlightedImageLoad`"); 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImageView+HighlightedWebCache.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "UIImageView+HighlightedWebCache.h" 10 | #import "UIView+WebCacheOperation.h" 11 | 12 | #define UIImageViewHighlightedWebCacheOperationKey @"highlightedImage" 13 | 14 | @implementation UIImageView (HighlightedWebCache) 15 | 16 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url { 17 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; 18 | } 19 | 20 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options { 21 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; 22 | } 23 | 24 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock { 25 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; 26 | } 27 | 28 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { 29 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; 30 | } 31 | 32 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { 33 | [self sd_cancelCurrentHighlightedImageLoad]; 34 | 35 | if (url) { 36 | __weak __typeof(self)wself = self; 37 | id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 38 | if (!wself) return; 39 | dispatch_main_sync_safe (^ 40 | { 41 | if (!wself) return; 42 | if (image) { 43 | wself.highlightedImage = image; 44 | [wself setNeedsLayout]; 45 | } 46 | if (completedBlock && finished) { 47 | completedBlock(image, error, cacheType, url); 48 | } 49 | }); 50 | }]; 51 | [self sd_setImageLoadOperation:operation forKey:UIImageViewHighlightedWebCacheOperationKey]; 52 | } else { 53 | dispatch_main_async_safe(^{ 54 | NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; 55 | if (completedBlock) { 56 | completedBlock(nil, error, SDImageCacheTypeNone, url); 57 | } 58 | }); 59 | } 60 | } 61 | 62 | - (void)sd_cancelCurrentHighlightedImageLoad { 63 | [self sd_cancelImageLoadOperationWithKey:UIImageViewHighlightedWebCacheOperationKey]; 64 | } 65 | 66 | @end 67 | 68 | 69 | @implementation UIImageView (HighlightedWebCacheDeprecated) 70 | 71 | - (void)setHighlightedImageWithURL:(NSURL *)url { 72 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; 73 | } 74 | 75 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options { 76 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; 77 | } 78 | 79 | - (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock { 80 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 81 | if (completedBlock) { 82 | completedBlock(image, error, cacheType); 83 | } 84 | }]; 85 | } 86 | 87 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { 88 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 89 | if (completedBlock) { 90 | completedBlock(image, error, cacheType); 91 | } 92 | }]; 93 | } 94 | 95 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock { 96 | [self sd_setHighlightedImageWithURL:url options:0 progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 97 | if (completedBlock) { 98 | completedBlock(image, error, cacheType); 99 | } 100 | }]; 101 | } 102 | 103 | - (void)cancelCurrentHighlightedImageLoad { 104 | [self sd_cancelCurrentHighlightedImageLoad]; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIImageView+WebCache.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "UIImageView+WebCache.h" 10 | #import "objc/runtime.h" 11 | #import "UIView+WebCacheOperation.h" 12 | 13 | static char imageURLKey; 14 | 15 | @implementation UIImageView (WebCache) 16 | 17 | - (void)sd_setImageWithURL:(NSURL *)url { 18 | [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; 19 | } 20 | 21 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { 22 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; 23 | } 24 | 25 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { 26 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; 27 | } 28 | 29 | - (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock { 30 | [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:completedBlock]; 31 | } 32 | 33 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock { 34 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:completedBlock]; 35 | } 36 | 37 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { 38 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:completedBlock]; 39 | } 40 | 41 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { 42 | [self sd_cancelCurrentImageLoad]; 43 | objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 44 | 45 | if (!(options & SDWebImageDelayPlaceholder)) { 46 | dispatch_main_async_safe(^{ 47 | self.image = placeholder; 48 | }); 49 | } 50 | 51 | if (url) { 52 | __weak __typeof(self)wself = self; 53 | id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 54 | if (!wself) return; 55 | dispatch_main_sync_safe(^{ 56 | if (!wself) return; 57 | if (image && (options & SDWebImageAvoidAutoSetImage) && completedBlock) 58 | { 59 | completedBlock(image, error, cacheType, url); 60 | return; 61 | } 62 | else if (image) { 63 | wself.image = image; 64 | [wself setNeedsLayout]; 65 | } else { 66 | if ((options & SDWebImageDelayPlaceholder)) { 67 | wself.image = placeholder; 68 | [wself setNeedsLayout]; 69 | } 70 | } 71 | if (completedBlock && finished) { 72 | completedBlock(image, error, cacheType, url); 73 | } 74 | }); 75 | }]; 76 | [self sd_setImageLoadOperation:operation forKey:@"UIImageViewImageLoad"]; 77 | } else { 78 | dispatch_main_async_safe(^{ 79 | NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; 80 | if (completedBlock) { 81 | completedBlock(nil, error, SDImageCacheTypeNone, url); 82 | } 83 | }); 84 | } 85 | } 86 | 87 | - (void)sd_setImageWithPreviousCachedImageWithURL:(NSURL *)url andPlaceholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { 88 | NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:url]; 89 | UIImage *lastPreviousCachedImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:key]; 90 | 91 | [self sd_setImageWithURL:url placeholderImage:lastPreviousCachedImage ?: placeholder options:options progress:progressBlock completed:completedBlock]; 92 | } 93 | 94 | - (NSURL *)sd_imageURL { 95 | return objc_getAssociatedObject(self, &imageURLKey); 96 | } 97 | 98 | - (void)sd_setAnimationImagesWithURLs:(NSArray *)arrayOfURLs { 99 | [self sd_cancelCurrentAnimationImagesLoad]; 100 | __weak __typeof(self)wself = self; 101 | 102 | NSMutableArray *operationsArray = [[NSMutableArray alloc] init]; 103 | 104 | for (NSURL *logoImageURL in arrayOfURLs) { 105 | id operation = [SDWebImageManager.sharedManager downloadImageWithURL:logoImageURL options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 106 | if (!wself) return; 107 | dispatch_main_sync_safe(^{ 108 | __strong UIImageView *sself = wself; 109 | [sself stopAnimating]; 110 | if (sself && image) { 111 | NSMutableArray *currentImages = [[sself animationImages] mutableCopy]; 112 | if (!currentImages) { 113 | currentImages = [[NSMutableArray alloc] init]; 114 | } 115 | [currentImages addObject:image]; 116 | 117 | sself.animationImages = currentImages; 118 | [sself setNeedsLayout]; 119 | } 120 | [sself startAnimating]; 121 | }); 122 | }]; 123 | [operationsArray addObject:operation]; 124 | } 125 | 126 | [self sd_setImageLoadOperation:[NSArray arrayWithArray:operationsArray] forKey:@"UIImageViewAnimationImages"]; 127 | } 128 | 129 | - (void)sd_cancelCurrentImageLoad { 130 | [self sd_cancelImageLoadOperationWithKey:@"UIImageViewImageLoad"]; 131 | } 132 | 133 | - (void)sd_cancelCurrentAnimationImagesLoad { 134 | [self sd_cancelImageLoadOperationWithKey:@"UIImageViewAnimationImages"]; 135 | } 136 | 137 | @end 138 | 139 | 140 | @implementation UIImageView (WebCacheDeprecated) 141 | 142 | - (NSURL *)imageURL { 143 | return [self sd_imageURL]; 144 | } 145 | 146 | - (void)setImageWithURL:(NSURL *)url { 147 | [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:nil]; 148 | } 149 | 150 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { 151 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:nil]; 152 | } 153 | 154 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { 155 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:nil]; 156 | } 157 | 158 | - (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock { 159 | [self sd_setImageWithURL:url placeholderImage:nil options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 160 | if (completedBlock) { 161 | completedBlock(image, error, cacheType); 162 | } 163 | }]; 164 | } 165 | 166 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock { 167 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 168 | if (completedBlock) { 169 | completedBlock(image, error, cacheType); 170 | } 171 | }]; 172 | } 173 | 174 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { 175 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 176 | if (completedBlock) { 177 | completedBlock(image, error, cacheType); 178 | } 179 | }]; 180 | } 181 | 182 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock { 183 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 184 | if (completedBlock) { 185 | completedBlock(image, error, cacheType); 186 | } 187 | }]; 188 | } 189 | 190 | - (void)cancelCurrentArrayLoad { 191 | [self sd_cancelCurrentAnimationImagesLoad]; 192 | } 193 | 194 | - (void)cancelCurrentImageLoad { 195 | [self sd_cancelCurrentImageLoad]; 196 | } 197 | 198 | - (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs { 199 | [self sd_setAnimationImagesWithURLs:arrayOfURLs]; 200 | } 201 | 202 | @end 203 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIView+WebCacheOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageManager.h" 11 | 12 | @interface UIView (WebCacheOperation) 13 | 14 | /** 15 | * Set the image load operation (storage in a UIView based dictionary) 16 | * 17 | * @param operation the operation 18 | * @param key key for storing the operation 19 | */ 20 | - (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key; 21 | 22 | /** 23 | * Cancel all operations for the current UIView and key 24 | * 25 | * @param key key for identifying the operations 26 | */ 27 | - (void)sd_cancelImageLoadOperationWithKey:(NSString *)key; 28 | 29 | /** 30 | * Just remove the operations corresponding to the current UIView and key without cancelling them 31 | * 32 | * @param key key for identifying the operations 33 | */ 34 | - (void)sd_removeImageLoadOperationWithKey:(NSString *)key; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /TestPhotoKit/ThirdLibrary/SDWebImage/UIView+WebCacheOperation.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "UIView+WebCacheOperation.h" 10 | #import "objc/runtime.h" 11 | 12 | static char loadOperationKey; 13 | 14 | @implementation UIView (WebCacheOperation) 15 | 16 | - (NSMutableDictionary *)operationDictionary { 17 | NSMutableDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); 18 | if (operations) { 19 | return operations; 20 | } 21 | operations = [NSMutableDictionary dictionary]; 22 | objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 23 | return operations; 24 | } 25 | 26 | - (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key { 27 | [self sd_cancelImageLoadOperationWithKey:key]; 28 | NSMutableDictionary *operationDictionary = [self operationDictionary]; 29 | [operationDictionary setObject:operation forKey:key]; 30 | } 31 | 32 | - (void)sd_cancelImageLoadOperationWithKey:(NSString *)key { 33 | // Cancel in progress downloader from queue 34 | NSMutableDictionary *operationDictionary = [self operationDictionary]; 35 | id operations = [operationDictionary objectForKey:key]; 36 | if (operations) { 37 | if ([operations isKindOfClass:[NSArray class]]) { 38 | for (id operation in operations) { 39 | if (operation) { 40 | [operation cancel]; 41 | } 42 | } 43 | } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){ 44 | [(id) operations cancel]; 45 | } 46 | [operationDictionary removeObjectForKey:key]; 47 | } 48 | } 49 | 50 | - (void)sd_removeImageLoadOperationWithKey:(NSString *)key { 51 | NSMutableDictionary *operationDictionary = [self operationDictionary]; 52 | [operationDictionary removeObjectForKey:key]; 53 | } 54 | 55 | @end 56 | --------------------------------------------------------------------------------