├── .DS_Store ├── README.md ├── SDImagePickerController.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ ├── mac.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ │ └── zhangwei.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ ├── mac.xcuserdatad │ └── xcschemes │ │ ├── SDImagePickerController.xcscheme │ │ └── xcschememanagement.plist │ └── zhangwei.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── SDImagePickerController.xcscheme │ └── xcschememanagement.plist ├── SDImagePickerController ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── PrefixHeader.pch ├── SDShowCell.h ├── SDShowCell.m ├── ViewController.h ├── ViewController.m └── main.m ├── SDImagePickerControllerTests ├── Info.plist └── SDImagePickerControllerTests.m ├── SDImagePickerControllerUITests ├── Info.plist └── SDImagePickerControllerUITests.m ├── SDPickerController.podspec └── SDPickerController ├── .DS_Store ├── Gategory ├── .DS_Store ├── SD.h ├── SD.m ├── SDNavigationController.h ├── SDNavigationController.m ├── UIImage+SD.h ├── UIImage+SD.m ├── UIView+SD.h └── UIView+SD.m ├── Lib ├── .DS_Store └── SDAutoLayout │ ├── .DS_Store │ ├── SDAutoLayout.h │ ├── UITableView+SDAutoTableViewCellHeight.h │ ├── UITableView+SDAutoTableViewCellHeight.m │ ├── UIView+SDAutoLayout.h │ └── UIView+SDAutoLayout.m ├── Resources ├── .DS_Store └── Mytools.bundle │ ├── 120-1.png │ ├── Angle_@2x.png │ ├── Angle_@3x.png │ ├── MMVideoPreviewPlay@2x.png │ ├── MMVideoPreviewPlayHL@2x.png │ ├── TableViewArrow@2x.png │ ├── VideoSendIcon@2x.png │ ├── icon_photos_arrowbottom@2x.png │ ├── icon_photos_arrowbottom@3x.png │ ├── icon_photos_arrowup@2x.png │ ├── icon_photos_arrowup@3x.png │ ├── navi_back@2x.png │ ├── photo_def_photoPickerVc@2x.png │ ├── photo_def_previewVc@2x.png │ ├── photo_number_icon@2x.png │ ├── photo_original_def@2x.png │ ├── photo_original_sel@2x.png │ ├── photo_sel_photoPickerVc@2x.png │ ├── photo_sel_previewVc@2x.png │ ├── preview_number_icon@2x.png │ └── preview_original_def@2x.png ├── SDManagerModel ├── SDAssetModel.h ├── SDAssetModel.m ├── SDImageManager.h ├── SDImageManager.m └── SDImagePicker.h ├── ViewController ├── SDImagePickerController.h └── SDImagePickerController.m └── Views ├── AuthorityView.h ├── AuthorityView.m ├── BottomToolBar.h ├── BottomToolBar.m ├── NavAlbumCell.h ├── NavAlbumCell.m ├── NavigationAlbumView.h ├── NavigationAlbumView.m ├── PhotoAlbumView.h ├── PhotoAlbumView.m ├── SDAssetCell.h ├── SDAssetCell.m └── SDPickerVCType.h /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SDImagePickerController(关于相册看它就行) 2 | ====== 3 | 一个支持多选、选原图的图片选择器,致力于将相册封装成最简单的模型数据。 4 | 与类似库对比: 5 | ======= 6 | 1.优化 获取image导致的内存过高问题 7 | 8 | 2.优化 选择image页滑动卡顿问题 9 | 10 | 3.记录选中状态,再次进入时,之前选中过的image,直接进入选中状态 11 | 12 | 13 | ### 14 | 15 | 更新记录: 16 | ======== 17 | 2016.11.29  --SDImageManager:1.新增创建相册。 2.新增保存图片到相册。 3,当最大选择数为1时,进入单选模式。 4,增加导航栏选择相册类型 18 | 19 | 20 | 2016.11.22 --SDImageManager 编写,实现了相册多选功能,UI选择设计按照 lofter(网易旗下的图片社交app),开发者可根据自己需要定制UI。 21 | 22 | 效果: 23 | === 24 | ##1、选择相册分组导航栏模式 25 | 26 | ![ABC](http://zw.hiqianjin.com/01%281%29.gif) 27 | 28 | ##2、选择相册分组toolBar模式 29 | 30 | ![ABC](http://zw.hiqianjin.com/toolBar.gif) 31 | 32 | 安装: 33 | ===== 34 | 1.下载demo,拖动SDPickerController文件到项目中(建议用此种方式,图片选择UI无法满足所有项目需求,加入项目里方便更改UI) 35 | 36 | 2.pod "SDPickerController" 37 | 38 | #用法简介: 39 | ======== 40 | ##添加头文件 #import "SDImagePicker.h" 41 | 42 | 43 | SDImagePickerController *pickerController=[[SDImagePickerController alloc]initWithMaxImagesCount:9 columnNumber:3 delegate:self]; 44 | 45 | UINavigationController *pickerNav =[[UINavigationController alloc]initWithRootViewController:pickerController]; 46 | 47 | if (_isSelectedPhotoArray.count!=0) { 48 | pickerController.selectedAssets = _isSelectedPhotoArray; 49 | } 50 | 51 | //最小选择数 52 | pickerController.minImagesCount = 1; 53 | 54 | pickerController.photoPreviewMaxWidth = 600; 55 | 56 | //是否显示相机 57 | pickerController.cameraBtn = YES; 58 | 59 | //排序方式 60 | pickerController.sortAscendingByModificationDate =NO; 61 | 62 | //相册选择 63 | pickerController.pickingImage = YES; 64 | 65 | //更多设置参数详见demo 66 | 67 | [self.navigationController presentViewController:pickerNav animated:YES completion:nil]; 68 | -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/project.xcworkspace/xcuserdata/mac.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDImagePickerController.xcodeproj/project.xcworkspace/xcuserdata/mac.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/project.xcworkspace/xcuserdata/zhangwei.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDImagePickerController.xcodeproj/project.xcworkspace/xcuserdata/zhangwei.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/xcuserdata/mac.xcuserdatad/xcschemes/SDImagePickerController.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/xcuserdata/mac.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SDImagePickerController.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 04358C531DE3228B00F5DD53 16 | 17 | primary 18 | 19 | 20 | 04358C6C1DE3228B00F5DD53 21 | 22 | primary 23 | 24 | 25 | 04358C771DE3228B00F5DD53 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcschemes/SDImagePickerController.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /SDImagePickerController.xcodeproj/xcuserdata/zhangwei.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SDImagePickerController.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 04358C531DE3228B00F5DD53 16 | 17 | primary 18 | 19 | 20 | 04358C6C1DE3228B00F5DD53 21 | 22 | primary 23 | 24 | 25 | 04358C771DE3228B00F5DD53 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /SDImagePickerController/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SDImagePickerController 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. 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 | -------------------------------------------------------------------------------- /SDImagePickerController/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SDImagePickerController 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 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 | 21 | 22 | 23 | ViewController *v=[[ViewController alloc]init]; 24 | UINavigationController *nav =[[UINavigationController alloc]initWithRootViewController:v]; 25 | _window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; 26 | _window.rootViewController = nav; 27 | return YES; 28 | return YES; 29 | } 30 | 31 | 32 | - (void)applicationWillResignActive:(UIApplication *)application { 33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 35 | } 36 | 37 | 38 | - (void)applicationDidEnterBackground:(UIApplication *)application { 39 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 41 | } 42 | 43 | 44 | - (void)applicationWillEnterForeground:(UIApplication *)application { 45 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 46 | } 47 | 48 | 49 | - (void)applicationDidBecomeActive:(UIApplication *)application { 50 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 51 | } 52 | 53 | 54 | - (void)applicationWillTerminate:(UIApplication *)application { 55 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 56 | } 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /SDImagePickerController/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 | } -------------------------------------------------------------------------------- /SDImagePickerController/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 | -------------------------------------------------------------------------------- /SDImagePickerController/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SDImagePickerController/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | SDImagePickerController 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.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | NSPhotoLibraryUsageDescription 38 | 获取相册权限 39 | UILaunchStoryboardName 40 | LaunchScreen 41 | CFBundleAllowMixedLocalizations 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /SDImagePickerController/PrefixHeader.pch: -------------------------------------------------------------------------------- 1 | // 2 | // PrefixHeader.pch 3 | // SDImagePickerController 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #ifndef PrefixHeader_pch 10 | #define PrefixHeader_pch 11 | 12 | #import "SDImagePicker.h" 13 | 14 | // Include any system framework and library headers here that should be included in all compilation units. 15 | // You will also need to set the Prefix Header build setting of one or more of your targets to reference this file. 16 | 17 | #endif /* PrefixHeader_pch */ 18 | -------------------------------------------------------------------------------- /SDImagePickerController/SDShowCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDShowCell.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/22. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SDShowCell : UICollectionViewCell 12 | 13 | @property(nonatomic,strong)UIView *bottomView; 14 | @property(nonatomic,strong)UIImageView *imageView; 15 | 16 | @property(nonatomic,strong)id asset; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SDImagePickerController/SDShowCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDShowCell.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/22. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "SDShowCell.h" 10 | #import 11 | #import 12 | @implementation SDShowCell 13 | 14 | -(instancetype)initWithFrame:(CGRect)frame{ 15 | if (self=[super initWithFrame:frame]) { 16 | [self createUI]; 17 | } 18 | return self; 19 | } 20 | 21 | -(void)createUI{ 22 | 23 | _bottomView =[[UIView alloc]initWithFrame:self.bounds]; 24 | [self addSubview:_bottomView]; 25 | 26 | _imageView =[[UIImageView alloc]initWithFrame:self.bounds]; 27 | _imageView.contentMode = UIViewContentModeScaleAspectFill; 28 | self.clipsToBounds = YES; 29 | [self addSubview:_imageView]; 30 | } 31 | 32 | 33 | 34 | 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /SDImagePickerController/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SDImagePickerController 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /SDImagePickerController/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/10. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "SDShowCell.h" 11 | #import "SDImagePickerController.h" 12 | #import "UIImage+SD.h" 13 | #import "SDImagePicker.h" 14 | @interface ViewController () 15 | 16 | 17 | @property(nonatomic,strong)NSMutableArray *photosArray; //保存用户选择的图片 18 | @property(nonatomic,strong)NSMutableArray *isSelectedPhotoArray; //保存用户已经选中的asstest 19 | 20 | @property (nonatomic, strong) UICollectionView *collectionView; //仅仅用来展示选中的图片 21 | 22 | @end 23 | 24 | @implementation ViewController 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | // Do any additional setup after loading the view, typically from a nib. 29 | self.view.backgroundColor =[UIColor whiteColor]; 30 | 31 | UIButton *addBtn =[[UIButton alloc]init]; 32 | addBtn.backgroundColor =[UIColor redColor]; 33 | [addBtn setTitle:@"添加" forState:UIControlStateNormal]; 34 | addBtn.frame = CGRectMake(([UIScreen mainScreen].bounds.size.width -120 -30)/2.f, 90, 60, 60); 35 | [addBtn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside]; 36 | [self.view addSubview:addBtn]; 37 | 38 | UIButton *deleteBtn =[[UIButton alloc]init]; 39 | deleteBtn.backgroundColor =[UIColor redColor]; 40 | [deleteBtn setTitle:@"删除" forState:UIControlStateNormal]; 41 | deleteBtn.frame = CGRectMake(CGRectGetMaxX(addBtn.frame)+30, 90, 60, 60); 42 | [deleteBtn addTarget:self action:@selector(deleteBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 43 | [self.view addSubview:deleteBtn]; 44 | [self createUI]; 45 | 46 | } 47 | 48 | -(void)deleteBtnClick:(UIButton *)sender{ 49 | 50 | 51 | [_isSelectedPhotoArray removeAllObjects]; 52 | [_photosArray removeAllObjects]; 53 | [_collectionView reloadData]; 54 | } 55 | 56 | -(void)click:(UIButton *)sender{ 57 | 58 | SDImagePickerController *pickerController=[[SDImagePickerController alloc]initWithMaxImagesCount:1 columnNumber:4 delegate:self]; 59 | // UINavigationController *pickerNav =[[UINavigationController alloc]initWithRootViewController:pickerController]; 60 | if (_isSelectedPhotoArray.count!=0) { 61 | pickerController.selectedAssets = _isSelectedPhotoArray; 62 | } 63 | //最小选择数 64 | pickerController.minImagesCount = 1; 65 | pickerController.photoPreviewMaxWidth = 600; 66 | //是否显示相机 67 | pickerController.cameraBtn = YES; 68 | //排序方式 69 | pickerController.sortAscendingByModificationDate =NO; 70 | //相册选择 71 | pickerController.pickingImage = YES; 72 | // pickerController.pickerVCType = SDPickerVCToolBar; 73 | 74 | // pickerController.browserSelect =YES; 游览选择暂时未做,后续会添加上去, 75 | // pickerController.pickingVideo =NO; //暂时未做,后续会添加 76 | // [self.navigationController presentViewController:pickerNav animated:YES completion:nil]; 77 | 78 | // [self.navigationController pushViewController:pickerController animated:YES]; 79 | 80 | [self presentViewController:pickerController animated:YES completion:nil]; 81 | 82 | } 83 | 84 | #pragma mark ---SDImagePickControllerDelegate 85 | -(void)imagePickerController:(SDImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto{ 86 | 87 | [picker dismissViewControllerAnimated:YES completion:nil]; 88 | _photosArray =[NSMutableArray arrayWithArray:photos]; 89 | _isSelectedPhotoArray =[NSMutableArray arrayWithArray:assets]; 90 | [_collectionView reloadData]; 91 | 92 | } 93 | 94 | -(void)imagePickerController:(SDImagePickerController *)picker seletedCamera:(id)info{ 95 | 96 | NSLog(@"你点击的是拍照按钮,请自行处理"); 97 | 98 | } 99 | 100 | #pragma mark UICollectionView 101 | 102 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 103 | return _photosArray.count; 104 | } 105 | 106 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 107 | SDShowCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"SDShowCell" forIndexPath:indexPath]; 108 | cell.imageView.image =_photosArray[indexPath.row]; 109 | return cell; 110 | } 111 | 112 | -(void)createUI{ 113 | UICollectionViewFlowLayout *layout =[[UICollectionViewFlowLayout alloc]init]; 114 | CGFloat margin =2; 115 | CGFloat itemWH = ([UIScreen mainScreen].bounds.size.width - 2 * margin) / 3 ; 116 | layout.itemSize = CGSizeMake(itemWH, itemWH); 117 | layout.minimumInteritemSpacing = margin; 118 | layout.minimumLineSpacing = margin; 119 | _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 244, [UIScreen mainScreen].bounds.size.width, HEIGHT - 244) collectionViewLayout:layout]; 120 | _collectionView.backgroundColor = UIColorFromRGB(0x697787); 121 | _collectionView.dataSource = self; 122 | _collectionView.delegate = self; 123 | [self.view addSubview:_collectionView]; 124 | [_collectionView registerClass:[SDShowCell class] forCellWithReuseIdentifier:@"SDShowCell"]; 125 | } 126 | 127 | 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /SDImagePickerController/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SDImagePickerController 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. 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 | -------------------------------------------------------------------------------- /SDImagePickerControllerTests/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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SDImagePickerControllerTests/SDImagePickerControllerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDImagePickerControllerTests.m 3 | // SDImagePickerControllerTests 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SDImagePickerControllerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SDImagePickerControllerTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /SDImagePickerControllerUITests/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 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SDImagePickerControllerUITests/SDImagePickerControllerUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDImagePickerControllerUITests.m 3 | // SDImagePickerControllerUITests 4 | // 5 | // Created by mac on 2016/11/21. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SDImagePickerControllerUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SDImagePickerControllerUITests 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 | -------------------------------------------------------------------------------- /SDPickerController.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint SDPickerController.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # 12 | # 13 | # These will help people to find your library, and whilst it 14 | # can feel like a chore to fill in it's definitely to your advantage. The 15 | # summary should be tweet-length, and the description more in depth. 16 | # 17 | 18 | s.name = "SDPickerController" 19 | s.version = "1.0.6" 20 | s.summary = "A Very beautiful of SDPickerController." 21 | s.description = "this is very good SDPickerControlle,Used in photo album, thin, and some optimization " 22 | s.homepage = "http://www.jianshu.com/users/3efefee71c8c/latest_articles" 23 | s.license = { :type => "MIT", :file => "LICENSE" } 24 | 25 | s.author = { "zhangwei111" => "18580228790@163.com" } 26 | s.platform = :ios, "7.0" 27 | s.source = { :git => "https://github.com/IOSzhangwei/SDImagePickerController.git", :tag => "1.0.6" } 28 | s.source_files = "SDPickerController/**/*" 29 | s.resource = "SDPickerController/Resources/Mytools.bundle" 30 | s.exclude_files = "Classes/Exclude" 31 | s.requires_arc=true 32 | 33 | 34 | end 35 | -------------------------------------------------------------------------------- /SDPickerController/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/.DS_Store -------------------------------------------------------------------------------- /SDPickerController/Gategory/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Gategory/.DS_Store -------------------------------------------------------------------------------- /SDPickerController/Gategory/SD.h: -------------------------------------------------------------------------------- 1 | // 2 | // SD.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/23. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SD : UIImage 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/SD.m: -------------------------------------------------------------------------------- 1 | // 2 | // SD.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/23. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "SD.h" 10 | 11 | @implementation SD 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/SDNavigationController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDNavigationController.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SDNavigationController : UINavigationController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/SDNavigationController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDNavigationController.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "SDNavigationController.h" 10 | 11 | @interface SDNavigationController () 12 | 13 | @end 14 | 15 | @implementation SDNavigationController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | - (void)didReceiveMemoryWarning { 23 | [super didReceiveMemoryWarning]; 24 | // Dispose of any resources that can be recreated. 25 | } 26 | - (UIViewController *)childViewControllerForStatusBarStyle 27 | { 28 | return self.topViewController; 29 | } 30 | /* 31 | #pragma mark - Navigation 32 | 33 | // In a storyboard-based application, you will often want to do a little preparation before navigation 34 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 35 | // Get the new view controller using [segue destinationViewController]. 36 | // Pass the selected object to the new view controller. 37 | } 38 | */ 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/UIImage+SD.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+SD.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/23. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (SD) 12 | 13 | +(UIImage *)SD_imageNamed:(NSString *)name; 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/UIImage+SD.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+SD.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/23. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "UIImage+SD.h" 10 | 11 | @implementation UIImage (SD) 12 | 13 | +(UIImage *)SD_imageNamed:(NSString *)name{ 14 | UIImage *image = [UIImage imageNamed:[@"Mytools.bundle" stringByAppendingPathComponent:name]]; 15 | 16 | 17 | return image; 18 | 19 | 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/UIView+SD.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SD.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum : NSUInteger { 12 | SDAnimationToBigger, 13 | SDAnimationToSmaller, 14 | } SDAnimationType; 15 | @interface UIView (SD) 16 | - (CGPoint)origin; 17 | - (void)setOrigin:(CGPoint) point; 18 | 19 | - (CGSize)size; 20 | - (void)setSize:(CGSize) size; 21 | 22 | - (CGFloat)x; 23 | - (void)setX:(CGFloat)x; 24 | 25 | - (CGFloat)y; 26 | - (void)setY:(CGFloat)y; 27 | 28 | 29 | - (CGFloat)height; 30 | - (void)setHeight:(CGFloat)height; 31 | 32 | 33 | - (CGFloat)width; 34 | - (void)setWidth:(CGFloat)width; 35 | 36 | - (CGFloat)tail; 37 | - (void)setTail:(CGFloat)tail; 38 | 39 | - (CGFloat)bottom; 40 | - (void)setBottom:(CGFloat)bottom; 41 | 42 | - (CGFloat)right; 43 | - (void)setRight:(CGFloat)right; 44 | 45 | + (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(SDAnimationType)type; 46 | 47 | //@property (nonatomic, assign) CGFloat center; 48 | //@property (nonatomic, assign) CGFloat center; 49 | 50 | //@property(nonatomic)CGFloat layerZ; 51 | @end 52 | -------------------------------------------------------------------------------- /SDPickerController/Gategory/UIView+SD.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SD.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "UIView+SD.h" 10 | 11 | @implementation UIView (SD) 12 | - (CGPoint) origin { 13 | return self.frame.origin; 14 | } 15 | 16 | - (void) setOrigin:(CGPoint) point { 17 | self.frame = CGRectMake(point.x, point.y, self.frame.size.width, self.frame.size.height); 18 | } 19 | 20 | - (CGSize) size { 21 | return self.frame.size; 22 | } 23 | 24 | - (void) setSize:(CGSize) size { 25 | self.frame = CGRectMake(self.x, self.y, size.width, size.height); 26 | } 27 | 28 | - (CGFloat) x { 29 | return self.frame.origin.x; 30 | } 31 | 32 | - (void) setX:(CGFloat)x { 33 | self.frame = CGRectMake(x, self.y, self.width, self.height); 34 | } 35 | 36 | - (CGFloat) y { 37 | return self.frame.origin.y; 38 | } 39 | - (void) setY:(CGFloat)y { 40 | self.frame = CGRectMake(self.x, y, self.width, self.height); 41 | } 42 | 43 | - (CGFloat) height { 44 | return self.frame.size.height; 45 | } 46 | - (void)setHeight:(CGFloat)height { 47 | self.frame = CGRectMake(self.x, self.y, self.width, height); 48 | } 49 | 50 | - (CGFloat)width { 51 | return self.frame.size.width; 52 | } 53 | - (void)setWidth:(CGFloat)width { 54 | self.frame = CGRectMake(self.x, self.y, width, self.height); 55 | } 56 | 57 | - (CGFloat)tail { 58 | return self.y + self.height; 59 | } 60 | 61 | - (void)setTail:(CGFloat)tail { 62 | self.frame = CGRectMake(self.x, tail - self.height, self.width, self.height); 63 | } 64 | 65 | - (CGFloat)bottom { 66 | return self.tail; 67 | } 68 | 69 | - (void)setBottom:(CGFloat)bottom { 70 | [self setTail:bottom]; 71 | } 72 | 73 | - (CGFloat)right { 74 | return self.x + self.width; 75 | } 76 | 77 | - (void)setRight:(CGFloat)right { 78 | self.frame = CGRectMake(right - self.width, self.y, self.width, self.height); 79 | } 80 | 81 | -(void)setLayerZ:(CGFloat)layerZ{ 82 | self.layer.cornerRadius=layerZ; 83 | self.layer.masksToBounds=YES; 84 | } 85 | 86 | - (void)setCenterX:(CGFloat)centerX 87 | { 88 | CGPoint center = self.center; 89 | center.x = centerX; 90 | self.center = center; 91 | } 92 | 93 | - (CGFloat)centerX 94 | { 95 | return self.center.x; 96 | } 97 | 98 | - (void)setCenterY:(CGFloat)centerY 99 | { 100 | CGPoint center = self.center; 101 | center.y = centerY; 102 | self.center = center; 103 | } 104 | 105 | - (CGFloat)centerY 106 | { 107 | return self.center.y; 108 | } 109 | 110 | + (void)showOscillatoryAnimationWithLayer:(CALayer *)layer type:(SDAnimationType)type{ 111 | NSNumber *animationScale1 = type == SDAnimationToBigger ? @(1.15) : @(0.5); 112 | NSNumber *animationScale2 = type == SDAnimationToBigger ? @(0.92) : @(1.15); 113 | 114 | 115 | [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{ 116 | [layer setValue:animationScale1 forKeyPath:@"transform.scale"]; 117 | } completion:^(BOOL finished) { 118 | [UIView animateWithDuration:0.15 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{ 119 | [layer setValue:animationScale2 forKeyPath:@"transform.scale"]; 120 | } completion:^(BOOL finished) { 121 | [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut animations:^{ 122 | [layer setValue:@(1.0) forKeyPath:@"transform.scale"]; 123 | } completion:nil]; 124 | }]; 125 | }]; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /SDPickerController/Lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Lib/.DS_Store -------------------------------------------------------------------------------- /SDPickerController/Lib/SDAutoLayout/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Lib/SDAutoLayout/.DS_Store -------------------------------------------------------------------------------- /SDPickerController/Lib/SDAutoLayout/SDAutoLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDAutoLayout.h 3 | // SDAutoLayoutDemo 4 | // 5 | // Created by gsd on 16/6/27. 6 | // Copyright © 2016年 gsd. All rights reserved. 7 | // 8 | 9 | 10 | /* 11 | 12 | SDAutoLayout 13 | 版本:2.1.7 14 | 发布:2016.08.12 15 | 16 | */ 17 | 18 | #ifndef SDAutoLayout_h 19 | #define SDAutoLayout_h 20 | 21 | #import "UIView+SDAutoLayout.h" 22 | #import "UITableView+SDAutoTableViewCellHeight.h" 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /SDPickerController/Lib/SDAutoLayout/UITableView+SDAutoTableViewCellHeight.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+SDAutoTableViewCellHeight.h 3 | // SDAutoLayout 测试 Demo 4 | // 5 | // Created by aier on 15/11/1. 6 | // Copyright © 2015年 gsd. All rights reserved. 7 | // 8 | 9 | /* 10 | 11 | ********************************************************************************* 12 | * * 13 | * 在您使用此自动布局库的过程中如果出现bug请及时以以下任意一种方式联系我们,我们会及时修复bug并 * 14 | * 帮您解决问题。 * 15 | * QQ : 2689718696(gsdios) * 16 | * Email : gsdios@126.com * 17 | * GitHub: https://github.com/gsdios * 18 | * 新浪微博:GSD_iOS * 19 | * * 20 | ********************************************************************************* 21 | 22 | */ 23 | 24 | 25 | 26 | 27 | /* 28 | PS:cell高度自适应前提>>应该调用cell的“- (void)setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法进行cell的自动高度设置 29 | */ 30 | 31 | #import 32 | 33 | #import "UIView+SDAutoLayout.h" 34 | 35 | @class SDCellAutoHeightManager; 36 | 37 | typedef void (^AutoCellHeightDataSettingBlock)(UITableViewCell *cell); 38 | 39 | #define kSDModelCellTag 199206 40 | 41 | 42 | 43 | #pragma mark - UITableView 方法,返回自动计算出的cell高度 44 | 45 | @interface UITableView (SDAutoTableViewCellHeight) 46 | 47 | @property (nonatomic, strong) SDCellAutoHeightManager *cellAutoHeightManager; 48 | 49 | 50 | /** 51 | * 返回计算出的cell高度(普通简化版方法,同样只需一步设置即可完成)(用法:单cell详见demo5,多cell详见demo7) 52 | * model : cell的数据模型实例 53 | * keyPath : cell的数据模型属性的属性名字符串(即kvc原理中的key) 54 | * cellClass : 当前的indexPath对应的cell的class 55 | * contentViewWidth : cell的contentView的宽度 56 | */ 57 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass contentViewWidth:(CGFloat)contentViewWidth; 58 | 59 | /** 60 | * 返回计算出的cell高度(普通简化版方法,同样只需一步设置即可完成)(用法:见DemoVC14) 61 | * cellClass : 当前的indexPath对应的cell的class 62 | * contentViewWidth : cell的contentView的宽度 63 | * cellDataSetting : 设置cell数据的block 64 | */ 65 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellClass:(Class)cellClass cellContentViewWidth:(CGFloat)width cellDataSetting:(AutoCellHeightDataSettingBlock)cellDataSetting; 66 | 67 | /** 刷新tableView但不清空之前已经计算好的高度缓存,用于直接将新数据拼接在旧数据之后的tableView刷新 */ 68 | - (void)reloadDataWithExistedHeightCache; 69 | 70 | /** 刷新tableView同时调整已经计算好的高度缓存,用于直接将新数据插在旧数据前面的tableView的刷新 */ 71 | - (void)reloadDataWithInsertingDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count; 72 | 73 | /** 74 | * 刷新tableView同时调整已经计算好的高度缓存,用于直接将新数据插在旧数据前面的tableView的刷新(用于刷新多个section) 75 | * sectionNumsArray : 要刷新的所有section序号组成的数组, 例@[@(0), @(1)] 76 | * dataCountsArray : 每个section的数据条数组成的数组, 例@[@(20), @(10)] 77 | */ 78 | - (void)reloadDataWithInsertingDataAtTheBeginingOfSections:(NSArray *)sectionNumsArray newDataCounts:(NSArray *)dataCountsArray; 79 | 80 | /** 返回所有cell的高度总和 */ 81 | - (CGFloat)cellsTotalHeight; 82 | 83 | @property (nonatomic, copy) AutoCellHeightDataSettingBlock cellDataSetting; 84 | 85 | @end 86 | 87 | 88 | 89 | 90 | #pragma mark - UITableViewController 方法,返回自动计算出的cell高度 91 | 92 | @interface UITableViewController (SDTableViewControllerAutoCellHeight) 93 | 94 | /** (UITableViewController方法)升级版!一行代码(一步设置)搞定tableview的cell高度自适应,同时适用于单cell和多cell,性能比普通版稍微差一些,不建议在数据量大的tableview中使用 */ 95 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width; 96 | 97 | @end 98 | 99 | 100 | 101 | #pragma mark - NSObject 方法,返回自动计算出的cell高度 102 | 103 | @interface NSObject (SDAnyObjectAutoCellHeight) 104 | 105 | /** (NSObject方法)升级版!一行代码(一步设置)搞定tableview的cell高度自适应,同时适用于单cell和多cell,性能比普通版稍微差一些,不建议在数据量大的tableview中使用 */ 106 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width tableView:(UITableView *)tableView; 107 | 108 | @end 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | // ------------------------------- 以下为库内部使用无须了解 -------------------- 127 | 128 | @interface SDCellAutoHeightManager : NSObject 129 | 130 | @property (nonatomic, assign) BOOL shouldKeepHeightCacheWhenReloadingData; 131 | 132 | @property (nonatomic, assign) CGFloat contentViewWidth; 133 | 134 | @property (nonatomic, assign) Class cellClass; 135 | 136 | @property (nonatomic, assign) CGFloat cellHeight; 137 | 138 | @property (nonatomic, strong) UITableViewCell *modelCell; 139 | 140 | @property (nonatomic, strong) NSMutableDictionary *subviewFrameCacheDict; 141 | 142 | @property (nonatomic, strong, readonly) NSDictionary *heightCacheDict; 143 | 144 | @property (nonatomic, copy) AutoCellHeightDataSettingBlock cellDataSetting; 145 | 146 | - (void)clearHeightCache; 147 | 148 | - (void)clearHeightCacheOfIndexPaths:(NSArray *)indexPaths; 149 | 150 | - (void)deleteThenResetHeightCache:(NSIndexPath *)indexPathToDelete; 151 | 152 | - (void)insertNewDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count; 153 | 154 | - (void)insertNewDataAtIndexPaths:(NSArray *)indexPaths; 155 | 156 | - (NSNumber *)heightCacheForIndexPath:(NSIndexPath *)indexPath; 157 | 158 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath; 159 | 160 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass; 161 | 162 | 163 | - (NSMutableArray *)subviewFrameCachesWithIndexPath:(NSIndexPath *)indexPath;; 164 | - (void)setSubviewFrameCache:(CGRect)rect WithIndexPath:(NSIndexPath *)indexPath; 165 | 166 | - (instancetype)initWithCellClass:(Class)cellClass tableView:(UITableView *)tableView; 167 | + (instancetype)managerWithCellClass:(Class)cellClass tableView:(UITableView *)tableView; 168 | @end 169 | 170 | -------------------------------------------------------------------------------- /SDPickerController/Lib/SDAutoLayout/UITableView+SDAutoTableViewCellHeight.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+SDAutoTableViewCellHeight.m 3 | // SDAutoLayout 测试 Demo 4 | // 5 | // Created by aier on 15/11/1. 6 | // Copyright © 2015年 gsd. All rights reserved. 7 | // 8 | 9 | /* 10 | 11 | ********************************************************************************* 12 | * * 13 | * 在您使用此自动布局库的过程中如果出现bug请及时以以下任意一种方式联系我们,我们会及时修复bug并 * 14 | * 帮您解决问题。 * 15 | * QQ : 2689718696(gsdios) * 16 | * Email : gsdios@126.com * 17 | * GitHub: https://github.com/gsdios * 18 | * 新浪微博:GSD_iOS * 19 | * * 20 | ********************************************************************************* 21 | 22 | */ 23 | 24 | #import "UITableView+SDAutoTableViewCellHeight.h" 25 | #import 26 | 27 | @interface SDCellAutoHeightManager () 28 | 29 | @property (nonatomic, weak) UITableView *modelTableview; 30 | 31 | @end 32 | 33 | @implementation SDCellAutoHeightManager 34 | { 35 | NSMutableDictionary *_cacheDictionary; 36 | NSMutableDictionary *_modelCellsDict; 37 | } 38 | 39 | - (instancetype)init 40 | { 41 | if (self = [super init]) { 42 | [self setup]; 43 | } 44 | return self; 45 | } 46 | 47 | - (instancetype)initWithCellClass:(Class)cellClass tableView:(UITableView *)tableView 48 | { 49 | if (self = [super init]) { 50 | [self setup]; 51 | self.modelTableview = tableView; 52 | [self registerCellWithCellClass:cellClass]; 53 | } 54 | return self; 55 | } 56 | 57 | - (instancetype)initWithCellClasses:(NSArray *)cellClassArray tableView:(UITableView *)tableView 58 | { 59 | if (self = [super init]) { 60 | [self setup]; 61 | self.modelTableview = tableView; 62 | [cellClassArray enumerateObjectsUsingBlock:^(Class obj, NSUInteger idx, BOOL *stop) { 63 | [self registerCellWithCellClass:obj]; 64 | }]; 65 | } 66 | return self; 67 | } 68 | 69 | - (void)setup 70 | { 71 | _cacheDictionary = [NSMutableDictionary new]; 72 | _modelCellsDict = [NSMutableDictionary new]; 73 | } 74 | 75 | - (void)registerCellWithCellClass:(Class)cellClass 76 | { 77 | [_modelTableview registerClass:cellClass forCellReuseIdentifier:NSStringFromClass(cellClass)]; 78 | self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)]; 79 | 80 | if (!self.modelCell.contentView.subviews.count) { 81 | NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@.nib", NSStringFromClass(cellClass)] ofType:nil]; 82 | if (path) { 83 | self.modelCell = nil; 84 | [_modelTableview registerNib:[UINib nibWithNibName:NSStringFromClass(cellClass) bundle:nil] forCellReuseIdentifier:NSStringFromClass(cellClass)]; 85 | self.modelCell = [_modelTableview dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)]; 86 | } 87 | } 88 | if (self.modelCell) { 89 | [_modelCellsDict setObject:self.modelCell forKey:NSStringFromClass(cellClass)]; 90 | } 91 | } 92 | 93 | + (instancetype)managerWithCellClass:(Class)cellClass tableView:(UITableView *)tableView 94 | { 95 | SDCellAutoHeightManager *manager = [[self alloc] initWithCellClass:cellClass tableView:tableView]; 96 | return manager; 97 | } 98 | 99 | - (UITableViewCell *)modelCell 100 | { 101 | if (_modelCell.contentView.tag != kSDModelCellTag) { 102 | _modelCell.contentView.tag = kSDModelCellTag; 103 | } 104 | return _modelCell; 105 | } 106 | 107 | - (NSDictionary *)heightCacheDict 108 | { 109 | return _cacheDictionary; 110 | } 111 | 112 | - (void)clearHeightCache 113 | { 114 | [_cacheDictionary removeAllObjects]; 115 | [_subviewFrameCacheDict removeAllObjects]; 116 | } 117 | 118 | - (NSString *)cacheKeyForIndexPath:(NSIndexPath *)indexPath 119 | { 120 | return [NSString stringWithFormat:@"%ld-%ld", (long)indexPath.section, (long)indexPath.row]; 121 | } 122 | 123 | - (void)clearHeightCacheOfIndexPaths:(NSArray *)indexPaths 124 | { 125 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { 126 | NSString *cacheKey = [self cacheKeyForIndexPath:indexPath]; 127 | [_cacheDictionary removeObjectForKey:cacheKey]; 128 | [_subviewFrameCacheDict removeObjectForKey:cacheKey]; 129 | }]; 130 | } 131 | 132 | - (void)deleteThenResetHeightCache:(NSIndexPath *)indexPathToDelete 133 | { 134 | 135 | NSString *cacheKey = [self cacheKeyForIndexPath:indexPathToDelete]; 136 | [_cacheDictionary removeObjectForKey:cacheKey]; 137 | [_subviewFrameCacheDict removeObjectForKey:cacheKey]; 138 | 139 | long sectionOfToDeleteItem = indexPathToDelete.section; 140 | long rowOfToDeleteItem = indexPathToDelete.row; 141 | NSMutableDictionary *tempHeightCacheDict = [NSMutableDictionary new]; 142 | NSMutableDictionary *tempFrameCacheDict = [NSMutableDictionary new]; 143 | for (NSString *key in _cacheDictionary.allKeys) { 144 | NSArray *res = [key componentsSeparatedByString:@"-"]; 145 | long section = [res.firstObject integerValue]; 146 | long row = [res.lastObject integerValue]; 147 | if (section == sectionOfToDeleteItem && row > rowOfToDeleteItem) { 148 | NSNumber *heightCache = _cacheDictionary[key]; 149 | NSArray *frameCache = _subviewFrameCacheDict[key]; 150 | NSString *newKey = [NSString stringWithFormat:@"%ld-%ld", section, (row - 1)]; 151 | [tempHeightCacheDict setValue:heightCache forKey:newKey]; 152 | [tempFrameCacheDict setValue:frameCache forKey:newKey]; 153 | [_cacheDictionary removeObjectForKey:key]; 154 | [_subviewFrameCacheDict removeObjectForKey:key]; 155 | } 156 | } 157 | [_cacheDictionary addEntriesFromDictionary:tempHeightCacheDict]; 158 | [_subviewFrameCacheDict addEntriesFromDictionary:tempFrameCacheDict]; 159 | 160 | } 161 | 162 | - (void)insertNewDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count 163 | { 164 | NSMutableDictionary *tempHeightCacheDict = [NSMutableDictionary new]; 165 | NSMutableDictionary *tempFrameCacheDict = [NSMutableDictionary new]; 166 | for (NSString *key in _cacheDictionary.allKeys) { 167 | NSArray *res = [key componentsSeparatedByString:@"-"]; 168 | long originalSection = [res.firstObject integerValue]; 169 | long row = [res.lastObject integerValue]; 170 | if (originalSection == section) { 171 | NSNumber *heightCache = _cacheDictionary[key]; 172 | NSArray *frameCache = _subviewFrameCacheDict[key]; 173 | NSString *newKey = [NSString stringWithFormat:@"%ld-%ld", originalSection, (row + count)]; 174 | [tempHeightCacheDict setValue:heightCache forKey:newKey]; 175 | [tempFrameCacheDict setValue:frameCache forKey:newKey]; 176 | [_cacheDictionary removeObjectForKey:key]; 177 | [_subviewFrameCacheDict removeObjectForKey:key]; 178 | } 179 | } 180 | [_cacheDictionary addEntriesFromDictionary:tempHeightCacheDict]; 181 | [_subviewFrameCacheDict addEntriesFromDictionary:tempFrameCacheDict]; 182 | } 183 | 184 | - (void)insertNewDataAtIndexPaths:(NSArray *)indexPaths 185 | { 186 | NSMutableDictionary *sectionsdict = [NSMutableDictionary new]; 187 | for (NSIndexPath *indexPath in indexPaths) { 188 | NSString *sectionkey = [@(indexPath.section) stringValue]; 189 | if (![sectionsdict objectForKey:sectionkey]) { 190 | [sectionsdict setValue:[NSMutableArray new] forKey:sectionkey]; 191 | } 192 | NSMutableArray *arr = sectionsdict[sectionkey]; 193 | [arr addObject:indexPath]; 194 | } 195 | for (NSString *sectionkey in sectionsdict.allKeys) { 196 | NSMutableArray *tempHeightCaches = [NSMutableArray new]; 197 | NSMutableArray *tempFrameCaches = [NSMutableArray new]; 198 | NSInteger section = [sectionkey integerValue]; 199 | NSInteger rowCount = [self.modelTableview numberOfRowsInSection:section]; 200 | if (rowCount <= 0) { 201 | continue; 202 | } else { 203 | for (int i = 0; i < rowCount; i++) { 204 | [tempHeightCaches addObject:[NSNull null]]; 205 | [tempFrameCaches addObject:[NSNull null]]; 206 | } 207 | } 208 | 209 | for (NSString *key in _cacheDictionary.allKeys) { 210 | NSArray *res = [key componentsSeparatedByString:@"-"]; 211 | long originalSection = [res.firstObject integerValue]; 212 | long row = [res.lastObject integerValue]; 213 | if (originalSection == section) { 214 | NSNumber *heightCache = _cacheDictionary[key]; 215 | NSArray *frameCache = _subviewFrameCacheDict[key]; 216 | [tempHeightCaches setObject:heightCache atIndexedSubscript:row]; 217 | [tempFrameCaches setObject:frameCache atIndexedSubscript:row]; 218 | [_cacheDictionary removeObjectForKey:key]; 219 | [_subviewFrameCacheDict removeObjectForKey:key]; 220 | } 221 | } 222 | NSMutableArray *objsToInsert = [NSMutableArray new]; 223 | NSMutableIndexSet *indexSet = [NSMutableIndexSet new]; 224 | NSArray *indexPaths = sectionsdict[sectionkey]; 225 | [indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *obj, NSUInteger idx, BOOL *stop) { 226 | [objsToInsert addObject:[NSNull null]]; 227 | [indexSet addIndex:obj.row]; 228 | }]; 229 | [tempHeightCaches insertObjects:objsToInsert atIndexes:indexSet]; 230 | [tempFrameCaches insertObjects:objsToInsert atIndexes:indexSet]; 231 | [tempHeightCaches enumerateObjectsUsingBlock:^(NSNumber *heightCache, NSUInteger idx, BOOL *stop) { 232 | if (![heightCache isKindOfClass:[NSNull class]]) { 233 | NSString *key = [NSString stringWithFormat:@"%zd-%zd", section, idx]; 234 | [_cacheDictionary setValue:heightCache forKey:key]; 235 | [_subviewFrameCacheDict setValue:[tempFrameCaches objectAtIndex:idx] forKey:key]; 236 | } 237 | }]; 238 | } 239 | } 240 | 241 | - (NSNumber *)heightCacheForIndexPath:(NSIndexPath *)indexPath 242 | { 243 | /* 244 | 如果程序卡在了这里很可能是由于你用了“dequeueReusableCellWithIdentifier:forIndexPath:”方法来重用cell,换成““dequeueReusableCellWithIdentifier:”(不带IndexPath)方法即可解决 245 | */ 246 | NSString *cacheKey = [self cacheKeyForIndexPath:indexPath]; 247 | return (NSNumber *)[_cacheDictionary objectForKey:cacheKey]; 248 | } 249 | 250 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath 251 | { 252 | 253 | NSNumber *cacheHeight = [self heightCacheForIndexPath:indexPath]; 254 | if (cacheHeight) { 255 | return [cacheHeight floatValue]; 256 | } else { 257 | if (!self.modelCell) { 258 | return 0; 259 | } 260 | 261 | if (self.modelTableview && self.modelTableview != self.modelCell.sd_tableView) { 262 | self.modelCell.sd_tableView = self.modelTableview; 263 | } 264 | self.modelCell.sd_indexPath = indexPath; 265 | 266 | if (model && keyPath) { 267 | [self.modelCell setValue:model forKey:keyPath]; 268 | } else if (self.cellDataSetting) { 269 | self.cellDataSetting(self.modelCell); 270 | } 271 | 272 | 273 | #ifdef SDDebugWithAssert 274 | /* 275 | 如果程序卡在了这里说明你的cell还没有调用“setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法或者你传递的bottomView为nil,请检查并修改。例: 276 | 277 | //注意:bottomView不能为nil 278 | [cell setupAutoHeightWithBottomView:bottomView bottomMargin:bottomMargin]; 279 | */ 280 | NSAssert(self.modelCell.sd_bottomViewsArray.count, @">>>>>> 你的cell还没有调用“setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin”方法或者你传递的bottomView为nil,请检查并修改"); 281 | 282 | #endif 283 | 284 | [self.modelCell.contentView layoutSubviews]; 285 | NSString *cacheKey = [self cacheKeyForIndexPath:indexPath]; 286 | [_cacheDictionary setObject:@(self.modelCell.autoHeight) forKey:cacheKey]; 287 | 288 | 289 | if (self.modelCell.sd_indexPath && self.modelCell.sd_tableView) { 290 | if (self.modelCell.contentView.shouldReadjustFrameBeforeStoreCache) { 291 | self.modelCell.contentView.height_sd = self.modelCell.autoHeight; 292 | [self.modelCell.contentView layoutSubviews]; 293 | } 294 | [self.modelCell.contentView.autoLayoutModelsArray enumerateObjectsUsingBlock:^(SDAutoLayoutModel *model, NSUInteger idx, BOOL *stop) { 295 | [self.modelTableview.cellAutoHeightManager setSubviewFrameCache:model.needsAutoResizeView.frame WithIndexPath:self.modelCell.sd_indexPath]; 296 | }]; 297 | } 298 | 299 | 300 | return self.modelCell.autoHeight; 301 | } 302 | } 303 | 304 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass 305 | { 306 | if (![self.modelCell isKindOfClass:cellClass]) { 307 | self.modelCell = nil; 308 | self.modelCell = [_modelCellsDict objectForKey:NSStringFromClass(cellClass)]; 309 | if (!self.modelCell) { 310 | [self registerCellWithCellClass:cellClass]; 311 | } 312 | _modelCell.contentView.tag = kSDModelCellTag; 313 | } 314 | if (self.modelCell.contentView.width_sd != self.contentViewWidth) { 315 | _modelCell.contentView.width_sd = self.contentViewWidth; 316 | } 317 | return [self cellHeightForIndexPath:indexPath model:model keyPath:keyPath]; 318 | } 319 | 320 | - (void)setContentViewWidth:(CGFloat)contentViewWidth 321 | { 322 | if (_contentViewWidth == contentViewWidth) return; 323 | 324 | CGFloat lastContentViewWidth = _contentViewWidth; 325 | _contentViewWidth = contentViewWidth; 326 | 327 | self.modelCell.contentView.width_sd = self.contentViewWidth; 328 | 329 | if (lastContentViewWidth > 0) { 330 | [_subviewFrameCacheDict removeAllObjects]; 331 | dispatch_async(dispatch_get_main_queue(), ^{ 332 | [self clearHeightCache]; 333 | [self.modelTableview reloadData]; 334 | }); 335 | } 336 | } 337 | 338 | 339 | - (void)setSubviewFrameCache:(CGRect)rect WithIndexPath:(NSIndexPath *)indexPath 340 | { 341 | if (!self.subviewFrameCacheDict) { 342 | self.subviewFrameCacheDict = [NSMutableDictionary new]; 343 | } 344 | NSString *cacheKey = [self cacheKeyForIndexPath:indexPath]; 345 | NSMutableArray *caches = [self.subviewFrameCacheDict objectForKey:cacheKey]; 346 | if (!caches) { 347 | caches = [NSMutableArray new]; 348 | [self.subviewFrameCacheDict setValue:caches forKey:cacheKey]; 349 | } 350 | [caches addObject:[NSValue valueWithCGRect:rect]]; 351 | } 352 | 353 | - (NSMutableArray *)subviewFrameCachesWithIndexPath:(NSIndexPath *)indexPath 354 | { 355 | NSString *cacheKey = [self cacheKeyForIndexPath:indexPath]; 356 | return [self.subviewFrameCacheDict valueForKey:cacheKey]; 357 | } 358 | 359 | @end 360 | 361 | 362 | @implementation UITableView (SDAutoTableViewCellHeight) 363 | 364 | + (void)load { 365 | static dispatch_once_t onceToken; 366 | dispatch_once(&onceToken, ^{ 367 | 368 | NSArray *selStringsArray = @[@"reloadData", @"reloadRowsAtIndexPaths:withRowAnimation:", @"deleteRowsAtIndexPaths:withRowAnimation:", @"insertRowsAtIndexPaths:withRowAnimation:"]; 369 | 370 | [selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) { 371 | NSString *mySelString = [@"sd_" stringByAppendingString:selString]; 372 | 373 | Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString)); 374 | Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString)); 375 | method_exchangeImplementations(originalMethod, myMethod); 376 | }]; 377 | }); 378 | } 379 | 380 | - (void)sd_reloadData 381 | { 382 | if (!self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData) { 383 | [self.cellAutoHeightManager clearHeightCache]; 384 | } 385 | [self sd_reloadData]; 386 | self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = NO; 387 | } 388 | 389 | - (void)sd_reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation 390 | { 391 | [self.cellAutoHeightManager clearHeightCacheOfIndexPaths:indexPaths]; 392 | [self sd_reloadRowsAtIndexPaths:indexPaths withRowAnimation:animation]; 393 | } 394 | 395 | - (void)sd_deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation 396 | { 397 | for (NSIndexPath *indexPath in indexPaths) { 398 | [self.cellAutoHeightManager deleteThenResetHeightCache:indexPath]; 399 | } 400 | [self sd_deleteRowsAtIndexPaths:indexPaths withRowAnimation:animation]; 401 | } 402 | 403 | 404 | - (void)sd_insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation 405 | { 406 | [self.cellAutoHeightManager insertNewDataAtIndexPaths:indexPaths]; 407 | [self sd_insertRowsAtIndexPaths:indexPaths withRowAnimation:animation]; 408 | } 409 | 410 | /* 411 | * 下一步即将实现的功能 412 | 413 | - (void)sd_moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath 414 | { 415 | [self sd_moveRowAtIndexPath:indexPath toIndexPath:newIndexPath]; 416 | } 417 | 418 | */ 419 | 420 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath model:(id)model keyPath:(NSString *)keyPath cellClass:(Class)cellClass contentViewWidth:(CGFloat)contentViewWidth 421 | { 422 | self.cellAutoHeightManager.modelTableview = self; 423 | 424 | self.cellAutoHeightManager.contentViewWidth = contentViewWidth; 425 | 426 | return [self.cellAutoHeightManager cellHeightForIndexPath:indexPath model:model keyPath:keyPath cellClass:cellClass]; 427 | } 428 | 429 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellClass:(__unsafe_unretained Class)cellClass cellContentViewWidth:(CGFloat)width cellDataSetting:(AutoCellHeightDataSettingBlock)cellDataSetting 430 | { 431 | 432 | self.cellDataSetting = cellDataSetting; 433 | 434 | return [self cellHeightForIndexPath:indexPath model:nil keyPath:nil cellClass:cellClass contentViewWidth:width]; 435 | } 436 | 437 | - (void)reloadDataWithExistedHeightCache 438 | { 439 | self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = YES; 440 | [self reloadData]; 441 | } 442 | 443 | - (void)reloadDataWithInsertingDataAtTheBeginingOfSection:(NSInteger)section newDataCount:(NSInteger)count 444 | { 445 | self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = YES; 446 | [self.cellAutoHeightManager insertNewDataAtTheBeginingOfSection:section newDataCount:count]; 447 | [self reloadData]; 448 | } 449 | 450 | - (void)reloadDataWithInsertingDataAtTheBeginingOfSections:(NSArray *)sectionNumsArray newDataCounts:(NSArray *)dataCountsArray 451 | { 452 | self.cellAutoHeightManager.shouldKeepHeightCacheWhenReloadingData = YES; 453 | [sectionNumsArray enumerateObjectsUsingBlock:^(NSNumber *num, NSUInteger idx, BOOL *stop) { 454 | int section = [num intValue]; 455 | int dataCountForSection = [dataCountsArray[idx] intValue]; 456 | [self.cellAutoHeightManager insertNewDataAtTheBeginingOfSection:section newDataCount:dataCountForSection]; 457 | }]; 458 | [self reloadData]; 459 | } 460 | 461 | - (CGFloat)cellsTotalHeight 462 | { 463 | CGFloat h = 0; 464 | if (!self.cellAutoHeightManager.heightCacheDict.count) { 465 | [self reloadData]; 466 | } 467 | NSArray *values = [self.cellAutoHeightManager.heightCacheDict allValues]; 468 | for (NSNumber *number in values) { 469 | h += [number floatValue]; 470 | } 471 | return h; 472 | } 473 | 474 | - (SDCellAutoHeightManager *)cellAutoHeightManager 475 | { 476 | 477 | SDCellAutoHeightManager *cellAutoHeightManager = objc_getAssociatedObject(self, _cmd); 478 | 479 | if (!cellAutoHeightManager) { 480 | 481 | cellAutoHeightManager = [[SDCellAutoHeightManager alloc] init]; 482 | 483 | [self setCellAutoHeightManager:cellAutoHeightManager]; 484 | } 485 | 486 | return cellAutoHeightManager; 487 | } 488 | 489 | - (void)setCellAutoHeightManager:(SDCellAutoHeightManager *)cellAutoHeightManager 490 | { 491 | objc_setAssociatedObject(self, @selector(cellAutoHeightManager), cellAutoHeightManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 492 | } 493 | 494 | - (void)setCellDataSetting:(AutoCellHeightDataSettingBlock)cellDataSetting 495 | { 496 | self.cellAutoHeightManager.cellDataSetting = cellDataSetting; 497 | } 498 | 499 | - (AutoCellHeightDataSettingBlock)cellDataSetting 500 | { 501 | return self.cellAutoHeightManager.cellDataSetting; 502 | } 503 | 504 | @end 505 | 506 | 507 | @implementation UITableViewController (SDTableViewControllerAutoCellHeight) 508 | 509 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width 510 | { 511 | return [self cellHeightForIndexPath:indexPath cellContentViewWidth:width tableView:self.tableView]; 512 | } 513 | 514 | @end 515 | 516 | @implementation NSObject (SDAnyObjectAutoCellHeight) 517 | 518 | - (CGFloat)cellHeightForIndexPath:(NSIndexPath *)indexPath cellContentViewWidth:(CGFloat)width tableView:(UITableView *)tableView 519 | { 520 | tableView.cellAutoHeightManager.modelTableview = tableView; 521 | 522 | if (tableView.cellAutoHeightManager.contentViewWidth != width) { 523 | tableView.cellAutoHeightManager.contentViewWidth = width; 524 | } 525 | if ([tableView.cellAutoHeightManager heightCacheForIndexPath:indexPath]) { 526 | return [[tableView.cellAutoHeightManager heightCacheForIndexPath:indexPath] floatValue]; 527 | } 528 | UITableViewCell *cell = [tableView.dataSource tableView:tableView cellForRowAtIndexPath:indexPath]; 529 | tableView.cellAutoHeightManager.modelCell = cell; 530 | if (cell.contentView.width_sd != width) { 531 | cell.contentView.width_sd = width; 532 | } 533 | return [[tableView cellAutoHeightManager] cellHeightForIndexPath:indexPath model:nil keyPath:nil]; 534 | } 535 | 536 | @end 537 | 538 | -------------------------------------------------------------------------------- /SDPickerController/Lib/SDAutoLayout/UIView+SDAutoLayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SDAutoLayout.h 3 | // 4 | // Created by gsd on 15/10/6. 5 | // Copyright (c) 2015年 gsd. All rights reserved. 6 | // 7 | 8 | /* 9 | ************************************************************************* 10 | 11 | --------- INTRODUCTION --------- 12 | 13 | USAGE: 14 | 15 | MODE 1. >>>>>>>>>>>>>>> You can use it in this way: 16 | 17 | Demo.sd_layout 18 | .topSpaceToView(v1, 100) 19 | .bottomSpaceToView(v3, 100) 20 | .leftSpaceToView(v0, 150) 21 | .rightSpaceToView(v2, 150); 22 | 23 | MODE 2. >>>>>>>>>>>>>>> You can also use it in this way that is more brevity: 24 | 25 | Demo.sd_layout.topSpaceToView(v1, 100).bottomSpaceToView(v3, 100).leftSpaceToView(v0, 150).rightSpaceToView(v2, 150); 26 | 27 | 28 | ************************************************************************* 29 | */ 30 | 31 | 32 | /* 33 | 34 | ********************************************************************************* 35 | * 36 | * 在您使用此自动布局库的过程中如果出现bug请及时以以下任意一种方式联系我们,我们会及时修复bug并 37 | * 帮您解决问题。 38 | * QQ : 2689718696(gsdios) 39 | * Email : gsdios@126.com 40 | * GitHub: https://github.com/gsdios 41 | * 新浪微博:GSD_iOS 42 | * 43 | * 视频教程:http://www.letv.com/ptv/vplay/24038772.html 44 | * 用法示例:https://github.com/gsdios/SDAutoLayout/blob/master/README.md 45 | * 46 | ********************************************************************************* 47 | 48 | 49 | SDAutoLayout 50 | 版本:2.1.7 51 | 发布:2016.08.12 52 | 53 | */ 54 | 55 | 56 | // 如果需要用“断言”调试程序请打开此宏 57 | 58 | //#define SDDebugWithAssert 59 | 60 | #import 61 | 62 | @class SDAutoLayoutModel, SDUIViewCategoryManager; 63 | 64 | typedef SDAutoLayoutModel *(^MarginToView)(id viewOrViewsArray, CGFloat value); 65 | typedef SDAutoLayoutModel *(^Margin)(CGFloat value); 66 | typedef SDAutoLayoutModel *(^MarginEqualToView)(UIView *toView); 67 | typedef SDAutoLayoutModel *(^WidthHeight)(CGFloat value); 68 | typedef SDAutoLayoutModel *(^WidthHeightEqualToView)(UIView *toView, CGFloat ratioValue); 69 | typedef SDAutoLayoutModel *(^AutoHeight)(CGFloat ratioValue); 70 | typedef SDAutoLayoutModel *(^SameWidthHeight)(); 71 | typedef SDAutoLayoutModel *(^Offset)(CGFloat value); 72 | typedef void (^SpaceToSuperView)(UIEdgeInsets insets); 73 | 74 | @interface SDAutoLayoutModel : NSObject 75 | 76 | /* 77 | *************************说明************************ 78 | 79 | 方法名中带有“SpaceToView”的需要传递2个参数:(UIView)参照view 和 (CGFloat)间距数值 80 | 方法名中带有“RatioToView”的需要传递2个参数:(UIView)参照view 和 (CGFloat)倍数 81 | 方法名中带有“EqualToView”的需要传递1个参数:(UIView)参照view 82 | 方法名中带有“Is”的需要传递1个参数:(CGFloat)数值 83 | 84 | ***************************************************** 85 | */ 86 | 87 | 88 | /* 设置距离其它view的间距 */ 89 | 90 | /** 左边到其参照view之间的间距,参数为“(View 或者 view数组, CGFloat)” */ 91 | @property (nonatomic, copy, readonly) MarginToView leftSpaceToView; 92 | /** 右边到其参照view之间的间距,参数为“(View, CGFloat)” */ 93 | @property (nonatomic, copy, readonly) MarginToView rightSpaceToView; 94 | /** 顶部到其参照view之间的间距,参数为“(View 或者 view数组, CGFloat)” */ 95 | @property (nonatomic, copy, readonly) MarginToView topSpaceToView; 96 | /** 底部到其参照view之间的间距,参数为“(View, CGFloat)” */ 97 | @property (nonatomic, copy, readonly) MarginToView bottomSpaceToView; 98 | 99 | 100 | 101 | /* 设置x、y、width、height、centerX、centerY 值 */ 102 | 103 | /** x值,参数为“(CGFloat)” */ 104 | @property (nonatomic, copy, readonly) Margin xIs; 105 | /** y值,参数为“(CGFloat)” */ 106 | @property (nonatomic, copy, readonly) Margin yIs; 107 | /** centerX值,参数为“(CGFloat)” */ 108 | @property (nonatomic, copy, readonly) Margin centerXIs; 109 | /** centerY值,参数为“(CGFloat)” */ 110 | @property (nonatomic, copy, readonly) Margin centerYIs; 111 | /** 宽度值,参数为“(CGFloat)” */ 112 | @property (nonatomic, copy, readonly) WidthHeight widthIs; 113 | /** 高度值,参数为“(CGFloat)” */ 114 | @property (nonatomic, copy, readonly) WidthHeight heightIs; 115 | 116 | 117 | 118 | /* 设置最大宽度和高度、最小宽度和高度 */ 119 | 120 | /** 最大宽度值,参数为“(CGFloat)” */ 121 | @property (nonatomic, copy, readonly) WidthHeight maxWidthIs; 122 | /** 最大高度值,参数为“(CGFloat)” */ 123 | @property (nonatomic, copy, readonly) WidthHeight maxHeightIs; 124 | /** 最小宽度值,参数为“(CGFloat)” */ 125 | @property (nonatomic, copy, readonly) WidthHeight minWidthIs; 126 | /** 最小高度值,参数为“(CGFloat)” */ 127 | @property (nonatomic, copy, readonly) WidthHeight minHeightIs; 128 | 129 | 130 | 131 | /* 设置和某个参照view的边距相同 */ 132 | 133 | /** 左间距与参照view相同,参数为“(View)” */ 134 | @property (nonatomic, copy, readonly) MarginEqualToView leftEqualToView; 135 | /** 右间距与参照view相同,参数为“(View)” */ 136 | @property (nonatomic, copy, readonly) MarginEqualToView rightEqualToView; 137 | /** 顶部间距与参照view相同,参数为“(View)” */ 138 | @property (nonatomic, copy, readonly) MarginEqualToView topEqualToView; 139 | /** 底部间距与参照view相同,参数为“(View)” */ 140 | @property (nonatomic, copy, readonly) MarginEqualToView bottomEqualToView; 141 | /** centerX与参照view相同,参数为“(View)” */ 142 | @property (nonatomic, copy, readonly) MarginEqualToView centerXEqualToView; 143 | /** centerY与参照view相同,参数为“(View)” */ 144 | @property (nonatomic, copy, readonly) MarginEqualToView centerYEqualToView; 145 | 146 | 147 | 148 | /* 设置宽度或者高度等于参照view的多少倍 */ 149 | 150 | /** 宽度是参照view宽度的多少倍,参数为“(View, CGFloat)” */ 151 | @property (nonatomic, copy, readonly) WidthHeightEqualToView widthRatioToView; 152 | /** 高度是参照view高度的多少倍,参数为“(View, CGFloat)” */ 153 | @property (nonatomic, copy, readonly) WidthHeightEqualToView heightRatioToView; 154 | /** 设置一个view的宽度和它的高度相同,参数为空“()” */ 155 | @property (nonatomic, copy, readonly) SameWidthHeight widthEqualToHeight; 156 | /** 设置一个view的高度和它的宽度相同,参数为空“()” */ 157 | @property (nonatomic, copy, readonly) SameWidthHeight heightEqualToWidth; 158 | /** 自适应高度,传入高宽比值,label可以传0实现文字高度自适应 */ 159 | @property (nonatomic, copy, readonly) AutoHeight autoHeightRatio; 160 | 161 | 162 | 163 | /* 填充父view(快捷方法) */ 164 | 165 | /** 传入UIEdgeInsetsMake(top, left, bottom, right),可以快捷设置view到其父view上左下右的间距 */ 166 | @property (nonatomic, copy, readonly) SpaceToSuperView spaceToSuperView; 167 | 168 | /** 设置偏移量,参数为“(CGFloat value),目前只有带有equalToView的方法可以设置offset” */ 169 | @property (nonatomic, copy, readonly) Offset offset; 170 | 171 | @property (nonatomic, weak) UIView *needsAutoResizeView; 172 | 173 | @end 174 | 175 | 176 | 177 | #pragma mark - UIView 高度、宽度自适应相关方法 178 | 179 | @interface UIView (SDAutoHeightWidth) 180 | 181 | /** 设置Cell的高度自适应,也可用于设置普通view内容高度自适应 */ 182 | - (void)setupAutoHeightWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin; 183 | 184 | /** 用于设置普通view内容宽度自适应 */ 185 | - (void)setupAutoWidthWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin; 186 | 187 | /** 设置Cell的高度自适应,也可用于设置普通view内容自适应(应用于当你不确定哪个view在自动布局之后会排布在最下方最为bottomView的时候可以调用次方法将所有可能在最下方的view都传过去) */ 188 | - (void)setupAutoHeightWithBottomViewsArray:(NSArray *)bottomViewsArray bottomMargin:(CGFloat)bottomMargin; 189 | 190 | /** 更新布局(主动刷新布局,如果你需要设置完布局代码就获得view的frame请调用此方法) */ 191 | - (void)updateLayout; 192 | 193 | /** 更新cell内部的控件的布局(cell内部控件专属的更新约束方法,如果启用了cell frame缓存则会自动清除缓存再更新约束) */ 194 | - (void)updateLayoutWithCellContentView:(UIView *)cellContentView; 195 | 196 | /** 清空高度自适应设置 */ 197 | - (void)clearAutoHeigtSettings; 198 | 199 | /** 清空宽度自适应设置 */ 200 | - (void)clearAutoWidthSettings; 201 | 202 | @property (nonatomic) CGFloat autoHeight; 203 | 204 | @property (nonatomic, readonly) SDUIViewCategoryManager *sd_categoryManager; 205 | 206 | @property (nonatomic, readonly) NSMutableArray *sd_bottomViewsArray; 207 | @property (nonatomic) CGFloat sd_bottomViewBottomMargin; 208 | 209 | @property (nonatomic) NSArray *sd_rightViewsArray; 210 | @property (nonatomic) CGFloat sd_rightViewRightMargin; 211 | 212 | @end 213 | 214 | 215 | 216 | #pragma mark - UIView 设置圆角半径、自动布局回调block等相关方法 217 | 218 | @interface UIView (SDLayoutExtention) 219 | 220 | /** 自动布局完成后的回调block,可以在这里获取到view的真实frame */ 221 | @property (nonatomic) void (^didFinishAutoLayoutBlock)(CGRect frame); 222 | 223 | /** 添加一组子view */ 224 | - (void)sd_addSubviews:(NSArray *)subviews; 225 | 226 | /* 设置圆角 */ 227 | 228 | /** 设置圆角半径值 */ 229 | @property (nonatomic, strong) NSNumber *sd_cornerRadius; 230 | /** 设置圆角半径值为view宽度的多少倍 */ 231 | @property (nonatomic, strong) NSNumber *sd_cornerRadiusFromWidthRatio; 232 | /** 设置圆角半径值为view高度的多少倍 */ 233 | @property (nonatomic, strong) NSNumber *sd_cornerRadiusFromHeightRatio; 234 | 235 | /** 设置等宽子view(子view需要在同一水平方向) */ 236 | @property (nonatomic, strong) NSArray *sd_equalWidthSubviews; 237 | 238 | @end 239 | 240 | 241 | 242 | #pragma mark - UIView 九宫格浮动布局效果 243 | 244 | @interface UIView (SDAutoFlowItems) 245 | 246 | /** 247 | * 设置类似collectionView效果的固定间距自动宽度浮动子view 248 | * viewsArray : 需要浮动布局的所有视图 249 | * perRowItemsCount : 每行显示的视图个数 250 | * verticalMargin : 视图之间的垂直间距 251 | * horizontalMargin : 视图之间的水平间距 252 | * vInset : 上下缩进值 253 | * hInset : 左右缩进值 254 | */ 255 | - (void)setupAutoWidthFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount verticalMargin:(CGFloat)verticalMargin horizontalMargin:(CGFloat)horizontalMagin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset; 256 | 257 | /** 清除固定间距自动宽度浮动子view设置 */ 258 | - (void)clearAutoWidthFlowItemsSettings; 259 | 260 | /** 261 | * 设置类似collectionView效果的固定宽带自动间距浮动子view 262 | * viewsArray : 需要浮动布局的所有视图 263 | * perRowItemsCount : 每行显示的视图个数 264 | * verticalMargin : 视图之间的垂直间距 265 | * vInset : 上下缩进值 266 | * hInset : 左右缩进值 267 | */ 268 | - (void)setupAutoMarginFlowItems:(NSArray *)viewsArray withPerRowItemsCount:(NSInteger)perRowItemsCount itemWidth:(CGFloat)itemWidth verticalMargin:(CGFloat)verticalMargin verticalEdgeInset:(CGFloat)vInset horizontalEdgeInset:(CGFloat)hInset; 269 | 270 | /** 清除固定宽带自动间距浮动子view设置 */ 271 | - (void)clearAutoMarginFlowItemsSettings; 272 | 273 | @end 274 | 275 | 276 | 277 | #pragma mark - UIView 设置约束、更新约束、清空约束、从父view移除并清空约束、开启cell的frame缓存等相关方法 278 | 279 | @interface UIView (SDAutoLayout) 280 | 281 | /** 开始自动布局 */ 282 | - (SDAutoLayoutModel *)sd_layout; 283 | 284 | /** 清空之前的自动布局设置,重新开始自动布局(重新生成布局约束并使其在父view的布局序列数组中位置保持不变) */ 285 | - (SDAutoLayoutModel *)sd_resetLayout; 286 | 287 | /** 清空之前的自动布局设置,重新开始自动布局(重新生成布局约束并添加到父view布局序列数组中的最后一个位置) */ 288 | - (SDAutoLayoutModel *)sd_resetNewLayout; 289 | 290 | /** 是否关闭自动布局 */ 291 | @property (nonatomic, getter = sd_isClosingAutoLayout) BOOL sd_closeAutoLayout; 292 | 293 | /** 从父view移除并清空约束 */ 294 | - (void)removeFromSuperviewAndClearAutoLayoutSettings; 295 | 296 | /** 清空之前的自动布局设置 */ 297 | - (void)sd_clearAutoLayoutSettings; 298 | 299 | /** 将自身frame清零(一般在cell内部控件重用前调用) */ 300 | - (void)sd_clearViewFrameCache; 301 | 302 | /** 将自己的需要自动布局的subviews的frame(或者frame缓存)清零 */ 303 | - (void)sd_clearSubviewsAutoLayoutFrameCaches; 304 | 305 | /** 设置固定宽度保证宽度不在自动布局过程再做中调整 */ 306 | @property (nonatomic, strong) NSNumber *fixedWidth; 307 | 308 | /** 设置固定高度保证高度不在自动布局过程中再做调整 */ 309 | @property (nonatomic, strong) NSNumber *fixedHeight; 310 | 311 | /** 启用cell frame缓存(可以提高cell滚动的流畅度, 目前为cell专用方法,后期会扩展到其他view) */ 312 | - (void)useCellFrameCacheWithIndexPath:(NSIndexPath *)indexPath tableView:(UITableView *)tableview; 313 | 314 | /** 所属tableview(目前为cell专用属性,后期会扩展到其他view) */ 315 | @property (nonatomic) UITableView *sd_tableView; 316 | 317 | /** cell的indexPath(目前为cell专用属性,后期会扩展到cell的其他子view) */ 318 | @property (nonatomic) NSIndexPath *sd_indexPath; 319 | 320 | - (NSMutableArray *)autoLayoutModelsArray; 321 | - (void)addAutoLayoutModel:(SDAutoLayoutModel *)model; 322 | @property (nonatomic) SDAutoLayoutModel *ownLayoutModel; 323 | @property (nonatomic, strong) NSNumber *sd_maxWidth; 324 | @property (nonatomic, strong) NSNumber *autoHeightRatioValue; 325 | 326 | @end 327 | 328 | 329 | 330 | #pragma mark - UIScrollView 内容竖向自适应、内容横向自适应方法 331 | 332 | @interface UIScrollView (SDAutoContentSize) 333 | 334 | /** 设置scrollview内容竖向自适应 */ 335 | - (void)setupAutoContentSizeWithBottomView:(UIView *)bottomView bottomMargin:(CGFloat)bottomMargin; 336 | 337 | /** 设置scrollview内容横向自适应 */ 338 | - (void)setupAutoContentSizeWithRightView:(UIView *)rightView rightMargin:(CGFloat)rightMargin; 339 | 340 | @end 341 | 342 | 343 | 344 | #pragma mark - UILabel 开启富文本布局、设置单行文本label宽度自适应、 设置label最多可以显示的行数 345 | 346 | @interface UILabel (SDLabelAutoResize) 347 | 348 | /** 是否是attributedString */ 349 | @property (nonatomic) BOOL isAttributedContent; 350 | 351 | /** 设置单行文本label宽度自适应 */ 352 | - (void)setSingleLineAutoResizeWithMaxWidth:(CGFloat)maxWidth; 353 | 354 | /** 设置label最多可以显示多少行,如果传0则显示所有行文字 */ 355 | - (void)setMaxNumberOfLinesToShow:(NSInteger)lineCount; 356 | 357 | @end 358 | 359 | 360 | 361 | #pragma mark - UIButton 设置button根据单行文字自适应 362 | 363 | @interface UIButton (SDExtention) 364 | 365 | /* 366 | * 设置button根据单行文字自适应 367 | * hPadding:左右边距 368 | */ 369 | - (void)setupAutoSizeWithHorizontalPadding:(CGFloat)hPadding buttonHeight:(CGFloat)buttonHeight; 370 | 371 | @end 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | #pragma mark - 其他方法(如果有需要可以自己利用以下接口拓展更多功能) 401 | 402 | @interface SDAutoLayoutModelItem : NSObject 403 | 404 | @property (nonatomic, strong) NSNumber *value; 405 | @property (nonatomic, weak) UIView *refView; 406 | @property (nonatomic, assign) CGFloat offset; 407 | @property (nonatomic, strong) NSArray *refViewsArray; 408 | 409 | @end 410 | 411 | 412 | @interface UIView (SDChangeFrame) 413 | 414 | @property (nonatomic) BOOL shouldReadjustFrameBeforeStoreCache; 415 | 416 | @property (nonatomic) CGFloat left_sd; 417 | @property (nonatomic) CGFloat top_sd; 418 | @property (nonatomic) CGFloat right_sd; 419 | @property (nonatomic) CGFloat bottom_sd; 420 | @property (nonatomic) CGFloat centerX_sd; 421 | @property (nonatomic) CGFloat centerY_sd; 422 | 423 | @property (nonatomic) CGFloat width_sd; 424 | @property (nonatomic) CGFloat height_sd; 425 | 426 | 427 | @property (nonatomic) CGPoint origin_sd; 428 | @property (nonatomic) CGSize size_sd; 429 | 430 | 431 | // 兼容旧版本 432 | @property (nonatomic) CGFloat left; 433 | @property (nonatomic) CGFloat top; 434 | @property (nonatomic) CGFloat right; 435 | @property (nonatomic) CGFloat bottom; 436 | @property (nonatomic) CGFloat centerX; 437 | @property (nonatomic) CGFloat centerY; 438 | @property (nonatomic) CGFloat width; 439 | @property (nonatomic) CGFloat height; 440 | @property (nonatomic) CGPoint origin; 441 | @property (nonatomic) CGSize size; 442 | 443 | @end 444 | 445 | 446 | @interface SDUIViewCategoryManager : NSObject 447 | 448 | @property (nonatomic, strong) NSArray *rightViewsArray; 449 | @property (nonatomic, assign) CGFloat rightViewRightMargin; 450 | 451 | @property (nonatomic, weak) UITableView *sd_tableView; 452 | @property (nonatomic, strong) NSIndexPath *sd_indexPath; 453 | 454 | @property (nonatomic, assign) BOOL hasSetFrameWithCache; 455 | 456 | @property (nonatomic) BOOL shouldReadjustFrameBeforeStoreCache; 457 | 458 | @property (nonatomic, assign, getter = sd_isClosingAutoLayout) BOOL sd_closeAutoLayout; 459 | 460 | 461 | /** 设置类似collectionView效果的固定间距自动宽度浮动子view */ 462 | 463 | @property (nonatomic, strong) NSArray *flowItems; 464 | @property (nonatomic, assign) CGFloat verticalMargin; 465 | @property (nonatomic, assign) CGFloat horizontalMargin; 466 | @property (nonatomic, assign) NSInteger perRowItemsCount; 467 | @property (nonatomic, assign) CGFloat lastWidth; 468 | 469 | 470 | /** 设置类似collectionView效果的固定宽带自动间距浮动子view */ 471 | 472 | @property (nonatomic, assign) CGFloat flowItemWidth; 473 | @property (nonatomic, assign) BOOL shouldShowAsAutoMarginViews; 474 | 475 | 476 | @property (nonatomic) CGFloat horizontalEdgeInset; 477 | @property (nonatomic) CGFloat verticalEdgeInset; 478 | 479 | @end 480 | 481 | -------------------------------------------------------------------------------- /SDPickerController/Resources/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/.DS_Store -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/120-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/120-1.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/Angle_@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/Angle_@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/Angle_@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/Angle_@3x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/MMVideoPreviewPlay@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/MMVideoPreviewPlay@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/MMVideoPreviewPlayHL@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/MMVideoPreviewPlayHL@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/TableViewArrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/TableViewArrow@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/VideoSendIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/VideoSendIcon@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/icon_photos_arrowbottom@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/icon_photos_arrowbottom@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/icon_photos_arrowbottom@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/icon_photos_arrowbottom@3x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/icon_photos_arrowup@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/icon_photos_arrowup@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/icon_photos_arrowup@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/icon_photos_arrowup@3x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/navi_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/navi_back@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_def_photoPickerVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_def_photoPickerVc@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_def_previewVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_def_previewVc@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_number_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_number_icon@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_original_def@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_original_def@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_original_sel@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_original_sel@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_sel_photoPickerVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_sel_photoPickerVc@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/photo_sel_previewVc@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/photo_sel_previewVc@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/preview_number_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/preview_number_icon@2x.png -------------------------------------------------------------------------------- /SDPickerController/Resources/Mytools.bundle/preview_original_def@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IOSzhangwei/SDImagePickerController/28d01f315c95b5befbc9296dbc7064045cc9ed0c/SDPickerController/Resources/Mytools.bundle/preview_original_def@2x.png -------------------------------------------------------------------------------- /SDPickerController/SDManagerModel/SDAssetModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDAssetModel.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | typedef enum : NSUInteger { 12 | SDAssetModelTypePhoto = 0, 13 | SDAssetModelTypeLivePhoto, 14 | SDAssetModelTypeVideo, 15 | SDAssetModelTypeAudio 16 | } SDAssetModelType; 17 | @class PHAsset; 18 | @interface SDAssetModel : NSObject 19 | 20 | @property (nonatomic, strong) id asset; // PHAsset 和 ALAsset 类型 21 | 22 | @property (nonatomic, assign) BOOL isSelected; //选中状态 23 | 24 | @property (nonatomic, assign) SDAssetModelType type; //获取到的数asset类型 25 | 26 | @property (nonatomic, copy) NSString *timeLength; //视频时长 27 | 28 | /** 29 | asset(PHAsset/ALAsset实例)转成照片模型 30 | 31 | */ 32 | + (instancetype)modelWithAsset:(id)asset type:(SDAssetModelType)type; 33 | //video 34 | + (instancetype)modelWithAsset:(id)asset type:(SDAssetModelType)type timeLength:(NSString *)timeLength; 35 | 36 | @end 37 | 38 | /**=====相薄分组model*/ 39 | @class PHFetchResult; 40 | @interface SDAlbumModel : NSObject 41 | @property (nonatomic, strong) NSString *name; //分组名 42 | 43 | @property (nonatomic, assign) NSInteger count; 44 | 45 | @property (nonatomic, strong) id result; // PHAsset 和 ALAsset 类型 46 | 47 | @property (nonatomic, strong) NSArray *models; 48 | 49 | @property (nonatomic, strong) NSArray *selectedModels; 50 | 51 | @property (nonatomic, assign) NSUInteger selectedCount; 52 | 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /SDPickerController/SDManagerModel/SDAssetModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDAssetModel.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "SDAssetModel.h" 10 | #import "SDImageManager.h" 11 | @implementation SDAssetModel 12 | 13 | + (instancetype)modelWithAsset:(id)asset type:(SDAssetModelType)type{ 14 | SDAssetModel *model = [[SDAssetModel alloc] init]; 15 | model.asset = asset; 16 | model.isSelected = NO; 17 | model.type = type; 18 | return model; 19 | } 20 | + (instancetype)modelWithAsset:(id)asset type:(SDAssetModelType)type timeLength:(NSString *)timeLength { 21 | SDAssetModel *model = [self modelWithAsset:asset type:type]; 22 | model.timeLength = timeLength; 23 | return model; 24 | } 25 | 26 | @end 27 | 28 | 29 | @implementation SDAlbumModel 30 | 31 | -(void)setResult:(id)result{ 32 | _result =result; 33 | BOOL pickingImage = [SDImageManager manager].pickingImage; 34 | BOOL pickingVideo = [SDImageManager manager].pickingVideo; 35 | [[SDImageManager manager] getAssetsFromFetchResult:result allowPickingVideo:pickingVideo allowPickingImage:pickingImage completion:^(NSArray *models) { 36 | 37 | _models = models; 38 | if (_selectedModels) { 39 | [self checkSelectedModels]; 40 | } 41 | 42 | }]; 43 | } 44 | 45 | 46 | 47 | 48 | - (void)checkSelectedModels { 49 | self.selectedCount = 0; 50 | NSMutableArray *selectedAssets = [NSMutableArray array]; 51 | for (SDAssetModel *model in _selectedModels) { 52 | [selectedAssets addObject:model.asset]; 53 | } 54 | for (SDAssetModel *model in _models) { 55 | if ([[SDImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) { 56 | self.selectedCount ++; 57 | } 58 | } 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SDPickerController/SDManagerModel/SDImageManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDImageManager.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import "SDAssetModel.h" 14 | #import "SDImagePicker.h" 15 | @interface SDImageManager : NSObject 16 | 17 | @property (nonatomic, strong) PHCachingImageManager *cachingImageManager; 18 | 19 | + (instancetype)manager; 20 | 21 | 22 | 23 | 24 | @property (nonatomic, assign) BOOL fixOrientation; //修成图片方向,相机获取图片会用到 25 | 26 | @property (nonatomic, assign) CGFloat photoPreviewMaxWidth; // 默认600像素宽 27 | 28 | /** 29 | ==需要展示照片的列数,通过此确定要取出的image size 30 | */ 31 | @property (nonatomic, assign) NSInteger columnNumber; 32 | /** 33 | 对照片排序,按修改时间升序 34 | */ 35 | @property (nonatomic, assign) BOOL sortAscendingByModificationDate; 36 | /** 37 | 最小可选中的图片宽高,默认是0,小于这个宽度的图片不可选中 38 | 防止columnNumber 属性出错 39 | */ 40 | @property (nonatomic, assign) NSInteger minPhotoWidthSelectable; 41 | @property (nonatomic, assign) NSInteger minPhotoHeightSelectable; 42 | @property (nonatomic, assign) BOOL hideWhenCanNotSelect; 43 | 44 | /** 45 | 图片选择 46 | */ 47 | @property(nonatomic,assign)BOOL pickingImage; 48 | /** 49 | 视频选择 50 | */ 51 | @property(nonatomic,assign)BOOL pickingVideo; 52 | 53 | /** 54 | 返回YES如果得到了授权 55 | */ 56 | - (BOOL)authorizationStatusAuthorized; 57 | /** 58 | 获取所有照片 59 | */ 60 | -(void)getCameraRollVideo:(BOOL)pickingVideo PickingImage:(BOOL)PickingImage completion:(void(^)(SDAlbumModel *model))completion; 61 | /** 62 | 获取所有分组 63 | */ 64 | - (void)getAllAlbums:(BOOL)pickingVideo PickingImage:(BOOL)PickingImage completion:(void (^)(NSArray *models))completion; 65 | /** 66 | 获得Asset数组 67 | */ 68 | - (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray *models))completion; 69 | /** 70 | 获取相薄分组封面图 71 | */ 72 | - (void)getPostImageWithAlbumModel:(SDAlbumModel *)model completion:(void (^)(UIImage *postImage))completion; 73 | /** 74 | 获得照片数据 75 | */ 76 | - (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; 77 | //获得照片zw 78 | - (PHImageRequestID)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion; 79 | /** 80 | 通过asste获得原图 81 | */ 82 | - (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion; 83 | /** 84 | 通过asste data 85 | */ 86 | - (void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *data,NSDictionary *info))completion; 87 | /** 88 | 判断一个assets数组是否包含这个asset 89 | */ 90 | - (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset; 91 | - (NSString *)getAssetIdentifier:(id)asset; 92 | - (BOOL)isPhotoSelectableWithAsset:(id)asset; 93 | 94 | 95 | #pragma mark ========相册创建======== 96 | /** 97 | 创建一个相册,存在的话不会创建 98 | 99 | @param albumName 创建的相册名字 100 | @param completion success为YES 创建成功 101 | */ 102 | -(void)createAssetAlbumForName:( NSString *)albumName completion:( void(^)(BOOL success, NSError * error))completion; 103 | 104 | /** 105 | 106 | 保存image 到指定相册中。。如果没有该相册,自动创建并保存 107 | 108 | @param image image 109 | @param albumName albumName 110 | */ 111 | -(void)saveImage:(UIImage *)image AlbumForName:(NSString *)albumName; 112 | @end 113 | -------------------------------------------------------------------------------- /SDPickerController/SDManagerModel/SDImageManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDImageManager.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | /** 9 | 10 | PhotoKit 相关博客:http://ju.outofmemory.cn/entry/209200 11 | 12 | */ 13 | 14 | #import "SDImageManager.h" 15 | #import 16 | 17 | 18 | 19 | @interface SDImageManager () 20 | @property (nonatomic, strong) ALAssetsLibrary *assetLibrary; 21 | 22 | @end 23 | 24 | @implementation SDImageManager 25 | static CGSize AssetGridThumbnailSize; 26 | static CGFloat SDScreenWidth; 27 | static CGFloat SDScreenScale; 28 | 29 | + (instancetype)manager { 30 | static SDImageManager *manager; 31 | static dispatch_once_t onceToken; 32 | dispatch_once(&onceToken, ^{ 33 | manager = [[self alloc] init]; 34 | if (SDiOS8) { 35 | manager.cachingImageManager = [[PHCachingImageManager alloc] init]; 36 | } 37 | 38 | SDScreenWidth = [UIScreen mainScreen].bounds.size.width; 39 | SDScreenScale = 2.0; 40 | if (SDScreenWidth > 700) { 41 | SDScreenScale = 1.5; 42 | } 43 | }); 44 | return manager; 45 | } 46 | 47 | 48 | -(void)getCameraRollVideo:(BOOL)pickingVideo PickingImage:(BOOL)PickingImage completion:(void(^)(SDAlbumModel *model))completion{ 49 | 50 | __block SDAlbumModel *model; 51 | if (SDiOS8) { 52 | PHFetchOptions *option = [[PHFetchOptions alloc] init]; //选择类型描述 53 | if (!pickingVideo) { 54 | option.predicate =[NSPredicate predicateWithFormat:@"mediaType == %ld",PHAssetMediaTypeImage]; 55 | } 56 | if (!PickingImage){ 57 | option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", 58 | PHAssetMediaTypeVideo]; 59 | 60 | } 61 | if (!self.sortAscendingByModificationDate) { 62 | option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]]; 63 | } 64 | PHFetchResult *result =[PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; 65 | 66 | for (PHAssetCollection *collection in result) { 67 | //过滤PHCollectionList 68 | if (![collection isKindOfClass:[PHAssetCollection class]]) continue; 69 | if ([self isCameraRollAlbum:collection.localizedTitle]) { 70 | 71 | PHFetchResult *result = [PHAsset fetchAssetsInAssetCollection:collection options:option]; //获取结果,option:描述信息 72 | model =[self modelWithResult:result name:collection.localizedTitle]; 73 | 74 | if (completion) { 75 | completion(model); 76 | } 77 | } 78 | 79 | } 80 | 81 | } 82 | 83 | } 84 | 85 | - (void)getAllAlbums:(BOOL)pickingVideo PickingImage:(BOOL)PickingImage completion:(void (^)(NSArray *models))completion{ 86 | 87 | NSMutableArray *albumArr = [NSMutableArray array]; 88 | if (SDiOS8) { 89 | PHFetchOptions *option = [[PHFetchOptions alloc] init]; 90 | if (!pickingVideo) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage]; 91 | if (!PickingImage) option.predicate = [NSPredicate predicateWithFormat:@"mediaType == %ld", 92 | PHAssetMediaTypeVideo]; 93 | // option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"modificationDate" ascending:self.sortAscendingByModificationDate]]; 94 | if (!self.sortAscendingByModificationDate) { 95 | option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:self.sortAscendingByModificationDate]]; 96 | } 97 | /*** 98 | // 我的照片流 隐藏 99 | PHFetchResult *myPhotoStreamAlbum = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumMyPhotoStream options:nil]; 100 | 101 | for (PHAssetCollection *collection in myPhotoStreamAlbum) { 102 | PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option]; 103 | if (fetchResult.count < 1) continue; 104 | [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]]; 105 | } 106 | */ 107 | PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; 108 | 109 | PHFetchResult *Collections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil]; 110 | for (PHAssetCollection *collection in smartAlbums) { 111 | if (![collection isKindOfClass:[PHAssetCollection class]]) continue; 112 | PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option]; 113 | if (fetchResult.count < 1) continue; 114 | if ([collection.localizedTitle containsString:@"Deleted"] || [collection.localizedTitle isEqualToString:@"最近删除"]) continue; 115 | if ([self isCameraRollAlbum:collection.localizedTitle]) { 116 | [albumArr insertObject:[self modelWithResult:fetchResult name:collection.localizedTitle] atIndex:0]; 117 | } else { 118 | [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]]; 119 | } 120 | 121 | } 122 | for (PHAssetCollection *collection in Collections) { 123 | if (![collection isKindOfClass:[PHAssetCollection class]]) continue; 124 | PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:option]; 125 | if (fetchResult.count < 1) continue; 126 | [albumArr addObject:[self modelWithResult:fetchResult name:collection.localizedTitle]]; 127 | } 128 | if (completion && albumArr.count > 0) completion(albumArr); 129 | } else { 130 | [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll usingBlock:^(ALAssetsGroup *group, BOOL *stop) { 131 | if (group == nil) { 132 | if (completion && albumArr.count > 0) completion(albumArr); 133 | } 134 | if ([group numberOfAssets] < 1) return; 135 | NSString *name = [group valueForProperty:ALAssetsGroupPropertyName]; 136 | if ([self isCameraRollAlbum:name]) { 137 | [albumArr insertObject:[self modelWithResult:group name:name] atIndex:0]; 138 | } else if ([name isEqualToString:@"My Photo Stream"] || [name isEqualToString:@"我的照片流"]) { 139 | if (albumArr.count) { 140 | [albumArr insertObject:[self modelWithResult:group name:name] atIndex:1]; 141 | } else { 142 | [albumArr addObject:[self modelWithResult:group name:name]]; 143 | } 144 | } else { 145 | [albumArr addObject:[self modelWithResult:group name:name]]; 146 | } 147 | } failureBlock:nil]; 148 | } 149 | 150 | } 151 | 152 | - (void)getAssetsFromFetchResult:(id)result allowPickingVideo:(BOOL)allowPickingVideo allowPickingImage:(BOOL)allowPickingImage completion:(void (^)(NSArray *models))completion{ 153 | NSMutableArray *photoArr = [NSMutableArray array]; 154 | if ([result isKindOfClass:[PHFetchResult class]]) { 155 | PHFetchResult *fetchResult = (PHFetchResult *)result; 156 | 157 | [fetchResult enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 158 | PHAsset *asset = (PHAsset *)obj; 159 | SDAssetModelType type = SDAssetModelTypePhoto; 160 | if (asset.mediaType == PHAssetMediaTypeVideo) type = SDAssetModelTypeVideo; 161 | else if (asset.mediaType == PHAssetMediaTypeAudio) type = SDAssetModelTypeAudio; 162 | else if (asset.mediaType == PHAssetMediaTypeImage) { 163 | if (SDiOS9_1) { 164 | } 165 | } 166 | if (!allowPickingVideo && type == SDAssetModelTypeVideo) return; 167 | if (!allowPickingImage && type == SDAssetModelTypePhoto) return; 168 | 169 | if (self.hideWhenCanNotSelect) { 170 | // 过滤掉尺寸不满足要求的图片 171 | if (![self isPhotoSelectableWithAsset:asset]) { 172 | return; 173 | } 174 | } 175 | 176 | NSString *timeLength = type == SDAssetModelTypeVideo ? [NSString stringWithFormat:@"%0.0f",asset.duration] : @""; 177 | timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue]; 178 | [photoArr addObject:[SDAssetModel modelWithAsset:asset type:type timeLength:timeLength]]; 179 | }]; 180 | if (completion) completion(photoArr); 181 | } else if ([result isKindOfClass:[ALAssetsGroup class]]) { 182 | ALAssetsGroup *group = (ALAssetsGroup *)result; 183 | if (allowPickingImage && allowPickingVideo) { 184 | [group setAssetsFilter:[ALAssetsFilter allAssets]]; 185 | } else if (allowPickingVideo) { 186 | [group setAssetsFilter:[ALAssetsFilter allVideos]]; 187 | } else if (allowPickingImage) { 188 | [group setAssetsFilter:[ALAssetsFilter allPhotos]]; 189 | } 190 | ALAssetsGroupEnumerationResultsBlock resultBlock = ^(ALAsset *result, NSUInteger index, BOOL *stop) { 191 | if (result == nil) { 192 | if (completion) completion(photoArr); 193 | } 194 | SDAssetModelType type = SDAssetModelTypePhoto; 195 | if (!allowPickingVideo){ 196 | [photoArr addObject:[SDAssetModel modelWithAsset:result type:type]]; 197 | return; 198 | } 199 | /// picking video 200 | if ([[result valueForProperty:ALAssetPropertyType] isEqualToString:ALAssetTypeVideo]) { 201 | type = SDAssetModelTypeVideo; 202 | NSTimeInterval duration = [[result valueForProperty:ALAssetPropertyDuration] integerValue]; 203 | NSString *timeLength = [NSString stringWithFormat:@"%0.0f",duration]; 204 | timeLength = [self getNewTimeFromDurationSecond:timeLength.integerValue]; 205 | [photoArr addObject:[SDAssetModel modelWithAsset:result type:type timeLength:timeLength]]; 206 | } else { 207 | if (self.hideWhenCanNotSelect) { 208 | // 过滤掉尺寸不满足要求的图片 209 | if (![self isPhotoSelectableWithAsset:result]) { 210 | return; 211 | } 212 | } 213 | [photoArr addObject:[SDAssetModel modelWithAsset:result type:type]]; 214 | } 215 | }; 216 | if (self.sortAscendingByModificationDate) { 217 | [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { 218 | if (resultBlock) { resultBlock(result,index,stop); } 219 | }]; 220 | } else { 221 | [group enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { 222 | if (resultBlock) { resultBlock(result,index,stop); } 223 | }]; 224 | } 225 | } 226 | } 227 | 228 | - (void)getPostImageWithAlbumModel:(SDAlbumModel *)model completion:(void (^)(UIImage *postImage))completion{ 229 | if (SDiOS8) { 230 | id asset = [model.result lastObject]; 231 | if (!self.sortAscendingByModificationDate) { 232 | asset = [model.result firstObject]; 233 | } 234 | [[SDImageManager manager] getPhotoWithAsset:asset photoWidth:80 completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { 235 | if (completion) completion(photo); 236 | }]; 237 | } else { 238 | ALAssetsGroup *group = model.result; 239 | UIImage *postImage = [UIImage imageWithCGImage:group.posterImage]; 240 | if (completion) completion(postImage); 241 | } 242 | } 243 | 244 | //获得照片本身 245 | - (PHImageRequestID)getPhotoWithAsset:(id)asset completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion { 246 | CGFloat fullScreenWidth = SDScreenWidth; 247 | if (fullScreenWidth > _photoPreviewMaxWidth) { 248 | fullScreenWidth = _photoPreviewMaxWidth; 249 | } 250 | 251 | return [self getPhotoWithAsset:asset photoWidth:fullScreenWidth completion:completion]; 252 | 253 | } 254 | 255 | - (PHImageRequestID)getPhotoWithAsset:(id)asset photoWidth:(CGFloat)photoWidth completion:(void (^)(UIImage *, NSDictionary *, BOOL isDegraded))completion { 256 | 257 | if ([asset isKindOfClass:[PHAsset class]]) { 258 | CGSize imageSize; 259 | if (photoWidth < SDScreenWidth && photoWidth < _photoPreviewMaxWidth) { 260 | imageSize = AssetGridThumbnailSize; 261 | } else { 262 | PHAsset *phAsset = (PHAsset *)asset; 263 | CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight; 264 | CGFloat pixelWidth = photoWidth * SDScreenScale; 265 | CGFloat pixelHeight = pixelWidth / aspectRatio; 266 | imageSize = CGSizeMake(pixelWidth, pixelHeight); 267 | } 268 | // 修复获取图片时出现的瞬间内存过高问题 269 | PHImageRequestOptions *option = [[PHImageRequestOptions alloc] init]; 270 | option.resizeMode = PHImageRequestOptionsResizeModeFast; 271 | 272 | /** 273 | resultHandler 可能会被多次调用,这种情况就是图像需要从 iCloud 中下载的情况。在?requestImageForAsset 返回的内容中,一开始的那一次请求中会返回一个小尺寸的图像版本,当高清图像还在下载时,开发者可以首先给用户展示这个低清的图像版本,然后 block 在多次调用后,最终会返回高清的原图 274 | BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]; 275 | */ 276 | PHImageRequestID imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:imageSize contentMode:PHImageContentModeAspectFill options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 277 | 278 | BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); 279 | if (downloadFinined && result) { 280 | result = [self fixOrientation:result]; 281 | if (completion) completion(result,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); 282 | 283 | } 284 | //从iCloud下载图片 285 | if ([info objectForKey:PHImageResultIsInCloudKey] && !result) { 286 | PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; 287 | option.networkAccessAllowed = YES; 288 | option.resizeMode = PHImageRequestOptionsResizeModeFast; 289 | [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { 290 | UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1]; 291 | resultImage = [self scaleImage:resultImage toSize:imageSize]; 292 | if (resultImage) { 293 | resultImage = [self fixOrientation:resultImage]; 294 | if (completion) completion(resultImage,info,[[info objectForKey:PHImageResultIsDegradedKey] boolValue]); 295 | } 296 | }]; 297 | } 298 | }]; 299 | return imageRequestID; 300 | } else if ([asset isKindOfClass:[ALAsset class]]) { 301 | ALAsset *alAsset = (ALAsset *)asset; 302 | dispatch_async(dispatch_get_global_queue(0,0), ^{ 303 | CGImageRef thumbnailImageRef = alAsset.thumbnail; 304 | UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp]; 305 | dispatch_async(dispatch_get_main_queue(), ^{ 306 | if (completion) completion(thumbnailImage,nil,YES); 307 | 308 | if (photoWidth == SDScreenWidth || photoWidth == _photoPreviewMaxWidth) { 309 | dispatch_async(dispatch_get_global_queue(0,0), ^{ 310 | ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; 311 | CGImageRef fullScrennImageRef = [assetRep fullScreenImage]; 312 | UIImage *fullScrennImage = [UIImage imageWithCGImage:fullScrennImageRef scale:2.0 orientation:UIImageOrientationUp]; 313 | 314 | dispatch_async(dispatch_get_main_queue(), ^{ 315 | if (completion) completion(fullScrennImage,nil,NO); 316 | }); 317 | }); 318 | } 319 | }); 320 | }); 321 | } 322 | return 0; 323 | } 324 | 325 | 326 | // 获取原图 327 | - (void)getOriginalPhotoWithAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info))completion { 328 | if ([asset isKindOfClass:[PHAsset class]]) { 329 | PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; 330 | option.networkAccessAllowed = YES; 331 | [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:PHImageManagerMaximumSize contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 332 | BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); 333 | if (downloadFinined && result) { 334 | result = [self fixOrientation:result]; 335 | if (completion) completion(result,info); 336 | } 337 | }]; 338 | } else if ([asset isKindOfClass:[ALAsset class]]) { 339 | ALAsset *alAsset = (ALAsset *)asset; 340 | ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; 341 | 342 | dispatch_async(dispatch_get_global_queue(0,0), ^{ 343 | CGImageRef originalImageRef = [assetRep fullResolutionImage]; 344 | UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp]; 345 | dispatch_async(dispatch_get_main_queue(), ^{ 346 | if (completion) completion(originalImage,nil); 347 | }); 348 | }); 349 | } 350 | } 351 | 352 | -(void)getOriginalPhotoDataWithAsset:(id)asset completion:(void (^)(NSData *, NSDictionary *))completion{ 353 | if ([asset isKindOfClass:[PHAsset class]]) { 354 | PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init]; 355 | option.networkAccessAllowed = YES; 356 | [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { 357 | BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]); 358 | if (downloadFinined && imageData) { 359 | if (completion) completion(imageData,info); 360 | } 361 | }]; 362 | } else if ([asset isKindOfClass:[ALAsset class]]) { 363 | ALAsset *alAsset = (ALAsset *)asset; 364 | ALAssetRepresentation *assetRep = [alAsset defaultRepresentation]; 365 | 366 | dispatch_async(dispatch_get_global_queue(0,0), ^{ 367 | CGImageRef originalImageRef = [assetRep fullResolutionImage]; 368 | UIImage *originalImage = [UIImage imageWithCGImage:originalImageRef scale:1.0 orientation:UIImageOrientationUp]; 369 | NSData *data = UIImageJPEGRepresentation(originalImage, 0.9); 370 | dispatch_async(dispatch_get_main_queue(), ^{ 371 | if (completion) completion(data,nil); 372 | }); 373 | }); 374 | } 375 | } 376 | 377 | - (BOOL)isAssetsArray:(NSArray *)assets containAsset:(id)asset { 378 | if (SDiOS8) { 379 | return [assets containsObject:asset]; 380 | } else { 381 | NSMutableArray *selectedAssetUrls = [NSMutableArray array]; 382 | for (ALAsset *asset_item in assets) { 383 | [selectedAssetUrls addObject:[asset_item valueForProperty:ALAssetPropertyURLs]]; 384 | } 385 | return [selectedAssetUrls containsObject:[asset valueForProperty:ALAssetPropertyURLs]]; 386 | } 387 | } 388 | 389 | - (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size { 390 | if (image.size.width > size.width) { 391 | UIGraphicsBeginImageContext(size); 392 | [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; 393 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 394 | UIGraphicsEndImageContext(); 395 | return newImage; 396 | } else { 397 | return image; 398 | } 399 | } 400 | 401 | //返回本地标识符 402 | - (NSString *)getAssetIdentifier:(id)asset { 403 | if (SDiOS8) { 404 | PHAsset *phAsset = (PHAsset *)asset; 405 | return phAsset.localIdentifier; 406 | } else { 407 | ALAsset *alAsset = (ALAsset *)asset; 408 | NSURL *assetUrl = [alAsset valueForProperty:ALAssetPropertyAssetURL]; 409 | return assetUrl.absoluteString; 410 | } 411 | } 412 | 413 | /// 修正图片转向 (从相机获取图片需要使用) 414 | - (UIImage *)fixOrientation:(UIImage *)aImage { 415 | if (!self.fixOrientation) return aImage; 416 | 417 | if (aImage.imageOrientation == UIImageOrientationUp) 418 | return aImage; 419 | 420 | CGAffineTransform transform = CGAffineTransformIdentity; 421 | 422 | switch (aImage.imageOrientation) { 423 | case UIImageOrientationDown: 424 | case UIImageOrientationDownMirrored: 425 | transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height); 426 | transform = CGAffineTransformRotate(transform, M_PI); 427 | break; 428 | 429 | case UIImageOrientationLeft: 430 | case UIImageOrientationLeftMirrored: 431 | transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); 432 | transform = CGAffineTransformRotate(transform, M_PI_2); 433 | break; 434 | 435 | case UIImageOrientationRight: 436 | case UIImageOrientationRightMirrored: 437 | transform = CGAffineTransformTranslate(transform, 0, aImage.size.height); 438 | transform = CGAffineTransformRotate(transform, -M_PI_2); 439 | break; 440 | default: 441 | break; 442 | } 443 | 444 | switch (aImage.imageOrientation) { 445 | case UIImageOrientationUpMirrored: 446 | case UIImageOrientationDownMirrored: 447 | transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); 448 | transform = CGAffineTransformScale(transform, -1, 1); 449 | break; 450 | 451 | case UIImageOrientationLeftMirrored: 452 | case UIImageOrientationRightMirrored: 453 | transform = CGAffineTransformTranslate(transform, aImage.size.height, 0); 454 | transform = CGAffineTransformScale(transform, -1, 1); 455 | break; 456 | default: 457 | break; 458 | } 459 | 460 | 461 | CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, 462 | CGImageGetBitsPerComponent(aImage.CGImage), 0, 463 | CGImageGetColorSpace(aImage.CGImage), 464 | CGImageGetBitmapInfo(aImage.CGImage)); 465 | CGContextConcatCTM(ctx, transform); 466 | switch (aImage.imageOrientation) { 467 | case UIImageOrientationLeft: 468 | case UIImageOrientationLeftMirrored: 469 | case UIImageOrientationRight: 470 | case UIImageOrientationRightMirrored: 471 | // Grr... 472 | CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage); 473 | break; 474 | 475 | default: 476 | CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage); 477 | break; 478 | } 479 | CGImageRef cgimg = CGBitmapContextCreateImage(ctx); 480 | UIImage *img = [UIImage imageWithCGImage:cgimg]; 481 | CGContextRelease(ctx); 482 | CGImageRelease(cgimg); 483 | return img; 484 | } 485 | 486 | 487 | //转换视频时间显示方式 488 | - (NSString *)getNewTimeFromDurationSecond:(NSInteger)duration { 489 | NSString *newTime; 490 | if (duration < 10) { 491 | newTime = [NSString stringWithFormat:@"0:0%zd",duration]; 492 | } else if (duration < 60) { 493 | newTime = [NSString stringWithFormat:@"0:%zd",duration]; 494 | } else { 495 | NSInteger min = duration / 60; 496 | NSInteger sec = duration - (min * 60); 497 | if (sec < 10) { 498 | newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec]; 499 | } else { 500 | newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec]; 501 | } 502 | } 503 | return newTime; 504 | } 505 | 506 | /// 检查照片大小是否满足最小要求 507 | - (BOOL)isPhotoSelectableWithAsset:(id)asset { 508 | CGSize photoSize = [self photoSizeWithAsset:asset]; 509 | if (self.minPhotoWidthSelectable > photoSize.width || self.minPhotoHeightSelectable > photoSize.height) { 510 | return NO; 511 | } 512 | return YES; 513 | } 514 | - (CGSize)photoSizeWithAsset:(id)asset { 515 | if (SDiOS8) { 516 | PHAsset *phAsset = (PHAsset *)asset; 517 | return CGSizeMake(phAsset.pixelWidth, phAsset.pixelHeight); 518 | } else { 519 | ALAsset *alAsset = (ALAsset *)asset; 520 | return alAsset.defaultRepresentation.dimensions; 521 | } 522 | } 523 | - (SDAlbumModel *)modelWithResult:(id)result name:(NSString *)name{ 524 | SDAlbumModel *model = [[SDAlbumModel alloc] init]; 525 | model.result = result; 526 | model.name = name; 527 | if ([result isKindOfClass:[PHFetchResult class]]) { 528 | PHFetchResult *fetchResult = (PHFetchResult *)result; 529 | model.count = fetchResult.count; 530 | } else if ([result isKindOfClass:[ALAssetsGroup class]]) { 531 | ALAssetsGroup *group = (ALAssetsGroup *)result; 532 | model.count = [group numberOfAssets]; 533 | } 534 | return model; 535 | } 536 | 537 | - (ALAssetsLibrary *)assetLibrary { 538 | if (_assetLibrary == nil) _assetLibrary = [[ALAssetsLibrary alloc] init]; 539 | #pragma clang diagnostic pop 540 | return _assetLibrary; 541 | } 542 | 543 | /// Return YES if Authorized 返回YES如果得到了授权 544 | - (BOOL)authorizationStatusAuthorized { 545 | return [self authorizationStatus] == 3; 546 | } 547 | - (NSInteger)authorizationStatus { 548 | if (SDiOS8) { 549 | return [PHPhotoLibrary authorizationStatus]; 550 | } else { 551 | return [ALAssetsLibrary authorizationStatus]; 552 | } 553 | return NO; 554 | } 555 | - (BOOL)isCameraRollAlbum:(NSString *)albumName{ 556 | NSString *versionStr = [[UIDevice currentDevice].systemVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; 557 | if (versionStr.length <= 1) { 558 | versionStr = [versionStr stringByAppendingString:@"00"]; 559 | } else if (versionStr.length <= 2) { 560 | versionStr = [versionStr stringByAppendingString:@"0"]; 561 | } 562 | CGFloat version = versionStr.floatValue; 563 | if (version >= 800 && version <= 802) { 564 | return [albumName isEqualToString:@"最近添加"] || [albumName isEqualToString:@"Recently Added"]; 565 | } else { 566 | return [albumName isEqualToString:@"Camera Roll"] || [albumName isEqualToString:@"相机胶卷"] || [albumName isEqualToString:@"所有照片"] || [albumName isEqualToString:@"All Photos"]; 567 | } 568 | } 569 | -(void)setColumnNumber:(NSInteger)columnNumber{ 570 | 571 | _columnNumber = columnNumber; 572 | CGFloat margin = 4; 573 | CGFloat itemWH = (SDScreenWidth - 2 * margin - 4) / columnNumber - margin; 574 | AssetGridThumbnailSize = CGSizeMake(itemWH * SDScreenScale, itemWH * SDScreenScale); 575 | } 576 | 577 | #pragma mark ========相册创建======== 578 | -(void)createAssetAlbumForName:( NSString *)albumName completion:( void(^)(BOOL success, NSError * error))completion{ 579 | 580 | if ([self checkAlbum:albumName]) { 581 | if (completion) { 582 | NSError *error = [NSError errorWithDomain:@"https://github.com/IOSzhangwei/SDImagePickerController" code:-101 userInfo:@{@"error":@"相册已经存在"}]; 583 | completion(NO,error); 584 | } 585 | }else{ 586 | [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ 587 | [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:albumName]; 588 | } completionHandler:^(BOOL success, NSError * _Nullable error) { 589 | if (completion) { 590 | completion(success,error); 591 | } 592 | }]; 593 | } 594 | } 595 | 596 | -(void)saveImage:(UIImage *)image AlbumForName:(NSString *)albumName{ 597 | 598 | [self createAssetAlbumForName:albumName completion:nil]; 599 | 600 | PHAssetCollection *collection =[self findAlbumName:albumName]; 601 | [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{ 602 | 603 | PHAssetChangeRequest *createAsset= [PHAssetChangeRequest creationRequestForAssetFromImage:image]; 604 | // Request editing the album. 605 | PHAssetCollectionChangeRequest *albumChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:collection]; 606 | // Get a placeholder for the new asset and add it to the album editing request. 607 | PHObjectPlaceholder *assetPlaceholder = [createAsset placeholderForCreatedAsset]; 608 | [albumChangeRequest addAssets:@[ assetPlaceholder ]]; 609 | 610 | } completionHandler:^(BOOL success, NSError * _Nullable error) { 611 | if (success) { 612 | NSLog(@"保存成功"); 613 | }else{ 614 | NSLog(@"保存失败"); 615 | } 616 | }]; 617 | } 618 | 619 | 620 | /** 621 | 根据相册名,查找到对应的 PHAssetCollection 622 | */ 623 | -(PHAssetCollection *)findAlbumName:(NSString *)albumName{ 624 | PHFetchResult *result =[PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil]; 625 | PHAssetCollection *collection = nil; 626 | for (PHAssetCollection *collectionList in result) { 627 | if ([[collectionList valueForKey:@"title"] isEqualToString:albumName]) { 628 | collection =collectionList; 629 | return collection; 630 | } 631 | } 632 | return nil; 633 | } 634 | 635 | /** 636 | 检查相册是否存在。存在返回YES ,不存在返回NO 637 | */ 638 | -(BOOL)checkAlbum:(NSString *)album{ 639 | 640 | PHFetchResult *result =[PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil]; 641 | 642 | for (PHCollection *collectionList in result) { 643 | if ([[collectionList valueForKey:@"title"] isEqualToString:album]) { 644 | return YES; 645 | } 646 | } 647 | return NO; 648 | } 649 | 650 | 651 | @end 652 | -------------------------------------------------------------------------------- /SDPickerController/SDManagerModel/SDImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDImagePicker.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 2016/11/21. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #ifndef SDImagePicker_h 10 | #define SDImagePicker_h 11 | 12 | #import "SDAutoLayout.h" 13 | #import "SDImageManager.h" 14 | #import "SDAssetModel.h" 15 | #import "UIView+SD.h" 16 | #import "SDImagePickerController.h" 17 | 18 | //#define SD_DEBUG [SDImageManager manager].isLog 19 | 20 | #define SDiOS7 ([UIDevice currentDevice].systemVersion.floatValue >= 7.0f) 21 | #define SDiOS8 ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f) 22 | #define SDiOS9 ([UIDevice currentDevice].systemVersion.floatValue >= 9.0f) 23 | #define SDiOS9_1 ([UIDevice currentDevice].systemVersion.floatValue >= 9.1f) 24 | // 屏幕宽 25 | #define WIDTH [UIScreen mainScreen].bounds.size.width 26 | // 屏幕高 27 | #define HEIGHT [UIScreen mainScreen].bounds.size.height 28 | #define SDUserDefault [NSUserDefaults standardUserDefaults] 29 | #define UIColorFromRGB(rgbValue) [UIColor colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 green:((float)((rgbValue & 0xFF00) >> 8))/255.0 blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0] 30 | 31 | 32 | #ifdef DEBUG 33 | #define NSLog(FORMAT, ...) fprintf(stderr,"%s:%d \t%s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]); 34 | #else 35 | #define NSLog(FORMAT, ...) nil 36 | #endif 37 | 38 | 39 | #endif /* SDImagePicker_h */ 40 | -------------------------------------------------------------------------------- /SDPickerController/ViewController/SDImagePickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDImagePickerContriller.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/14. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SDAssetModel.h" 11 | #import "SDPickerVCType.h" 12 | @protocol SDImagePickControllerDelegate; 13 | @interface SDImagePickerController : UIViewController 14 | 15 | 16 | 17 | 18 | /** 19 | 是否开启游览选择方式,默认关闭NO, 开启YES:点击左上角为选中效果,点击其他区域为进入游览选择方式 20 | */ 21 | @property(nonatomic,assign)BOOL browserSelect; 22 | /** 23 | 默认最大可选9张图片 24 | */ 25 | @property (nonatomic, assign) NSInteger maxImagesCount; 26 | /** 27 | 最小照片必选张数,至少选择一张 28 | */ 29 | @property (nonatomic, assign) NSInteger minImagesCount; 30 | 31 | /** 32 | @property (nonatomic, assign) NSInteger timeout; 超时时间 33 | */ 34 | /** 35 | 照片列数,默认4列 36 | */ 37 | @property (nonatomic, assign) NSInteger columnNumber; 38 | 39 | /** 40 | @property (nonatomic, assign) BOOL originalPhoto; 41 | */ 42 | 43 | /** 44 | 选择视频 45 | */ 46 | @property (nonatomic, assign) BOOL pickingVideo; 47 | /** 48 | 选择相册 49 | */ 50 | @property(nonatomic, assign) BOOL pickingImage; 51 | /** 52 | 默认600像素宽 53 | */ 54 | @property (nonatomic, assign) CGFloat photoPreviewMaxWidth; 55 | /** 56 | 对照片排序,按修改时间升序,默认是NO。如果设置为NO,最新的照片会显示在最前面,内部的拍照按钮会排在第一个 57 | */ 58 | @property (nonatomic, assign) BOOL sortAscendingByModificationDate; 59 | /** 60 | 是否显示相机按钮 默认为yes 61 | */ 62 | @property(nonatomic,assign)BOOL cameraBtn; 63 | /** 64 | 用户选中过的图片数组 65 | */ 66 | @property (nonatomic, strong) NSMutableArray *selectedAssets; 67 | 68 | /** 69 | 选择页的UI样式:toolbar 和Nav 70 | */ 71 | @property(nonatomic,assign)SDPickerVCUI pickerVCType; 72 | /** 73 | 当前选中的图片数组 74 | */ 75 | @property (nonatomic, strong) NSMutableArray *selectedModels; 76 | 77 | @property (nonatomic, weak) id pickerDelegate; 78 | /** 79 | maxImagesCount 为1时,自动进入单选模式(无选中与非选中UI图) 80 | */ 81 | - (instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id)delegate; 82 | 83 | @end 84 | 85 | 86 | @protocol SDImagePickControllerDelegate 87 | 88 | 89 | /** 90 | 91 | 获取选中的image 92 | @param picker SDImagePickerController 93 | @param photos 选中的图片(大图) 94 | @param assets 选择的asstes。可根据manager里的方法获取到原图 95 | @param isSelectOriginalPhoto nil 96 | */ 97 | - (void)imagePickerController:(SDImagePickerController *)picker didFinishPickingPhotos:(NSArray *)photos sourceAssets:(NSArray *)assets isSelectOriginalPhoto:(BOOL)isSelectOriginalPhoto; 98 | 99 | /** 100 | 拍照按钮点击事件 101 | @param picker SDImagePickerController 102 | @param info 为nil 。作为扩展参数 103 | */ 104 | - (void)imagePickerController:(SDImagePickerController *)picker seletedCamera:(id)info; 105 | ///返回按钮 106 | - (void)backImagePickerController:(SDImagePickerController *)picker; 107 | @end 108 | 109 | @interface SDCollectionView : UICollectionView 110 | 111 | @end 112 | 113 | 114 | -------------------------------------------------------------------------------- /SDPickerController/ViewController/SDImagePickerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDImagePickerContriller.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/14. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "SDImagePickerController.h" 10 | #import "BottomToolBar.h" 11 | #import "SDAssetCell.h" 12 | #import "BottomToolBar.h" 13 | #import "PhotoAlbumView.h" 14 | #import "AuthorityView.h" 15 | #import "SDImageManager.h" 16 | #import "UIImage+SD.h" 17 | #import "NavigationAlbumView.h" 18 | #import "SDImagePicker.h" 19 | @interface SDImagePickerController (){ 20 | // BOOL _showCameraBtn; //从这里开始研究 中间变量的意义 21 | NSTimer *_timer; 22 | CGFloat ToolBarViewH; 23 | } 24 | @property (nonatomic, strong) SDCollectionView *collectionView; 25 | @property(nonatomic,strong)NSMutableArray *modelWithDataS; 26 | 27 | @property (nonatomic, strong) SDAlbumModel *model; 28 | 29 | @property(nonatomic,strong)BottomToolBar *bottomToolBarView; 30 | 31 | @property(nonatomic,strong)PhotoAlbumView *photoAlbumView; 32 | 33 | @property(nonatomic,strong)NavigationAlbumView *navigationAlbumView; 34 | 35 | @property(nonatomic,assign)BOOL collectionViewBottom; //collectionView 是否定位到底部() 36 | 37 | @property(nonatomic,assign)BOOL albumSelected; 38 | 39 | @property(nonatomic,strong)AuthorityView *authorityView; 40 | @end 41 | 42 | @implementation SDImagePickerController 43 | 44 | -(NSMutableArray *)modelWithDataS{ 45 | if (!_modelWithDataS) { 46 | _modelWithDataS = [NSMutableArray array]; 47 | } 48 | return _modelWithDataS; 49 | } 50 | 51 | -(instancetype)initWithMaxImagesCount:(NSInteger)maxImagesCount columnNumber:(NSInteger)columnNumber delegate:(id)delegate{ 52 | if (self =[super init]) { 53 | 54 | _maxImagesCount = maxImagesCount; 55 | _minImagesCount = _minImagesCount==0?1:_minImagesCount; 56 | _columnNumber = columnNumber; 57 | _columnNumber = _columnNumber==0?4:_columnNumber; 58 | [SDImageManager manager].columnNumber = _columnNumber; 59 | _cameraBtn = YES; 60 | self.pickerDelegate=delegate; 61 | _selectedModels =[NSMutableArray array]; 62 | _pickerVCType = _pickerVCType ==SDPickerVCNav?SDPickerVCNav:SDPickerVCToolBar; 63 | 64 | } 65 | return self; 66 | } 67 | 68 | -(BOOL)prefersStatusBarHidden 69 | { 70 | return YES; 71 | } 72 | 73 | - (void)viewWillAppear:(BOOL)animated { 74 | [super viewWillAppear:animated]; 75 | [self.navigationController setNavigationBarHidden:YES] ; 76 | [self scrollCollectionViewToBottom]; //定位CollectionView 的frame 底部和顶部 77 | } 78 | 79 | -(void)setPickingImage:(BOOL)pickingImage{ 80 | _pickingImage = pickingImage; 81 | [SDImageManager manager].pickingImage = pickingImage; 82 | 83 | } 84 | 85 | -(void)setPickingVideo:(BOOL)pickingVideo{ 86 | _pickingVideo = pickingVideo; 87 | [SDImageManager manager].pickingVideo = pickingVideo; 88 | } 89 | 90 | - (void)viewDidLoad { 91 | [super viewDidLoad]; 92 | _collectionViewBottom = YES; 93 | self.view.backgroundColor =[UIColor whiteColor]; 94 | 95 | 96 | 97 | [self createCollectionView]; 98 | [self createBottomToolBar]; 99 | if (_pickerVCType == SDPickerVCNav) { 100 | _collectionView.frame = CGRectMake(0, 44, WIDTH, HEIGHT-44); 101 | _bottomToolBarView.y = 0; 102 | _bottomToolBarView.backgroundColor =UIColorFromRGB(0x353338); 103 | 104 | } 105 | 106 | if (![[SDImageManager manager] authorizationStatusAuthorized]) { 107 | 108 | _collectionView.hidden =YES; 109 | _authorityView =[[AuthorityView alloc]init]; 110 | _authorityView.backgroundColor =[UIColor clearColor]; 111 | //[self.view bringSubviewToFront:_authorityView]; 112 | [self.view addSubview:_authorityView]; 113 | _authorityView.sd_layout.widthIs([UIScreen mainScreen].bounds.size.width).centerXEqualToView(self.view).centerYEqualToView(self.view); 114 | [_authorityView setupAutoHeightWithBottomView:_authorityView.setupBtn bottomMargin:10]; 115 | _timer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(observeAuthrizationStatusChange) userInfo:nil repeats:YES]; 116 | 117 | }else{ 118 | [[SDImageManager manager] getCameraRollVideo:_pickingVideo PickingImage:_pickingImage completion:^(SDAlbumModel *model) { 119 | _model= model; 120 | self.modelWithDataS =[NSMutableArray arrayWithArray:_model.models]; 121 | [self checkSelectedModels]; //获取数据源之后,检查有没上次选中的图片 122 | [_collectionView reloadData]; 123 | }]; 124 | } 125 | 126 | 127 | } 128 | 129 | - (void)checkSelectedModels { 130 | 131 | for (SDAssetModel *model in _modelWithDataS) { 132 | model.isSelected = NO; 133 | NSMutableArray *selectedAssets = [NSMutableArray array]; 134 | for (SDAssetModel *model in self.selectedModels) { 135 | [selectedAssets addObject:model.asset]; 136 | } 137 | if ([[SDImageManager manager] isAssetsArray:selectedAssets containAsset:model.asset]) { 138 | model.isSelected = YES; 139 | } 140 | } 141 | } 142 | 143 | //CollectionView 定位到最低部 144 | - (void)scrollCollectionViewToBottom { 145 | 146 | if (_modelWithDataS.count>0&&_sortAscendingByModificationDate) { 147 | NSInteger item = _modelWithDataS.count - 1; 148 | if (_cameraBtn) { 149 | item+=1; 150 | } 151 | 152 | [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:item inSection:0] atScrollPosition:UICollectionViewScrollPositionBottom animated:NO]; 153 | _collectionViewBottom = YES; 154 | } 155 | } 156 | 157 | #pragma mark - UICollectionViewDataSource && Delegate 158 | -(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{ 159 | if (_cameraBtn) { 160 | return self.modelWithDataS.count+1; 161 | } 162 | return self.modelWithDataS.count; 163 | } 164 | 165 | 166 | 167 | -(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{ 168 | if ([self hiddenCamera:indexPath] &&[self.pickerDelegate respondsToSelector:@selector(imagePickerController:seletedCamera:)]) { 169 | [self.pickerDelegate imagePickerController:self seletedCamera:nil]; 170 | return; 171 | } 172 | if (_maxImagesCount==1) { //单选模式, 173 | [self oneSelect:indexPath]; 174 | } 175 | 176 | NSLog(@"点击进入游览页面===%@",self.navigationController); 177 | } 178 | 179 | -(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{ 180 | 181 | 182 | if ([self hiddenCamera:indexPath]) { 183 | 184 | SDAssetCameraCell *cell =[collectionView dequeueReusableCellWithReuseIdentifier:@"SDAssetCameraCell" forIndexPath:indexPath]; 185 | cell.cameraView.image =[UIImage SD_imageNamed:@"120-1"]; 186 | return cell; 187 | } 188 | SDAssetCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"SDAssetCell" forIndexPath:indexPath]; 189 | cell.photoBrowseSelect =_browserSelect; 190 | cell.maxImagesCount= _maxImagesCount; 191 | SDAssetModel *model; 192 | if (!_cameraBtn||self.sortAscendingByModificationDate) { 193 | model =_modelWithDataS[indexPath.row]; //隐藏相机 194 | }else{ 195 | model =_modelWithDataS[indexPath.row-1]; //显示相机 196 | } 197 | 198 | if (_maxImagesCount ==1) { 199 | cell.oneSelect = YES; 200 | } 201 | 202 | cell.model = model; 203 | __weak typeof(cell) weakCell =cell; 204 | cell.selectBtnBlock = ^(BOOL isSelected){ 205 | if (isSelected) { 206 | model.isSelected = NO; 207 | weakCell.selectBtn.selected = NO; 208 | NSArray *selected =[NSArray arrayWithArray:_selectedModels]; 209 | for (SDAssetModel *assetModel in selected) { // 210 | if ([[[SDImageManager manager] getAssetIdentifier:model.asset] isEqualToString:[[SDImageManager manager] getAssetIdentifier:assetModel.asset]]) { 211 | [_selectedModels removeObject:assetModel]; //取消选择的图片,从 _selectedModels中删除 212 | break; 213 | } 214 | } 215 | }else{ 216 | if (_selectedModels.count<_maxImagesCount) { //判断是否超过最大限制数 , 217 | model.isSelected = YES; 218 | weakCell.selectBtn.selected = YES; 219 | [_selectedModels addObject:model]; //保存选择的图片 220 | 221 | }else{ 222 | NSLog(@"超过最大限制,自己做提示"); 223 | } 224 | } 225 | [_bottomToolBarView refreshToolBarStatus:_selectedModels.count]; 226 | }; 227 | 228 | return cell; 229 | 230 | } 231 | //是否显示 camera 232 | -(BOOL)hiddenCamera:(NSIndexPath *)indexPath{ 233 | if (((self.sortAscendingByModificationDate &&indexPath.row>=_modelWithDataS.count)||(!self.sortAscendingByModificationDate&&indexPath.row ==0))&&_cameraBtn) { 234 | return YES; 235 | }else{ 236 | return NO; 237 | } 238 | } 239 | - (void)didGetAllPhotos:(NSArray *)photos assets:(NSArray *)assets infoArr:(NSArray *)infoArr{ 240 | 241 | if ([self.pickerDelegate respondsToSelector:@selector(imagePickerController:didFinishPickingPhotos:sourceAssets:isSelectOriginalPhoto:)]) { 242 | 243 | [self.pickerDelegate imagePickerController:self didFinishPickingPhotos:photos sourceAssets:assets isSelectOriginalPhoto:NO]; 244 | 245 | } 246 | 247 | // [self dismissViewControllerAnimated:YES completion:nil]; 248 | 249 | } 250 | 251 | 252 | //将之前用户选择的图片设定为选中状态,并添加到_selectedModels 253 | -(void)setSelectedAssets:(NSMutableArray *)selectedAssets{ 254 | _selectedModels= selectedAssets; 255 | _selectedModels =[NSMutableArray array]; 256 | for (id asset in selectedAssets) { 257 | SDAssetModel *model =[SDAssetModel modelWithAsset:asset type:SDAssetModelTypePhoto]; 258 | model.isSelected=YES; 259 | [_selectedModels addObject:model]; 260 | } 261 | } 262 | 263 | - (void)setPhotoPreviewMaxWidth:(CGFloat)photoPreviewMaxWidth { 264 | _photoPreviewMaxWidth = photoPreviewMaxWidth; 265 | if (photoPreviewMaxWidth > 800) { 266 | _photoPreviewMaxWidth = 800; 267 | } else if (photoPreviewMaxWidth < 500) { 268 | _photoPreviewMaxWidth = 500; 269 | } 270 | [SDImageManager manager].photoPreviewMaxWidth = _photoPreviewMaxWidth; 271 | } 272 | 273 | -(void)setSortAscendingByModificationDate:(BOOL)sortAscendingByModificationDate{ 274 | _sortAscendingByModificationDate = sortAscendingByModificationDate; 275 | [SDImageManager manager].sortAscendingByModificationDate = sortAscendingByModificationDate; 276 | } 277 | 278 | #pragma mark ---click--- 279 | -(void)photoAlbumBtnClick:(UIButton *)btn{ 280 | // btn.imageView.transform = CGAffineTransformMakeRotation(0); 281 | if (self.albumSelected) { 282 | self.albumSelected = NO; 283 | btn.selected=!btn.selected; 284 | } 285 | 286 | if (btn.isSelected) { 287 | if (_pickerVCType ==SDPickerVCNav) { 288 | 289 | NSLog(@"SDPickerVCNav 模式下隐藏"); 290 | [_navigationAlbumView dismiss]; 291 | 292 | }else if (_pickerVCType ==SDPickerVCToolBar){ 293 | [_photoAlbumView dismiss]; 294 | } 295 | btn.selected = NO; 296 | }else{ 297 | if (_pickerVCType ==SDPickerVCNav) { 298 | 299 | [_navigationAlbumView showPhotoAlbum]; 300 | 301 | NSLog(@"SDPickerVCNav 模式下显示"); 302 | 303 | }else if (_pickerVCType ==SDPickerVCToolBar){ 304 | [_photoAlbumView showPhotoAlbum:self.view]; 305 | } 306 | btn.selected = YES; 307 | } 308 | } 309 | -(void)doneClick{ 310 | 311 | if (_selectedModels.count <_minImagesCount) { //判断是否满足最小选中数 312 | NSLog(@"最小选择%ld张图片,此处做提示",_minImagesCount); 313 | return; 314 | } 315 | NSMutableArray *photos =[NSMutableArray array]; 316 | NSMutableArray *assets = [NSMutableArray array]; 317 | NSMutableArray *infoArr=[NSMutableArray array]; 318 | 319 | for (int i=0; i<_selectedModels.count; i++) { 320 | SDAssetModel *model = _selectedModels[i]; 321 | NSLog(@"===%@",model.asset); 322 | 323 | [[SDImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { 324 | if (isDegraded) { 325 | return ; 326 | } 327 | if (photo) { 328 | //此处未做缩放,返回原图大小图片 329 | // photo= [self scaleImage:photo toSize:CGSizeMake(828, 1747)]; 330 | [photos addObject:photo]; 331 | } 332 | if (info) { 333 | [infoArr addObject:info]; 334 | } 335 | [assets addObject:model.asset]; 336 | 337 | if (photos.count ==_selectedModels.count) { 338 | [self didGetAllPhotos:photos assets:assets infoArr:infoArr]; 339 | } 340 | }]; 341 | } 342 | } 343 | 344 | -(void)backBtnClick{ 345 | if ([self.pickerDelegate respondsToSelector:@selector(backImagePickerController:)]) { 346 | [self.pickerDelegate backImagePickerController:self]; 347 | }else{ 348 | [self dismissViewControllerAnimated:YES completion:nil]; 349 | } 350 | } 351 | 352 | #pragma mark ---initView--- 353 | -(void)createBottomToolBar{ 354 | 355 | __weak typeof(self)weakSelf =self; 356 | 357 | ToolBarViewH = 50; 358 | if (_pickerVCType==SDPickerVCNav) { 359 | [self PickerVCNav]; 360 | ToolBarViewH =44; 361 | }else if (_pickerVCType ==SDPickerVCToolBar){ 362 | [self pickerVCToolBar]; 363 | } 364 | 365 | 366 | 367 | _bottomToolBarView =[[BottomToolBar alloc]initWithFrame:CGRectMake(0,[UIScreen mainScreen].bounds.size.height-50, [UIScreen mainScreen].bounds.size.width, ToolBarViewH)]; 368 | if (self.pickerVCType ==SDPickerVCToolBar) { 369 | _bottomToolBarView.pickerVCToolBar = YES; 370 | }else{ 371 | _bottomToolBarView.pickerVCToolBar = NO; 372 | } 373 | if (_maxImagesCount ==1) { 374 | _bottomToolBarView.oneSelect = YES; 375 | }else{ 376 | _bottomToolBarView.numberLable.hidden =_selectedModels.count<=0; 377 | _bottomToolBarView.numberView.hidden=_selectedModels.count<=0; 378 | } 379 | 380 | _bottomToolBarView.numberLable.text =[NSString stringWithFormat:@"%zd",_selectedModels.count]; 381 | _bottomToolBarView.toolBarBtnBlock = ^(UIButton * btn){ 382 | switch (btn.tag-200) { 383 | case 0: 384 | [weakSelf backBtnClick]; 385 | break; 386 | case 1: 387 | [weakSelf photoAlbumBtnClick:btn]; 388 | break; 389 | case 2: 390 | [weakSelf doneClick]; 391 | break; 392 | 393 | default: 394 | break; 395 | } 396 | 397 | }; 398 | [self.view addSubview:_bottomToolBarView]; 399 | 400 | } 401 | 402 | -(void)PickerVCNav{ 403 | __weak typeof(self)weakSelf =self; 404 | _navigationAlbumView =[[NavigationAlbumView alloc] initWithFrame:CGRectMake(0, 0, WIDTH, 0)]; 405 | _navigationAlbumView.navCollectionaViewBlock =^(SDAlbumModel *model){ 406 | weakSelf.albumSelected = YES; 407 | _modelWithDataS = [NSMutableArray arrayWithArray:model.models]; 408 | [weakSelf.bottomToolBarView.photoAlbumBtn setTitle:model.name forState:UIControlStateNormal]; 409 | [weakSelf checkSelectedModels]; 410 | [weakSelf.collectionView reloadData]; 411 | [weakSelf scrollCollectionViewToBottom]; 412 | }; 413 | [self.view addSubview:_navigationAlbumView]; 414 | [[SDImageManager manager] getAllAlbums:NO PickingImage:YES completion:^(NSArray *models) { 415 | _navigationAlbumView.albumData =[NSMutableArray arrayWithArray:models]; 416 | }]; 417 | 418 | } 419 | 420 | -(void)pickerVCToolBar{ 421 | __weak typeof(self)weakSelf =self; 422 | _photoAlbumView =[[PhotoAlbumView alloc]initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 112, HEIGHT - 360, 250, 300)]; 423 | //分组点击选择事件 424 | _photoAlbumView.reloadCollectionaViewBlock=^(SDAlbumModel *model){ 425 | weakSelf.albumSelected = YES; 426 | _modelWithDataS = [NSMutableArray arrayWithArray:model.models]; 427 | [weakSelf.bottomToolBarView.photoAlbumBtn setTitle:model.name forState:UIControlStateNormal]; 428 | [weakSelf checkSelectedModels]; 429 | [weakSelf.collectionView reloadData]; 430 | [weakSelf scrollCollectionViewToBottom]; 431 | }; 432 | [[SDImageManager manager] getAllAlbums:NO PickingImage:YES completion:^(NSArray *models) { 433 | _photoAlbumView.albumData =[NSMutableArray arrayWithArray:models]; 434 | }]; 435 | } 436 | 437 | -(void)createCollectionView{ 438 | 439 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 440 | CGFloat margin=2; //item 间距 441 | CGFloat itemWH =(self.view.frame.size.width - (_columnNumber + 1) * margin) / _columnNumber; //修改默认个数 442 | layout.itemSize = CGSizeMake(itemWH, itemWH); 443 | layout.minimumInteritemSpacing = margin; 444 | layout.minimumLineSpacing = margin; 445 | _collectionView = [[SDCollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height-50) collectionViewLayout:layout]; 446 | _collectionView.backgroundColor = UIColorFromRGB(0x222222); 447 | _collectionView.delegate =self; 448 | _collectionView.dataSource =self; 449 | _collectionView.alwaysBounceHorizontal = NO; 450 | _collectionView.contentInset = UIEdgeInsetsMake(margin, margin, margin, margin); 451 | [_collectionView registerClass:[SDAssetCell class] forCellWithReuseIdentifier:@"SDAssetCell"]; 452 | [_collectionView registerClass:[SDAssetCameraCell class] forCellWithReuseIdentifier:@"SDAssetCameraCell"]; 453 | [self.view addSubview:_collectionView]; 454 | 455 | 456 | } 457 | 458 | #pragma mark Scale image / ---缩放图片--- 459 | - (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)size { 460 | 461 | if (image.size.width < size.width) { 462 | return image; 463 | } 464 | UIGraphicsBeginImageContext(size); 465 | [image drawInRect:CGRectMake(0, 0, size.width, size.height)]; 466 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 467 | UIGraphicsEndImageContext(); 468 | return newImage; 469 | } 470 | /** 471 | 是否显示 camera。 如果cameraBtn为yes,默认相机交卷显示,其他分组不显示 472 | @param albumName 分组名臣 473 | */ 474 | -(BOOL)showCamera:(NSString *)albumName{ 475 | return self.cameraBtn; 476 | 477 | } 478 | //检测相机权限是否获取 479 | - (void)observeAuthrizationStatusChange { 480 | if ([[SDImageManager manager] authorizationStatusAuthorized]) { 481 | [_timer invalidate]; 482 | _timer = nil; 483 | [[SDImageManager manager] getCameraRollVideo:YES PickingImage:YES completion:^(SDAlbumModel *model) { 484 | _model= model; 485 | self.modelWithDataS =[NSMutableArray arrayWithArray:_model.models]; 486 | [self checkSelectedModels]; //获取数据源之后,检查有没上次选中的图片 487 | _collectionView.hidden =NO; 488 | _authorityView.hidden = YES; 489 | [_collectionView reloadData]; 490 | }]; 491 | [self.view bringSubviewToFront:_collectionView]; 492 | } 493 | 494 | } 495 | 496 | //单选模式点击事件 497 | -(void)oneSelect:(NSIndexPath *)indexPath{ 498 | SDAssetModel *model; 499 | if (!_cameraBtn||self.sortAscendingByModificationDate) { 500 | model =_modelWithDataS[indexPath.row]; //隐藏相机 501 | }else{ 502 | model =_modelWithDataS[indexPath.row-1]; //显示相机 503 | } 504 | 505 | [[SDImageManager manager] getPhotoWithAsset:model.asset completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { 506 | 507 | if (isDegraded) { 508 | return ; 509 | } 510 | NSArray *array =@[photo]; 511 | NSArray *assetArray =@[model.asset]; 512 | NSArray *infoArray =@[info]; 513 | [self didGetAllPhotos:array assets:assetArray infoArr:infoArray]; 514 | }]; 515 | } 516 | 517 | @end 518 | 519 | 520 | @implementation SDCollectionView 521 | 522 | - (BOOL)touchesShouldCancelInContentView:(UIView *)view { 523 | if ( [view isKindOfClass:[UIControl class]]) { 524 | return YES; 525 | } 526 | return [super touchesShouldCancelInContentView:view]; 527 | } 528 | @end 529 | 530 | -------------------------------------------------------------------------------- /SDPickerController/Views/AuthorityView.h: -------------------------------------------------------------------------------- 1 | // 2 | // AuthorityView.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/23. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SDAutoLayout.h" 11 | #import "SDImagePicker.h" 12 | @interface AuthorityView : UIView 13 | 14 | @property(nonatomic,strong)UILabel *titleLabel; 15 | @property(nonatomic,copy)UIButton *setupBtn; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SDPickerController/Views/AuthorityView.m: -------------------------------------------------------------------------------- 1 | // 2 | // AuthorityView.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/23. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "AuthorityView.h" 10 | 11 | @implementation AuthorityView 12 | 13 | -(instancetype)initWithFrame:(CGRect)frame{ 14 | if (self=[super initWithFrame:frame]) { 15 | 16 | [self createUI]; 17 | } 18 | return self; 19 | } 20 | -(void)createUI{ 21 | 22 | _titleLabel =[[UILabel alloc]init]; 23 | [self addSubview:_titleLabel]; 24 | _titleLabel.font =[UIFont systemFontOfSize:17]; 25 | _titleLabel.textColor =[UIColor blackColor]; 26 | _titleLabel.text =@"请先去设置中打开相册访问权限"; 27 | _titleLabel.backgroundColor =[UIColor clearColor]; 28 | _titleLabel.sd_layout.topSpaceToView(self,5).heightIs(25).centerXEqualToView(self).autoHeightRatio(0); 29 | [_titleLabel setSingleLineAutoResizeWithMaxWidth:[UIScreen mainScreen].bounds.size.width]; 30 | 31 | 32 | _setupBtn=[UIButton buttonWithType:UIButtonTypeSystem]; 33 | [_setupBtn addTarget:self action:@selector(setupClick) forControlEvents:UIControlEventTouchUpInside]; 34 | [self addSubview:_setupBtn]; 35 | [_setupBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; 36 | [_setupBtn setTitle:@"去设置" forState:UIControlStateNormal]; 37 | _setupBtn.titleLabel.font =[UIFont systemFontOfSize:17]; 38 | _setupBtn.sd_layout.topSpaceToView(_titleLabel,10).heightIs(30).centerXEqualToView(self); 39 | [_setupBtn setupAutoSizeWithHorizontalPadding:10 buttonHeight:30]; 40 | 41 | } 42 | -(void)setupClick{ 43 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; 44 | } 45 | @end 46 | -------------------------------------------------------------------------------- /SDPickerController/Views/BottomToolBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // BottomToolBar.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/16. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "UIView+SD.h" 11 | #import "SDImagePicker.h" 12 | typedef void (^ToolBarBtnBlock)(UIButton * Btn); 13 | @interface BottomToolBar : UIView 14 | 15 | @property(nonatomic,copy)NSString *titlePhoto; 16 | 17 | @property(nonatomic,copy)ToolBarBtnBlock toolBarBtnBlock; 18 | @property(nonatomic,strong)UIButton *doneBtn; 19 | @property(nonatomic,strong)UILabel *numberLable; 20 | @property(nonatomic,strong)UIImageView *numberView; 21 | @property(nonatomic,strong)UIButton *photoAlbumBtn; 22 | 23 | @property(nonatomic)BOOL pickerVCToolBar; 24 | 25 | 26 | @property(nonatomic,assign)BOOL oneSelect; 27 | /** 28 | 刷新ToolBar 状态 29 | */ 30 | -(void)refreshToolBarStatus:(NSInteger)selectedCount; 31 | @end 32 | -------------------------------------------------------------------------------- /SDPickerController/Views/BottomToolBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // BottomToolBar.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/16. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "BottomToolBar.h" 10 | #import "SDAutoLayout.h" 11 | #import "UIImage+SD.h" 12 | @interface BottomToolBar () 13 | 14 | 15 | @end 16 | @implementation BottomToolBar 17 | 18 | 19 | 20 | -(instancetype)initWithFrame:(CGRect)frame{ 21 | if (self =[super initWithFrame:frame]) { 22 | self.backgroundColor =UIColorFromRGB(0x141414); 23 | [self createUI]; 24 | 25 | } 26 | return self; 27 | } 28 | 29 | 30 | 31 | -(void)createUI{ 32 | 33 | UIButton *backBtn =[UIButton buttonWithType:UIButtonTypeCustom]; 34 | 35 | backBtn.tag = 200; 36 | backBtn.backgroundColor =[UIColor clearColor]; 37 | backBtn.titleLabel.font =[UIFont systemFontOfSize:18]; 38 | backBtn.frame = CGRectMake(0, 0, 70, self.height); 39 | [backBtn setTitle:@"返回" forState:UIControlStateNormal]; 40 | backBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; 41 | backBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0); 42 | [backBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 43 | [backBtn addTarget:self action:@selector(backBtn:) forControlEvents:UIControlEventTouchUpInside]; 44 | [self addSubview:backBtn]; 45 | 46 | 47 | _photoAlbumBtn =[UIButton buttonWithType:UIButtonTypeCustom]; 48 | _photoAlbumBtn.tag = 201; 49 | [self addSubview:_photoAlbumBtn]; 50 | _photoAlbumBtn.backgroundColor =[UIColor clearColor]; 51 | _photoAlbumBtn.titleLabel.font =[UIFont systemFontOfSize:18]; 52 | [_photoAlbumBtn setTitle:@"相机胶卷" forState:UIControlStateNormal]; 53 | _photoAlbumBtn.size = CGSizeMake(120, self.height); 54 | _photoAlbumBtn.centerX=self.centerX; 55 | #define albumBtnWidth 110 56 | #define imageWidth 14 57 | NSString *str=@"相机胶卷"; 58 | CGSize btnSize = [str sizeWithAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:18]}]; 59 | //icon_photos_arrowbottom 60 | // [_photoAlbumBtn setImage:[UIImage SD_imageNamed:@"icon_photos_arrowup"] forState:UIControlStateNormal]; 61 | _photoAlbumBtn.imageEdgeInsets = UIEdgeInsetsMake(0, albumBtnWidth-imageWidth-5, 0, 10 - btnSize.width); 62 | CGFloat titleRightInset = albumBtnWidth - 10 - btnSize.width; 63 | if (titleRightInset < 10 + imageWidth) { 64 | titleRightInset = 10 + imageWidth; 65 | } 66 | [_photoAlbumBtn setTitleEdgeInsets:UIEdgeInsetsMake(0, (10 - 14), 0, titleRightInset)]; 67 | [_photoAlbumBtn addTarget:self action:@selector(photoAlbumBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 68 | 69 | _doneBtn =[UIButton buttonWithType:UIButtonTypeCustom]; 70 | _doneBtn.tag = 202; 71 | _doneBtn.backgroundColor =[UIColor clearColor]; 72 | _doneBtn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; 73 | _doneBtn.titleEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 10); 74 | _doneBtn.frame = CGRectMake(WIDTH - 70, 0, 70, self.height); 75 | [self addSubview:_doneBtn]; 76 | _doneBtn.titleLabel.font =[UIFont systemFontOfSize:18]; 77 | [_doneBtn setTitle:@"完成" forState:UIControlStateNormal]; 78 | [_doneBtn addTarget:self action:@selector(doneClick:) forControlEvents:UIControlEventTouchUpInside]; 79 | 80 | 81 | _numberView =[UIImageView new]; 82 | [self addSubview:_numberView]; 83 | _numberView.backgroundColor =[UIColor clearColor]; 84 | _numberView.frame = CGRectMake([UIScreen mainScreen].bounds.size.width - 80,10, 30, 30); 85 | _numberView.centerY = _doneBtn.centerY; 86 | _numberView.image =[UIImage SD_imageNamed:@"photo_number_icon"]; 87 | 88 | _numberLable =[UILabel new]; 89 | [self addSubview:_numberLable]; 90 | _numberLable.frame =_numberView.frame; 91 | _numberLable.backgroundColor =[UIColor clearColor]; 92 | //_numberLable.text = @"1"; 93 | _numberLable.textColor =[UIColor whiteColor]; 94 | _numberLable.backgroundColor =[UIColor clearColor]; 95 | _numberLable.textAlignment = NSTextAlignmentCenter; 96 | _numberLable.font =[UIFont systemFontOfSize:15]; 97 | 98 | 99 | 100 | } 101 | -(void)setPickerVCToolBar:(BOOL)pickerVCToolBar{ 102 | _pickerVCToolBar = pickerVCToolBar; 103 | if (pickerVCToolBar) { 104 | [_photoAlbumBtn setImage:[UIImage SD_imageNamed:@"icon_photos_arrowup"] forState:UIControlStateNormal]; 105 | }else{ 106 | [_photoAlbumBtn setImage:[UIImage SD_imageNamed:@"icon_photos_arrowbottom"] forState:UIControlStateNormal]; 107 | _pickerVCToolBar=!_pickerVCToolBar; 108 | } 109 | } 110 | 111 | -(void)setOneSelect:(BOOL)oneSelect{ 112 | _oneSelect=oneSelect; 113 | if (_oneSelect) { 114 | _doneBtn.hidden = YES; 115 | _numberView.hidden =YES; 116 | _numberLable.hidden = YES; 117 | }else{ 118 | _doneBtn.hidden = NO; 119 | _numberView.hidden =NO; 120 | _numberLable.hidden = NO; 121 | } 122 | } 123 | 124 | -(void)doneClick:(UIButton *)btn{ 125 | if (_toolBarBtnBlock) { 126 | _toolBarBtnBlock(btn); 127 | } 128 | } 129 | 130 | -(void)photoAlbumBtnClick:(UIButton *)btn{ 131 | 132 | 133 | 134 | [UIView animateWithDuration:0.25 animations:^{ 135 | 136 | btn.imageView.transform = _pickerVCToolBar?CGAffineTransformMakeRotation(M_PI):CGAffineTransformMakeRotation(0); 137 | }]; 138 | _pickerVCToolBar=!_pickerVCToolBar; 139 | if (_toolBarBtnBlock) { 140 | _toolBarBtnBlock(btn); 141 | } 142 | } 143 | 144 | -(void)backBtn:(UIButton *)btn{ 145 | if (_toolBarBtnBlock) { 146 | _toolBarBtnBlock(btn); 147 | } 148 | } 149 | 150 | -(void)refreshToolBarStatus:(NSInteger)selectedCount{ 151 | 152 | if (_oneSelect) { 153 | return; 154 | } 155 | _doneBtn.enabled = selectedCount>0; 156 | _numberView.hidden=selectedCount<=0; 157 | _numberLable.hidden =selectedCount<=0; 158 | _numberLable.text = [NSString stringWithFormat:@"%zd",selectedCount]; 159 | [UIView showOscillatoryAnimationWithLayer:_numberView.layer type:SDAnimationToBigger]; 160 | } 161 | 162 | 163 | @end 164 | -------------------------------------------------------------------------------- /SDPickerController/Views/NavAlbumCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // NavAlbumCell.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/28. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SDImagePicker.h" 11 | @interface NavAlbumCell : UITableViewCell 12 | @property (nonatomic, strong) SDAlbumModel *model; 13 | @end 14 | -------------------------------------------------------------------------------- /SDPickerController/Views/NavAlbumCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // NavAlbumCell.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/28. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "NavAlbumCell.h" 10 | #import "SDImagePicker.h" 11 | @interface NavAlbumCell () 12 | 13 | @property(nonatomic,strong)UIImageView *albumImageView; 14 | 15 | @property(nonatomic,strong)UILabel *titleLabel; 16 | 17 | 18 | @end 19 | 20 | @implementation NavAlbumCell 21 | 22 | -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ 23 | if (self =[super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 24 | 25 | self.backgroundColor =UIColorFromRGB(0x353338); 26 | [self createUI]; 27 | 28 | } 29 | return self; 30 | } 31 | 32 | -(void)createUI{ 33 | 34 | CGFloat albumWH = 64 - 8; 35 | _albumImageView =[[UIImageView alloc]initWithFrame:CGRectMake(5, 64 -albumWH -4 , albumWH, albumWH)]; 36 | [self.contentView addSubview:_albumImageView]; 37 | 38 | _titleLabel =[[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(_albumImageView.frame)+22, 0, 200, 20)]; 39 | _titleLabel.centerY =_albumImageView.centerY; 40 | _titleLabel.textColor =[UIColor whiteColor]; 41 | _titleLabel.font =[UIFont systemFontOfSize:13]; 42 | [self.contentView addSubview:_titleLabel]; 43 | _albumImageView.contentMode =UIViewContentModeScaleAspectFill; 44 | _albumImageView.clipsToBounds = YES; 45 | 46 | UIView *lineView=[[UIView alloc] initWithFrame:CGRectMake(0, 63, WIDTH, 1)]; 47 | lineView.backgroundColor =UIColorFromRGB(0x3A383D); 48 | [self.contentView addSubview:lineView]; 49 | 50 | } 51 | 52 | -(void)setModel:(SDAlbumModel *)model{ 53 | [[SDImageManager manager] getPostImageWithAlbumModel:model completion:^(UIImage *postImage) { 54 | _albumImageView.image =postImage; 55 | }]; 56 | _titleLabel.text = [NSString stringWithFormat:@"%@ (%zd)",model.name,model.count]; 57 | } 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /SDPickerController/Views/NavigationAlbumView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationAlbumView.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/28. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SDAssetModel.h" 11 | typedef void(^NavCollectionaViewBlock)(SDAlbumModel *model); 12 | @interface NavigationAlbumView : UIView 13 | 14 | @property(nonatomic,copy)NavCollectionaViewBlock navCollectionaViewBlock; 15 | 16 | @property(nonatomic,strong)NSMutableArray *albumData; 17 | 18 | 19 | -(void)showPhotoAlbum; 20 | 21 | -(void)dismiss; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /SDPickerController/Views/NavigationAlbumView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationAlbumView.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/28. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | #import "NavigationAlbumView.h" 10 | #import "NavAlbumCell.h" 11 | #import "SDImagePicker.h" 12 | @interface NavigationAlbumView (){ 13 | CGFloat _selfWIDTH; 14 | } 15 | 16 | @property(nonatomic,strong)UITableView *tableView; 17 | 18 | @end 19 | 20 | @implementation NavigationAlbumView 21 | 22 | -(instancetype)initWithFrame:(CGRect)frame{ 23 | if (self =[super initWithFrame:frame]) { 24 | 25 | self.backgroundColor =[UIColor orangeColor]; 26 | [self createUI]; 27 | } 28 | return self; 29 | } 30 | 31 | -(void)createUI{ 32 | 33 | _tableView =[[UITableView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, 0) style:UITableViewStylePlain]; 34 | _tableView.delegate =self; 35 | _tableView.dataSource =self; 36 | _tableView.separatorStyle = NO; 37 | _tableView.rowHeight = 64; 38 | [_tableView registerClass:[NavAlbumCell class] forCellReuseIdentifier:@"NavAlbumCell"]; 39 | _tableView.backgroundColor =UIColorFromRGB(0x353338); 40 | [self addSubview:_tableView]; 41 | 42 | 43 | } 44 | 45 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 46 | return _albumData.count; 47 | } 48 | 49 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 50 | 51 | NavAlbumCell *cell =[tableView dequeueReusableCellWithIdentifier:@"NavAlbumCell" forIndexPath:indexPath]; 52 | cell.model = _albumData [indexPath.row]; 53 | return cell; 54 | } 55 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 56 | 57 | [self dismiss]; 58 | if (_navCollectionaViewBlock) { 59 | _navCollectionaViewBlock(_albumData[indexPath.row]); 60 | } 61 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 62 | 63 | } 64 | 65 | -(void)setAlbumData:(NSMutableArray *)albumData{ 66 | _albumData = albumData; 67 | _selfWIDTH = albumData.count *64; 68 | if (_selfWIDTH>HEIGHT-44) { 69 | _selfWIDTH =HEIGHT-74; 70 | } 71 | 72 | } 73 | 74 | -(void)showPhotoAlbum{ 75 | 76 | [UIView animateWithDuration:0.3 animations:^{ 77 | self.frame =CGRectMake(0, 44, WIDTH, _selfWIDTH); 78 | _tableView.height =_selfWIDTH; 79 | }]; 80 | } 81 | 82 | -(void)dismiss{ 83 | [UIView animateWithDuration:0.3 animations:^{ 84 | self.frame =CGRectMake(0, 0, WIDTH, 0); 85 | _tableView.height = 0; 86 | }]; 87 | } 88 | 89 | @end 90 | -------------------------------------------------------------------------------- /SDPickerController/Views/PhotoAlbumView.h: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoAlbumView.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/18. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SDAssetModel.h" 11 | typedef void(^ReloadCollectionaViewBlock)(SDAlbumModel *model); 12 | @interface PhotoAlbumView : UIView 13 | 14 | 15 | @property(nonatomic,strong)NSMutableArray *albumData; 16 | 17 | @property(nonatomic,copy)ReloadCollectionaViewBlock reloadCollectionaViewBlock; 18 | 19 | -(void)showPhotoAlbum:(UIView *)view; 20 | 21 | -(void)dismiss; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /SDPickerController/Views/PhotoAlbumView.m: -------------------------------------------------------------------------------- 1 | // 2 | // PhotoAlbumView.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/18. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "PhotoAlbumView.h" 10 | #import "SDAssetCell.h" 11 | #import "UIView+SD.h" 12 | #import "UIImage+SD.h" 13 | @interface PhotoAlbumView () 14 | 15 | @property(nonatomic,strong)UIVisualEffectView *effectview; 16 | 17 | @property(nonatomic,assign)CGRect layerFrame; 18 | 19 | @property(nonatomic,strong)UITableView *tableView; 20 | @property(nonatomic,strong)UIImageView *angleImageView; 21 | @end 22 | 23 | @implementation PhotoAlbumView 24 | 25 | 26 | -(instancetype)initWithFrame:(CGRect)frame{ 27 | if (self=[super initWithFrame:frame]) { 28 | 29 | _layerFrame = frame; 30 | self.backgroundColor =[UIColor clearColor]; 31 | 32 | self.layer.cornerRadius=25.f; 33 | self.layer.masksToBounds=YES; 34 | [self createUI]; 35 | } 36 | return self; 37 | } 38 | 39 | 40 | -(void)createUI{ 41 | _angleImageView.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 55/2.f, [UIScreen mainScreen].bounds.size.height-50, 55, 29); 42 | _angleImageView =[UIImageView new]; 43 | _angleImageView.image =[UIImage SD_imageNamed:@"Angle_"]; 44 | self.alpha =0.f; 45 | _tableView =[[UITableView alloc]initWithFrame:self.layer.bounds style:UITableViewStylePlain]; 46 | _tableView.delegate =self; 47 | _tableView.dataSource = self; 48 | _tableView.rowHeight =45; 49 | [_tableView registerClass:[SDAlbumCell class] forCellReuseIdentifier:@"SDAlbumCell"]; 50 | _tableView.separatorStyle = NO; 51 | [self addSubview:_tableView]; 52 | 53 | } 54 | 55 | #pragma mark ---tableView delegae 56 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 57 | return _albumData.count; 58 | } 59 | 60 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 61 | 62 | SDAlbumCell *cell=[tableView dequeueReusableCellWithIdentifier:@"SDAlbumCell" forIndexPath:indexPath]; 63 | if (indexPath.row==_albumData.count-1) { 64 | cell.lineView.hidden =YES; 65 | } 66 | 67 | cell.model =_albumData[indexPath.row]; 68 | return cell; 69 | } 70 | 71 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 72 | 73 | [self dismiss]; 74 | if (self.reloadCollectionaViewBlock) { 75 | self.reloadCollectionaViewBlock(_albumData[indexPath.row]); 76 | } 77 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 78 | } 79 | 80 | 81 | 82 | -(void)setAlbumData:(NSMutableArray *)albumData{ 83 | _albumData =albumData; 84 | //此处修改frame 85 | _layerFrame = CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 250/2.f, [UIScreen mainScreen].bounds.size.height -68 -45*_albumData.count, 250, 45*_albumData.count); 86 | _tableView.height = 45*_albumData.count; 87 | } 88 | -(void)effectviewClick{ 89 | [self dismiss]; 90 | } 91 | 92 | 93 | -(void)showPhotoAlbum:(UIView *)view{ 94 | NSLog(@"显示显示"); 95 | UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; 96 | _effectview = [[UIVisualEffectView alloc] initWithEffect:blur]; 97 | _effectview.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height-50); 98 | _effectview.userInteractionEnabled= YES; 99 | UITapGestureRecognizer *tap =[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(effectviewClick)]; 100 | tap.numberOfTapsRequired = 1; 101 | tap.numberOfTouchesRequired = 1; 102 | [_effectview addGestureRecognizer:tap]; 103 | 104 | 105 | 106 | 107 | [view insertSubview:_effectview atIndex:0]; 108 | [view bringSubviewToFront:_effectview]; 109 | [view bringSubviewToFront:self]; 110 | _effectview.alpha =1.f; 111 | self.alpha =1.f; 112 | [self.layer setValue:@(0.1) forKeyPath:@"transform.scale"]; 113 | [view addSubview:self]; 114 | [view addSubview:_angleImageView]; 115 | self.layer.frame= CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 250/2.f, [UIScreen mainScreen].bounds.size.height -68 -45*_albumData.count+70, 250, 45*_albumData.count); 116 | [UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 117 | _effectview.alpha =1; 118 | self.alpha =1.f; 119 | 120 | self.layer.anchorPoint=CGPointMake(0.5, 0.9); 121 | [self.layer setValue:@(1.08) forKeyPath:@"transform.scale"]; 122 | #pragma mark ---设置弹出View frame 123 | _angleImageView.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 55/2.f, [UIScreen mainScreen].bounds.size.height -68, 55, 29); 124 | self.layer.frame=_layerFrame; 125 | _angleImageView.alpha =1.f; 126 | 127 | } completion:^(BOOL finished) { 128 | [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ 129 | [self.layer setValue:@(1.0) forKeyPath:@"transform.scale"]; 130 | } completion:^(BOOL finished) { 131 | 132 | }]; 133 | }]; 134 | 135 | } 136 | 137 | -(void)dismiss{ 138 | NSLog(@"dismissssss"); 139 | _angleImageView.alpha =0; 140 | self.layer.frame= CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 250/2.f, [UIScreen mainScreen].bounds.size.height -68 -45*_albumData.count+70, 250, 45*_albumData.count); 141 | _angleImageView.frame = CGRectMake([UIScreen mainScreen].bounds.size.width/2.f - 55/2.f, [UIScreen mainScreen].bounds.size.height-30, 55, 29); 142 | self.alpha =0.f; 143 | [UIView animateWithDuration:0.5*0.618 animations:^{ 144 | 145 | _effectview.alpha =0; 146 | 147 | [self.layer setValue:@(0.1) forKeyPath:@"transform.scale"]; 148 | 149 | } completion:^(BOOL finished) { 150 | 151 | 152 | }]; 153 | } 154 | 155 | 156 | 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /SDPickerController/Views/SDAssetCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDAssetCell.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/14. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "SDAssetModel.h" 12 | #import "SDImageManager.h" 13 | #import "UIView+SD.h" 14 | #import "SDAutoLayout.h" 15 | #import "SDImagePicker.h" 16 | typedef enum : NSUInteger { 17 | SDAssetCellTypePhoto = 0, 18 | SDAssetCellTypeLivePhoto, 19 | SDAssetCellTypeVideo, 20 | SDAssetCellTypeAudio, 21 | } SDAssetCellType; 22 | 23 | @interface SDAssetCell : UICollectionViewCell 24 | 25 | @property (nonatomic,strong) UIButton *selectBtn; 26 | @property (nonatomic, strong) SDAssetModel *model; 27 | @property(nonatomic,copy)void (^selectBtnBlock)(BOOL); 28 | @property(nonatomic,assign)SDAssetCellType type; 29 | @property (nonatomic, copy) NSString *representedAssetIdentifier; 30 | @property (nonatomic, assign) PHImageRequestID imageRequestID; 31 | 32 | @property (nonatomic, copy) NSString *photoSelImageName; 33 | @property (nonatomic, copy) NSString *photoDefImageName; 34 | 35 | @property (nonatomic, assign) NSInteger maxImagesCount; 36 | 37 | /** 38 | 是否游览选择 39 | */ 40 | @property(nonatomic)BOOL photoBrowseSelect; 41 | 42 | /** 43 | 单选模式 44 | */ 45 | @property(nonatomic,assign)BOOL oneSelect; 46 | 47 | @end 48 | 49 | 50 | 51 | 52 | 53 | 54 | //相机cell 55 | @interface SDAssetCameraCell : UICollectionViewCell 56 | 57 | @property (nonatomic, strong) UIImageView *cameraView; 58 | 59 | @end 60 | 61 | //相薄分组cell 62 | @interface SDAlbumCell : UITableViewCell 63 | 64 | @property (nonatomic, strong) SDAlbumModel *model; 65 | @property (nonatomic, strong) UILabel *groupTitleLabel; 66 | @property(nonatomic,strong)UILabel *numberLabel; 67 | @property(nonatomic,strong)UIView *lineView; 68 | @end 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /SDPickerController/Views/SDAssetCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDAssetCell.m 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/14. 6 | // Copyright © 2016年 张伟. All rights reserved. 7 | // 8 | 9 | #import "SDAssetCell.h" 10 | #import "UIImage+SD.h" 11 | #define iOS8Later ([UIDevice currentDevice].systemVersion.floatValue >= 8.0f) 12 | 13 | @interface SDAssetCell () 14 | 15 | @property(nonatomic,strong)UIImageView *photoImageView; 16 | @property (nonatomic,strong) UIImageView *selectImageView; 17 | @property(nonatomic,strong)UIView *bottomView; 18 | @property(nonatomic,strong)UILabel *timeLabel; 19 | @property(nonatomic,strong)UIImageView *imageView; 20 | 21 | @end 22 | 23 | @implementation SDAssetCell 24 | 25 | 26 | -(instancetype)initWithFrame:(CGRect)frame{ 27 | if (self =[super initWithFrame:frame]) { 28 | 29 | [self createUI]; 30 | self.backgroundColor =[UIColor blueColor]; 31 | } 32 | return self; 33 | } 34 | 35 | -(void)createUI{ 36 | 37 | _bottomView = [[UIView alloc]initWithFrame:self.bounds]; 38 | [self.contentView addSubview:_bottomView]; 39 | 40 | _selectBtn.frame = CGRectMake(self.frame.size.width-44, 0, 44, 44); 41 | _selectBtn =[[UIButton alloc]init]; 42 | 43 | 44 | [_selectBtn addTarget:self action:@selector(selectBtnClick:) forControlEvents:UIControlEventTouchUpInside]; 45 | [self.contentView addSubview:_selectBtn]; 46 | 47 | _selectImageView =[[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width -27, 0, 27, 27)]; 48 | [self.contentView addSubview:_selectImageView]; 49 | 50 | _timeLabel = [[UILabel alloc]initWithFrame:CGRectMake(_imageView.frame.origin.x + _imageView.frame.size.width, 0, 60, 17)]; //改下布局 51 | _timeLabel.font =[UIFont boldSystemFontOfSize:11]; 52 | _timeLabel.textColor =[UIColor whiteColor]; 53 | _timeLabel.textAlignment = NSTextAlignmentRight; 54 | [self.bottomView addSubview:_timeLabel]; 55 | 56 | _imageView =[[UIImageView alloc]initWithFrame:self.bounds]; 57 | _imageView.contentMode =UIViewContentModeScaleAspectFill; 58 | _imageView.clipsToBounds = YES; 59 | [self.contentView addSubview:_imageView]; 60 | [self.contentView bringSubviewToFront:_selectImageView]; 61 | [self.contentView bringSubviewToFront:_selectBtn]; 62 | [self.contentView bringSubviewToFront:_bottomView]; 63 | } 64 | 65 | 66 | 67 | -(void)setModel:(SDAssetModel *)model{ 68 | _model= model; 69 | if (_photoBrowseSelect) { 70 | _selectBtn.frame = CGRectMake(self.frame.size.width-44, 0, 44, 44); 71 | }else{ 72 | _selectBtn.frame= self.bounds; 73 | } 74 | 75 | 76 | 77 | if (iOS8Later) { 78 | self.representedAssetIdentifier =[[SDImageManager manager] getAssetIdentifier:model.asset]; 79 | } 80 | 81 | PHImageRequestID imageRequestID=[[SDImageManager manager] getPhotoWithAsset:model.asset photoWidth:self.frame.size.width completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) { 82 | 83 | if (!iOS8Later) { 84 | self.imageView.image = photo; return; 85 | } 86 | 87 | if ([self.representedAssetIdentifier isEqualToString:[[SDImageManager manager] getAssetIdentifier:model.asset]]) { 88 | self.imageView.image = photo; 89 | } else { 90 | // NSLog(@"this cell is showing other asset"); 91 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; 92 | } 93 | 94 | if (!isDegraded) { 95 | self.imageRequestID = 0; 96 | } 97 | 98 | }]; 99 | 100 | if (imageRequestID && self.imageRequestID && imageRequestID != self.imageRequestID) { 101 | [[PHImageManager defaultManager] cancelImageRequest:self.imageRequestID]; 102 | } 103 | self.imageRequestID = imageRequestID; 104 | self.selectBtn.selected = model.isSelected; 105 | self.selectImageView.image =self.selectBtn.isSelected?[UIImage SD_imageNamed:@"photo_sel_photoPickerVc.png"]:[UIImage SD_imageNamed:@"photo_def_photoPickerVc.png"]; 106 | self.type = SDAssetCellTypePhoto; 107 | if (model.type == SDAssetModelTypePhoto){ 108 | self.type = SDAssetCellTypeLivePhoto; 109 | }else if (model.type == SDAssetModelTypeAudio){ 110 | self.type = SDAssetCellTypeAudio; 111 | }else if (model.type == SDAssetModelTypeVideo){ 112 | self.type = SDAssetCellTypeVideo; 113 | } 114 | 115 | if (![[SDImageManager manager] isPhotoSelectableWithAsset:model.asset]) { 116 | if (_selectImageView.hidden == NO) { 117 | _selectImageView.hidden = YES; 118 | } 119 | } 120 | 121 | if (_oneSelect) { 122 | _selectImageView.hidden = YES; 123 | _selectBtn.hidden = YES; 124 | }else{ 125 | _selectImageView.hidden = NO; 126 | _selectBtn.hidden = NO; 127 | } 128 | 129 | } 130 | 131 | -(void)setMaxImagesCount:(NSInteger)maxImagesCount{ 132 | _maxImagesCount = maxImagesCount; 133 | if (self.selectBtn.hidden) { 134 | self.selectBtn.hidden = maxImagesCount= 1; 135 | } 136 | if (!self.selectImageView.hidden) { 137 | self.selectImageView.hidden = maxImagesCount =1; 138 | } 139 | } 140 | 141 | -(void)setType:(SDAssetCellType)type{ 142 | _type = type; 143 | if (type == SDAssetCellTypePhoto ||type == SDAssetCellTypeLivePhoto) { 144 | _selectImageView.hidden =NO; 145 | _selectBtn.hidden = NO; 146 | _bottomView.hidden = YES; 147 | }else{ 148 | _selectImageView.hidden =YES; 149 | _selectBtn.hidden = YES; 150 | _bottomView.hidden = NO; 151 | } 152 | } 153 | -(void)selectBtnClick:(UIButton *)btn{ 154 | 155 | if (self.selectBtnBlock) { 156 | self.selectBtnBlock(btn.isSelected); 157 | } 158 | self.selectImageView.image =btn.isSelected?[UIImage SD_imageNamed:@"photo_sel_photoPickerVc.png"]:[UIImage SD_imageNamed:@"photo_def_photoPickerVc.png"]; 159 | if (btn.isSelected) { 160 | [UIView showOscillatoryAnimationWithLayer:_selectImageView.layer type:SDAnimationToBigger]; 161 | } 162 | } 163 | 164 | @end 165 | 166 | 167 | 168 | //相机cell 169 | @implementation SDAssetCameraCell 170 | 171 | - (instancetype)initWithFrame:(CGRect)frame { 172 | self = [super initWithFrame:frame]; 173 | if (self) { 174 | self.backgroundColor = [UIColor whiteColor]; 175 | _cameraView = [[UIImageView alloc] init]; 176 | _cameraView.backgroundColor = [UIColor colorWithWhite:1.000 alpha:0.500]; 177 | _cameraView.contentMode = UIViewContentModeScaleAspectFill; 178 | //_cameraView.image =[UIImage imageNamed:@"camera.png"]; 179 | [self addSubview:_cameraView]; 180 | 181 | self.clipsToBounds = YES; 182 | } 183 | return self; 184 | } 185 | 186 | - (void)layoutSubviews { 187 | [super layoutSubviews]; 188 | _cameraView.frame = self.bounds; 189 | } 190 | @end 191 | 192 | @implementation SDAlbumCell 193 | 194 | 195 | -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ 196 | if (self =[super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 197 | 198 | [self createUI]; 199 | 200 | } 201 | return self; 202 | } 203 | 204 | 205 | -(void)setModel:(SDAlbumModel *)model{ 206 | 207 | _model = model; 208 | 209 | 210 | 211 | _groupTitleLabel.text=model.name; 212 | _numberLabel.text =[NSString stringWithFormat:@"%zd",model.count]; 213 | //此方法可获取封面图 214 | 215 | } 216 | 217 | -(void)createUI{ 218 | 219 | _groupTitleLabel =[UILabel new]; 220 | [self addSubview:_groupTitleLabel]; 221 | _groupTitleLabel.textColor=UIColorFromRGB(0x262626); 222 | _groupTitleLabel.font =[UIFont systemFontOfSize:17]; 223 | _groupTitleLabel.sd_layout.leftSpaceToView(self,24).centerYEqualToView(self).autoHeightRatio(0); 224 | [_groupTitleLabel setSingleLineAutoResizeWithMaxWidth:150]; 225 | 226 | 227 | _numberLabel=[UILabel new]; 228 | [self addSubview:_numberLabel]; 229 | _numberLabel.font =[UIFont systemFontOfSize:16]; 230 | _numberLabel.textColor =UIColorFromRGB(0xadadad); 231 | _numberLabel.sd_layout.rightSpaceToView(self,24).centerYEqualToView(self).autoHeightRatio(0); 232 | [_numberLabel setSingleLineAutoResizeWithMaxWidth:50]; 233 | 234 | _lineView =[UIView new]; 235 | [self addSubview:_lineView]; 236 | _lineView.sd_layout.rightSpaceToView(self,0).leftSpaceToView(self,0).bottomSpaceToView(self,0).heightIs(1); 237 | _lineView.backgroundColor =UIColorFromRGB(0xeeeeee); 238 | 239 | } 240 | 241 | @end 242 | -------------------------------------------------------------------------------- /SDPickerController/Views/SDPickerVCType.h: -------------------------------------------------------------------------------- 1 | // 2 | // SDPickerVCType.h 3 | // SDImagePickerController 4 | // 5 | // Created by 张伟 on 16/11/28. 6 | // Copyright © 2016年 mac. All rights reserved. 7 | // 8 | 9 | typedef enum : NSUInteger { 10 | SDPickerVCToolBar, 11 | SDPickerVCNav, 12 | 13 | } SDPickerVCUI; 14 | --------------------------------------------------------------------------------