├── SuPhotoPickerDemo ├── img_add@2x.png ├── SuPhotoPicker │ ├── Resource │ │ ├── SuBack@2x.png │ │ ├── SuBack@3x.png │ │ ├── SuPhoto_circle@2x.png │ │ ├── SuPhoto_selected@2x.png │ │ └── SuPhoto_unselected@2x.png │ ├── Category │ │ ├── NSString+SU.h │ │ ├── UIImage+SU.h │ │ ├── UIView+SuLine.h │ │ ├── UIView+SU.h │ │ ├── UIImage+SU.m │ │ ├── UIView+SuAnimation.h │ │ ├── UIButton+SU.h │ │ ├── NSString+SU.m │ │ ├── UIView+SuLine.m │ │ ├── UIView+SU.m │ │ ├── UIButton+SU.m │ │ └── UIView+SuAnimation.m │ ├── Tool │ │ ├── SuMessageTool.h │ │ ├── SuPhotoManager.h │ │ ├── SuPhotoCenter.h │ │ ├── SuMessageTool.m │ │ ├── SuPhotoCenter.m │ │ └── SuPhotoManager.m │ ├── Controller │ │ ├── SuPhotoBaseController.h │ │ ├── SuPhotoAblumList.h │ │ ├── SuPhotoBrowser.h │ │ ├── SuPhotoPreviewer.h │ │ ├── SuPhotoBaseController.m │ │ ├── SuPhotoAblumList.m │ │ ├── SuPhotoHeader.h │ │ ├── SuPhotoBrowser.m │ │ ├── SuPhotoPreviewer.m │ │ ├── SuPhotoPreviewer.xib │ │ └── SuPhotoBrowser.xib │ ├── View │ │ ├── SuPhotoBrowserCell.h │ │ ├── SuPhotoBrowserCell.m │ │ ├── SuPhotoAblumCell.h │ │ ├── SuPhotoAblumCell.m │ │ ├── SuPhotoBrowserCell.xib │ │ └── SuPhotoAblumCell.xib │ ├── Model │ │ ├── SuAblumInfo.m │ │ └── SuAblumInfo.h │ ├── SuPhotoPicker.h │ └── SuPhotoPicker.m ├── ViewController.h ├── AppDelegate.h ├── main.m ├── ViewController.m ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard └── AppDelegate.m ├── SuPhotoPickerDemo.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── project.pbxproj ├── SuPhotoPicker.podspec ├── LICENSE ├── .gitignore └── README.md /SuPhotoPickerDemo/img_add@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaMingShen/SuPhotoPicker/HEAD/SuPhotoPickerDemo/img_add@2x.png -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Resource/SuBack@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaMingShen/SuPhotoPicker/HEAD/SuPhotoPickerDemo/SuPhotoPicker/Resource/SuBack@2x.png -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Resource/SuBack@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaMingShen/SuPhotoPicker/HEAD/SuPhotoPickerDemo/SuPhotoPicker/Resource/SuBack@3x.png -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Resource/SuPhoto_circle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaMingShen/SuPhotoPicker/HEAD/SuPhotoPickerDemo/SuPhotoPicker/Resource/SuPhoto_circle@2x.png -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Resource/SuPhoto_selected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaMingShen/SuPhotoPicker/HEAD/SuPhotoPickerDemo/SuPhotoPicker/Resource/SuPhoto_selected@2x.png -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Resource/SuPhoto_unselected@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaMingShen/SuPhotoPicker/HEAD/SuPhotoPickerDemo/SuPhotoPicker/Resource/SuPhoto_unselected@2x.png -------------------------------------------------------------------------------- /SuPhotoPickerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/NSString+SU.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+SuAblum.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/7. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (SU) 12 | 13 | - (NSString *)chineseName; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. 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 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIImage+SU.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+SU.h 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by 万众科技 on 16/5/3. 6 | // Copyright © 2016年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (SU) 12 | 13 | //对图片尺寸进行压缩 14 | + (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Tool/SuMessageTool.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuMessageTool.h 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/23. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SuMessageTool : NSObject 12 | 13 | /* 14 | * 显示提示信息 15 | */ 16 | - (void)ToastMessage:(NSString *)message; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIView+SuLine.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SuLine.h 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (SuLine) 12 | 13 | /* 14 | * 寻找1像素的线(可以用来隐藏导航栏下面的黑线) 15 | */ 16 | - (UIImageView *)findHairlineImageViewUnder; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. 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 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoBaseController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuBaseViewController.h 3 | // NewsReader 4 | // 5 | // Created by KevinSu on 15/10/15. 6 | // Copyright (c) 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SuPhotoBaseController : UIViewController 12 | 13 | /* 14 | * 设置标题 15 | */ 16 | - (void)setNavigationTitle:(NSString *)title; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoAblumList.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoBrowser.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoBaseController.h" 10 | #import "SuPhotoBrowser.h" 11 | 12 | @interface SuPhotoAblumList : SuPhotoBaseController 13 | 14 | @property (nonatomic, strong) NSArray * assetCollections; //相册列表 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoBrowser.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoBrowser.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoBaseController.h" 10 | 11 | @class PHAssetCollection; 12 | @interface SuPhotoBrowser : SuPhotoBaseController 13 | 14 | @property (nonatomic, copy) NSString * collectionTitle; 15 | @property (nonatomic, strong) PHAssetCollection * assetCollection; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIView+SU.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SuExt.h 3 | // SuUtility 4 | // 5 | // Created by KevinSu on 15/10/17. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (SU) 12 | 13 | /* 14 | 设置或返回View的 x y h w 15 | */ 16 | @property (nonatomic, assign) float h; 17 | @property (nonatomic, assign) float w; 18 | @property (nonatomic, assign) float x; 19 | @property (nonatomic, assign) float y; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/View/SuPhotoBrowserCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoBrowserCell.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SuPhotoBrowserCell : UICollectionViewCell 12 | 13 | @property (weak, nonatomic) IBOutlet UIButton *selBtn; 14 | @property (weak, nonatomic) IBOutlet UIImageView *imageIV; 15 | 16 | @property (nonatomic, copy) void(^selectedBlock)(BOOL isSelected); 17 | @property (nonatomic, copy) void(^imgTapBlock)(); 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/View/SuPhotoBrowserCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoBrowserCell.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoBrowserCell.h" 10 | 11 | @implementation SuPhotoBrowserCell 12 | 13 | - (IBAction)selectBtnAction:(UIButton *)sender { 14 | sender.selected = !sender.selected; 15 | if (self.selectedBlock) self.selectedBlock(sender.selected); 16 | } 17 | 18 | - (IBAction)imageTapAction:(UIButton *)sender { 19 | if (self.imgTapBlock) self.imgTapBlock(); 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/View/SuPhotoAblumCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoAblumCell.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class SuAblumInfo; 12 | @interface SuPhotoAblumCell : UITableViewCell 13 | 14 | @property (weak, nonatomic) IBOutlet UIImageView *ablumCover; 15 | @property (weak, nonatomic) IBOutlet UILabel *ablumName; 16 | @property (weak, nonatomic) IBOutlet UILabel *ablumCount; 17 | 18 | + (instancetype)cellForTableView:(UITableView *)tableView info:(SuAblumInfo *)info; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIImage+SU.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+SU.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by 万众科技 on 16/5/3. 6 | // Copyright © 2016年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "UIImage+SU.h" 10 | 11 | @implementation UIImage (SU) 12 | 13 | //对图片尺寸进行压缩 14 | + (UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize { 15 | UIGraphicsBeginImageContext(newSize); 16 | [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; 17 | UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 18 | UIGraphicsEndImageContext(); 19 | return newImage; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoPreviewer.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoPreviewPage.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/8. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoBaseController.h" 10 | 11 | @class PHAsset; 12 | @interface SuPhotoPreviewer : SuPhotoBaseController 13 | 14 | @property (nonatomic, strong) PHAsset * selectedAsset; //初始显示的图片 15 | @property (nonatomic, strong) NSArray * previewPhotos; 16 | @property (nonatomic, assign) BOOL isPreviewSelectedPhotos; 17 | @property (nonatomic, copy) void(^backBlock)(); 18 | @property (nonatomic, copy) void(^doneBlock)(); 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIView+SuAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SuAnimation.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (SuAnimation) 12 | 13 | /** 14 | * 从底部升起出现 15 | */ 16 | - (void)showFromBottom; 17 | 18 | /** 19 | * 消失降到底部 20 | */ 21 | - (void)dismissToBottomWithCompleteBlock:(void(^)())completeBlock; 22 | 23 | /** 24 | * 从透明到不透明 25 | */ 26 | - (void)emerge; 27 | 28 | /** 29 | * 从不透明到透明 30 | */ 31 | - (void)fake; 32 | 33 | /** 34 | * 按钮震动动画 35 | */ 36 | - (void)startSelectedAnimation; 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Model/SuAblumInfo.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuAblumInfo.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuAblumInfo.h" 10 | 11 | @implementation SuAblumInfo 12 | 13 | + (instancetype)infoFromResult:(PHFetchResult *)result collection:(PHAssetCollection *)collection { 14 | SuAblumInfo * ablumInfo = [[SuAblumInfo alloc]init]; 15 | ablumInfo.ablumName = collection.localizedTitle; 16 | ablumInfo.count = result.count; 17 | ablumInfo.coverAsset = result[0]; 18 | ablumInfo.assetCollection = collection; 19 | return ablumInfo; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIButton+SU.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+SuExt.h 3 | // SuUtility 4 | // 5 | // Created by KevinSu on 15/10/17. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIButton (SU) 12 | 13 | + (UIButton *)buttonWithFrame:(CGRect)frame title:(NSString *)title target:(id)target selector:(SEL)selector; 14 | 15 | + (UIButton *)buttonWithFrame:(CGRect)frame Target:(id)target Selector:(SEL)selector Image:(NSString*)image ImagePressed:(NSString *)imagePressed; 16 | 17 | + (UIButton *)buttonWithFrame:(CGRect)frame Target:(id)target Selector:(SEL)selector Image:(NSString*)image ImageSelected:(NSString *)imageSelected; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Model/SuAblumInfo.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuAblumInfo.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface SuAblumInfo : NSObject 13 | 14 | @property (nonatomic, copy) NSString * ablumName; //相册名字 15 | 16 | @property (nonatomic, assign) NSInteger count; //总照片数 17 | 18 | @property (nonatomic, strong) PHAssetCollection * assetCollection; //相册 19 | 20 | @property (nonatomic, strong) PHAsset * coverAsset; //封面 21 | 22 | + (instancetype)infoFromResult:(PHFetchResult *)result collection:(PHAssetCollection *)collection; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/NSString+SU.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+SuAblum.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/7. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "NSString+SU.h" 10 | 11 | @implementation NSString (SU) 12 | 13 | - (NSString *)chineseName { 14 | NSArray * engNameList = @[@"All Photos", @"Recently Added", @"Camera Roll", @"Videos", @"Favorites", @"Screenshots", @"Recently Deleted"]; 15 | NSArray * chineseNameList = @[@"所有照片", @"最近添加", @"相机胶卷", @"视频", @"最爱", @"屏幕快照", @"最近删除"]; 16 | if ([engNameList containsObject:self]) { 17 | NSInteger index = [engNameList indexOfObject:self]; 18 | return chineseNameList[index]; 19 | } 20 | return self; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIView+SuLine.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SuLine.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "UIView+SuLine.h" 10 | #import 11 | 12 | @implementation UIView (SuLine) 13 | 14 | - (UIImageView *)findHairlineImageViewUnder { 15 | 16 | if ([self isKindOfClass:UIImageView.class] && self.bounds.size.height <= 1.0) { 17 | return (UIImageView *)self; 18 | } 19 | 20 | for (UIView * subview in self.subviews) { 21 | UIImageView * imageView = [subview findHairlineImageViewUnder]; 22 | if (imageView) { 23 | return imageView; 24 | } 25 | } 26 | return nil; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /SuPhotoPicker.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SuPhotoPicker" 3 | s.version = "1.0.0" 4 | s.summary = “一款具有预览功能的照片选择器” 5 | s.description = <<-DESC 6 | 这是一款具有预览功能的照片选择器,Objective-C版本。 7 | DESC 8 | s.homepage = "https://github.com/DaMingShen/SuPhotoPicker" 9 | s.license = 'MIT' 10 | s.author = { “DaMingShen” => “446135517@qq.com" } 11 | s.source = { :git => "https://github.com/DaMingShen/SuPhotoPicker.git", :tag => “1.0.0” } 12 | 13 | s.platform = :ios, ‘8.0’ 14 | s.ios.deployment_target = ‘8.0’ 15 | s.osx.deployment_target = '10.7’ 16 | s.requires_arc = true 17 | 18 | s.source_files = 'SuPhotoPickerDemo/**/*’ 19 | 20 | end -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/SuPhotoPicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoPicker.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SuPhotoPicker : UIView 12 | 13 | /* 14 | * 最大选择数,默认为20 15 | */ 16 | @property (nonatomic, assign) NSInteger selectedCount; 17 | 18 | /* 19 | * 最大预览数,默认为20 20 | */ 21 | @property (nonatomic, assign) NSInteger preViewCount; 22 | 23 | /** 24 | * 弹出图片选择器 25 | * 26 | * @param sender 27 | sender:需要弹出图片选择器的VC 28 | sender:无tabbar传入当前VC 29 | sender:无tabbar且需要遮盖导航栏传入VC.navigationController 30 | sender:有tabbar需传入VC.tabbarController 31 | * 32 | * @param handle 回调(图片数组) 33 | */ 34 | - (void)showInSender:(UIViewController *)sender handle:(void(^)(NSArray * photos))handle; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIView+SU.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SuExt.m 3 | // SuUtility 4 | // 5 | // Created by KevinSu on 15/10/17. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "UIView+SU.h" 10 | 11 | @implementation UIView (SU) 12 | 13 | //h 14 | - (void)setH:(float)h { 15 | CGRect frm = self.frame; 16 | frm.size.height = h; 17 | self.frame = frm; 18 | } 19 | 20 | - (float)h { 21 | return self.frame.size.height; 22 | } 23 | 24 | //w 25 | - (void)setW:(float)w { 26 | CGRect frm = self.frame; 27 | frm.size.width = w; 28 | self.frame = frm; 29 | } 30 | 31 | - (float)w { 32 | return self.frame.size.width; 33 | } 34 | 35 | 36 | //x 37 | - (void)setX:(float)x { 38 | CGRect frm = self.frame; 39 | frm.origin.x = x; 40 | self.frame = frm; 41 | } 42 | 43 | - (float)x { 44 | return self.frame.origin.x; 45 | } 46 | 47 | //y 48 | - (void)setY:(float)y { 49 | CGRect frm = self.frame; 50 | frm.origin.y = y; 51 | self.frame = frm; 52 | } 53 | 54 | - (float)y { 55 | return self.frame.origin.y; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "SuPhotoPicker.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | 22 | } 23 | 24 | - (IBAction)choosePhoto:(id)sender { 25 | __weak typeof(self) weakSelf = self; 26 | SuPhotoPicker * picker = [[SuPhotoPicker alloc]init]; 27 | // picker.selectedCount = 12; 28 | // picker.preViewCount = 2; 29 | [picker showInSender:self handle:^(NSArray *photos) { 30 | [weakSelf showSelectedPhotos:photos]; 31 | }]; 32 | } 33 | 34 | - (void)showSelectedPhotos:(NSArray *)imgs { 35 | for (int i = 0; i < imgs.count; i ++) { 36 | UIImageView * iv = [[UIImageView alloc]initWithFrame:CGRectMake(50 * i, 200, 50, 50)]; 37 | iv.image = imgs[i]; 38 | [self.view addSubview:iv]; 39 | } 40 | } 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 KevinSu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Tool/SuPhotoManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoManager.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SuAblumInfo.h" 11 | 12 | @interface SuPhotoManager : NSObject 13 | 14 | + (instancetype)manager; 15 | 16 | /* 17 | * 获取所有相册 18 | */ 19 | - (NSArray *)getAllAblums; 20 | 21 | /* 22 | * 获取所有相册图片资源 23 | */ 24 | - (NSArray *)fetchAllAssets; 25 | 26 | /* 27 | * 获取指定相册图片资源 28 | */ 29 | - (NSArray *)fetchAssetsInCollection:(PHAssetCollection *)collection asending:(BOOL)asending; 30 | 31 | /* 32 | * 获取资源对应的图片 33 | */ 34 | - (void)fetchImageInAsset:(PHAsset *)asset size:(CGSize)size isResize:(BOOL)isResize completeBlock:(void(^)(UIImage * image, NSDictionary * info))completeBlock; 35 | 36 | /* 37 | * 获取资源对应的原图大小 38 | */ 39 | - (void)getImageDataLength:(PHAsset *)asset completeBlock:(void(^)(CGFloat length))completeBlock; 40 | 41 | /* 42 | * 获取资源数组对应的图片数组 43 | */ 44 | - (void)fetchImagesWithAssetsArray:(NSMutableArray *)assetsArray isOriginal:(BOOL)isOriginal completeBlock:(void(^)(NSArray * images))completeBlock; 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/View/SuPhotoAblumCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoAblumCell.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoAblumCell.h" 10 | #import "SuPhotoHeader.h" 11 | 12 | 13 | @implementation SuPhotoAblumCell 14 | 15 | + (instancetype)cellForTableView:(UITableView *)tableView info:(SuAblumInfo *)info { 16 | //表格列表不多,不选择重用机制 17 | SuPhotoAblumCell * cell = [[NSBundle mainBundle]loadNibNamed:@"SuPhotoAblumCell" owner:tableView options:nil][0]; 18 | [[SuPhotoManager manager]fetchImageInAsset:info.coverAsset size:CGSizeMake(120, 120) isResize:YES completeBlock:^(UIImage *image, NSDictionary *info) { 19 | 20 | cell.ablumCover.image = image; 21 | }]; 22 | cell.ablumName.text = [info.ablumName chineseName]; 23 | cell.ablumCount.text = [NSString stringWithFormat:@"(%ld)",info.count]; 24 | 25 | //line 26 | UIView * line = [[UIView alloc]initWithFrame:CGRectMake(100, 61 - SINGLE_LINE_ADJUST_OFFSET, SCREEN_W - 100, SINGLE_LINE_WIDTH)]; 27 | line.backgroundColor = AblumsListLineColor; 28 | [cell.contentView addSubview:line]; 29 | 30 | //indicator 31 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 32 | 33 | return cell; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Tool/SuPhotoCenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoCenter.h 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by 万众科技 on 16/5/3. 6 | // Copyright © 2016年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class UIImage; 12 | @interface SuPhotoCenter : NSObject 13 | 14 | /* 15 | * 最大选择数,默认为20 16 | */ 17 | @property (nonatomic, assign) NSInteger selectedCount; 18 | 19 | /* 20 | * 是否原图 21 | */ 22 | @property (nonatomic, assign) BOOL isOriginal; 23 | 24 | /** 25 | * 所有的图片 26 | */ 27 | @property (nonatomic, strong) NSArray * allPhotos; 28 | 29 | /** 30 | * 选择的图片 31 | */ 32 | @property (nonatomic, strong) NSMutableArray * selectedPhotos; 33 | 34 | /** 35 | * 选择完毕回调 36 | */ 37 | @property (nonatomic, copy) void(^handle)(NSArray * photos); 38 | 39 | /** 40 | * 单例 41 | */ 42 | + (instancetype)shareCenter; 43 | 44 | /** 45 | * 获取所有照片 46 | */ 47 | - (void)fetchAllAsset; 48 | 49 | /** 50 | * 获取相机权限 51 | */ 52 | - (void)cameraAuthoriationValidWithHandle:(void(^)())handle; 53 | 54 | /** 55 | * 判断是否达到最大选择数 56 | */ 57 | - (BOOL)isReachMaxSelectedCount; 58 | 59 | /** 60 | * 完成选择(相机的照片) 61 | */ 62 | - (void)endPickWithImage:(UIImage *)cameraPhoto; 63 | 64 | /** 65 | * 完成选择(相册的照片) 66 | */ 67 | - (void)endPick; 68 | 69 | /** 70 | * 清除信息 71 | */ 72 | - (void)clearInfos; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ####简介 2 | 用法简单的iOS图片选择库 3 | 项目主页:https://github.com/DaMingShen/SuPhotoPicker 4 | 1、只需两行代码搞定 5 | 2、仿QQ图片选择界面 6 | 7 | ####如何导入 8 | cocoapods导入:```暂无``` 9 | 手动导入:将 SuPhotoPicker 文件夹拽入项目中 10 | 11 | 12 | ####如何使用 13 | 1、导入主头文件: 14 | ``` 15 | #import "SuPhotoPicker.h" 16 | ``` 17 | 2、创建一个图片选择库实例并选择其显示界面 18 | ``` 19 | SuPhotoPicker * picker = [[SuPhotoPicker alloc]init]; 20 | //最大选择图片的数量以及最大快速预览图片的数量,默认为20 21 | picker.selectedCount = 12; 22 | picker.preViewCount = 15; 23 | //现在在界面上 24 | [picker showInSender:self handle:^(NSArray *photos) { 25 | //完成选择后的操作 26 | }]; 27 | ``` 28 | 29 | ####效果图 30 | 1、快速预览界面及图片选择(GIF 3.4M) 31 | 32 | ![SuPhotoPicker.gif](http://upload-images.jianshu.io/upload_images/1644426-44525c3a67704157.gif?imageMogr2/auto-orient/strip) 33 | 34 | 2、相册界面及图片选择(GIF 1.2M) 35 | 36 | ![SuPhotoPicker - album.gif](http://upload-images.jianshu.io/upload_images/1644426-d1a97ae0d530bafe.gif?imageMogr2/auto-orient/strip) 37 | 38 | 3、图片预览界面及图片选择(GIF 6.7M) 39 | 40 | ![SuPhotoPicker - album - preview.gif](http://upload-images.jianshu.io/upload_images/1644426-80fb190de7a955be.gif?imageMogr2/auto-orient/strip) 41 | 42 | 4、相机使用功能无法录制GIF,请在真机上实际使用体验 43 | 44 | ####提醒 45 | 本工具纯ARC,由于使用Photos库来实现,要求iOS8.0以上系统 46 | 47 | ####期待 48 | 1、大牛们能提供建议(包括优化和完善功能) 49 | 2、使用中遇到BUG,请联系我,谢谢 50 | 3、小伙伴能输出代码,Pull Requests我 51 | 4、本库能帮助到大家 ^_^ 52 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/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 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoBaseController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuBaseViewController.m 3 | // NewsReader 4 | // 5 | // Created by KevinSu on 15/10/15. 6 | // Copyright (c) 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoBaseController.h" 10 | #import "SuPhotoHeader.h" 11 | 12 | @implementation SuPhotoBaseController 13 | 14 | - (void)viewDidLoad { 15 | [super viewDidLoad]; 16 | self.view.backgroundColor = WHITECOLOR; 17 | self.automaticallyAdjustsScrollViewInsets = NO; 18 | [self setupNavbar]; 19 | } 20 | 21 | #pragma mark - 导航栏 22 | - (void)setupNavbar { 23 | self.navigationController.navigationBar.barTintColor = BTNCOLOR; 24 | self.navigationController.navigationBar.tintColor = WHITECOLOR; 25 | //隐藏导航栏下面的线 26 | [self.navigationController.navigationBar findHairlineImageViewUnder].hidden = YES; 27 | 28 | if (self.navigationController.viewControllers.count > 1) { 29 | UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:[UIButton buttonWithFrame:CGRectMake(0, 0, 22, 22) Target:self Selector:@selector(backBtnAction) Image:@"SuBack.png" ImagePressed:@"SuBack.png"]]; 30 | self.navigationItem.leftBarButtonItem = item; 31 | } 32 | } 33 | 34 | - (void)backBtnAction { 35 | [self.navigationController popViewControllerAnimated:YES]; 36 | } 37 | 38 | - (void)setNavigationTitle:(NSString *)title { 39 | self.title = title; 40 | [self.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:WHITECOLOR}]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Tool/SuMessageTool.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuMessageTool.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/23. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "SuMessageTool.h" 10 | #import "SuPhotoHeader.h" 11 | 12 | @implementation SuMessageTool 13 | 14 | /* 15 | * 显示提示信息 16 | */ 17 | - (void)ToastMessage:(NSString *)message { 18 | CGSize size = [message sizeWithAttributes:@{NSFontAttributeName: [UIFont systemFontOfSize:15.0f]}]; 19 | CGSize textSize = CGSizeMake(ceilf(size.width), ceilf(size.height)); 20 | 21 | UILabel * msg = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, textSize.width + 30, textSize.height + 20)]; 22 | msg.center = CGPointMake(SCREEN_W / 2, SCREEN_H * 8.0 / 9.0); 23 | msg.text = message; 24 | msg.font = [UIFont systemFontOfSize:15.0]; 25 | msg.textAlignment = NSTextAlignmentCenter; 26 | msg.backgroundColor = [UIColor blackColor]; 27 | msg.textColor = [UIColor whiteColor]; 28 | msg.layer.masksToBounds = YES; 29 | msg.layer.cornerRadius = (textSize.height + 20) / 2; 30 | [[UIApplication sharedApplication].keyWindow addSubview:msg]; 31 | [UIView animateWithDuration:1.0 delay:0.f usingSpringWithDamping:0.5 initialSpringVelocity:20 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 32 | msg.transform = CGAffineTransformMakeScale(1.2, 1.2); 33 | } completion:^(BOOL finished) { 34 | [self performSelector:@selector(dismissMsg:) withObject:msg afterDelay:0.5]; 35 | }]; 36 | } 37 | 38 | - (void)dismissMsg:(UIView *)msg { 39 | [UIView animateWithDuration:0.3 animations:^{ 40 | msg.alpha = 0.f; 41 | } completion:^(BOOL finished) { 42 | [msg removeFromSuperview]; 43 | }]; 44 | } 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/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 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIButton+SU.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+SuExt.m 3 | // SuUtility 4 | // 5 | // Created by KevinSu on 15/10/17. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "UIButton+SU.h" 10 | #import "SuPhotoHeader.h" 11 | 12 | @implementation UIButton (SU) 13 | 14 | + (UIButton *)buttonWithFrame:(CGRect)frame title:(NSString *)title target:(id)target selector:(SEL)selector { 15 | UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; 16 | button.titleLabel.font = [UIFont systemFontOfSize:17.0]; 17 | [button setFrame:frame]; 18 | [button setTitle:title forState:UIControlStateNormal]; 19 | [button setTitleColor:BTNCOLOR forState:UIControlStateNormal]; 20 | [button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside]; 21 | return button; 22 | } 23 | 24 | + (UIButton *)buttonWithFrame:(CGRect)frame Target:(id)target Selector:(SEL)selector Image:(NSString *)image ImagePressed:(NSString *)imagePressed { 25 | UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; 26 | [button setFrame:frame]; 27 | [button setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal]; 28 | [button setBackgroundImage:[UIImage imageNamed:imagePressed] forState:UIControlStateHighlighted]; 29 | [button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside]; 30 | return button; 31 | } 32 | 33 | + (UIButton *)buttonWithFrame:(CGRect)frame Target:(id)target Selector:(SEL)selector Image:(NSString*)image ImageSelected:(NSString *)imageSelected { 34 | UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; 35 | [button setFrame:frame]; 36 | [button setBackgroundImage:[UIImage imageNamed:image] forState:UIControlStateNormal]; 37 | [button setBackgroundImage:[UIImage imageNamed:imageSelected] forState:UIControlStateSelected]; 38 | [button addTarget:target action:selector forControlEvents:UIControlEventTouchUpInside]; 39 | return button; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by KevinSu on 15/12/22. 6 | // Copyright © 2015年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Category/UIView+SuAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+SuAnimation.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "UIView+SuAnimation.h" 10 | #import "SuPhotoHeader.h" 11 | #import 12 | 13 | #define BottomRect CGRectMake(self.frame.origin.x, SCREEN_H, self.frame.size.width, self.frame.size.height) 14 | 15 | @implementation UIView (SuAnimation) 16 | 17 | #pragma mark - 底部出现动画 18 | - (void)showFromBottom { 19 | CGRect rect = self.frame; 20 | self.frame = BottomRect; 21 | [self executeAnimationWithFrame:rect completeBlock:nil]; 22 | } 23 | 24 | #pragma mark - 底部消失动画 25 | - (void)dismissToBottomWithCompleteBlock:(void(^)())completeBlock { 26 | [self executeAnimationWithFrame:BottomRect completeBlock:completeBlock]; 27 | } 28 | 29 | #pragma mark - 背景浮现动画 30 | - (void)emerge { 31 | self.alpha = 0.0; 32 | [self executeAnimationWithAlpha:0.2 completeBlock:nil]; 33 | } 34 | 35 | #pragma mark - 背景淡去动画 36 | - (void)fake { 37 | [self executeAnimationWithAlpha:0.f completeBlock:nil]; 38 | } 39 | 40 | #pragma mark - 执行动画 41 | - (void)executeAnimationWithAlpha:(CGFloat)alpha completeBlock:(void(^)())completeBlock{ 42 | [UIView animateWithDuration:0.2 animations:^{ 43 | self.alpha = alpha; 44 | } completion:^(BOOL finished) { 45 | if (finished && completeBlock) completeBlock(); 46 | }]; 47 | } 48 | 49 | - (void)executeAnimationWithFrame:(CGRect)rect completeBlock:(void(^)())completeBlock{ 50 | [UIView animateWithDuration:0.2 animations:^{ 51 | self.frame = rect; 52 | } completion:^(BOOL finished) { 53 | if (finished && completeBlock) completeBlock(); 54 | }]; 55 | } 56 | 57 | #pragma mark - 按钮震动动画 58 | - (void)startSelectedAnimation { 59 | CAKeyframeAnimation * ani = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 60 | ani.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)], 61 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.3, 1.3, 1.0)], 62 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.9, 0.9, 1.0)], 63 | [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]]; 64 | ani.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 65 | ani.removedOnCompletion = YES; 66 | ani.fillMode = kCAFillModeForwards; 67 | ani.duration = 0.4; 68 | [self.layer addAnimation:ani forKey:@"transformAni"]; 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoAblumList.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoBrowser.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoAblumList.h" 10 | #import "SuPhotoHeader.h" 11 | #import "SuPhotoAblumCell.h" 12 | 13 | @interface SuPhotoAblumList () 14 | 15 | @property (nonatomic, strong) UITableView * tableView; 16 | 17 | @end 18 | 19 | @implementation SuPhotoAblumList 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | [self setNavigationTitle:@"照片"]; 24 | [self setupUI]; 25 | } 26 | 27 | #pragma mark - UI 28 | - (void)setupUI { 29 | self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 64, SCREEN_W, SCREEN_H - 64) style:UITableViewStylePlain]; 30 | self.tableView.delegate = self; 31 | self.tableView.dataSource = self; 32 | self.tableView.showsHorizontalScrollIndicator = NO; 33 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 34 | self.tableView.tableFooterView = [[UIView alloc]init]; 35 | [self.view addSubview:self.tableView]; 36 | 37 | [self setupCancelBtn]; 38 | } 39 | 40 | - (void)setupCancelBtn { 41 | UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelBtnAction)]; 42 | self.navigationItem.rightBarButtonItem = item; 43 | } 44 | 45 | - (void)cancelBtnAction { 46 | [self.navigationController dismissViewControllerAnimated:YES completion:nil]; 47 | } 48 | 49 | #pragma mark - tableView代理 50 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 51 | return self.assetCollections.count; 52 | } 53 | 54 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 55 | SuPhotoAblumCell * cell = [SuPhotoAblumCell cellForTableView:tableView info:self.assetCollections[indexPath.row]]; 56 | return cell; 57 | } 58 | 59 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPat { 60 | return 62.0; 61 | } 62 | 63 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 64 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 65 | SuPhotoBrowser * browser = [[SuPhotoBrowser alloc]init]; 66 | SuAblumInfo * info = self.assetCollections[indexPath.row]; 67 | browser.assetCollection = info.assetCollection; 68 | browser.collectionTitle = [info.ablumName chineseName];; 69 | [self.navigationController pushViewController:browser animated:YES]; 70 | } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoHeader.h 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/7. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #ifndef SuPhotoHeader_h 10 | #define SuPhotoHeader_h 11 | 12 | #define SCREEN_W ([[UIScreen mainScreen] bounds].size.width) 13 | #define SCREEN_H ([[UIScreen mainScreen] bounds].size.height) 14 | #define SCREEN_B [[UIScreen mainScreen] bounds] 15 | 16 | #define RGBColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] 17 | #define AblumsListLineColor RGBColor(192, 192, 192) 18 | #define BGCOLOR RGBColor(237, 238, 242) 19 | #define BTNCOLOR RGBColor(38, 184, 243) 20 | #define CLEARCOLOR [UIColor clearColor] 21 | #define WHITECOLOR [UIColor whiteColor] 22 | #define BLACKCOLOR [UIColor blackColor] 23 | 24 | #define Space 5 25 | 26 | #define SINGLE_LINE_WIDTH (1 / [UIScreen mainScreen].scale) 27 | #define SINGLE_LINE_ADJUST_OFFSET ((1 / [UIScreen mainScreen].scale) / 2) 28 | 29 | #define ShowMsg(_msg) [[[SuMessageTool alloc]init]ToastMessage:_msg] 30 | 31 | #define PhotoLibraryChangeNotification @"PhotoLibraryChangeNotification" 32 | 33 | #import 34 | #import 35 | #import 36 | 37 | #import "SuPhotoCenter.h" 38 | #import "SuPhotoAblumList.h" 39 | #import "SuPhotoPreviewer.h" 40 | #import "SuPhotoManager.h" 41 | 42 | #import "UIView+SuAnimation.h" 43 | #import "UIView+SuLine.h" 44 | #import "UIView+SU.h" 45 | #import "NSString+SU.h" 46 | #import "UIButton+SU.h" 47 | #import "UIImage+SU.h" 48 | #import "SuMessageTool.h" 49 | 50 | #endif /* SuPhotoHeader_h */ 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | /* 65 | PHAsset: 代表照片库中的一个资源,跟 ALAsset 类似,通过 PHAsset 可以获取和保存资源 66 | PHFetchOptions: 获取资源时的参数,可以传 nil,即使用系统默认值 67 | PHFetchResult: 表示一系列的资源集合,也可以是相册的集合 68 | PHAssetCollection: 表示一个相册或者一个时刻,或者是一个「智能相册(系统提供的特定的一系列相册,例如:最近删除,视频列表,收藏等等,如下图所示) 69 | PHImageManager: 用于处理资源的加载,加载图片的过程带有缓存处理,可以通过传入一个 PHImageRequestOptions 控制资源的输出尺寸等规格 70 | PHImageRequestOptions: 如上面所说,控制加载图片时的一系列参数 71 | 72 | enum PHAssetCollectionType : Int { 73 | case Album //从 iTunes 同步来的相册,以及用户在 Photos 中自己建立的相册 74 | case SmartAlbum //经由相机得来的相册 75 | case Moment //Photos 为我们自动生成的时间分组的相册 76 | } 77 | 78 | enum PHAssetCollectionSubtype : Int { 79 | case AlbumRegular //用户在 Photos 中创建的相册,也就是我所谓的逻辑相册 80 | case AlbumSyncedEvent //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而,在iTunes 12 以及iOS 9.0 beta4上,选用该类型没法获取同步的事件相册,而必须使用AlbumSyncedAlbum。 81 | case AlbumSyncedFaces //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。 82 | case AlbumSyncedAlbum //做了 AlbumSyncedEvent 应该做的事 83 | case AlbumImported //从相机或是外部存储导入的相册,完全没有这方面的使用经验,没法验证。 84 | case AlbumMyPhotoStream //用户的 iCloud 照片流 85 | case AlbumCloudShared //用户使用 iCloud 共享的相册 86 | case SmartAlbumGeneric //文档解释为非特殊类型的相册,主要包括从 iPhoto 同步过来的相册。由于本人的 iPhoto 已被 Photos 替代,无法验证。不过,在我的 iPad mini 上是无法获取的,而下面类型的相册,尽管没有包含照片或视频,但能够获取到。 87 | case SmartAlbumPanoramas //相机拍摄的全景照片 88 | case SmartAlbumVideos //相机拍摄的视频 89 | case SmartAlbumFavorites //收藏文件夹 90 | case SmartAlbumTimelapses //延时视频文件夹,同时也会出现在视频文件夹中 91 | case SmartAlbumAllHidden //包含隐藏照片或视频的文件夹 92 | case SmartAlbumRecentlyAdded //相机近期拍摄的照片或视频 93 | case SmartAlbumBursts //连拍模式拍摄的照片,在 iPad mini 上按住快门不放就可以了,但是照片依然没有存放在这个文件夹下,而是在相机相册里。 94 | case SmartAlbumSlomoVideos //Slomo 是 slow motion 的缩写,高速摄影慢动作解析,在该模式下,iOS 设备以120帧拍摄。不过我的 iPad mini 不支持,没法验证。 95 | case SmartAlbumUserLibrary //这个命名最神奇了,就是相机相册,所有相机拍摄的照片或视频都会出现在该相册中,而且使用其他应用保存的照片也会出现在这里。 96 | case Any //包含所有类型 97 | } 98 | */ -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Tool/SuPhotoCenter.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoCenter.m 3 | // SuPhotoPickerDemo 4 | // 5 | // Created by 万众科技 on 16/5/3. 6 | // Copyright © 2016年 KevinSu. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoCenter.h" 10 | #import "SuPhotoHeader.h" 11 | 12 | @interface SuPhotoCenter () 13 | 14 | @end 15 | 16 | @implementation SuPhotoCenter 17 | 18 | + (instancetype)shareCenter { 19 | static SuPhotoCenter * center = nil; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | center = [[SuPhotoCenter alloc]init]; 23 | center.selectedPhotos = [NSMutableArray array]; 24 | }); 25 | return center; 26 | } 27 | 28 | #pragma mark - 获取所有图片 29 | - (void)fetchAllAsset { 30 | [self clearInfos]; 31 | [[PHPhotoLibrary sharedPhotoLibrary]registerChangeObserver:self]; 32 | [self photoLibaryAuthorizationValid]; 33 | } 34 | 35 | - (void)reloadPhotos { 36 | self.allPhotos = [[SuPhotoManager manager]fetchAllAssets]; 37 | [[NSNotificationCenter defaultCenter] postNotificationName:PhotoLibraryChangeNotification object:nil]; 38 | } 39 | 40 | #pragma mark - 完成图片选择 41 | - (void)endPickWithImage:(UIImage *)cameraPhoto { 42 | if (self.handle) self.handle(@[cameraPhoto]); 43 | } 44 | 45 | - (void)endPick { 46 | if (self.handle) { 47 | [[SuPhotoManager manager]fetchImagesWithAssetsArray:self.selectedPhotos isOriginal:self.isOriginal completeBlock:^(NSArray *images) { 48 | self.handle(images); 49 | }]; 50 | } 51 | } 52 | 53 | - (BOOL)isReachMaxSelectedCount { 54 | if (self.selectedPhotos.count >= self.selectedCount) { 55 | NSString * msg = [NSString stringWithFormat:@"最多只能选择%ld张", self.selectedCount]; 56 | ShowMsg(msg); 57 | return YES; 58 | } 59 | return NO; 60 | } 61 | 62 | #pragma mark - 清除信息 63 | - (void)clearInfos { 64 | self.selectedCount = 20; 65 | self.isOriginal = NO; 66 | self.handle = nil; 67 | self.allPhotos = nil; 68 | [self.selectedPhotos removeAllObjects]; 69 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 70 | } 71 | 72 | #pragma mark - 监听图片变化代理 73 | - (void)photoLibraryDidChange:(PHChange *)changeInstance { 74 | //此代理方法里的线程非主线程 75 | [self reloadPhotos]; 76 | } 77 | 78 | #pragma mark - 权限验证 79 | - (void)photoLibaryAuthorizationValid { 80 | PHAuthorizationStatus authoriation = [PHPhotoLibrary authorizationStatus]; 81 | if (authoriation == PHAuthorizationStatusNotDetermined) { 82 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 83 | //这里非主线程,选择完成后会出发相册变化代理方法 84 | }]; 85 | }else if (authoriation == PHAuthorizationStatusAuthorized) { 86 | [self reloadPhotos]; 87 | }else { 88 | UIAlertView * photoLibaryNotice = [[UIAlertView alloc]initWithTitle:@"不能预览图片" message:@"应用程序无访问照片权限, 请在“设置\"-\"隐私\"-\"照片”中设置允许访问" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"设置", nil]; 89 | [photoLibaryNotice show]; 90 | } 91 | } 92 | 93 | - (void)cameraAuthoriationValidWithHandle:(void(^)())handle { 94 | AVAuthorizationStatus authoriation = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; 95 | if (authoriation == AVAuthorizationStatusNotDetermined) { 96 | [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { 97 | if (granted) { 98 | dispatch_async(dispatch_get_main_queue(), ^{ 99 | if (handle) handle(); 100 | }); 101 | } 102 | }]; 103 | }else if (authoriation == AVAuthorizationStatusAuthorized) { 104 | if (handle) handle(); 105 | }else { 106 | UIAlertView * cameraNotice = [[UIAlertView alloc]initWithTitle:@"应用程序无访问相机权限" message:@"请在“设置\"-\"隐私\"-\"相机”中设置允许访问" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"设置", nil]; 107 | [cameraNotice show]; 108 | } 109 | } 110 | 111 | #pragma mark - AlertView代理 112 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 113 | if (buttonIndex) { 114 | NSURL * setting = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; 115 | if ([[UIApplication sharedApplication]canOpenURL:setting]) { 116 | [[UIApplication sharedApplication]openURL:setting]; 117 | } 118 | } 119 | } 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/View/SuPhotoBrowserCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/View/SuPhotoAblumCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 34 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoBrowser.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoBrowser.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoBrowser.h" 10 | #import "SuPhotoHeader.h" 11 | #import "SuPhotoBrowserCell.h" 12 | 13 | @interface SuPhotoBrowser () 14 | 15 | @property (weak, nonatomic) IBOutlet UIView *bottomView; //底部面板 16 | @property (weak, nonatomic) IBOutlet UIButton *isOriginalBtn; //原图按钮 17 | @property (weak, nonatomic) IBOutlet UIView *bottomViewCover; //底部面板遮罩层 18 | @property (weak, nonatomic) IBOutlet UILabel *comBtn; //完成按钮 19 | 20 | @property (nonatomic, strong) UICollectionView * collectionView; 21 | @property (nonatomic, strong) NSArray * dataSource; 22 | 23 | @end 24 | 25 | @implementation SuPhotoBrowser 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | [self setNavigationTitle:self.collectionTitle ? self.collectionTitle : @"相机胶卷"]; 30 | [self setupUI]; 31 | [self loadAssetData]; 32 | } 33 | 34 | - (void)viewWillAppear:(BOOL)animated { 35 | [super viewWillAppear:animated]; 36 | [self refreshBottomView]; 37 | [self.collectionView reloadData]; 38 | } 39 | 40 | #pragma mark - UI 41 | - (void)setupUI { 42 | UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init]; 43 | layout.itemSize = CGSizeMake((SCREEN_W - 5 * 3) / 4, (SCREEN_W - 5 * 3) / 4); 44 | layout.minimumInteritemSpacing = 5.0; 45 | layout.minimumLineSpacing = 5.0; 46 | 47 | self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 64, SCREEN_W, SCREEN_H - 64 - 38) collectionViewLayout:layout]; 48 | self.collectionView.backgroundColor = [UIColor whiteColor]; 49 | self.collectionView.delegate = self; 50 | self.collectionView.dataSource = self; 51 | [self.collectionView registerNib:[UINib nibWithNibName:@"SuPhotoBrowserCell" bundle:nil] forCellWithReuseIdentifier:@"browserCell"]; 52 | [self.view insertSubview:self.collectionView belowSubview:self.bottomView]; 53 | 54 | UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(cancelBtnAction)]; 55 | self.navigationItem.rightBarButtonItem = item; 56 | } 57 | 58 | - (void)cancelBtnAction { 59 | [self.navigationController dismissViewControllerAnimated:YES completion:nil]; 60 | } 61 | 62 | - (void)refreshBottomView { 63 | if ([SuPhotoCenter shareCenter].selectedPhotos.count > 0) { 64 | self.bottomViewCover.hidden = YES; 65 | self.isOriginalBtn.selected = [SuPhotoCenter shareCenter].isOriginal; 66 | self.comBtn.text = [NSString stringWithFormat:@"完成(%ld)",[SuPhotoCenter shareCenter].selectedPhotos.count]; 67 | }else { 68 | self.bottomViewCover.hidden = NO; 69 | self.isOriginalBtn.selected = NO; 70 | self.comBtn.text = @"完成"; 71 | } 72 | } 73 | 74 | #pragma mark - 数据 75 | - (void)loadAssetData { 76 | self.dataSource = [[SuPhotoManager manager]fetchAssetsInCollection:self.assetCollection asending:NO]; 77 | } 78 | 79 | #pragma mark - collectionView代理 80 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 81 | return self.dataSource.count; 82 | } 83 | 84 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 85 | SuPhotoBrowserCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"browserCell" forIndexPath:indexPath]; 86 | [[SuPhotoManager manager]fetchImageInAsset:self.dataSource[indexPath.row] size:CGSizeMake(cell.w * 2, cell.h * 2) isResize:YES completeBlock:^(UIImage *image, NSDictionary *info) { 87 | cell.imageIV.image = image; 88 | }]; 89 | cell.selBtn.selected = [[SuPhotoCenter shareCenter].selectedPhotos containsObject:self.dataSource[indexPath.row]]; 90 | 91 | __weak typeof(cell) weakCell = cell; 92 | __weak typeof(self) weakSelf = self; 93 | [cell setSelectedBlock:^(BOOL isSelected) { 94 | if (isSelected) { 95 | if ([[SuPhotoCenter shareCenter] isReachMaxSelectedCount]) { 96 | weakCell.selBtn.selected = NO; 97 | return; 98 | } 99 | [weakCell.selBtn startSelectedAnimation]; 100 | [[SuPhotoCenter shareCenter].selectedPhotos addObject:weakSelf.dataSource[indexPath.row]]; 101 | }else { 102 | [[SuPhotoCenter shareCenter].selectedPhotos removeObject:weakSelf.dataSource[indexPath.row]]; 103 | } 104 | [weakSelf refreshBottomView]; 105 | }]; 106 | [cell setImgTapBlock:^{ 107 | SuPhotoPreviewer * previewer = [[SuPhotoPreviewer alloc]init]; 108 | if (weakCell.selBtn.selected) { 109 | previewer.isPreviewSelectedPhotos = YES; 110 | } 111 | previewer.selectedAsset = weakSelf.dataSource[indexPath.row]; 112 | [previewer setBackBlock:^(){ 113 | [collectionView reloadData]; 114 | [weakSelf refreshBottomView]; 115 | }]; 116 | [weakSelf.navigationController pushViewController:previewer animated:YES]; 117 | }]; 118 | return cell; 119 | } 120 | 121 | 122 | #pragma mark - 按钮 123 | - (IBAction)senBtnAction:(UIButton *)sender { 124 | [[SuPhotoCenter shareCenter] endPick]; 125 | [self.navigationController dismissViewControllerAnimated:YES completion:nil]; 126 | } 127 | 128 | - (IBAction)changeSizeAction:(UIButton *)sender { 129 | sender.selected = !sender.selected; 130 | [SuPhotoCenter shareCenter].isOriginal = sender.selected; 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoPreviewer.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoPreviewPage.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/8. 6 | // Copyright © 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoPreviewer.h" 10 | #import "SuPhotoHeader.h" 11 | #import "SuPhotoBrowserCell.h" 12 | 13 | @interface SuPhotoPreviewer () 14 | 15 | @property (weak, nonatomic) IBOutlet UIView *bottomView; 16 | @property (weak, nonatomic) IBOutlet UILabel *sendCount; 17 | @property (weak, nonatomic) IBOutlet UILabel *sizeCount; 18 | @property (weak, nonatomic) IBOutlet UIButton *isOriginalBtn; //原图按钮 19 | 20 | @property (nonatomic, strong) UICollectionView * collectionView; 21 | @property (nonatomic, strong) NSArray * dataSource; 22 | @property (nonatomic, strong) UIButton * selBtn; 23 | @property (nonatomic, assign) NSInteger currentPage; 24 | 25 | @end 26 | 27 | @implementation SuPhotoPreviewer 28 | 29 | - (void)viewDidLoad { 30 | [super viewDidLoad]; 31 | [self setupUI]; 32 | } 33 | 34 | #pragma mark - UI 35 | - (void)setupUI { 36 | if (self.previewPhotos) { 37 | self.dataSource = self.previewPhotos.copy; 38 | }else if (self.isPreviewSelectedPhotos) { 39 | self.dataSource = [SuPhotoCenter shareCenter].selectedPhotos.copy; 40 | }else { 41 | self.dataSource = [SuPhotoCenter shareCenter].allPhotos.copy; 42 | } 43 | 44 | UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init]; 45 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 46 | layout.itemSize = CGSizeMake(SCREEN_W, SCREEN_H); 47 | layout.minimumLineSpacing = 40.0; 48 | layout.sectionInset = UIEdgeInsetsMake(0, 20, 0, 20); 49 | 50 | self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(-20, 0, SCREEN_W + 40, SCREEN_H) collectionViewLayout:layout]; 51 | self.collectionView.backgroundColor = [UIColor blackColor]; 52 | self.collectionView.delegate = self; 53 | self.collectionView.dataSource = self; 54 | self.collectionView.pagingEnabled = YES; 55 | self.collectionView.showsHorizontalScrollIndicator = NO; 56 | [self.collectionView registerNib:[UINib nibWithNibName:@"SuPhotoBrowserCell" bundle:nil] forCellWithReuseIdentifier:@"headCell"]; 57 | [self.view insertSubview:self.collectionView belowSubview:self.bottomView]; 58 | 59 | if (self.navigationController.viewControllers.count < 2) { 60 | UIBarButtonItem * backItem = [[UIBarButtonItem alloc] initWithCustomView:[UIButton buttonWithFrame:CGRectMake(0, 0, 22, 22) Target:self Selector:@selector(dismissPreviewer) Image:@"SuBack.png" ImagePressed:@"SuBack.png"]]; 61 | self.navigationItem.leftBarButtonItem = backItem; 62 | } 63 | 64 | self.selBtn = [UIButton buttonWithFrame:CGRectMake(0, 0, 26, 26) Target:self Selector:@selector(selBtnAction:) Image:@"SuPhoto_circle" ImageSelected:@"SuPhoto_selected"]; 65 | UIBarButtonItem * navSelItem = [[UIBarButtonItem alloc]initWithCustomView:self.selBtn]; 66 | self.navigationItem.rightBarButtonItem = navSelItem; 67 | 68 | self.isOriginalBtn.selected = [SuPhotoCenter shareCenter].isOriginal; 69 | self.currentPage = [self.dataSource indexOfObject:self.selectedAsset]; 70 | [self refreshSelBtnStatusWithCurrentPage:(int)self.currentPage]; 71 | [self refreshCompleteBtnStatus]; 72 | [self refreshTitle]; 73 | [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:self.currentPage inSection:0] atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO]; 74 | } 75 | 76 | #pragma mark - UI状态 77 | - (void)refreshBottomHiddenStatus { 78 | self.bottomView.hidden = !self.bottomView.hidden; 79 | self.navigationController.navigationBarHidden = self.bottomView.hidden; 80 | [UIApplication sharedApplication].statusBarHidden = self.bottomView.hidden; 81 | } 82 | 83 | - (void)refreshSelBtnStatusWithCurrentPage:(int)page { 84 | self.selBtn.selected = [[SuPhotoCenter shareCenter].selectedPhotos containsObject:self.dataSource[page]]; 85 | self.currentPage = page; 86 | } 87 | 88 | - (void)refreshTitle { 89 | [self setNavigationTitle:[NSString stringWithFormat:@"%ld / %ld", self.currentPage + 1, self.dataSource.count]]; 90 | } 91 | 92 | - (void)refreshCompleteBtnStatus { 93 | if ([SuPhotoCenter shareCenter].selectedPhotos.count) { 94 | self.sendCount.text = [NSString stringWithFormat:@"完成(%ld)",[SuPhotoCenter shareCenter].selectedPhotos.count]; 95 | }else { 96 | self.sendCount.text = @"完成"; 97 | } 98 | } 99 | 100 | 101 | #pragma mark - collectionView代理 102 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 103 | return self.dataSource.count; 104 | } 105 | 106 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 107 | SuPhotoBrowserCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"headCell" forIndexPath:indexPath]; 108 | [[SuPhotoManager manager]fetchImageInAsset:self.dataSource[indexPath.row] size:CGSizeMake(cell.w, cell.h) isResize:NO completeBlock:^(UIImage *image, NSDictionary *info) { 109 | cell.imageIV.contentMode = UIViewContentModeScaleAspectFit; 110 | cell.imageIV.image = image; 111 | }]; 112 | cell.selBtn.hidden = YES; 113 | __weak typeof(self) weakSelf = self; 114 | [cell setImgTapBlock:^{ 115 | [weakSelf refreshBottomHiddenStatus]; 116 | }]; 117 | return cell; 118 | } 119 | 120 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { 121 | int currentPage = (int)scrollView.contentOffset.x / self.collectionView.w; 122 | [self refreshSelBtnStatusWithCurrentPage:currentPage]; 123 | [self refreshTitle]; 124 | } 125 | 126 | 127 | #pragma mark - 按钮 128 | - (void)selBtnAction:(UIButton *)sender { 129 | if (sender.selected) { 130 | [[SuPhotoCenter shareCenter].selectedPhotos removeObject:self.dataSource[self.currentPage]]; 131 | }else { 132 | if ([[SuPhotoCenter shareCenter] isReachMaxSelectedCount]) return; 133 | [sender startSelectedAnimation]; 134 | [[SuPhotoCenter shareCenter].selectedPhotos addObject:self.dataSource[self.currentPage]]; 135 | } 136 | sender.selected = !sender.selected; 137 | [self refreshCompleteBtnStatus]; 138 | } 139 | 140 | //发送 141 | - (IBAction)sendAction:(UIButton *)sender { 142 | //如果没有选中图片,则发送当前预览的图片 143 | if ([SuPhotoCenter shareCenter].selectedPhotos.count <= 0) [[SuPhotoCenter shareCenter].selectedPhotos addObject:self.dataSource[self.currentPage]]; 144 | [[SuPhotoCenter shareCenter] endPick]; 145 | [self.navigationController dismissViewControllerAnimated:YES completion:nil]; 146 | if (self.doneBlock) self.doneBlock(); 147 | } 148 | 149 | //原图 150 | - (IBAction)changeSizeAction:(UIButton *)sender { 151 | sender.selected = !sender.selected; 152 | [SuPhotoCenter shareCenter].isOriginal = sender.selected; 153 | } 154 | 155 | - (void)dismissPreviewer { 156 | if (self.backBlock) self.backBlock(); 157 | [self.navigationController dismissViewControllerAnimated:YES completion:nil]; 158 | } 159 | 160 | 161 | @end 162 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Tool/SuPhotoManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoManager.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoManager.h" 10 | #import "SuPhotoHeader.h" 11 | 12 | #define OriginalRatio 0.9 13 | 14 | @interface SuPhotoManager () 15 | 16 | @property (nonatomic ,strong) NSMutableArray * ablumsList; 17 | 18 | @end 19 | 20 | @implementation SuPhotoManager 21 | 22 | 23 | + (instancetype)manager { 24 | 25 | static SuPhotoManager * manager = nil; 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | manager = [[SuPhotoManager alloc]init]; 29 | manager.ablumsList = [NSMutableArray array]; 30 | }); 31 | return manager; 32 | } 33 | 34 | /* 35 | * 获取所有相册 36 | */ 37 | - (NSArray *)getAllAblums { 38 | 39 | //先清空数组 40 | [_ablumsList removeAllObjects]; 41 | 42 | //列出并加入所有智能相册 43 | PHFetchResult * smartAblums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil]; 44 | [self fetchCollection:smartAblums]; 45 | 46 | //列出列出并加入所有用户创建的相册 47 | PHFetchResult * topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil]; 48 | [self fetchCollection:topLevelUserCollections]; 49 | 50 | return _ablumsList; 51 | } 52 | 53 | /* 54 | * 获取相册资源 55 | */ 56 | - (void)fetchCollection:(PHFetchResult *)obj { 57 | 58 | //如果obj是所有相册的合集 59 | [obj enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 60 | 61 | if ([obj isKindOfClass:[PHAssetCollection class]]) { 62 | 63 | //返回此相册的资源集合 64 | PHFetchResult * result = [self fetchResultInCollection:obj asending:NO]; 65 | 66 | //如果有资源 67 | if (result.count) { 68 | 69 | //创建此相册的信息集 70 | SuAblumInfo * info = [SuAblumInfo infoFromResult:result collection:obj]; 71 | 72 | //加入到数组中 73 | [_ablumsList addObject:info]; 74 | } 75 | } 76 | }]; 77 | } 78 | 79 | 80 | /* 81 | * 获取(指定相册)或者(所有相册)资源的合集,并按资源的创建时间进行排序 YES 倒序 NO 82 | */ 83 | - (PHFetchResult *)fetchResultInCollection:(PHAssetCollection *)collection asending:(BOOL)asending { 84 | 85 | PHFetchOptions * option = [[PHFetchOptions alloc]init]; 86 | option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:asending]]; 87 | // option.predicate = [NSPredicate predicateWithFormat:@"mediaType = %d",PHAssetMediaTypeImage]; 88 | PHFetchResult * result; 89 | //获取指定相册资源合集 90 | if (collection) { 91 | 92 | result = [PHAsset fetchAssetsInAssetCollection:collection options:option]; 93 | 94 | } 95 | //获取所有相册资源合集 96 | else { 97 | 98 | result = [PHAsset fetchAssetsWithOptions:option]; 99 | } 100 | return result; 101 | } 102 | 103 | /* 104 | * 获取所有相册图片资源 105 | */ 106 | - (NSArray *)fetchAllAssets { 107 | 108 | return [self fetchAssetsInCollection:nil asending:NO]; 109 | } 110 | 111 | /* 112 | * 获取(指定相册)或者(所有相册 collection为nil)资源 113 | */ 114 | - (NSArray *)fetchAssetsInCollection:(PHAssetCollection *)collection asending:(BOOL)asending{ 115 | 116 | NSMutableArray * list = [NSMutableArray array]; 117 | 118 | PHFetchResult * result; 119 | 120 | //获取指定相册资源 121 | if (collection) { 122 | 123 | result = [self fetchResultInCollection:collection asending:asending]; 124 | } 125 | //获取所有相册资源 126 | else { 127 | 128 | result = [self fetchResultInCollection:nil asending:asending]; 129 | 130 | } 131 | 132 | //枚举添加到数组 133 | [result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 134 | 135 | [list addObject:obj]; 136 | }]; 137 | 138 | return list; 139 | } 140 | 141 | /* 142 | * 获取资源对应的图片 143 | */ 144 | - (void)fetchImageInAsset:(PHAsset *)asset size:(CGSize)size isResize:(BOOL)isResize completeBlock:(void(^)(UIImage * image, NSDictionary * info))completeBlock { 145 | 146 | PHImageRequestOptions * option = [[PHImageRequestOptions alloc]init]; 147 | //resizeMode:None,不缩放;Fast,尽快地提供接近或稍微大于要求的尺寸;Exact,精准提供要求的尺寸。 148 | option.resizeMode = isResize ? PHImageRequestOptionsResizeModeFast : PHImageRequestOptionsResizeModeNone; 149 | 150 | [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFit options:option resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 151 | 152 | if (completeBlock) completeBlock(result, info); 153 | }]; 154 | } 155 | 156 | /* 157 | * 获取资源对应的原图大小 158 | */ 159 | - (void)getImageDataLength:(PHAsset *)asset completeBlock:(void(^)(CGFloat length))completeBlock{ 160 | 161 | PHImageRequestOptions * option = [[PHImageRequestOptions alloc]init]; 162 | option.resizeMode = PHImageRequestOptionsResizeModeNone; 163 | 164 | [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { 165 | 166 | if (completeBlock) completeBlock(imageData.length / 1000.0); 167 | }]; 168 | } 169 | 170 | 171 | 172 | - (void)fetchImagesWithAssetsArray:(NSMutableArray *)assetsArray isOriginal:(BOOL)isOriginal completeBlock:(void(^)(NSArray * images))completeBlock { 173 | 174 | NSMutableArray * images = [NSMutableArray array]; 175 | 176 | for (int i = 0; i < assetsArray.count; i ++) { 177 | 178 | PHAsset * asset = assetsArray[i]; 179 | CGSize size; 180 | 181 | if (isOriginal) { 182 | 183 | //源图 -> 不压缩 184 | size = CGSizeMake((CGFloat)asset.pixelWidth, (CGFloat)asset.pixelHeight); 185 | 186 | }else { 187 | 188 | //压缩的图 -> 以最长边为屏幕分辨率压缩 189 | CGFloat scale = (CGFloat)asset.pixelWidth / (CGFloat)asset.pixelHeight; 190 | if (scale > 1.0) { 191 | 192 | if (asset.pixelWidth < SCREEN_W) { 193 | //最长边小于屏幕宽度时,采用原图 194 | size = CGSizeMake((CGFloat)asset.pixelWidth, (CGFloat)asset.pixelHeight); 195 | }else { 196 | //压缩 197 | size = CGSizeMake(SCREEN_W, SCREEN_W / scale); 198 | } 199 | 200 | }else { 201 | 202 | if (asset.pixelHeight < SCREEN_H) { 203 | //最长边小于屏幕高度时,采用原图 204 | size = CGSizeMake((CGFloat)asset.pixelWidth, (CGFloat)asset.pixelHeight); 205 | }else { 206 | //压缩 207 | size = CGSizeMake(SCREEN_H * scale, SCREEN_H); 208 | } 209 | 210 | } 211 | } 212 | 213 | [self fetchImageInAsset:asset size:size isResize:YES completeBlock:^(UIImage *image, NSDictionary *info) { 214 | 215 | //当图片读取到指定尺寸时 216 | if (image.size.width >= size.width * OriginalRatio || image.size.height >= size.height * OriginalRatio) { 217 | 218 | [images addObject:image]; 219 | 220 | //全部图片读取完毕 221 | if (images.count == assetsArray.count) { 222 | 223 | //执行block 224 | if (completeBlock) completeBlock(images); 225 | } 226 | } 227 | }]; 228 | } 229 | 230 | } 231 | 232 | 233 | 234 | 235 | @end 236 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoPreviewer.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 65 | 71 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/Controller/SuPhotoBrowser.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo/SuPhotoPicker/SuPhotoPicker.m: -------------------------------------------------------------------------------- 1 | // 2 | // SuPhotoPicker.m 3 | // LazyWeather 4 | // 5 | // Created by KevinSu on 15/12/6. 6 | // Copyright (c) 2015年 SuXiaoMing. All rights reserved. 7 | // 8 | 9 | #import "SuPhotoPicker.h" 10 | #import "SuPhotoHeader.h" 11 | #import "SuPhotoBrowserCell.h" 12 | 13 | @interface SuPhotoPicker () 18 | //背景 19 | @property (nonatomic, strong) UIView * bgView; 20 | //图片Sheet 21 | @property (nonatomic, strong) UIView * photoSheet; 22 | //图片列表 23 | @property (nonatomic, strong) UICollectionView * collectionView; 24 | //collectionView数据源 25 | @property (nonatomic, strong) NSArray * dataSource; 26 | //相机按钮 27 | @property (nonatomic, strong) UIButton * cameraBtn; 28 | //发送按钮 29 | @property (nonatomic, strong) UIButton * doneBtn; 30 | //原图按钮 31 | @property (nonatomic, strong) UIButton * originalBtn; 32 | //显示选择器的控制器 33 | @property (nonatomic, weak) UIViewController * sender; 34 | 35 | @end 36 | 37 | @implementation SuPhotoPicker 38 | 39 | - (id)init { 40 | if (self = [super init]) { 41 | [self configData]; 42 | [self configUI]; 43 | } 44 | return self; 45 | } 46 | 47 | - (void)dealloc { 48 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 49 | } 50 | 51 | - (void)setSelectedCount:(NSInteger)selectedCount { 52 | [SuPhotoCenter shareCenter].selectedCount = selectedCount; 53 | _selectedCount = selectedCount; 54 | } 55 | 56 | #pragma clang diagnostic push 57 | #pragma clang diagnostic ignored"-Wdeprecated-declarations" 58 | 59 | #pragma mark - UI 60 | - (void)configData { 61 | if (self.selectedCount <= 0) [self setSelectedCount:20]; 62 | if (self.preViewCount <= 0) self.preViewCount = 20; 63 | 64 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadAllPhotos) name:PhotoLibraryChangeNotification object:nil]; 65 | [[SuPhotoCenter shareCenter] fetchAllAsset]; 66 | } 67 | 68 | - (void)configUI { 69 | self.frame = SCREEN_B; 70 | self.backgroundColor = CLEARCOLOR; 71 | 72 | self.bgView = [[UIView alloc]initWithFrame:SCREEN_B]; 73 | self.bgView.backgroundColor = BLACKCOLOR; 74 | UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(dismissPhotoPicker)]; 75 | [self.bgView addGestureRecognizer:tap]; 76 | [self addSubview:self.bgView]; 77 | 78 | self.photoSheet = [[UIView alloc]initWithFrame:CGRectMake(0, SCREEN_H - 222, SCREEN_W, 222)]; 79 | self.photoSheet.backgroundColor = BGCOLOR; 80 | [self addSubview:self.photoSheet]; 81 | 82 | UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc]init]; 83 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 84 | layout.minimumInteritemSpacing = Space; 85 | self.collectionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_W, 190) collectionViewLayout:layout]; 86 | self.collectionView.backgroundColor = BGCOLOR; 87 | self.collectionView.delegate = self; 88 | self.collectionView.dataSource = self; 89 | self.collectionView.showsHorizontalScrollIndicator = NO; 90 | [self.collectionView registerNib:[UINib nibWithNibName:@"SuPhotoBrowserCell" bundle:nil] forCellWithReuseIdentifier:@"headCell"]; 91 | [self.photoSheet addSubview:self.collectionView]; 92 | 93 | self.doneBtn = [UIButton buttonWithFrame:CGRectMake(SCREEN_W - 80, 191, 60, 24) title:@"完成" target:self selector:@selector(endPick)]; 94 | [self.doneBtn setTitleColor:WHITECOLOR forState:UIControlStateNormal]; 95 | self.doneBtn.titleLabel.font = [UIFont systemFontOfSize:14.0]; 96 | self.doneBtn.layer.cornerRadius = 12.0; 97 | self.doneBtn.layer.masksToBounds = YES; 98 | [self refreshDoneStatus]; 99 | [self.photoSheet addSubview:self.doneBtn]; 100 | 101 | UIButton * cameraBtn = [UIButton buttonWithFrame:CGRectMake(20, 193, 40, 20) title:@"相机" target:self selector:@selector(takePhoto)]; 102 | [self.photoSheet addSubview:cameraBtn]; 103 | 104 | UIButton * albumBtn = [UIButton buttonWithFrame:CGRectMake(80, 193, 40, 20) title:@"相册" target:self selector:@selector(albumBrowser)]; 105 | [self.photoSheet addSubview:albumBtn]; 106 | 107 | self.originalBtn = [UIButton buttonWithFrame:CGRectMake(140, 194, 18, 18) Target:self Selector:@selector(originalSwitch:) Image:@"SuPhoto_unselected.png" ImageSelected:@"SuPhoto_selected.png"]; 108 | [self.photoSheet addSubview:self.originalBtn]; 109 | 110 | UIButton * originalTextBtn = [UIButton buttonWithFrame:CGRectMake(158, 193, 40, 20) title:@"原图" target:self selector:@selector(originalSwitch:)]; 111 | [self.photoSheet addSubview:originalTextBtn]; 112 | } 113 | 114 | - (void)refreshDoneStatus { 115 | if ([SuPhotoCenter shareCenter].selectedPhotos.count > 0) { 116 | [self.doneBtn setTitle:[NSString stringWithFormat:@"完成(%ld)",[SuPhotoCenter shareCenter].selectedPhotos.count] forState:UIControlStateNormal]; 117 | [self.doneBtn setBackgroundColor:BTNCOLOR]; 118 | self.doneBtn.enabled = YES; 119 | }else { 120 | [self.doneBtn setTitle:@"完成" forState:UIControlStateNormal]; 121 | [self.doneBtn setBackgroundColor:[UIColor grayColor]]; 122 | self.doneBtn.enabled = NO; 123 | } 124 | } 125 | 126 | #pragma mark - 通知处理 127 | - (void)reloadAllPhotos { 128 | dispatch_async(dispatch_get_main_queue(), ^{ 129 | self.dataSource = [SuPhotoCenter shareCenter].allPhotos; 130 | [self.collectionView reloadData]; 131 | }); 132 | } 133 | 134 | #pragma mark - 出现和消失 135 | - (void)showInSender:(UIViewController *)sender handle:(void(^)(NSArray * photos))handle { 136 | self.sender = sender; 137 | [sender.view addSubview:self]; 138 | [SuPhotoCenter shareCenter].handle = handle; 139 | [self.photoSheet showFromBottom]; 140 | [self.bgView emerge]; 141 | 142 | } 143 | 144 | - (void)dismissPhotoPicker { 145 | [self.bgView fake]; 146 | [self.photoSheet dismissToBottomWithCompleteBlock:^{ 147 | [self removeFromSuperview]; 148 | }]; 149 | } 150 | 151 | - (void)dismissPhotoPickerWithoutAni { 152 | [self removeFromSuperview]; 153 | } 154 | 155 | #pragma mark - collectionView代理 156 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 157 | return self.dataSource.count > self.preViewCount ? self.preViewCount : self.dataSource.count; 158 | } 159 | 160 | 161 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 162 | SuPhotoBrowserCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"headCell" forIndexPath:indexPath]; 163 | [self fetchImageFromAsset:self.dataSource[indexPath.row] completeBlock:^(UIImage *image, NSDictionary *info) { 164 | cell.imageIV.image = image; 165 | [self changeCellSelBtnPosition]; 166 | }]; 167 | cell.selBtn.selected = [[SuPhotoCenter shareCenter].selectedPhotos containsObject:self.dataSource[indexPath.row]]; 168 | 169 | __weak typeof(cell) weakCell = cell; 170 | __weak typeof(self) weakSelf = self; 171 | [cell setSelectedBlock:^(BOOL isSelected) { 172 | if (isSelected) { 173 | if ([[SuPhotoCenter shareCenter] isReachMaxSelectedCount]) { 174 | weakCell.selBtn.selected = NO; 175 | return; 176 | } 177 | [weakCell.selBtn startSelectedAnimation]; 178 | [[SuPhotoCenter shareCenter].selectedPhotos addObject:weakSelf.dataSource[indexPath.row]]; 179 | //调整位置 180 | NSInteger photoCount = weakSelf.dataSource.count > weakSelf.preViewCount ? weakSelf.preViewCount : weakSelf.dataSource.count; 181 | //取得当前cell的位置 182 | CGRect rect = [collectionView convertRect:weakCell.frame fromView:collectionView]; 183 | CGPoint point = collectionView.contentOffset; 184 | float cellEndX = rect.origin.x + rect.size.width - point.x; 185 | //滚动到屏幕三分之二处 186 | if (cellEndX > SCREEN_W * 2 / 3) { 187 | float forwardLen; 188 | if (indexPath.item == photoCount - 1) { 189 | forwardLen = cellEndX - SCREEN_W + Space; 190 | }else { 191 | forwardLen = cellEndX - SCREEN_W * 2 / 3; 192 | } 193 | point.x += forwardLen; 194 | [collectionView setContentOffset:point animated:YES]; 195 | } 196 | }else { 197 | [[SuPhotoCenter shareCenter].selectedPhotos removeObject:weakSelf.dataSource[indexPath.row]]; 198 | } 199 | [weakSelf refreshDoneStatus]; 200 | }]; 201 | 202 | [cell setImgTapBlock:^{ 203 | SuPhotoPreviewer * previewer = [[SuPhotoPreviewer alloc]init]; 204 | if (weakCell.selBtn.selected) { 205 | previewer.isPreviewSelectedPhotos = YES; 206 | } 207 | previewer.selectedAsset = weakSelf.dataSource[indexPath.row]; 208 | [previewer setBackBlock:^(){ 209 | [collectionView reloadData]; 210 | [weakSelf refreshDoneStatus]; 211 | }]; 212 | [previewer setDoneBlock:^{ 213 | [weakSelf dismissPhotoPickerWithoutAni]; 214 | }]; 215 | UINavigationController * NVC = [[UINavigationController alloc]initWithRootViewController:previewer]; 216 | [weakSelf.sender presentViewController:NVC animated:YES completion:nil]; 217 | }]; 218 | 219 | return cell; 220 | } 221 | 222 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 223 | return [self calculateCellSizeFromAsset:self.dataSource[indexPath.row]]; 224 | } 225 | 226 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { 227 | return UIEdgeInsetsMake(0, Space, 0, Space); 228 | } 229 | 230 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 231 | [self changeCellSelBtnPosition]; 232 | } 233 | 234 | #pragma mark - cell相关处理 235 | - (void)changeCellSelBtnPosition { 236 | for (SuPhotoBrowserCell * cell in self.collectionView.visibleCells) { 237 | //获取每个cell在当前屏幕上的位置 238 | CGRect rect = [self convertRect:cell.frame fromView:_collectionView]; 239 | //获取最右边的cell, 停在屏幕的边上 240 | if (rect.origin.x > SCREEN_W - cell.w) { 241 | //获取cell里的选择按钮在当前屏幕上的位置 242 | CGRect cellRect = [self convertRect:cell.selBtn.frame fromView:cell]; 243 | //选择按钮在屏幕上固定的位置 244 | cellRect.origin.x = SCREEN_W - 25.0 - 1.0 - 5.0; 245 | //转化成在cell内的位置 246 | cellRect = [self convertRect:cellRect toView:cell]; 247 | //如果在cell外则固定在左侧,如果在cell里则移动到相应的位置 248 | if (cellRect.origin.x < 1.0) { 249 | cellRect.origin.x = 1.0; 250 | } 251 | cell.selBtn.x = cellRect.origin.x; 252 | } 253 | //如果不是最右边, 则停在cell的右上角 254 | else { 255 | cell.selBtn.x = cell.w - Space - cell.selBtn.w; 256 | } 257 | } 258 | } 259 | 260 | - (CGSize)calculateImgSizeFromAsset:(PHAsset *)asset { 261 | CGFloat scale = asset.pixelWidth / (CGFloat)asset.pixelHeight; 262 | CGFloat imgW = (self.collectionView.h - Space * 2) * scale; 263 | CGFloat imgH = self.collectionView.h - Space * 2; 264 | return CGSizeMake(imgW * 2, imgH * 2); 265 | } 266 | 267 | - (CGSize)calculateCellSizeFromAsset:(PHAsset *)asset { 268 | CGSize size = [self calculateImgSizeFromAsset:asset]; 269 | return CGSizeMake(size.width / 2, size.height / 2); 270 | } 271 | 272 | - (void)fetchImageFromAsset:(PHAsset *)asset completeBlock:(void(^)(UIImage * image, NSDictionary * info))completeBlock { 273 | CGSize size = [self calculateImgSizeFromAsset:asset]; 274 | [[SuPhotoManager manager]fetchImageInAsset:asset size:size isResize:YES completeBlock:^(UIImage *image, NSDictionary *info) { 275 | if (completeBlock) completeBlock(image, info); 276 | }]; 277 | } 278 | 279 | #pragma mark - 相机 280 | - (void)takePhoto { 281 | [[SuPhotoCenter shareCenter] cameraAuthoriationValidWithHandle:^{ 282 | [self launchCamera]; 283 | }]; 284 | } 285 | 286 | - (void)launchCamera { 287 | UIImagePickerController * picker = [[UIImagePickerController alloc]init]; 288 | picker.delegate = self; 289 | if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { 290 | [[[UIAlertView alloc]initWithTitle:nil message:@"相机启动失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil] show]; 291 | [self dismissPhotoPicker]; 292 | return; 293 | } 294 | picker.sourceType = UIImagePickerControllerSourceTypeCamera; 295 | picker.modalPresentationStyle = UIModalPresentationOverCurrentContext; 296 | [self.sender presentViewController:picker animated:YES completion:nil]; 297 | 298 | } 299 | 300 | - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 301 | UIImage * image = [info objectForKey:@"UIImagePickerControllerOriginalImage"]; 302 | //将该图像保存到媒体库中 303 | UIImageWriteToSavedPhotosAlbum(image, self, nil, nil); 304 | //压缩图片 -> 以最长边为屏幕分辨率压缩 305 | CGSize size; 306 | CGFloat scale = image.size.width / image.size.height; 307 | if (scale > 1.0) { 308 | if (image.size.width < SCREEN_W) { 309 | //最长边小于屏幕宽度时,采用原图 310 | size = CGSizeMake(image.size.width, image.size.height); 311 | }else { 312 | size = CGSizeMake(SCREEN_W, SCREEN_W / scale); 313 | } 314 | }else { 315 | if (image.size.height < SCREEN_H) { 316 | //最长边小于屏幕高度时,采用原图 317 | size = CGSizeMake(image.size.width, image.size.height); 318 | }else { 319 | size = CGSizeMake(SCREEN_H * scale, SCREEN_H); 320 | } 321 | 322 | } 323 | image = [UIImage imageWithImage:image scaledToSize:size]; 324 | [[SuPhotoCenter shareCenter] endPickWithImage:image]; 325 | [self dismissPhotoPickerWithoutAni]; 326 | [picker dismissViewControllerAnimated:YES completion:nil]; 327 | } 328 | 329 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { 330 | [self dismissPhotoPickerWithoutAni]; 331 | [picker dismissViewControllerAnimated:YES completion:nil]; 332 | } 333 | 334 | #pragma mark - 相册 335 | - (void)albumBrowser { 336 | if ([PHPhotoLibrary authorizationStatus] != PHAuthorizationStatusAuthorized) { 337 | UIAlertView * photoLibaryNotice = [[UIAlertView alloc]initWithTitle:@"应用程序无访问照片权限" message:@"请在“设置\"-\"隐私\"-\"照片”中设置允许访问" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:@"设置", nil]; 338 | [photoLibaryNotice show]; 339 | [self dismissPhotoPicker]; 340 | return; 341 | } 342 | SuPhotoAblumList * ablumsList = [[SuPhotoAblumList alloc]init]; 343 | ablumsList.assetCollections = [[SuPhotoManager manager]getAllAblums]; 344 | UINavigationController * NVC = [[UINavigationController alloc]initWithRootViewController:ablumsList]; 345 | //默认跳转到照片图册 346 | SuPhotoBrowser * browser = [[SuPhotoBrowser alloc]init]; 347 | [ablumsList.navigationController pushViewController:browser animated:NO]; 348 | [self dismissPhotoPicker]; 349 | [self.sender presentViewController:NVC animated:YES completion:nil]; 350 | } 351 | 352 | - (void)originalSwitch:(UIButton *)sender { 353 | self.originalBtn.selected = !self.originalBtn.selected; 354 | [SuPhotoCenter shareCenter].isOriginal = sender.selected; 355 | } 356 | 357 | #pragma mark - 完成 358 | - (void)endPick { 359 | [[SuPhotoCenter shareCenter] endPick]; 360 | [self dismissPhotoPicker]; 361 | } 362 | 363 | #pragma clang diagnostic pop 364 | 365 | @end 366 | -------------------------------------------------------------------------------- /SuPhotoPickerDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2B5834411C29978C00C86D30 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5834401C29978C00C86D30 /* main.m */; }; 11 | 2B5834441C29978C00C86D30 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5834431C29978C00C86D30 /* AppDelegate.m */; }; 12 | 2B5834471C29978C00C86D30 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5834461C29978C00C86D30 /* ViewController.m */; }; 13 | 2B58344A1C29978D00C86D30 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2B5834481C29978D00C86D30 /* Main.storyboard */; }; 14 | 2B58344C1C29978D00C86D30 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2B58344B1C29978D00C86D30 /* Assets.xcassets */; }; 15 | 2B58344F1C29978D00C86D30 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2B58344D1C29978D00C86D30 /* LaunchScreen.storyboard */; }; 16 | 2B5834861C2998B600C86D30 /* img_add@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2B5834851C2998B600C86D30 /* img_add@2x.png */; settings = {ASSET_TAGS = (); }; }; 17 | 2B5E567A1C299EE000A579DE /* NSString+SU.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56541C299EE000A579DE /* NSString+SU.m */; settings = {ASSET_TAGS = (); }; }; 18 | 2B5E567C1C299EE000A579DE /* UIButton+SU.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56581C299EE000A579DE /* UIButton+SU.m */; settings = {ASSET_TAGS = (); }; }; 19 | 2B5E567D1C299EE000A579DE /* UIView+SuAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E565A1C299EE000A579DE /* UIView+SuAnimation.m */; settings = {ASSET_TAGS = (); }; }; 20 | 2B5E567E1C299EE000A579DE /* SuPhotoBaseController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E565D1C299EE000A579DE /* SuPhotoBaseController.m */; settings = {ASSET_TAGS = (); }; }; 21 | 2B5E567F1C299EE000A579DE /* SuPhotoAblumList.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E565F1C299EE000A579DE /* SuPhotoAblumList.m */; settings = {ASSET_TAGS = (); }; }; 22 | 2B5E56801C299EE000A579DE /* SuPhotoBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56611C299EE000A579DE /* SuPhotoBrowser.m */; settings = {ASSET_TAGS = (); }; }; 23 | 2B5E56811C299EE000A579DE /* SuPhotoBrowser.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E56621C299EE000A579DE /* SuPhotoBrowser.xib */; settings = {ASSET_TAGS = (); }; }; 24 | 2B5E56821C299EE000A579DE /* SuPhotoPreviewer.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56641C299EE000A579DE /* SuPhotoPreviewer.m */; settings = {ASSET_TAGS = (); }; }; 25 | 2B5E56831C299EE000A579DE /* SuPhotoPreviewer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E56651C299EE000A579DE /* SuPhotoPreviewer.xib */; settings = {ASSET_TAGS = (); }; }; 26 | 2B5E56841C299EE000A579DE /* SuAblumInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56681C299EE000A579DE /* SuAblumInfo.m */; settings = {ASSET_TAGS = (); }; }; 27 | 2B5E56851C299EE000A579DE /* SuPhoto_circle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E566A1C299EE000A579DE /* SuPhoto_circle@2x.png */; settings = {ASSET_TAGS = (); }; }; 28 | 2B5E56861C299EE000A579DE /* SuPhoto_selected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E566B1C299EE000A579DE /* SuPhoto_selected@2x.png */; settings = {ASSET_TAGS = (); }; }; 29 | 2B5E56871C299EE000A579DE /* SuPhoto_unselected@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E566C1C299EE000A579DE /* SuPhoto_unselected@2x.png */; settings = {ASSET_TAGS = (); }; }; 30 | 2B5E56881C299EE000A579DE /* SuPhotoPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E566E1C299EE000A579DE /* SuPhotoPicker.m */; settings = {ASSET_TAGS = (); }; }; 31 | 2B5E56891C299EE000A579DE /* SuPhotoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56711C299EE000A579DE /* SuPhotoManager.m */; settings = {ASSET_TAGS = (); }; }; 32 | 2B5E568A1C299EE000A579DE /* SuPhotoAblumCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56751C299EE000A579DE /* SuPhotoAblumCell.m */; settings = {ASSET_TAGS = (); }; }; 33 | 2B5E568B1C299EE000A579DE /* SuPhotoAblumCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E56761C299EE000A579DE /* SuPhotoAblumCell.xib */; settings = {ASSET_TAGS = (); }; }; 34 | 2B5E568C1C299EE000A579DE /* SuPhotoBrowserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56781C299EE000A579DE /* SuPhotoBrowserCell.m */; settings = {ASSET_TAGS = (); }; }; 35 | 2B5E568D1C299EE000A579DE /* SuPhotoBrowserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2B5E56791C299EE000A579DE /* SuPhotoBrowserCell.xib */; settings = {ASSET_TAGS = (); }; }; 36 | 2B5E56901C29A09700A579DE /* UIView+SU.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E568F1C29A09700A579DE /* UIView+SU.m */; settings = {ASSET_TAGS = (); }; }; 37 | 2B5E56961C29A99E00A579DE /* UIView+SuLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56951C29A99E00A579DE /* UIView+SuLine.m */; settings = {ASSET_TAGS = (); }; }; 38 | 2B5E56991C29AD1500A579DE /* SuMessageTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B5E56981C29AD1500A579DE /* SuMessageTool.m */; settings = {ASSET_TAGS = (); }; }; 39 | B1B9A2D21CD8349C004A46EF /* SuPhotoCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B9A2D11CD8349C004A46EF /* SuPhotoCenter.m */; settings = {ASSET_TAGS = (); }; }; 40 | B1B9A2D51CD84F02004A46EF /* UIImage+SU.m in Sources */ = {isa = PBXBuildFile; fileRef = B1B9A2D41CD84F02004A46EF /* UIImage+SU.m */; settings = {ASSET_TAGS = (); }; }; 41 | B1B9A2D81CD89E0C004A46EF /* SuBack@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = B1B9A2D61CD89E0C004A46EF /* SuBack@3x.png */; settings = {ASSET_TAGS = (); }; }; 42 | B1B9A2D91CD89E0C004A46EF /* SuBack@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B1B9A2D71CD89E0C004A46EF /* SuBack@2x.png */; settings = {ASSET_TAGS = (); }; }; 43 | /* End PBXBuildFile section */ 44 | 45 | /* Begin PBXFileReference section */ 46 | 2B58343C1C29978C00C86D30 /* SuPhotoPickerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SuPhotoPickerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | 2B5834401C29978C00C86D30 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 48 | 2B5834421C29978C00C86D30 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 49 | 2B5834431C29978C00C86D30 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 50 | 2B5834451C29978C00C86D30 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 51 | 2B5834461C29978C00C86D30 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 52 | 2B5834491C29978D00C86D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 2B58344B1C29978D00C86D30 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 2B58344E1C29978D00C86D30 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 2B5834501C29978D00C86D30 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 2B5834851C2998B600C86D30 /* img_add@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "img_add@2x.png"; sourceTree = ""; }; 57 | 2B5E56531C299EE000A579DE /* NSString+SU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SU.h"; sourceTree = ""; }; 58 | 2B5E56541C299EE000A579DE /* NSString+SU.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SU.m"; sourceTree = ""; }; 59 | 2B5E56571C299EE000A579DE /* UIButton+SU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+SU.h"; sourceTree = ""; }; 60 | 2B5E56581C299EE000A579DE /* UIButton+SU.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+SU.m"; sourceTree = ""; }; 61 | 2B5E56591C299EE000A579DE /* UIView+SuAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+SuAnimation.h"; sourceTree = ""; }; 62 | 2B5E565A1C299EE000A579DE /* UIView+SuAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SuAnimation.m"; sourceTree = ""; }; 63 | 2B5E565C1C299EE000A579DE /* SuPhotoBaseController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoBaseController.h; sourceTree = ""; }; 64 | 2B5E565D1C299EE000A579DE /* SuPhotoBaseController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoBaseController.m; sourceTree = ""; }; 65 | 2B5E565E1C299EE000A579DE /* SuPhotoAblumList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoAblumList.h; sourceTree = ""; }; 66 | 2B5E565F1C299EE000A579DE /* SuPhotoAblumList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoAblumList.m; sourceTree = ""; }; 67 | 2B5E56601C299EE000A579DE /* SuPhotoBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoBrowser.h; sourceTree = ""; }; 68 | 2B5E56611C299EE000A579DE /* SuPhotoBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoBrowser.m; sourceTree = ""; }; 69 | 2B5E56621C299EE000A579DE /* SuPhotoBrowser.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SuPhotoBrowser.xib; sourceTree = ""; }; 70 | 2B5E56631C299EE000A579DE /* SuPhotoPreviewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoPreviewer.h; sourceTree = ""; }; 71 | 2B5E56641C299EE000A579DE /* SuPhotoPreviewer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoPreviewer.m; sourceTree = ""; }; 72 | 2B5E56651C299EE000A579DE /* SuPhotoPreviewer.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SuPhotoPreviewer.xib; sourceTree = ""; }; 73 | 2B5E56671C299EE000A579DE /* SuAblumInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuAblumInfo.h; sourceTree = ""; }; 74 | 2B5E56681C299EE000A579DE /* SuAblumInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuAblumInfo.m; sourceTree = ""; }; 75 | 2B5E566A1C299EE000A579DE /* SuPhoto_circle@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "SuPhoto_circle@2x.png"; sourceTree = ""; }; 76 | 2B5E566B1C299EE000A579DE /* SuPhoto_selected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "SuPhoto_selected@2x.png"; sourceTree = ""; }; 77 | 2B5E566C1C299EE000A579DE /* SuPhoto_unselected@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "SuPhoto_unselected@2x.png"; sourceTree = ""; }; 78 | 2B5E566D1C299EE000A579DE /* SuPhotoPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoPicker.h; sourceTree = ""; }; 79 | 2B5E566E1C299EE000A579DE /* SuPhotoPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoPicker.m; sourceTree = ""; }; 80 | 2B5E56701C299EE000A579DE /* SuPhotoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoManager.h; sourceTree = ""; }; 81 | 2B5E56711C299EE000A579DE /* SuPhotoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoManager.m; sourceTree = ""; }; 82 | 2B5E56721C299EE000A579DE /* SuPhotoHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoHeader.h; sourceTree = ""; }; 83 | 2B5E56741C299EE000A579DE /* SuPhotoAblumCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoAblumCell.h; sourceTree = ""; }; 84 | 2B5E56751C299EE000A579DE /* SuPhotoAblumCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoAblumCell.m; sourceTree = ""; }; 85 | 2B5E56761C299EE000A579DE /* SuPhotoAblumCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SuPhotoAblumCell.xib; sourceTree = ""; }; 86 | 2B5E56771C299EE000A579DE /* SuPhotoBrowserCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoBrowserCell.h; sourceTree = ""; }; 87 | 2B5E56781C299EE000A579DE /* SuPhotoBrowserCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoBrowserCell.m; sourceTree = ""; }; 88 | 2B5E56791C299EE000A579DE /* SuPhotoBrowserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SuPhotoBrowserCell.xib; sourceTree = ""; }; 89 | 2B5E568E1C29A09700A579DE /* UIView+SU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+SU.h"; sourceTree = ""; }; 90 | 2B5E568F1C29A09700A579DE /* UIView+SU.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SU.m"; sourceTree = ""; }; 91 | 2B5E56941C29A99E00A579DE /* UIView+SuLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+SuLine.h"; sourceTree = ""; }; 92 | 2B5E56951C29A99E00A579DE /* UIView+SuLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SuLine.m"; sourceTree = ""; }; 93 | 2B5E56971C29AD1500A579DE /* SuMessageTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuMessageTool.h; sourceTree = ""; }; 94 | 2B5E56981C29AD1500A579DE /* SuMessageTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuMessageTool.m; sourceTree = ""; }; 95 | B1B9A2D01CD8349C004A46EF /* SuPhotoCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuPhotoCenter.h; sourceTree = ""; }; 96 | B1B9A2D11CD8349C004A46EF /* SuPhotoCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SuPhotoCenter.m; sourceTree = ""; }; 97 | B1B9A2D31CD84F02004A46EF /* UIImage+SU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+SU.h"; sourceTree = ""; }; 98 | B1B9A2D41CD84F02004A46EF /* UIImage+SU.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+SU.m"; sourceTree = ""; }; 99 | B1B9A2D61CD89E0C004A46EF /* SuBack@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "SuBack@3x.png"; sourceTree = ""; }; 100 | B1B9A2D71CD89E0C004A46EF /* SuBack@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "SuBack@2x.png"; sourceTree = ""; }; 101 | /* End PBXFileReference section */ 102 | 103 | /* Begin PBXFrameworksBuildPhase section */ 104 | 2B5834391C29978C00C86D30 /* Frameworks */ = { 105 | isa = PBXFrameworksBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXFrameworksBuildPhase section */ 112 | 113 | /* Begin PBXGroup section */ 114 | 2B5834331C29978C00C86D30 = { 115 | isa = PBXGroup; 116 | children = ( 117 | 2B58343E1C29978C00C86D30 /* SuPhotoPickerDemo */, 118 | 2B58343D1C29978C00C86D30 /* Products */, 119 | ); 120 | sourceTree = ""; 121 | }; 122 | 2B58343D1C29978C00C86D30 /* Products */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 2B58343C1C29978C00C86D30 /* SuPhotoPickerDemo.app */, 126 | ); 127 | name = Products; 128 | sourceTree = ""; 129 | }; 130 | 2B58343E1C29978C00C86D30 /* SuPhotoPickerDemo */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 2B5E56511C299EE000A579DE /* SuPhotoPicker */, 134 | 2B5834421C29978C00C86D30 /* AppDelegate.h */, 135 | 2B5834431C29978C00C86D30 /* AppDelegate.m */, 136 | 2B5834451C29978C00C86D30 /* ViewController.h */, 137 | 2B5834461C29978C00C86D30 /* ViewController.m */, 138 | 2B5834851C2998B600C86D30 /* img_add@2x.png */, 139 | 2B5834481C29978D00C86D30 /* Main.storyboard */, 140 | 2B58344B1C29978D00C86D30 /* Assets.xcassets */, 141 | 2B58344D1C29978D00C86D30 /* LaunchScreen.storyboard */, 142 | 2B5834501C29978D00C86D30 /* Info.plist */, 143 | 2B58343F1C29978C00C86D30 /* Supporting Files */, 144 | ); 145 | path = SuPhotoPickerDemo; 146 | sourceTree = ""; 147 | }; 148 | 2B58343F1C29978C00C86D30 /* Supporting Files */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 2B5834401C29978C00C86D30 /* main.m */, 152 | ); 153 | name = "Supporting Files"; 154 | sourceTree = ""; 155 | }; 156 | 2B5E56511C299EE000A579DE /* SuPhotoPicker */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 2B5E566D1C299EE000A579DE /* SuPhotoPicker.h */, 160 | 2B5E566E1C299EE000A579DE /* SuPhotoPicker.m */, 161 | 2B5E565B1C299EE000A579DE /* Controller */, 162 | 2B5E56731C299EE000A579DE /* View */, 163 | 2B5E56661C299EE000A579DE /* Model */, 164 | 2B5E566F1C299EE000A579DE /* Manager */, 165 | 2B5E56521C299EE000A579DE /* Category */, 166 | 2B5E56691C299EE000A579DE /* Resource */, 167 | ); 168 | path = SuPhotoPicker; 169 | sourceTree = ""; 170 | }; 171 | 2B5E56521C299EE000A579DE /* Category */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 2B5E568E1C29A09700A579DE /* UIView+SU.h */, 175 | 2B5E568F1C29A09700A579DE /* UIView+SU.m */, 176 | B1B9A2D31CD84F02004A46EF /* UIImage+SU.h */, 177 | B1B9A2D41CD84F02004A46EF /* UIImage+SU.m */, 178 | 2B5E56531C299EE000A579DE /* NSString+SU.h */, 179 | 2B5E56541C299EE000A579DE /* NSString+SU.m */, 180 | 2B5E56941C29A99E00A579DE /* UIView+SuLine.h */, 181 | 2B5E56951C29A99E00A579DE /* UIView+SuLine.m */, 182 | 2B5E56571C299EE000A579DE /* UIButton+SU.h */, 183 | 2B5E56581C299EE000A579DE /* UIButton+SU.m */, 184 | 2B5E56591C299EE000A579DE /* UIView+SuAnimation.h */, 185 | 2B5E565A1C299EE000A579DE /* UIView+SuAnimation.m */, 186 | ); 187 | path = Category; 188 | sourceTree = ""; 189 | }; 190 | 2B5E565B1C299EE000A579DE /* Controller */ = { 191 | isa = PBXGroup; 192 | children = ( 193 | 2B5E56721C299EE000A579DE /* SuPhotoHeader.h */, 194 | 2B5E565C1C299EE000A579DE /* SuPhotoBaseController.h */, 195 | 2B5E565D1C299EE000A579DE /* SuPhotoBaseController.m */, 196 | 2B5E565E1C299EE000A579DE /* SuPhotoAblumList.h */, 197 | 2B5E565F1C299EE000A579DE /* SuPhotoAblumList.m */, 198 | 2B5E56601C299EE000A579DE /* SuPhotoBrowser.h */, 199 | 2B5E56611C299EE000A579DE /* SuPhotoBrowser.m */, 200 | 2B5E56621C299EE000A579DE /* SuPhotoBrowser.xib */, 201 | 2B5E56631C299EE000A579DE /* SuPhotoPreviewer.h */, 202 | 2B5E56641C299EE000A579DE /* SuPhotoPreviewer.m */, 203 | 2B5E56651C299EE000A579DE /* SuPhotoPreviewer.xib */, 204 | ); 205 | path = Controller; 206 | sourceTree = ""; 207 | }; 208 | 2B5E56661C299EE000A579DE /* Model */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | 2B5E56671C299EE000A579DE /* SuAblumInfo.h */, 212 | 2B5E56681C299EE000A579DE /* SuAblumInfo.m */, 213 | ); 214 | path = Model; 215 | sourceTree = ""; 216 | }; 217 | 2B5E56691C299EE000A579DE /* Resource */ = { 218 | isa = PBXGroup; 219 | children = ( 220 | B1B9A2D61CD89E0C004A46EF /* SuBack@3x.png */, 221 | B1B9A2D71CD89E0C004A46EF /* SuBack@2x.png */, 222 | 2B5E566A1C299EE000A579DE /* SuPhoto_circle@2x.png */, 223 | 2B5E566B1C299EE000A579DE /* SuPhoto_selected@2x.png */, 224 | 2B5E566C1C299EE000A579DE /* SuPhoto_unselected@2x.png */, 225 | ); 226 | path = Resource; 227 | sourceTree = ""; 228 | }; 229 | 2B5E566F1C299EE000A579DE /* Manager */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 2B5E56701C299EE000A579DE /* SuPhotoManager.h */, 233 | 2B5E56711C299EE000A579DE /* SuPhotoManager.m */, 234 | B1B9A2D01CD8349C004A46EF /* SuPhotoCenter.h */, 235 | B1B9A2D11CD8349C004A46EF /* SuPhotoCenter.m */, 236 | 2B5E56971C29AD1500A579DE /* SuMessageTool.h */, 237 | 2B5E56981C29AD1500A579DE /* SuMessageTool.m */, 238 | ); 239 | name = Manager; 240 | path = Tool; 241 | sourceTree = ""; 242 | }; 243 | 2B5E56731C299EE000A579DE /* View */ = { 244 | isa = PBXGroup; 245 | children = ( 246 | 2B5E56741C299EE000A579DE /* SuPhotoAblumCell.h */, 247 | 2B5E56751C299EE000A579DE /* SuPhotoAblumCell.m */, 248 | 2B5E56761C299EE000A579DE /* SuPhotoAblumCell.xib */, 249 | 2B5E56771C299EE000A579DE /* SuPhotoBrowserCell.h */, 250 | 2B5E56781C299EE000A579DE /* SuPhotoBrowserCell.m */, 251 | 2B5E56791C299EE000A579DE /* SuPhotoBrowserCell.xib */, 252 | ); 253 | path = View; 254 | sourceTree = ""; 255 | }; 256 | /* End PBXGroup section */ 257 | 258 | /* Begin PBXNativeTarget section */ 259 | 2B58343B1C29978C00C86D30 /* SuPhotoPickerDemo */ = { 260 | isa = PBXNativeTarget; 261 | buildConfigurationList = 2B5834531C29978D00C86D30 /* Build configuration list for PBXNativeTarget "SuPhotoPickerDemo" */; 262 | buildPhases = ( 263 | 2B5834381C29978C00C86D30 /* Sources */, 264 | 2B5834391C29978C00C86D30 /* Frameworks */, 265 | 2B58343A1C29978C00C86D30 /* Resources */, 266 | ); 267 | buildRules = ( 268 | ); 269 | dependencies = ( 270 | ); 271 | name = SuPhotoPickerDemo; 272 | productName = SuPhotoPickerDemo; 273 | productReference = 2B58343C1C29978C00C86D30 /* SuPhotoPickerDemo.app */; 274 | productType = "com.apple.product-type.application"; 275 | }; 276 | /* End PBXNativeTarget section */ 277 | 278 | /* Begin PBXProject section */ 279 | 2B5834341C29978C00C86D30 /* Project object */ = { 280 | isa = PBXProject; 281 | attributes = { 282 | LastUpgradeCheck = 0700; 283 | ORGANIZATIONNAME = KevinSu; 284 | TargetAttributes = { 285 | 2B58343B1C29978C00C86D30 = { 286 | CreatedOnToolsVersion = 7.0; 287 | }; 288 | }; 289 | }; 290 | buildConfigurationList = 2B5834371C29978C00C86D30 /* Build configuration list for PBXProject "SuPhotoPickerDemo" */; 291 | compatibilityVersion = "Xcode 3.2"; 292 | developmentRegion = English; 293 | hasScannedForEncodings = 0; 294 | knownRegions = ( 295 | en, 296 | Base, 297 | ); 298 | mainGroup = 2B5834331C29978C00C86D30; 299 | productRefGroup = 2B58343D1C29978C00C86D30 /* Products */; 300 | projectDirPath = ""; 301 | projectRoot = ""; 302 | targets = ( 303 | 2B58343B1C29978C00C86D30 /* SuPhotoPickerDemo */, 304 | ); 305 | }; 306 | /* End PBXProject section */ 307 | 308 | /* Begin PBXResourcesBuildPhase section */ 309 | 2B58343A1C29978C00C86D30 /* Resources */ = { 310 | isa = PBXResourcesBuildPhase; 311 | buildActionMask = 2147483647; 312 | files = ( 313 | 2B5834861C2998B600C86D30 /* img_add@2x.png in Resources */, 314 | 2B58344F1C29978D00C86D30 /* LaunchScreen.storyboard in Resources */, 315 | 2B58344C1C29978D00C86D30 /* Assets.xcassets in Resources */, 316 | 2B5E56811C299EE000A579DE /* SuPhotoBrowser.xib in Resources */, 317 | 2B5E56871C299EE000A579DE /* SuPhoto_unselected@2x.png in Resources */, 318 | 2B5E568D1C299EE000A579DE /* SuPhotoBrowserCell.xib in Resources */, 319 | B1B9A2D91CD89E0C004A46EF /* SuBack@2x.png in Resources */, 320 | 2B5E56831C299EE000A579DE /* SuPhotoPreviewer.xib in Resources */, 321 | 2B5E56851C299EE000A579DE /* SuPhoto_circle@2x.png in Resources */, 322 | 2B5E56861C299EE000A579DE /* SuPhoto_selected@2x.png in Resources */, 323 | 2B5E568B1C299EE000A579DE /* SuPhotoAblumCell.xib in Resources */, 324 | B1B9A2D81CD89E0C004A46EF /* SuBack@3x.png in Resources */, 325 | 2B58344A1C29978D00C86D30 /* Main.storyboard in Resources */, 326 | ); 327 | runOnlyForDeploymentPostprocessing = 0; 328 | }; 329 | /* End PBXResourcesBuildPhase section */ 330 | 331 | /* Begin PBXSourcesBuildPhase section */ 332 | 2B5834381C29978C00C86D30 /* Sources */ = { 333 | isa = PBXSourcesBuildPhase; 334 | buildActionMask = 2147483647; 335 | files = ( 336 | 2B5834471C29978C00C86D30 /* ViewController.m in Sources */, 337 | 2B5E56841C299EE000A579DE /* SuAblumInfo.m in Sources */, 338 | B1B9A2D21CD8349C004A46EF /* SuPhotoCenter.m in Sources */, 339 | 2B5E568A1C299EE000A579DE /* SuPhotoAblumCell.m in Sources */, 340 | 2B5E567E1C299EE000A579DE /* SuPhotoBaseController.m in Sources */, 341 | 2B5E567C1C299EE000A579DE /* UIButton+SU.m in Sources */, 342 | 2B5E568C1C299EE000A579DE /* SuPhotoBrowserCell.m in Sources */, 343 | 2B5E56901C29A09700A579DE /* UIView+SU.m in Sources */, 344 | 2B5E567A1C299EE000A579DE /* NSString+SU.m in Sources */, 345 | 2B5E56961C29A99E00A579DE /* UIView+SuLine.m in Sources */, 346 | 2B5E567D1C299EE000A579DE /* UIView+SuAnimation.m in Sources */, 347 | 2B5E56891C299EE000A579DE /* SuPhotoManager.m in Sources */, 348 | 2B5834441C29978C00C86D30 /* AppDelegate.m in Sources */, 349 | 2B5E56881C299EE000A579DE /* SuPhotoPicker.m in Sources */, 350 | 2B5834411C29978C00C86D30 /* main.m in Sources */, 351 | 2B5E56801C299EE000A579DE /* SuPhotoBrowser.m in Sources */, 352 | 2B5E56991C29AD1500A579DE /* SuMessageTool.m in Sources */, 353 | 2B5E56821C299EE000A579DE /* SuPhotoPreviewer.m in Sources */, 354 | 2B5E567F1C299EE000A579DE /* SuPhotoAblumList.m in Sources */, 355 | B1B9A2D51CD84F02004A46EF /* UIImage+SU.m in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | /* End PBXSourcesBuildPhase section */ 360 | 361 | /* Begin PBXVariantGroup section */ 362 | 2B5834481C29978D00C86D30 /* Main.storyboard */ = { 363 | isa = PBXVariantGroup; 364 | children = ( 365 | 2B5834491C29978D00C86D30 /* Base */, 366 | ); 367 | name = Main.storyboard; 368 | sourceTree = ""; 369 | }; 370 | 2B58344D1C29978D00C86D30 /* LaunchScreen.storyboard */ = { 371 | isa = PBXVariantGroup; 372 | children = ( 373 | 2B58344E1C29978D00C86D30 /* Base */, 374 | ); 375 | name = LaunchScreen.storyboard; 376 | sourceTree = ""; 377 | }; 378 | /* End PBXVariantGroup section */ 379 | 380 | /* Begin XCBuildConfiguration section */ 381 | 2B5834511C29978D00C86D30 /* Debug */ = { 382 | isa = XCBuildConfiguration; 383 | buildSettings = { 384 | ALWAYS_SEARCH_USER_PATHS = NO; 385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 386 | CLANG_CXX_LIBRARY = "libc++"; 387 | CLANG_ENABLE_MODULES = YES; 388 | CLANG_ENABLE_OBJC_ARC = YES; 389 | CLANG_WARN_BOOL_CONVERSION = YES; 390 | CLANG_WARN_CONSTANT_CONVERSION = YES; 391 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 392 | CLANG_WARN_EMPTY_BODY = YES; 393 | CLANG_WARN_ENUM_CONVERSION = YES; 394 | CLANG_WARN_INT_CONVERSION = YES; 395 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 396 | CLANG_WARN_UNREACHABLE_CODE = YES; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | COPY_PHASE_STRIP = NO; 400 | DEBUG_INFORMATION_FORMAT = dwarf; 401 | ENABLE_STRICT_OBJC_MSGSEND = YES; 402 | ENABLE_TESTABILITY = YES; 403 | GCC_C_LANGUAGE_STANDARD = gnu99; 404 | GCC_DYNAMIC_NO_PIC = NO; 405 | GCC_NO_COMMON_BLOCKS = YES; 406 | GCC_OPTIMIZATION_LEVEL = 0; 407 | GCC_PREPROCESSOR_DEFINITIONS = ( 408 | "DEBUG=1", 409 | "$(inherited)", 410 | ); 411 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 412 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 413 | GCC_WARN_UNDECLARED_SELECTOR = YES; 414 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 415 | GCC_WARN_UNUSED_FUNCTION = YES; 416 | GCC_WARN_UNUSED_VARIABLE = YES; 417 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 418 | MTL_ENABLE_DEBUG_INFO = YES; 419 | ONLY_ACTIVE_ARCH = YES; 420 | SDKROOT = iphoneos; 421 | TARGETED_DEVICE_FAMILY = "1,2"; 422 | }; 423 | name = Debug; 424 | }; 425 | 2B5834521C29978D00C86D30 /* Release */ = { 426 | isa = XCBuildConfiguration; 427 | buildSettings = { 428 | ALWAYS_SEARCH_USER_PATHS = NO; 429 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 430 | CLANG_CXX_LIBRARY = "libc++"; 431 | CLANG_ENABLE_MODULES = YES; 432 | CLANG_ENABLE_OBJC_ARC = YES; 433 | CLANG_WARN_BOOL_CONVERSION = YES; 434 | CLANG_WARN_CONSTANT_CONVERSION = YES; 435 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 436 | CLANG_WARN_EMPTY_BODY = YES; 437 | CLANG_WARN_ENUM_CONVERSION = YES; 438 | CLANG_WARN_INT_CONVERSION = YES; 439 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 440 | CLANG_WARN_UNREACHABLE_CODE = YES; 441 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 442 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 443 | COPY_PHASE_STRIP = NO; 444 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 445 | ENABLE_NS_ASSERTIONS = NO; 446 | ENABLE_STRICT_OBJC_MSGSEND = YES; 447 | GCC_C_LANGUAGE_STANDARD = gnu99; 448 | GCC_NO_COMMON_BLOCKS = YES; 449 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 450 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 451 | GCC_WARN_UNDECLARED_SELECTOR = YES; 452 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 453 | GCC_WARN_UNUSED_FUNCTION = YES; 454 | GCC_WARN_UNUSED_VARIABLE = YES; 455 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 456 | MTL_ENABLE_DEBUG_INFO = NO; 457 | SDKROOT = iphoneos; 458 | TARGETED_DEVICE_FAMILY = "1,2"; 459 | VALIDATE_PRODUCT = YES; 460 | }; 461 | name = Release; 462 | }; 463 | 2B5834541C29978D00C86D30 /* Debug */ = { 464 | isa = XCBuildConfiguration; 465 | buildSettings = { 466 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 467 | INFOPLIST_FILE = SuPhotoPickerDemo/Info.plist; 468 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 469 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 470 | PRODUCT_BUNDLE_IDENTIFIER = com.kevinSu.SuPhotoPickerDemo; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | }; 473 | name = Debug; 474 | }; 475 | 2B5834551C29978D00C86D30 /* Release */ = { 476 | isa = XCBuildConfiguration; 477 | buildSettings = { 478 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 479 | INFOPLIST_FILE = SuPhotoPickerDemo/Info.plist; 480 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 481 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 482 | PRODUCT_BUNDLE_IDENTIFIER = com.kevinSu.SuPhotoPickerDemo; 483 | PRODUCT_NAME = "$(TARGET_NAME)"; 484 | }; 485 | name = Release; 486 | }; 487 | /* End XCBuildConfiguration section */ 488 | 489 | /* Begin XCConfigurationList section */ 490 | 2B5834371C29978C00C86D30 /* Build configuration list for PBXProject "SuPhotoPickerDemo" */ = { 491 | isa = XCConfigurationList; 492 | buildConfigurations = ( 493 | 2B5834511C29978D00C86D30 /* Debug */, 494 | 2B5834521C29978D00C86D30 /* Release */, 495 | ); 496 | defaultConfigurationIsVisible = 0; 497 | defaultConfigurationName = Release; 498 | }; 499 | 2B5834531C29978D00C86D30 /* Build configuration list for PBXNativeTarget "SuPhotoPickerDemo" */ = { 500 | isa = XCConfigurationList; 501 | buildConfigurations = ( 502 | 2B5834541C29978D00C86D30 /* Debug */, 503 | 2B5834551C29978D00C86D30 /* Release */, 504 | ); 505 | defaultConfigurationIsVisible = 0; 506 | defaultConfigurationName = Release; 507 | }; 508 | /* End XCConfigurationList section */ 509 | }; 510 | rootObject = 2B5834341C29978C00C86D30 /* Project object */; 511 | } 512 | --------------------------------------------------------------------------------