├── Screenshots └── Untitled.gif ├── DNImagePicker ├── DNImagePicker │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Icon-29@2x.png │ │ │ ├── Icon-29@3x.png │ │ │ ├── Icon-40@2x.png │ │ │ ├── Icon-40@3x.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ ├── Default@2x.png │ │ │ ├── Default-1334@2x.png │ │ │ ├── Default-2208@3x.png │ │ │ ├── Default-568h@2x-2.png │ │ │ ├── Default-2208_lan@3x.png │ │ │ └── Contents.json │ ├── Resources │ │ ├── imageResources.xcassets │ │ │ ├── Contents.json │ │ │ └── images │ │ │ │ ├── back_normal.imageset │ │ │ │ ├── back_normal.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── back_highlight.imageset │ │ │ │ ├── back_highlight.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── image_unAuthorized.imageset │ │ │ │ ├── image_unAuthorized.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── photo_check_default.imageset │ │ │ │ ├── photo_check_default.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── picker_alert_sigh.imageset │ │ │ │ ├── picker_alert_sigh@2x.png │ │ │ │ └── Contents.json │ │ │ │ ├── photo_check_selected.imageset │ │ │ │ ├── photo_check_selected.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── photo_full_image_selected.imageset │ │ │ │ ├── photo_full_image_selected.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── picker_image_placeholder.imageset │ │ │ │ ├── picker_image_placeholder@2x.png │ │ │ │ └── Contents.json │ │ │ │ ├── photo_full_image_unselected.imageset │ │ │ │ ├── photo_full_image_unselected.pdf │ │ │ │ └── Contents.json │ │ │ │ ├── assets_placeholder_picture.imageset │ │ │ │ ├── assets_placeholder_picture@2x.png │ │ │ │ └── Contents.json │ │ │ │ └── compose_photograph_background.imageset │ │ │ │ ├── compose_photograph_background@2x.png │ │ │ │ └── Contents.json │ │ ├── zh-Hans.lproj │ │ │ └── DNImagePicker.strings │ │ └── en.lproj │ │ │ └── DNImagePicker.strings │ ├── ViewController.h │ ├── DNImagePicker.h │ ├── Classes │ │ ├── Views │ │ │ ├── DNBadgeLabel.h │ │ │ ├── DNAlbumCell.h │ │ │ ├── DNUnAuthorizedTipsView.h │ │ │ ├── DNSendButton.h │ │ │ ├── DNBrowserCell.h │ │ │ ├── DNFullImageButton.h │ │ │ ├── DNTapDetectingImageView.h │ │ │ ├── DNAssetsViewCell.h │ │ │ ├── DNTapDetectingImageView.m │ │ │ ├── DNBadgeLabel.m │ │ │ ├── DNAlbumCell.m │ │ │ ├── DNUnAuthorizedTipsView.m │ │ │ ├── DNSendButton.m │ │ │ ├── DNFullImageButton.m │ │ │ ├── DNBrowserCell.m │ │ │ └── DNAssetsViewCell.m │ │ ├── Controllers │ │ │ ├── DNAlbumTableViewController.h │ │ │ ├── DNImageFlowViewController.h │ │ │ ├── DNImageFetchOperation.h │ │ │ ├── DNPhotoBrowser.h │ │ │ ├── DNImagePickerController.h │ │ │ ├── DNImageFetchOperation.m │ │ │ ├── DNAlbumTableViewController.m │ │ │ ├── DNImagePickerController.m │ │ │ ├── DNImageFlowViewController.m │ │ │ └── DNPhotoBrowser.m │ │ ├── Models │ │ │ ├── DNAsset.h │ │ │ ├── DNAsset.m │ │ │ ├── DNAlbum.h │ │ │ └── DNAlbum.m │ │ ├── DNImagePickerHelper.h │ │ └── DNImagePickerHelper.m │ ├── AppDelegate.h │ ├── Support │ │ ├── UIColor+Hex.h │ │ ├── UIView+DNImagePicker.h │ │ ├── UIViewController+DNImagePicker.h │ │ ├── UIColor+Hex.m │ │ ├── UIView+DNImagePicker.m │ │ └── UIViewController+DNImagePicker.m │ ├── main.m │ ├── Info.plist │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── ViewController.m │ └── AppDelegate.m ├── DNImagePicker.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcuserdata │ │ └── Dennis.xcuserdatad │ │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── DNImagePicker.xcscheme │ └── project.pbxproj └── DNImagePickerDemo │ ├── InfoViewController.h │ ├── CollectionViewCell.h │ ├── CollectionViewController.h │ ├── CollectionViewCell.m │ ├── InfoViewController.m │ └── CollectionViewController.m ├── README.md └── .gitignore /Screenshots/Untitled.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/Screenshots/Untitled.gif -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-1334@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-1334@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-2208@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-2208@3x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x-2.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-2208_lan@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Default-2208_lan@3x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/back_normal.imageset/back_normal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/back_normal.imageset/back_normal.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/back_highlight.imageset/back_highlight.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/back_highlight.imageset/back_highlight.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/image_unAuthorized.imageset/image_unAuthorized.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/image_unAuthorized.imageset/image_unAuthorized.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_check_default.imageset/photo_check_default.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_check_default.imageset/photo_check_default.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/picker_alert_sigh.imageset/picker_alert_sigh@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/picker_alert_sigh.imageset/picker_alert_sigh@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_check_selected.imageset/photo_check_selected.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_check_selected.imageset/photo_check_selected.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/back_normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "back_normal.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/back_highlight.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "back_highlight.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/image_unAuthorized.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "image_unAuthorized.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_full_image_selected.imageset/photo_full_image_selected.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_full_image_selected.imageset/photo_full_image_selected.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/picker_image_placeholder.imageset/picker_image_placeholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/picker_image_placeholder.imageset/picker_image_placeholder@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_check_default.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "photo_check_default.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_check_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "photo_check_selected.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_full_image_unselected.imageset/photo_full_image_unselected.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_full_image_unselected.imageset/photo_full_image_unselected.pdf -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/5. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePickerDemo/InfoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // InfoViewController.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface InfoViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/DNImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNImagePicker.h 3 | // ImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/5. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DNImagePickerHelper.h" 11 | #import "DNAsset.h" 12 | #import "DNAlbum.h" 13 | 14 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/assets_placeholder_picture.imageset/assets_placeholder_picture@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/assets_placeholder_picture.imageset/assets_placeholder_picture@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_full_image_selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "photo_full_image_selected.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/compose_photograph_background.imageset/compose_photograph_background@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dennisxiaoding/DNImagePicker/HEAD/DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/compose_photograph_background.imageset/compose_photograph_background@2x.png -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/photo_full_image_unselected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "photo_full_image_unselected.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNBadgeLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNBadgeLabel.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/27. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DNBadgeLabel : UIView 12 | 13 | @property (nonatomic, copy) NSString *title; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/5. 6 | // Copyright © 2016年 Dennis. 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 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNAlbumTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNAlbumTableViewController.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/10. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DNAlbumTableViewController : UITableViewController 12 | 13 | - (void)showUnAuthorizedTipsView; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Support/UIColor+Hex.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Hex.h 3 | // imoffice 4 | // 5 | // Created by zhanghao on 14-9-11. 6 | // Copyright (c) 2014年 IMO. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColor (Hex) 12 | 13 | + (UIColor *)dn_hexStringToColor:(NSString *)stringToConvert; 14 | + (UIColor *)dn_colorWithHexNumber:(NSUInteger)hexColor; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/5. 6 | // Copyright © 2016年 Dennis. 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 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNAlbumCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNAlbumCell.h 3 | // DNImagePicker 4 | // 5 | // Created by DingXiao on 16/8/29. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DNAlbumCell : UITableViewCell 12 | 13 | @property (nonatomic, strong) UIImageView *postImageView; 14 | @property (nonatomic, strong) UILabel *titleLabel; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNUnAuthorizedTipsView.h: -------------------------------------------------------------------------------- 1 | // 2 | // UnAuthorizedTipsView.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/18. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DNUnAuthorizedTipsView : UIView 12 | @property (nonatomic, strong) UIImageView *imageView; 13 | @property (nonatomic, strong) UILabel *label; 14 | @end 15 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePickerDemo/CollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewCell.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CollectionViewCell : UICollectionViewCell 12 | @property (weak, nonatomic) IBOutlet UIImageView *imageView; 13 | @property (weak, nonatomic) IBOutlet UILabel *textLabel; 14 | @end 15 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePickerDemo/CollectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CollectionViewController : UICollectionViewController 12 | 13 | @property (nonatomic, strong) NSArray *imageArray; 14 | @property (nonatomic, assign) BOOL isFullImage; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNSendButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNSendButton.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/24. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DNSendButton : UIView 12 | 13 | @property (nonatomic, copy) NSString *badgeValue; 14 | 15 | - (instancetype)initWithFrame:(CGRect)frame; 16 | 17 | - (void)addTaget:(id)target action:(SEL)action; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/zh-Hans.lproj/DNImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | DNImagePicker.strings 3 | ImagePicker 4 | 5 | Created by DingXiao on 15/3/4. 6 | Copyright (c) 2015年 Dennis. All rights reserved. 7 | */ 8 | "albumTitle" = "照片"; 9 | "cancel" = "取消"; 10 | "send" = "发送"; 11 | "preview" = "预览"; 12 | "fullImage" = "原图"; 13 | "alertTitle" = "提示"; 14 | "alertContent" = "不能超过9张图片"; 15 | "alertButton" = "确定"; 16 | "UnAuthorizedTip" = "请在iPhone的\"设置-隐私-照片\"选项中,\n允许%@访问你的手机相册"; -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/picker_alert_sigh.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "picker_alert_sigh@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNBrowserCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNBrowserCell.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/28. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | @class DNAsset; 11 | @class DNPhotoBrowser; 12 | 13 | @interface DNBrowserCell : UICollectionViewCell 14 | 15 | @property (nonatomic, weak, nullable) DNPhotoBrowser *photoBrowser; 16 | 17 | @property (nonatomic, strong, nullable) DNAsset *asset; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/picker_image_placeholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "picker_image_placeholder@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNImageFlowViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNImageFlowViewController.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/11. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | @class DNAlbum; 11 | 12 | @interface DNImageFlowViewController : UIViewController 13 | 14 | - (instancetype)initWithAlbumIdentifier:(NSString *)albumIdentifier; 15 | 16 | - (instancetype)initWithAblum:(DNAlbum *)album; 17 | 18 | 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/assets_placeholder_picture.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "assets_placeholder_picture@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/imageResources.xcassets/images/compose_photograph_background.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "compose_photograph_background@2x.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Resources/en.lproj/DNImagePicker.strings: -------------------------------------------------------------------------------- 1 | /* 2 | DNImagePicker.strings 3 | ImagePicker 4 | 5 | Created by DingXiao on 15/3/4. 6 | Copyright (c) 2015年 Dennis. All rights reserved. 7 | */ 8 | "albumTitle" = "Photos"; 9 | "cancel" = "Cancel"; 10 | "send" = "send"; 11 | "preview" = "preview"; 12 | "fullImage" = "Full Image"; 13 | "alertTitle" = "Tips"; 14 | "alertContent" = "Can not select more than 9 photos"; 15 | "alertButton" = "OK"; 16 | "UnAuthorizedTip" = "Allow %@ to access your album in \"Settings\"->\"Privacy\"->\"Photos\""; -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNFullImageButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNFullImageButton.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/2. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface DNFullImageButton : UIView 12 | 13 | @property (nonatomic, assign) BOOL selected; 14 | @property (nonatomic, copy) NSString *text; 15 | 16 | - (instancetype)initWithFrame:(CGRect)frame; 17 | - (void)addTarget:(id)target action:(SEL)action; 18 | - (void)shouldAnimating:(BOOL)animate; 19 | @end 20 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePickerDemo/CollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewCell.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "CollectionViewCell.h" 10 | 11 | @implementation CollectionViewCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | self.textLabel.backgroundColor = [UIColor colorWithRed:0 green:162.0f/255.0f blue:255.0f/255.0f alpha:0.5]; 16 | } 17 | 18 | - (void)prepareForReuse { 19 | self.imageView.image = nil; 20 | self.textLabel.text = nil; 21 | } 22 | 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Models/DNAsset.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNAsset.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | @class PHAsset; 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | NS_CLASS_AVAILABLE_IOS(8.0) @interface DNAsset : NSObject 15 | 16 | @property (nonatomic, copy) NSString *assetIdentifier; 17 | @property (nonatomic, readonly) PHAsset *asset; 18 | @property (nonatomic, strong) UIImage *cacheImage; 19 | 20 | + (DNAsset *)assetWithPHAsset:(PHAsset *)asset; 21 | 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker.xcodeproj/xcuserdata/Dennis.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DNImagePicker.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 952600AC1D2B9D4100080227 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DNImagePicker 2 | A imagePicker functioned like wechat. 3 | 4 | DNImagePicker has a swift version [DXPhotoPickerController](https://github.com/AwesomeDennis/DXPhotoPicker) 5 | 6 | Thanks [JKImagePicker](https://github.com/pjk1129/JKImagePicker) 7 | and [mwaterfall/MWPhotoBrowser](https://github.com/mwaterfall/MWPhotoBrowser) 8 | 9 | ## RELEASE 10 | * [DNImagePicker V2.0](https://github.com/AwesomeDennis/DNImagePicker/releases/tag/V2.0) supports both `AssetsLibrary` and `PhotosFramework`. When iOS > 8.0 will use `PhotosFramework` automatically. 11 | 12 | ## USEAGE 13 | * Add AssetsLibrary.framework 14 | 15 | ## DEMO 16 | ![image](https://github.com/DennisXiaoDing/DNImagePicker/blob/master/Screenshots/Untitled.gif) 17 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Support/UIView+DNImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+DNImagePicker.h 3 | // JKImagePicker 4 | // 5 | // Created by DingXiao on 15/2/11. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (DNImagePicker) 12 | 13 | @property (nonatomic) CGFloat left; 14 | @property (nonatomic) CGFloat top; 15 | @property (nonatomic) CGFloat right; 16 | @property (nonatomic) CGFloat bottom; 17 | @property (nonatomic) CGFloat width; 18 | @property (nonatomic) CGFloat height; 19 | 20 | @property (nonatomic) CGFloat centerX; 21 | @property (nonatomic) CGFloat centerY; 22 | 23 | @property (nonatomic) CGPoint origin; 24 | @property (nonatomic) CGSize size; 25 | @end 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | 28 | ImagePicker.xcodeproj/project.xcworkspace/xcuserdata/Dennis.xcuserdatad/UserInterfaceState.xcuserstate 29 | 30 | .DS_Store 31 | 32 | *.xcuserstate 33 | 34 | *.xcuserstate 35 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNTapDetectingImageView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNTapDetectingImageView.h 3 | // ImagePicker 4 | // 5 | // Created by Ding Xiao on 16/1/8. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // In order to avoid confilict to MWTapDetectingImageView, Simplifing it to this class 8 | 9 | #import 10 | 11 | @protocol DNTapDetectingImageViewDelegate 12 | 13 | @optional 14 | 15 | - (void)imageView:(UIImageView *)imageView singleTapDetected:(UITouch *)touch; 16 | - (void)imageView:(UIImageView *)imageView doubleTapDetected:(UITouch *)touch; 17 | - (void)imageView:(UIImageView *)imageView tripleTapDetected:(UITouch *)touch; 18 | 19 | @end 20 | 21 | @interface DNTapDetectingImageView : UIImageView 22 | @property (nonatomic, weak) id tapDelegate; 23 | @end 24 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNImageFetchOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNImageFetchOperation.h 3 | // DNImagePicker 4 | // 5 | // Created by dingxiao on 2018/10/9. 6 | // Copyright © 2018 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | @class PHAsset; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | NS_CLASS_AVAILABLE_IOS(8.0) @interface DNImageFetchOperation : NSOperation 16 | 17 | @property (nonatomic, strong, nullable) PHAsset *asset; 18 | 19 | @property (assign, nonatomic, getter = isExecuting) BOOL executing; 20 | @property (assign, nonatomic, getter = isFinished) BOOL finished; 21 | 22 | - (instancetype)initWithAsset:(PHAsset *)asset; 23 | 24 | - (void)fetchImageWithTargetSize:(CGSize)size 25 | needHighQuality:(BOOL)isHighQuality 26 | imageResutHandler:(void (^)(UIImage * image))handler; 27 | 28 | @end 29 | 30 | NS_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNAssetsViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNAssetsViewCell.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/11. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DNAssetsViewCell; 12 | @class DNAsset; 13 | 14 | @protocol DNAssetsViewCellDelegate 15 | @optional 16 | 17 | - (void)didSelectItemAssetsViewCell:(nonnull DNAssetsViewCell *)assetsCell; 18 | - (void)didDeselectItemAssetsViewCell:(nonnull DNAssetsViewCell *)assetsCell; 19 | @end 20 | 21 | @interface DNAssetsViewCell : UICollectionViewCell 22 | 23 | @property (nonatomic, readonly, nonnull) UIImageView *imageView; 24 | @property (nonatomic, strong, nonnull) DNAsset *asset; 25 | @property (nonatomic, assign) BOOL isSelected; 26 | @property (nonatomic, weak, nullable) id delegate; 27 | 28 | - (void)fillWithAsset:(nonnull DNAsset *)asset isSelected:(BOOL)seleted; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "29x29", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-29@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "29x29", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-29@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "40x40", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-40@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "40x40", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-40@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "60x60", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-60@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "60x60", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-60@3x.png", 37 | "scale" : "3x" 38 | } 39 | ], 40 | "info" : { 41 | "version" : 1, 42 | "author" : "xcode" 43 | } 44 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Models/DNAsset.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNAsset.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNAsset.h" 10 | #import 11 | @interface DNAsset () 12 | @property (nonatomic, strong, nullable) PHAsset *asset; 13 | @end 14 | 15 | 16 | @implementation DNAsset 17 | 18 | - (instancetype)init { 19 | self = [super init]; 20 | if (self) { 21 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarningInAssets) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; 22 | } 23 | return self; 24 | } 25 | 26 | 27 | + (DNAsset *)assetWithPHAsset:(PHAsset *)asset { 28 | DNAsset *a = [[DNAsset alloc] init]; 29 | if (!asset) { 30 | return a; 31 | } 32 | a.asset = asset; 33 | a.assetIdentifier = asset.localIdentifier; 34 | return a; 35 | } 36 | 37 | - (void)didReceiveMemoryWarningInAssets { 38 | _cacheImage = nil; 39 | } 40 | 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Models/DNAlbum.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNAlbum.h 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/6. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | @class PHAssetCollection; 11 | @class PHFetchResult; 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | NS_AVAILABLE_IOS(8.0) @interface DNAlbum : NSObject 16 | 17 | + (DNAlbum *)albumWithAssetCollection:(PHAssetCollection *)collection 18 | results:(PHFetchResult *)results; 19 | 20 | /* 21 | @note use this model to store the album's 'result, 'count, 'name, 'startDate 22 | to avoid request and reserve too much times. 23 | */ 24 | @property (nonatomic, strong, nullable) PHFetchResult *results; 25 | 26 | @property (nonatomic, copy, nullable) NSString *identifier; 27 | 28 | @property (nonatomic, copy, nullable) NSString *albumTitle; 29 | 30 | @property (nonatomic, assign) NSInteger count; 31 | 32 | @property (nonatomic, readonly, nullable) NSAttributedString *albumAttributedString; 33 | 34 | - (void)fetchPostImageWithSize:(CGSize)size imageResutHandler:(void (^)(UIImage *))handler; 35 | 36 | @end 37 | 38 | 39 | NS_ASSUME_NONNULL_END 40 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePickerDemo/InfoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // InfoViewController.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "InfoViewController.h" 10 | 11 | @interface InfoViewController () 12 | @property (weak, nonatomic) IBOutlet UIButton *weiboButton; 13 | @property (weak, nonatomic) IBOutlet UIButton *twitterBt; 14 | - (IBAction)weiboAction:(id)sender; 15 | - (IBAction)twitterAction:(id)sender; 16 | 17 | @end 18 | 19 | @implementation InfoViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.title = NSLocalizedString(@"infoTitle", "infotitle"); 24 | // Do any additional setup after loading the view. 25 | } 26 | 27 | - (void)didReceiveMemoryWarning { 28 | [super didReceiveMemoryWarning]; 29 | // Dispose of any resources that can be recreated. 30 | } 31 | - (IBAction)weiboAction:(id)sender { 32 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://weibo.com/GreatDingXiao"]]; 33 | } 34 | 35 | - (IBAction)twitterAction:(id)sender { 36 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://twitter.com/Ding__Xiao"]]; 37 | } 38 | @end 39 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNPhotoBrowser.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNPhotoBrowserViewController.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/28. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class DNImageFlowViewController; 12 | @class DNPhotoBrowser; 13 | @class DNAsset; 14 | @protocol DNPhotoBrowserDelegate 15 | 16 | @required 17 | - (void)sendImagesFromPhotobrowser:(DNPhotoBrowser *)photoBrowse currentAsset:(DNAsset *)asset; 18 | - (NSUInteger)seletedPhotosNumberInPhotoBrowser:(DNPhotoBrowser *)photoBrowser; 19 | - (BOOL)photoBrowser:(DNPhotoBrowser *)photoBrowser currentPhotoAssetIsSeleted:(DNAsset *)asset; 20 | - (BOOL)photoBrowser:(DNPhotoBrowser *)photoBrowser seletedAsset:(DNAsset *)asset; 21 | - (void)photoBrowser:(DNPhotoBrowser *)photoBrowser deseletedAsset:(DNAsset *)asset; 22 | - (void)photoBrowser:(DNPhotoBrowser *)photoBrowser seleteFullImage:(BOOL)fullImage; 23 | @end 24 | 25 | @interface DNPhotoBrowser : UIViewController 26 | 27 | @property (nonatomic, weak) id delegate; 28 | 29 | - (instancetype)initWithPhotos:(NSArray *)photosArray 30 | currentIndex:(NSInteger)index 31 | fullImage:(BOOL)isFullImage; 32 | 33 | - (void)hideControls; 34 | - (void)toggleControls; 35 | @end 36 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "736h", 7 | "filename" : "Default-2208@3x.png", 8 | "minimum-system-version" : "8.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default-2208_lan@3x.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "landscape", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "667h", 25 | "filename" : "Default-1334@2x.png", 26 | "minimum-system-version" : "8.0", 27 | "orientation" : "portrait", 28 | "scale" : "2x" 29 | }, 30 | { 31 | "orientation" : "portrait", 32 | "idiom" : "iphone", 33 | "filename" : "Default@2x.png", 34 | "extent" : "full-screen", 35 | "minimum-system-version" : "7.0", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "extent" : "full-screen", 40 | "idiom" : "iphone", 41 | "subtype" : "retina4", 42 | "filename" : "Default-568h@2x-2.png", 43 | "minimum-system-version" : "7.0", 44 | "orientation" : "portrait", 45 | "scale" : "2x" 46 | } 47 | ], 48 | "info" : { 49 | "version" : 1, 50 | "author" : "xcode" 51 | } 52 | } -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNImagePickerController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNImagePickerController.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/10. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @class ALAssetsLibrary; 13 | @class ALAssetsFilter; 14 | FOUNDATION_EXTERN NSString *kDNImagePickerStoredGroupKey; 15 | typedef NS_ENUM(NSUInteger, DNImagePickerFilterType) { 16 | DNImagePickerFilterTypeNone, 17 | DNImagePickerFilterTypePhotos, 18 | DNImagePickerFilterTypeVideos, 19 | }; 20 | 21 | 22 | 23 | @class DNImagePickerController; 24 | @protocol DNImagePickerControllerDelegate 25 | @optional 26 | /** 27 | * imagePickerController‘s seleted photos 28 | * 29 | * @param imagePickerController 30 | * @param imageAssets the seleted photos packaged DNAsset type instances 31 | * @param fullImage if the value is yes, the seleted photos is full image 32 | */ 33 | - (void)dnImagePickerController:(DNImagePickerController *)imagePicker 34 | sendImages:(NSArray *)imageAssets 35 | isFullImage:(BOOL)fullImage; 36 | 37 | - (void)dnImagePickerControllerDidCancel:(DNImagePickerController *)imagePicker; 38 | @end 39 | 40 | 41 | @interface DNImagePickerController : UINavigationController 42 | 43 | @property (nonatomic, assign) DNImagePickerFilterType filterType; 44 | @property (nonatomic, weak) id imagePickerDelegate; 45 | 46 | //@property (nonatomic, readonly) ALAssetsLibrary *assetsLibrary; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | DNImagePicker 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSCameraUsageDescription 28 | 需要访问您的相机 29 | NSPhotoLibraryAddUsageDescription 30 | 需要访问你的相册 31 | NSPhotoLibraryUsageDescription 32 | 为了精准找到附近可连接WiFi,请选择允许 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UIRequiredDeviceCapabilities 38 | 39 | armv7 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/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 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Support/UIViewController+DNImagePicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+DNImagePicker.h 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/10. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | typedef NS_ENUM(NSInteger, DNImagePickerNavigationBarPosition) { 11 | DNImagePickerNavigationBarPositionLeft, 12 | DNImagePickerNavigationBarPositionRight 13 | }; 14 | 15 | 16 | @interface UIViewController (DNImagePicker) 17 | 18 | /** 19 | * 根据image创建导航栏左右item 20 | * 21 | * @param position 左右位置 22 | * @param normalImage normal状态image 23 | * @param highlightImage highlight状态image 24 | * @param action 动作 25 | */ 26 | - (void)createBarButtonItemAtPosition:(DNImagePickerNavigationBarPosition)position 27 | statusNormalImage:(UIImage *)normalImage 28 | statusHighlightImage:(UIImage *)highlightImage 29 | action:(SEL)action; 30 | 31 | /** 32 | * 根据文本创建导航栏左右item 33 | * 34 | * @param position 左右位置 35 | * @param text 文本 36 | * @param action 动作 37 | */ 38 | - (void)createBarButtonItemAtPosition:(DNImagePickerNavigationBarPosition)position 39 | text:(NSString *)text 40 | action:(SEL)action; 41 | 42 | /** 43 | * 根据image创建导航栏左item 44 | * 45 | * @param normalImage normal状态image 46 | * @param highlightImage highlight状态image 47 | * @param title 返回按钮title 48 | * @param action 动作 49 | */ 50 | - (void)createBackBarButtonItemStatusNormalImage:(UIImage *)normalImage 51 | statusHighlightImage:(UIImage *)highlightImage 52 | withTitle:(NSString *)title 53 | action:(SEL)action; 54 | 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/5. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "DNImagePickerController.h" 12 | #import "CollectionViewController.h" 13 | 14 | @interface ViewController () 15 | @property (nonatomic, strong) NSMutableArray *assetsArray; 16 | 17 | @property (nonatomic, weak) IBOutlet UIButton *button; 18 | - (IBAction)buttonAction:(id)sender; 19 | @end 20 | 21 | @implementation ViewController 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | [self.button setTitle:NSLocalizedString(@"add", @"add") forState:UIControlStateNormal]; 26 | } 27 | 28 | - (void)buttonAction:(id)sender { 29 | DNImagePickerController *imagePicker = [[DNImagePickerController alloc] init]; 30 | imagePicker.imagePickerDelegate = self; 31 | [self presentViewController:imagePicker animated:YES completion:nil]; 32 | } 33 | 34 | #pragma mark - DNImagePickerControllerDelegate 35 | 36 | - (void)dnImagePickerController:(DNImagePickerController *)imagePickerController 37 | sendImages:(NSArray *)imageAssets 38 | isFullImage:(BOOL)fullImage { 39 | self.assetsArray = [NSMutableArray arrayWithArray:imageAssets]; 40 | CollectionViewController *collectionVC = [self.storyboard instantiateViewControllerWithIdentifier:@"CollectionViewController"]; 41 | collectionVC.isFullImage = fullImage; 42 | collectionVC.imageArray = imageAssets; 43 | [self.navigationController pushViewController:collectionVC animated:YES]; 44 | } 45 | 46 | - (void)dnImagePickerControllerDidCancel:(DNImagePickerController *)imagePicker { 47 | [imagePicker dismissViewControllerAnimated:YES completion:nil]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Support/UIColor+Hex.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+Hex.m 3 | // imoffice 4 | // 5 | // Created by zhanghao on 14-9-11. 6 | // Copyright (c) 2014年 IMO. All rights reserved. 7 | // 8 | 9 | #import "UIColor+Hex.h" 10 | 11 | @implementation UIColor (Hex) 12 | 13 | + (UIColor *)dn_hexStringToColor:(NSString *)stringToConvert { 14 | NSString *cString = [[stringToConvert stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; 15 | 16 | if ([cString length] < 6) 17 | return [UIColor blackColor]; 18 | 19 | if ([cString hasPrefix:@"0X"]) 20 | cString = [cString substringFromIndex:2]; 21 | 22 | if ([cString hasPrefix:@"#"]) 23 | cString = [cString substringFromIndex:1]; 24 | 25 | if ([cString length] != 6) 26 | return [UIColor blackColor]; 27 | 28 | NSRange range; 29 | range.location = 0; 30 | range.length = 2; 31 | 32 | NSString *rString = [cString substringWithRange:range]; 33 | range.location = 2; 34 | 35 | NSString *gString = [cString substringWithRange:range]; 36 | range.location = 4; 37 | 38 | NSString *bString = [cString substringWithRange:range]; 39 | 40 | unsigned int r, g, b; 41 | 42 | [[NSScanner scannerWithString:rString] scanHexInt:&r]; 43 | [[NSScanner scannerWithString:gString] scanHexInt:&g]; 44 | [[NSScanner scannerWithString:bString] scanHexInt:&b]; 45 | 46 | return [UIColor colorWithRed:((float) r / 255.0f) 47 | green:((float) g / 255.0f) 48 | blue:((float) b / 255.0f) 49 | alpha:1.0f]; 50 | } 51 | 52 | + (UIColor *)dn_colorWithHexNumber:(NSUInteger)hexColor { 53 | float r = ((hexColor>>16) & 0xFF) / 255.0f; 54 | float g = ((hexColor>>8) & 0xFF) / 255.0f; 55 | float b = (hexColor & 0xFF) / 255.0f; 56 | return [UIColor colorWithRed:r green:g blue:b alpha:1.0f]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNTapDetectingImageView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNTapDetectingImageView.m 3 | // ImagePicker 4 | // 5 | // Created by Ding Xiao on 16/1/8. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNTapDetectingImageView.h" 10 | 11 | @implementation DNTapDetectingImageView 12 | 13 | - (id)initWithFrame:(CGRect)frame { 14 | if ((self = [super initWithFrame:frame])) { 15 | self.userInteractionEnabled = YES; 16 | } 17 | return self; 18 | } 19 | 20 | - (id)initWithImage:(UIImage *)image { 21 | if ((self = [super initWithImage:image])) { 22 | self.userInteractionEnabled = YES; 23 | } 24 | return self; 25 | } 26 | 27 | - (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage { 28 | if ((self = [super initWithImage:image highlightedImage:highlightedImage])) { 29 | self.userInteractionEnabled = YES; 30 | } 31 | return self; 32 | } 33 | 34 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 35 | UITouch *touch = [touches anyObject]; 36 | NSUInteger tapCount = touch.tapCount; 37 | switch (tapCount) { 38 | case 1: 39 | [self handleSingleTap:touch]; 40 | break; 41 | case 2: 42 | [self handleDoubleTap:touch]; 43 | break; 44 | case 3: 45 | [self handleTripleTap:touch]; 46 | break; 47 | default: 48 | break; 49 | } 50 | [[self nextResponder] touchesEnded:touches withEvent:event]; 51 | } 52 | 53 | - (void)handleSingleTap:(UITouch *)touch { 54 | if ([_tapDelegate respondsToSelector:@selector(imageView:singleTapDetected:)]) 55 | [_tapDelegate imageView:self singleTapDetected:touch]; 56 | } 57 | 58 | - (void)handleDoubleTap:(UITouch *)touch { 59 | if ([_tapDelegate respondsToSelector:@selector(imageView:doubleTapDetected:)]) 60 | [_tapDelegate imageView:self doubleTapDetected:touch]; 61 | } 62 | 63 | - (void)handleTripleTap:(UITouch *)touch { 64 | if ([_tapDelegate respondsToSelector:@selector(imageView:tripleTapDetected:)]) 65 | [_tapDelegate imageView:self tripleTapDetected:touch]; 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/5. 6 | // Copyright © 2016年 Dennis. 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 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePickerDemo/CollectionViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/6. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "CollectionViewController.h" 10 | #import "CollectionViewCell.h" 11 | #import "DNImagePicker.h" 12 | 13 | 14 | #define kSizeThumbnailCollectionView ceil(self.view.frame.size.width/2) 15 | 16 | @interface CollectionViewController () 17 | @end 18 | 19 | @implementation CollectionViewController 20 | 21 | static NSString * const reuseIdentifier = @"Cell"; 22 | 23 | - (void)viewDidLoad { 24 | [super viewDidLoad]; 25 | self.title = NSLocalizedString(@"seletedImageTitle", @"seletedImage"); 26 | self.collectionView.alwaysBounceVertical = YES; 27 | } 28 | #pragma mark 29 | - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { 30 | return 1; 31 | } 32 | 33 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 34 | return self.imageArray.count; 35 | } 36 | 37 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 38 | CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; 39 | DNAsset *dnasset = self.imageArray[indexPath.row]; 40 | [DNImagePickerHelper fetchImageWithAsset:dnasset targetSize:CGSizeMake(kSizeThumbnailCollectionView-4, kSizeThumbnailCollectionView*1.5) imageResutHandler:^(UIImage * _Nonnull image) { 41 | cell.imageView.image = image; 42 | }]; 43 | [DNImagePickerHelper fetchImageSizeWithAsset:dnasset imageSizeResultHandler:^(CGFloat imageSize, NSString * _Nonnull sizeString) { 44 | cell.textLabel.text = sizeString; 45 | }]; 46 | return cell; 47 | } 48 | 49 | #pragma mark - UICollectionViewDelegateFlowLayout 50 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 51 | return CGSizeMake(kSizeThumbnailCollectionView-8, kSizeThumbnailCollectionView*1.5); 52 | } 53 | 54 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section { 55 | return UIEdgeInsetsMake(2, 2, 2, 2); 56 | } 57 | 58 | 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Support/UIView+DNImagePicker.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+DNImagePicker.m 3 | // JKImagePicker 4 | // 5 | // Created by DingXiao on 15/2/11. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "UIView+DNImagePicker.h" 10 | 11 | @implementation UIView (DNImagePicker) 12 | 13 | - (CGFloat)left { 14 | return self.frame.origin.x; 15 | } 16 | 17 | - (void)setLeft:(CGFloat)x { 18 | CGRect frame = self.frame; 19 | frame.origin.x = x; 20 | self.frame = frame; 21 | } 22 | 23 | - (CGFloat)top { 24 | return self.frame.origin.y; 25 | } 26 | 27 | - (void)setTop:(CGFloat)y { 28 | CGRect frame = self.frame; 29 | frame.origin.y = y; 30 | self.frame = frame; 31 | } 32 | 33 | - (CGFloat)right { 34 | return self.frame.origin.x + self.frame.size.width; 35 | } 36 | 37 | - (void)setRight:(CGFloat)right { 38 | CGRect frame = self.frame; 39 | frame.origin.x = right - frame.size.width; 40 | self.frame = frame; 41 | } 42 | 43 | - (CGFloat)bottom { 44 | return self.frame.origin.y + self.frame.size.height; 45 | } 46 | 47 | - (void)setBottom:(CGFloat)bottom { 48 | CGRect frame = self.frame; 49 | frame.origin.y = bottom - frame.size.height; 50 | self.frame = frame; 51 | } 52 | 53 | - (CGFloat)centerX { 54 | return self.center.x; 55 | } 56 | 57 | - (void)setCenterX:(CGFloat)centerX { 58 | self.center = CGPointMake(centerX, self.center.y); 59 | } 60 | 61 | - (CGFloat)centerY { 62 | return self.center.y; 63 | } 64 | 65 | - (void)setCenterY:(CGFloat)centerY { 66 | self.center = CGPointMake(self.center.x, centerY); 67 | } 68 | 69 | - (CGFloat)width { 70 | return self.frame.size.width; 71 | } 72 | 73 | - (void)setWidth:(CGFloat)width { 74 | CGRect frame = self.frame; 75 | frame.size.width = width; 76 | self.frame = frame; 77 | } 78 | 79 | - (CGFloat)height { 80 | return self.frame.size.height; 81 | } 82 | 83 | - (void)setHeight:(CGFloat)height { 84 | CGRect frame = self.frame; 85 | frame.size.height = height; 86 | self.frame = frame; 87 | } 88 | 89 | - (CGPoint)origin { 90 | return self.frame.origin; 91 | } 92 | 93 | - (void)setOrigin:(CGPoint)origin { 94 | CGRect frame = self.frame; 95 | frame.origin = origin; 96 | self.frame = frame; 97 | } 98 | 99 | - (CGSize)size { 100 | return self.frame.size; 101 | } 102 | 103 | - (void)setSize:(CGSize)size { 104 | CGRect frame = self.frame; 105 | frame.size = size; 106 | self.frame = frame; 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Models/DNAlbum.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNAlbum.m 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/7/6. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DNAlbum.h" 11 | #import "DNImagePickerHelper.h" 12 | #import "DNAsset.h" 13 | 14 | @interface DNAlbum () 15 | @property (nonatomic, strong) NSAttributedString *albumAttributedString; 16 | @end 17 | 18 | @implementation DNAlbum 19 | 20 | - (instancetype)init { 21 | self = [super init]; 22 | if (self) { 23 | _albumTitle = @""; 24 | _identifier = @""; 25 | _count = 0; 26 | } 27 | return self; 28 | } 29 | 30 | + (DNAlbum *)albumWithAssetCollection:(PHAssetCollection *)collection results:(PHFetchResult *)results{ 31 | DNAlbum *album = [[DNAlbum alloc] init]; 32 | if (!collection || !results) { 33 | return album; 34 | } 35 | album.count = results.count; 36 | album.results = results; 37 | album.albumTitle = collection.localizedTitle; 38 | album.identifier = collection.localIdentifier; 39 | return album; 40 | } 41 | 42 | - (void)fetchPostImageWithSize:(CGSize)size 43 | imageResutHandler:(void (^)(UIImage *))handler { 44 | [DNImagePickerHelper fetchImageWithAsset:[DNAsset assetWithPHAsset:self.results.lastObject] 45 | targetSize:size 46 | imageResutHandler:^(UIImage *postImage) { 47 | handler(postImage); 48 | }]; 49 | } 50 | 51 | - (NSAttributedString *)albumAttributedString { 52 | if (!_albumAttributedString) { 53 | NSString *numberString = [NSString stringWithFormat:@" (%@)",@(self.count)]; 54 | NSString *cellTitleString = [NSString stringWithFormat:@"%@%@",self.albumTitle,numberString]; 55 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:cellTitleString]; 56 | [attributedString setAttributes: @{ 57 | NSFontAttributeName : [UIFont systemFontOfSize:16.0f], 58 | NSForegroundColorAttributeName : [UIColor blackColor], 59 | } 60 | range:NSMakeRange(0, self.albumTitle.length)]; 61 | [attributedString setAttributes:@{ 62 | NSFontAttributeName : [UIFont systemFontOfSize:16.0f], 63 | NSForegroundColorAttributeName : [UIColor grayColor], 64 | } range:NSMakeRange(self.albumTitle.length, numberString.length)]; 65 | _albumAttributedString = attributedString; 66 | } 67 | return _albumAttributedString; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNBadgeLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNBadgeLabel.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/27. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNBadgeLabel.h" 10 | #import "UIColor+Hex.h" 11 | #import "UIView+DNImagePicker.h" 12 | 13 | @interface DNBadgeLabel () 14 | @property (nonatomic, strong) UIView *backGroudView; 15 | @property (nonatomic, strong) UILabel *badgeLabel; 16 | 17 | @end 18 | 19 | @implementation DNBadgeLabel 20 | 21 | - (instancetype)initWithFrame:(CGRect)frame { 22 | self = [super initWithFrame:frame]; 23 | if (self) { 24 | self.backgroundColor = [UIColor clearColor]; 25 | [self setupViews]; 26 | self.hidden = YES; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)setupViews { 32 | _backGroudView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; 33 | _backGroudView.backgroundColor = [UIColor dn_hexStringToColor:@"#1FB823"]; 34 | _backGroudView.layer.cornerRadius = 10; 35 | [self addSubview:_backGroudView]; 36 | 37 | _badgeLabel = [[UILabel alloc] initWithFrame:_backGroudView.frame]; 38 | _badgeLabel.backgroundColor = [UIColor clearColor]; 39 | _badgeLabel.textColor = [UIColor whiteColor]; 40 | _badgeLabel.font = [UIFont systemFontOfSize:16.0f]; 41 | _badgeLabel.textAlignment = NSTextAlignmentCenter; 42 | [self addSubview:_badgeLabel]; 43 | 44 | _badgeLabel.userInteractionEnabled = YES; 45 | _backGroudView.userInteractionEnabled = YES; 46 | self.userInteractionEnabled = YES; 47 | } 48 | 49 | - (void)setTitle:(NSString *)title { 50 | CGRect rect = [title boundingRectWithSize:CGSizeMake(MAXFLOAT, 20) options:NSStringDrawingTruncatesLastVisibleLine attributes:nil context:nil]; 51 | self.frame = CGRectMake(self.left, self.top, (rect.size.width + 9) > 20?(rect.size.width + 9):20, 20); 52 | self.backGroudView.width = self.width; 53 | self.backGroudView.height = self.height; 54 | self.badgeLabel.width = self.width; 55 | self.badgeLabel.height = self.height; 56 | self.badgeLabel.text = title; 57 | 58 | if (title.integerValue > 0) { 59 | [self show]; 60 | self.backGroudView.transform =CGAffineTransformMakeScale(0, 0); 61 | [UIView animateWithDuration:0.2 animations:^{ 62 | self.backGroudView.transform = CGAffineTransformMakeScale(1.1, 1.1); 63 | } 64 | completion:^(BOOL finished){ 65 | [UIView animateWithDuration:0.1 animations:^{ 66 | self.backGroudView.transform = CGAffineTransformMakeScale(1.0, 1.0); 67 | }]; 68 | }]; 69 | 70 | } else { 71 | [self hide]; 72 | } 73 | } 74 | 75 | - (void)show { 76 | self.hidden = NO; 77 | } 78 | 79 | - (void)hide { 80 | self.hidden = YES; 81 | } 82 | @end 83 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNAlbumCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNAlbumCell.m 3 | // DNImagePicker 4 | // 5 | // Created by DingXiao on 16/8/29. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNAlbumCell.h" 10 | 11 | @implementation DNAlbumCell 12 | 13 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 14 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 15 | if (self) { 16 | [self postImageView]; 17 | [self titleLabel]; 18 | [self addContentConstraints]; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)addContentConstraints { 24 | // TODO: add Constraints 25 | NSString *vflForH = @"H:|-10-[_postImageView(64)]-20-[_titleLabel]-10-|"; 26 | NSString *vflForVPostImageView = @"V:|-0-[_postImageView]-0-|"; 27 | NSString *vflForVtitleLabel = @"V:|-1-[_titleLabel]-1-|"; 28 | NSArray *contraintsH = [NSLayoutConstraint 29 | constraintsWithVisualFormat:vflForH 30 | options:0 31 | metrics:nil 32 | views:NSDictionaryOfVariableBindings(_postImageView,_titleLabel)]; 33 | NSArray *contraintsVPostImageView = [NSLayoutConstraint 34 | constraintsWithVisualFormat:vflForVPostImageView 35 | options:0 36 | metrics:nil 37 | views:NSDictionaryOfVariableBindings(_postImageView)]; 38 | NSArray *contraintsVtitleLabel = [NSLayoutConstraint 39 | constraintsWithVisualFormat:vflForVtitleLabel 40 | options:0 41 | metrics:nil 42 | views:NSDictionaryOfVariableBindings(_titleLabel)]; 43 | [self.contentView addConstraints:contraintsH]; 44 | [self.contentView addConstraints:contraintsVPostImageView]; 45 | [self.contentView addConstraints:contraintsVtitleLabel]; 46 | } 47 | 48 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 49 | [super setSelected:selected animated:animated]; 50 | } 51 | 52 | - (UIImageView *)postImageView { 53 | if (!_postImageView) { 54 | _postImageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 55 | [_postImageView setTranslatesAutoresizingMaskIntoConstraints:NO]; 56 | [self.contentView addSubview:_postImageView]; 57 | } 58 | return _postImageView; 59 | } 60 | 61 | - (UILabel *)titleLabel { 62 | if (!_titleLabel) { 63 | _titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 64 | [_titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO]; 65 | _titleLabel.backgroundColor = [UIColor clearColor]; 66 | _titleLabel.textAlignment = NSTextAlignmentLeft; 67 | [self.contentView addSubview:_titleLabel]; 68 | } 69 | return _titleLabel; 70 | } 71 | @end 72 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/DNImagePickerHelper.h: -------------------------------------------------------------------------------- 1 | // 2 | // DNImagePickerHelper.h 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/8/23. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef NS_ENUM(NSUInteger, DNAlbumAuthorizationStatus) { 13 | // User has not yet made a choice with regards to this application 14 | DNAlbumAuthorizationStatusNotDetermined = 0, 15 | // This application is not authorized to access photo data. 16 | // The user cannot change this application’s status, possibly due to active restrictions 17 | // such as parental controls being in place. 18 | DNAlbumAuthorizationStatusRestricted, 19 | // User has explicitly denied this application access to photos data. 20 | DNAlbumAuthorizationStatusDenied, 21 | // User has authorized this application to access photos data. 22 | DNAlbumAuthorizationStatusAuthorized 23 | }; 24 | 25 | typedef NS_ENUM(NSUInteger, DNImagePickerFitlerType) { 26 | DNImagePickerFitlerTypeUnknown = 0, 27 | DNImagePickerFitlerTypeImage = 1, 28 | DNImagePickerFitlerTypeVideo = 2, 29 | DNImagePickerFitlerTypeAudio = 3, 30 | }; 31 | 32 | 33 | @class DNAlbum; 34 | @class DNAsset; 35 | 36 | NS_ASSUME_NONNULL_BEGIN 37 | FOUNDATION_EXTERN NSString * const DNImagePickerPhotoLibraryChangedNotification; 38 | NS_CLASS_AVAILABLE_IOS(8.0) @interface DNImagePickerHelper : NSObject 39 | 40 | + (instancetype)sharedHelper; 41 | 42 | 43 | + (void)cancelFetchWithAssets:(DNAsset *)asset; 44 | 45 | /** 46 | * Returns information about your app’s authorization for accessing the user’s Photos library. 47 | The current authorization status. See `DNAlbumAuthorizationStatus`. 48 | * 49 | * @return The current authorization status. 50 | */ 51 | + (DNAlbumAuthorizationStatus)authorizationStatus; 52 | 53 | /** 54 | * Fetch the albumlist 55 | * 56 | */ 57 | + (void)requestAlbumListWithCompleteHandler:(void(^)(NSArray* anblumList))competeHandler; 58 | 59 | /** 60 | * Fetch the album which is stored by identifier; if not stored, it'll return the album without anything. 61 | * 62 | * @return the stored album 63 | */ 64 | + (void)requestCurrentAblumWithCompleteHandler:(void(^)(DNAlbum * album))completeHandler; 65 | 66 | 67 | /** 68 | fetch images in the specific ablum 69 | 70 | @param album target album 71 | @param completeHandler callbacks with imageArray 72 | */ 73 | + (void)fetchImageAssetsInAlbum:(DNAlbum *)album completeHandler:(void(^)(NSArray* imageArray))completeHandler; 74 | 75 | 76 | + (void)fetchImageSizeWithAsset:(DNAsset *)asset 77 | imageSizeResultHandler:(void (^)(CGFloat imageSize, NSString * sizeString))handler; 78 | 79 | 80 | /** 81 | fetch Image with assets 82 | 83 | @param asset target assets 84 | @param targetSize target size 85 | @param isHighQuality is need highQuality 86 | @param handler callback with image 87 | */ 88 | + (void)fetchImageWithAsset:(DNAsset *)asset 89 | targetSize:(CGSize)targetSize 90 | needHighQuality:(BOOL)isHighQuality 91 | imageResutHandler:(void (^)(UIImage * image))handler; 92 | /** 93 | fetch Image with assets 94 | same as `fetchImageWithAsset:targetSize:needHighQuality:imageResutHandler:` param `isHighQuality` is NO 95 | */ 96 | + (void)fetchImageWithAsset:(DNAsset *)asset 97 | targetSize:(CGSize)targetSize 98 | imageResutHandler:(void (^)(UIImage *))handler; 99 | 100 | // storeage 101 | + (void)saveAblumIdentifier:(NSString *)identifier; 102 | 103 | + (NSString *)albumIdentifier; 104 | 105 | 106 | @end 107 | NS_ASSUME_NONNULL_END 108 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNImageFetchOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNImageFetchOperation.m 3 | // DNImagePicker 4 | // 5 | // Created by dingxiao on 2018/10/9. 6 | // Copyright © 2018 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNImageFetchOperation.h" 10 | #import 11 | #import 12 | 13 | typedef void(^DNImageResultHandler)(UIImage *image); 14 | 15 | @interface DNImageFetchOperation () 16 | @property (nonatomic, assign) PHImageRequestID requestID; 17 | @property (nonatomic, assign) CGSize targetSize; 18 | @property (nonatomic, assign) BOOL isHighQuality; 19 | @property (nonatomic, copy) DNImageResultHandler resultHandler; 20 | @end 21 | 22 | @implementation DNImageFetchOperation 23 | 24 | @synthesize executing = _executing; 25 | @synthesize finished = _finished; 26 | 27 | - (instancetype)initWithAsset:(PHAsset *)asset { 28 | self = [super init]; 29 | if (self) { 30 | _asset = asset; 31 | _executing = NO; 32 | _finished = NO; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)fetchImageWithTargetSize:(CGSize)size 38 | needHighQuality:(BOOL)isHighQuality 39 | imageResutHandler:(void (^)(UIImage * _Nonnull))handler { 40 | self.targetSize = size; 41 | self.isHighQuality = isHighQuality; 42 | self.resultHandler = handler; 43 | } 44 | 45 | - (void)start { 46 | @synchronized (self) { 47 | if (self.isCancelled) { 48 | self.finished = YES; 49 | [self reset]; 50 | return; 51 | } 52 | if (!self.asset) { 53 | self.finished = YES; 54 | [self reset]; 55 | return; 56 | } 57 | PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init]; 58 | if (self.isHighQuality) { 59 | options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat; 60 | } else { 61 | options.resizeMode = PHImageRequestOptionsResizeModeExact; 62 | } 63 | [[PHImageManager defaultManager] requestImageForAsset:self.asset targetSize:self.targetSize contentMode:PHImageContentModeAspectFill options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) { 64 | dispatch_async(dispatch_get_main_queue(), ^{ 65 | if (self.resultHandler) { 66 | self.resultHandler(result); 67 | } 68 | [self done]; 69 | }); 70 | }]; 71 | self.executing = YES; 72 | } 73 | } 74 | 75 | - (void)cancel { 76 | @synchronized (self) { 77 | if (self.isFinished) return; 78 | [super cancel]; 79 | 80 | if (self.asset && self.requestID != PHInvalidImageRequestID) { 81 | [[PHCachingImageManager defaultManager] cancelImageRequest:self.requestID]; 82 | if (self.isExecuting) self.executing = NO; 83 | if (!self.isFinished) self.finished = YES; 84 | } 85 | [self reset]; 86 | } 87 | } 88 | 89 | - (void)done { 90 | self.finished = YES; 91 | self.executing = NO; 92 | [self reset]; 93 | } 94 | 95 | - (void)reset { 96 | self.asset = nil; 97 | } 98 | 99 | - (void)setFinished:(BOOL)finished { 100 | [self willChangeValueForKey:@"isFinished"]; 101 | _finished = finished; 102 | [self didChangeValueForKey:@"isFinished"]; 103 | } 104 | 105 | - (void)setExecuting:(BOOL)executing { 106 | [self willChangeValueForKey:@"isExecuting"]; 107 | _executing = executing; 108 | [self didChangeValueForKey:@"isExecuting"]; 109 | } 110 | 111 | - (BOOL)isConcurrent { 112 | return YES; 113 | } 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker.xcodeproj/xcuserdata/Dennis.xcuserdatad/xcschemes/DNImagePicker.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNUnAuthorizedTipsView.m: -------------------------------------------------------------------------------- 1 | // 2 | // UnAuthorizedTipsView.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/18. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNUnAuthorizedTipsView.h" 10 | 11 | @implementation DNUnAuthorizedTipsView 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame { 14 | self = [super initWithFrame:frame]; 15 | if (self) { 16 | [self imageView]; 17 | [self label]; 18 | [self addContentConstraints]; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)addContentConstraints { 24 | NSDictionary *imageViewMetric = @{@"imageLength":@130,@"labelHeight":@60}; 25 | NSString *vflV = @"V:|-120-[_imageView(imageLength)]-30-[_label(<=labelHeight@750)]"; 26 | NSString *vflH = @"H:|-33-[_label]-33-|"; 27 | NSArray *contstraintsV = [NSLayoutConstraint constraintsWithVisualFormat:vflV options:0 metrics:imageViewMetric views:NSDictionaryOfVariableBindings(_imageView,_label)]; 28 | NSArray *contstraintsH = [NSLayoutConstraint constraintsWithVisualFormat:vflH options:0 metrics:imageViewMetric views:NSDictionaryOfVariableBindings(_label)]; 29 | NSLayoutConstraint *imageViewContstraintsCenterX = [NSLayoutConstraint 30 | constraintWithItem:self.imageView 31 | attribute:NSLayoutAttributeCenterX 32 | relatedBy:NSLayoutRelationEqual 33 | toItem:self 34 | attribute:NSLayoutAttributeCenterX 35 | multiplier:1.0f 36 | constant:0]; 37 | NSLayoutConstraint *imageViewConstraintsWidth = [NSLayoutConstraint 38 | constraintWithItem:self.imageView 39 | attribute:NSLayoutAttributeWidth 40 | relatedBy:NSLayoutRelationEqual 41 | toItem:nil 42 | attribute:NSLayoutAttributeNotAnAttribute 43 | multiplier:0 44 | constant:130.0f]; 45 | [self addConstraints:@[imageViewConstraintsWidth,imageViewContstraintsCenterX]]; 46 | [self addConstraints:contstraintsV]; 47 | [self addConstraints:contstraintsH]; 48 | } 49 | 50 | #pragma mark - getter 51 | - (UIImageView *)imageView { 52 | if (!_imageView) { 53 | _imageView = [UIImageView new]; 54 | _imageView.image = [UIImage imageNamed:@"image_unAuthorized"]; 55 | [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; 56 | [self addSubview:_imageView]; 57 | } 58 | return _imageView; 59 | } 60 | 61 | - (UILabel *)label { 62 | if (!_label) { 63 | _label = [UILabel new]; 64 | [_label setTranslatesAutoresizingMaskIntoConstraints:NO]; 65 | NSString *text = NSLocalizedStringFromTable(@"UnAuthorizedTip", @"DNImagePicker", @"UnAuthorizedTip"); 66 | NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary]; 67 | NSString*appName =[infoDict objectForKey:@"CFBundleDisplayName"] 68 | ; 69 | NSString *tipsString = [NSString stringWithFormat:text,appName]; 70 | _label.text = tipsString; 71 | _label.textColor = [UIColor blackColor]; 72 | _label.font = [UIFont systemFontOfSize:14.0f]; 73 | _label.textAlignment = NSTextAlignmentCenter; 74 | _label.numberOfLines = 0; 75 | _label.backgroundColor = [UIColor clearColor]; 76 | _label.lineBreakMode = NSLineBreakByTruncatingTail; 77 | [self addSubview:_label]; 78 | } 79 | return _label; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNAlbumTableViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNAlbumTableViewController.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/10. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNAlbumTableViewController.h" 10 | #import "DNImagePickerController.h" 11 | #import "DNImageFlowViewController.h" 12 | #import "DNAlbumCell.h" 13 | #import "UIViewController+DNImagePicker.h" 14 | #import "DNUnAuthorizedTipsView.h" 15 | #import "DNImagePickerHelper.h" 16 | #import "DNAlbum.h" 17 | 18 | static NSString* const dnalbumTableViewCellReuseIdentifier = @"dnalbumTableViewCellReuseIdentifier"; 19 | 20 | @interface DNAlbumTableViewController () 21 | @property (nonatomic, strong) NSArray *albumArray; 22 | @end 23 | 24 | @implementation DNAlbumTableViewController 25 | 26 | #pragma mark - life cycle 27 | 28 | - (void)viewDidLoad { 29 | [super viewDidLoad]; 30 | [self setupView]; 31 | [self reloadTableView]; 32 | } 33 | 34 | #pragma mark - public 35 | 36 | - (void)reloadTableView { 37 | [DNImagePickerHelper requestAlbumListWithCompleteHandler:^(NSArray * _Nonnull anblumList) { 38 | if (anblumList) { 39 | self.albumArray = [anblumList copy]; 40 | [self.tableView reloadData]; 41 | } 42 | }]; 43 | } 44 | 45 | #pragma mark - mark setup Data and View 46 | - (void)setupView { 47 | self.title = NSLocalizedStringFromTable(@"albumTitle", @"DNImagePicker", @"photos"); 48 | [self createBarButtonItemAtPosition:DNImagePickerNavigationBarPositionRight 49 | text:NSLocalizedStringFromTable(@"cancel", @"DNImagePicker", @"取消") 50 | action:@selector(cancelAction:)]; 51 | 52 | [self.tableView registerClass:[DNAlbumCell class] forCellReuseIdentifier:dnalbumTableViewCellReuseIdentifier]; 53 | UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; 54 | self.tableView.tableFooterView = view; 55 | } 56 | 57 | 58 | #pragma mark - ui actions 59 | - (void)cancelAction:(id)sender { 60 | DNImagePickerController *navController = [self dnImagePickerController]; 61 | if (navController && [navController.imagePickerDelegate respondsToSelector:@selector(dnImagePickerControllerDidCancel:)]) { 62 | [navController.imagePickerDelegate dnImagePickerControllerDidCancel:navController]; 63 | } 64 | } 65 | 66 | #pragma mark - getter/setter 67 | 68 | - (DNImagePickerController *)dnImagePickerController { 69 | if (!self.navigationController 70 | || 71 | ![self.navigationController isKindOfClass:[DNImagePickerController class]]) 72 | { 73 | NSAssert(false, @"check the navigation controller"); 74 | } 75 | return (DNImagePickerController *)self.navigationController; 76 | } 77 | 78 | - (void)showUnAuthorizedTipsView { 79 | DNUnAuthorizedTipsView *view = [[DNUnAuthorizedTipsView alloc] initWithFrame:self.tableView.frame]; 80 | self.tableView.backgroundView = view; 81 | } 82 | 83 | #pragma mark - Table view data source 84 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 85 | return self.albumArray.count; 86 | } 87 | 88 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 89 | DNAlbumCell *cell = [tableView dequeueReusableCellWithIdentifier:dnalbumTableViewCellReuseIdentifier forIndexPath:indexPath]; 90 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 91 | DNAlbum *album = self.albumArray[indexPath.row]; 92 | cell.titleLabel.attributedText = album.albumAttributedString; 93 | [album fetchPostImageWithSize:CGSizeMake(60, 60) imageResutHandler:^(UIImage * _Nullable postImage) { 94 | if (postImage) { 95 | cell.postImageView.image = postImage; 96 | } else { 97 | cell.postImageView.image = [UIImage imageNamed:@"assets_placeholder_picture"]; 98 | } 99 | }]; 100 | return cell; 101 | } 102 | 103 | - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { 104 | return 64; 105 | } 106 | 107 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 108 | return 64; 109 | } 110 | 111 | #pragma mark - tableView delegate 112 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 113 | DNAlbum *album = self.albumArray[indexPath.row]; 114 | DNImageFlowViewController *imageFlowViewController = [[DNImageFlowViewController alloc] initWithAblum:album]; 115 | [self.navigationController pushViewController:imageFlowViewController animated:YES]; 116 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 117 | } 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Support/UIViewController+DNImagePicker.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+DNImagePicker.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/10. 6 | // Copyright (c) 2015年 dennis. All rights reserved. 7 | // 8 | 9 | #import "UIViewController+DNImagePicker.h" 10 | #import "UIColor+Hex.h" 11 | 12 | @implementation UIViewController (DNImagePicker) 13 | - (void)createBarButtonItemAtPosition:(DNImagePickerNavigationBarPosition)position statusNormalImage:(UIImage *)normalImage statusHighlightImage:(UIImage *)highlightImage action:(SEL)action { 14 | 15 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 16 | UIEdgeInsets insets = UIEdgeInsetsZero; 17 | switch (position) { 18 | case DNImagePickerNavigationBarPositionLeft: 19 | insets = UIEdgeInsetsMake(0, -20, 0, 20); 20 | break; 21 | case DNImagePickerNavigationBarPositionRight: 22 | insets = UIEdgeInsetsMake(0, 13, 0, -13); 23 | break; 24 | default: 25 | break; 26 | } 27 | 28 | [button setImageEdgeInsets:insets]; 29 | [button setFrame:CGRectMake(0, 0, 44, 44)]; 30 | [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; 31 | [button setImage:normalImage forState:UIControlStateNormal]; 32 | [button setImage:highlightImage forState:UIControlStateHighlighted]; 33 | 34 | UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button]; 35 | switch (position) { 36 | case DNImagePickerNavigationBarPositionLeft: 37 | self.navigationItem.leftBarButtonItem = barButtonItem; 38 | break; 39 | case DNImagePickerNavigationBarPositionRight: 40 | self.navigationItem.rightBarButtonItem = barButtonItem; 41 | break; 42 | default: 43 | break; 44 | } 45 | } 46 | 47 | - (void)createBarButtonItemAtPosition:(DNImagePickerNavigationBarPosition)position text:(NSString *)text action:(SEL)action { 48 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 49 | 50 | UIEdgeInsets insets = UIEdgeInsetsZero; 51 | switch (position) { 52 | case DNImagePickerNavigationBarPositionLeft: 53 | insets = UIEdgeInsetsMake(0, -49 + 26, 0, 19); 54 | break; 55 | case DNImagePickerNavigationBarPositionRight: 56 | insets = UIEdgeInsetsMake(0, 49 - 26, 0, -19); 57 | break; 58 | default: 59 | break; 60 | } 61 | 62 | [button setTitleEdgeInsets:insets]; 63 | [button setFrame:CGRectMake(0, 0, 64, 30)]; 64 | [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; 65 | [button setTitle:text forState:UIControlStateNormal]; 66 | button.titleLabel.font = [UIFont systemFontOfSize:15.0f]; 67 | [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal]; 68 | [button setTitleColor:[UIColor dn_hexStringToColor:@"#808080"] forState:UIControlStateHighlighted]; 69 | 70 | UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button]; 71 | switch (position) { 72 | case DNImagePickerNavigationBarPositionLeft: 73 | self.navigationItem.leftBarButtonItem = barButtonItem; 74 | break; 75 | case DNImagePickerNavigationBarPositionRight: 76 | self.navigationItem.rightBarButtonItem = barButtonItem; 77 | break; 78 | default: 79 | break; 80 | } 81 | } 82 | 83 | - (void)createBackBarButtonItemStatusNormalImage:(UIImage *)normalImage statusHighlightImage:(UIImage *)highlightImage withTitle:(NSString *)title action:(SEL)action { 84 | 85 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 86 | [button setFrame:CGRectMake(0, 0, 84, 44)]; 87 | [button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; 88 | [button setTitleColor:[UIColor dn_hexStringToColor:@"#808080"] forState:UIControlStateHighlighted]; 89 | UIEdgeInsets imageInsets = UIEdgeInsetsMake(0, -20, 0, 60); 90 | UIEdgeInsets titleInsets = UIEdgeInsetsMake(0, -45, 0, -15); 91 | [button.titleLabel setFont:[UIFont systemFontOfSize:15.0f]]; 92 | [button setImageEdgeInsets:imageInsets]; 93 | [button setTitleEdgeInsets:titleInsets]; 94 | button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; 95 | 96 | [button setTitle:title forState:UIControlStateNormal]; 97 | [button setTitle:title forState:UIControlStateHighlighted]; 98 | [button setImage:normalImage forState:UIControlStateNormal]; 99 | [button addTarget:self action:action forControlEvents:UIControlEventTouchUpInside]; 100 | 101 | UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button]; 102 | 103 | self.navigationItem.leftBarButtonItem = barButtonItem; 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNSendButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNSendButton.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/24. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNSendButton.h" 10 | #import "UIView+DNImagePicker.h" 11 | #import "UIColor+Hex.h" 12 | #define kSendButtonFont [UIFont systemFontOfSize:15] 13 | static NSString *const dnSendButtonTintNormalColor = @"#1FB823"; 14 | //static NSString *const dnSendButtonTintAbnormalColor = @"#C9DCCA"; 15 | static NSString *const dnSendButtonTintAbnormalColor = @"#C9EFCA"; 16 | 17 | static CGFloat const kSendButtonTextWitdh = 38.0f; 18 | 19 | @interface DNSendButton () 20 | @property (nonatomic, strong) UILabel *badgeValueLabel; 21 | @property (nonatomic, strong) UIView *backGroudView; 22 | @property (nonatomic, strong) UIButton *sendButton; 23 | 24 | @end 25 | 26 | @implementation DNSendButton 27 | 28 | - (instancetype)initWithFrame:(CGRect)frame 29 | { 30 | self = [super initWithFrame:frame]; 31 | if (self) { 32 | self.left = 0; 33 | self.right = 0; 34 | self.top = 0; 35 | self.bottom = 0; 36 | self.width = 58; 37 | self.height = 26; 38 | [self setupViews]; 39 | self.badgeValue = @"0"; 40 | } 41 | return self; 42 | } 43 | 44 | - (void)setupViews 45 | { 46 | _backGroudView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)]; 47 | _backGroudView.centerY = self.centerY; 48 | _backGroudView.backgroundColor = [UIColor dn_hexStringToColor:dnSendButtonTintNormalColor]; 49 | _backGroudView.layer.cornerRadius = _backGroudView.height/2; 50 | [self addSubview:_backGroudView]; 51 | 52 | _badgeValueLabel = [[UILabel alloc] initWithFrame:_backGroudView.frame]; 53 | _badgeValueLabel.backgroundColor = [UIColor clearColor]; 54 | _badgeValueLabel.textColor = [UIColor whiteColor]; 55 | _badgeValueLabel.font = [UIFont systemFontOfSize:15.0f]; 56 | _badgeValueLabel.textAlignment = NSTextAlignmentCenter; 57 | [self addSubview:_badgeValueLabel]; 58 | 59 | _sendButton = [UIButton buttonWithType:UIButtonTypeCustom]; 60 | _sendButton.frame = CGRectMake(0, 0, self.width, self.height); 61 | [_sendButton setTitle:NSLocalizedStringFromTable(@"send", @"DNImagePicker", @"发送") 62 | forState:UIControlStateNormal]; 63 | [_sendButton setTitleColor:[UIColor dn_hexStringToColor:dnSendButtonTintNormalColor] forState:UIControlStateNormal]; 64 | [_sendButton setTitleColor:[UIColor dn_hexStringToColor:dnSendButtonTintAbnormalColor] forState:UIControlStateHighlighted]; 65 | [_sendButton setTitleColor:[UIColor dn_hexStringToColor:dnSendButtonTintAbnormalColor] forState:UIControlStateDisabled]; 66 | _sendButton.titleLabel.font = [UIFont systemFontOfSize:15.0f]; 67 | _sendButton.contentEdgeInsets = UIEdgeInsetsMake(0, 20, 0, 0); 68 | _sendButton.backgroundColor = [UIColor clearColor]; 69 | [self addSubview:_sendButton]; 70 | } 71 | 72 | - (void)setBadgeValue:(NSString *)badgeValue 73 | { 74 | CGRect rect = [badgeValue boundingRectWithSize:CGSizeMake(MAXFLOAT, 20) options:NSStringDrawingTruncatesLastVisibleLine attributes:@{NSFontAttributeName:kSendButtonFont} context:nil]; 75 | self.badgeValueLabel.frame = CGRectMake(self.badgeValueLabel.left, self.badgeValueLabel.top, (rect.size.width + 9) > 20?(rect.size.width + 9):20, 20); 76 | self.backGroudView.width = self.badgeValueLabel.width; 77 | self.backGroudView.height = self.badgeValueLabel.height; 78 | 79 | self.sendButton.width = self.badgeValueLabel.width + kSendButtonTextWitdh; 80 | self.width = self.sendButton.width; 81 | 82 | self.badgeValueLabel.text = badgeValue; 83 | 84 | if (badgeValue.integerValue > 0) { 85 | [self showBadgeValue]; 86 | self.backGroudView.transform =CGAffineTransformMakeScale(0, 0); 87 | [UIView animateWithDuration:0.2 animations:^{ 88 | self.backGroudView.transform = CGAffineTransformMakeScale(1.1, 1.1); 89 | } 90 | completion:^(BOOL finished){ 91 | [UIView animateWithDuration:0.1 animations:^{ 92 | self.backGroudView.transform = CGAffineTransformMakeScale(1.0, 1.0); 93 | }]; 94 | }]; 95 | 96 | } else { 97 | [self hideBadgeValue]; 98 | } 99 | } 100 | 101 | - (void)showBadgeValue 102 | { 103 | self.badgeValueLabel.hidden = NO; 104 | self.backGroudView.hidden = NO; 105 | } 106 | 107 | - (void)hideBadgeValue 108 | { 109 | self.badgeValueLabel.hidden = YES; 110 | self.backGroudView.hidden = YES; 111 | self.sendButton.adjustsImageWhenDisabled = YES; 112 | } 113 | 114 | 115 | - (void)addTaget:(id)target action:(SEL)action 116 | { 117 | [self.sendButton addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNImagePickerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNImagePickerController.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/10. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNImagePickerController.h" 10 | #import "DNAlbumTableViewController.h" 11 | #import "DNImageFlowViewController.h" 12 | #import "DNImagePickerHelper.h" 13 | 14 | NSString *kDNImagePickerStoredGroupKey = @"com.dennis.kDNImagePickerStoredGroup"; 15 | 16 | 17 | @interface DNImagePickerController () 18 | 19 | @property (nonatomic, weak) id navDelegate; 20 | @property (nonatomic, assign) BOOL isDuringPushAnimation; 21 | 22 | @end 23 | 24 | @implementation DNImagePickerController 25 | 26 | - (void)viewDidLoad { 27 | [super viewDidLoad]; 28 | 29 | if (!self.delegate) { 30 | self.delegate = self; 31 | } 32 | 33 | self.interactivePopGestureRecognizer.delegate = self; 34 | 35 | NSString *propwetyID = [[NSUserDefaults standardUserDefaults] objectForKey:kDNImagePickerStoredGroupKey]; 36 | 37 | if (propwetyID.length <= 0) { 38 | [self showAlbumList]; 39 | } else { 40 | [self showImageFlow]; 41 | } 42 | } 43 | 44 | 45 | - (void)didReceiveMemoryWarning { 46 | [super didReceiveMemoryWarning]; 47 | // Dispose of any resources that can be recreated. 48 | } 49 | #pragma mark - priviate methods 50 | - (void)showAlbumList { 51 | DNAlbumTableViewController *albumTableViewController = [[DNAlbumTableViewController alloc] init]; 52 | [self setViewControllers:@[albumTableViewController]]; 53 | } 54 | 55 | - (void)showImageFlow { 56 | NSString *albumIdentifier = [DNImagePickerHelper albumIdentifier]; 57 | DNAlbumTableViewController *albumTableViewController = [[DNAlbumTableViewController alloc] init]; 58 | DNImageFlowViewController *imageFlowController = [[DNImageFlowViewController alloc] initWithAlbumIdentifier:albumIdentifier]; 59 | [self setViewControllers:@[albumTableViewController,imageFlowController]]; 60 | } 61 | 62 | - (void)chargeAuthorizationStatus:(DNAlbumAuthorizationStatus)status { 63 | if (!self.viewControllers.firstObject) { 64 | [self showAlbumList]; 65 | } 66 | 67 | DNAlbumTableViewController *albumTableViewController = self.viewControllers.firstObject; 68 | 69 | switch (status) { 70 | case DNAlbumAuthorizationStatusAuthorized: 71 | // TODO:Authorized 72 | break; 73 | case DNAlbumAuthorizationStatusDenied: 74 | case DNAlbumAuthorizationStatusRestricted: 75 | [albumTableViewController showUnAuthorizedTipsView]; 76 | break; 77 | case DNAlbumAuthorizationStatusNotDetermined: 78 | // TODO: requestAuthorization 79 | break; 80 | 81 | default: 82 | break; 83 | } 84 | } 85 | 86 | #pragma mark - UINavigationController 87 | 88 | - (void)setDelegate:(id)delegate 89 | { 90 | [super setDelegate:delegate ? self : nil]; 91 | self.navDelegate = delegate != self ? delegate : nil; 92 | } 93 | 94 | - (void)pushViewController:(UIViewController *)viewController 95 | animated:(BOOL)animated __attribute__((objc_requires_super)) 96 | { 97 | self.isDuringPushAnimation = YES; 98 | [super pushViewController:viewController animated:animated]; 99 | } 100 | 101 | #pragma mark UINavigationControllerDelegate 102 | 103 | - (void)navigationController:(UINavigationController *)navigationController 104 | didShowViewController:(UIViewController *)viewController 105 | animated:(BOOL)animated 106 | { 107 | self.isDuringPushAnimation = NO; 108 | if ([self.navDelegate respondsToSelector:_cmd]) { 109 | [self.navDelegate navigationController:navigationController didShowViewController:viewController animated:animated]; 110 | } 111 | } 112 | 113 | #pragma mark - UIGestureRecognizerDelegate 114 | 115 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 116 | { 117 | if (gestureRecognizer == self.interactivePopGestureRecognizer) { 118 | return [self.viewControllers count] > 1 && !self.isDuringPushAnimation; 119 | } else { 120 | return YES; 121 | } 122 | } 123 | 124 | #pragma mark - Delegate Forwarder 125 | 126 | - (BOOL)respondsToSelector:(SEL)s { 127 | return [super respondsToSelector:s] || [self.navDelegate respondsToSelector:s]; 128 | } 129 | 130 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)s { 131 | return [super methodSignatureForSelector:s] ?: [(id)self.navDelegate methodSignatureForSelector:s]; 132 | } 133 | 134 | - (void)forwardInvocation:(NSInvocation *)invocation { 135 | id delegate = self.navDelegate; 136 | if ([delegate respondsToSelector:invocation.selector]) { 137 | [invocation invokeWithTarget:delegate]; 138 | } 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNFullImageButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNFullImageButton.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/3/2. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNFullImageButton.h" 10 | #import "UIView+DNImagePicker.h" 11 | 12 | #define kDNFullImageButtonFont [UIFont systemFontOfSize:13] 13 | static NSInteger const buttonPadding = 10; 14 | static NSInteger const buttonImageWidth = 16; 15 | 16 | @interface DNFullImageButton () 17 | @property (nonatomic, strong) UIButton *fullImageButton; 18 | @property (nonatomic, strong) UILabel *imageSizeLabel; 19 | @property (nonatomic, strong) UIActivityIndicatorView *indicatorView; 20 | @end 21 | 22 | @implementation DNFullImageButton 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame { 25 | self = [super initWithFrame:frame]; 26 | if (self) { 27 | self.backgroundColor = [UIColor clearColor]; 28 | self.height = 28; 29 | self.width = CGRectGetWidth([[UIScreen mainScreen] bounds])/2 -20; 30 | [self fullImageButton]; 31 | [self imageSizeLabel]; 32 | [self indicatorView]; 33 | self.selected = NO; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)addTarget:(id)target action:(SEL)action { 39 | [self.fullImageButton addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; 40 | } 41 | 42 | - (UILabel *)imageSizeLabel { 43 | if (!_imageSizeLabel) { 44 | _imageSizeLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 4, CGRectGetWidth(self.frame)- 100, 20)]; 45 | _imageSizeLabel.backgroundColor = [UIColor clearColor]; 46 | _imageSizeLabel.font = [UIFont systemFontOfSize:14.0f]; 47 | _imageSizeLabel.textAlignment = NSTextAlignmentLeft; 48 | _imageSizeLabel.textColor = [UIColor whiteColor]; 49 | [self addSubview:_imageSizeLabel]; 50 | } 51 | return _imageSizeLabel; 52 | } 53 | 54 | - (UIButton *)fullImageButton { 55 | if (!_fullImageButton) { 56 | _fullImageButton = [UIButton buttonWithType:UIButtonTypeCustom]; 57 | _fullImageButton.width = [self fullImageButtonWidth]; 58 | _fullImageButton.height = 28; 59 | _fullImageButton.backgroundColor = [UIColor clearColor]; 60 | [_fullImageButton setTitle:NSLocalizedStringFromTable(@"fullImage", @"DNImagePicker", @"原图") forState:UIControlStateNormal]; 61 | _fullImageButton.titleLabel.font = kDNFullImageButtonFont; 62 | [_fullImageButton setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; 63 | [_fullImageButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; 64 | [_fullImageButton setImage:[UIImage imageNamed:@"photo_full_image_unselected"] forState:UIControlStateNormal]; 65 | [_fullImageButton setImage:[UIImage imageNamed:@"photo_full_image_selected"] forState:UIControlStateSelected]; 66 | _fullImageButton.contentVerticalAlignment = NSTextAlignmentRight; 67 | [_fullImageButton setTitleEdgeInsets:UIEdgeInsetsMake(0, buttonPadding-buttonImageWidth, 6, 0)]; 68 | [_fullImageButton setImageEdgeInsets:UIEdgeInsetsMake(6, 0, 6, _fullImageButton.width - buttonImageWidth)]; 69 | [self addSubview:_fullImageButton]; 70 | } 71 | return _fullImageButton; 72 | } 73 | 74 | - (UIActivityIndicatorView *)indicatorView { 75 | if (!_indicatorView) { 76 | _indicatorView = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(self.fullImageButton.width, 2, 26, 26)]; 77 | _indicatorView.hidesWhenStopped = YES; 78 | [_indicatorView stopAnimating]; 79 | [self addSubview:_indicatorView]; 80 | } 81 | return _indicatorView; 82 | } 83 | 84 | - (CGFloat)fullImageButtonWidth { 85 | NSString *string = NSLocalizedStringFromTable(@"fullImage", @"DNImagePicker", @"原图"); 86 | CGRect rect = [string boundingRectWithSize:CGSizeMake(MAXFLOAT, 20) options:NSStringDrawingTruncatesLastVisibleLine attributes:@{NSFontAttributeName:kDNFullImageButtonFont} context:nil]; 87 | CGFloat width = buttonImageWidth + buttonPadding + CGRectGetWidth(rect); 88 | return width; 89 | } 90 | 91 | - (void)setSelected:(BOOL)selected { 92 | if (_selected != selected) { 93 | _selected = selected; 94 | self.fullImageButton.selected = _selected; 95 | self.fullImageButton.width = [self fullImageButtonWidth]; 96 | [self.fullImageButton setTitleEdgeInsets:UIEdgeInsetsMake(0, buttonPadding-buttonImageWidth, 6, 0)]; 97 | [self.fullImageButton setImageEdgeInsets:UIEdgeInsetsMake(6, 0, 6, self.fullImageButton.width - buttonImageWidth)]; 98 | CGFloat labelWidth = self.width - self.fullImageButton.width; 99 | self.imageSizeLabel.left = self.fullImageButton.width; 100 | self.imageSizeLabel.width = labelWidth; 101 | self.imageSizeLabel.hidden = !_selected; 102 | } 103 | } 104 | 105 | - (void)setText:(NSString *)text { 106 | self.imageSizeLabel.text = text; 107 | } 108 | 109 | - (void)shouldAnimating:(BOOL)animate { 110 | if (self.selected) { 111 | self.imageSizeLabel.hidden = animate; 112 | if (animate) { 113 | [self.indicatorView startAnimating]; 114 | } else { 115 | [self.indicatorView stopAnimating]; 116 | } 117 | } 118 | } 119 | @end 120 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNBrowserCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNBrowserCell.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/28. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNBrowserCell.h" 10 | #import "DNTapDetectingImageView.h" 11 | #import "DNPhotoBrowser.h" 12 | #import "UIView+DNImagePicker.h" 13 | #import "DNAsset.h" 14 | #import "DNImagePickerHelper.h" 15 | 16 | @interface DNBrowserCell () 17 | @property (nonatomic, strong) UIScrollView *zoomingScrollView; 18 | @property (nonatomic, strong) DNTapDetectingImageView *photoImageView; 19 | 20 | @end 21 | 22 | @implementation DNBrowserCell 23 | 24 | - (instancetype)initWithFrame:(CGRect)frame 25 | { 26 | self = [super initWithFrame:frame]; 27 | if (self) { 28 | [self zoomingScrollView]; 29 | [self photoImageView]; 30 | } 31 | return self; 32 | } 33 | 34 | - (void)prepareForReuse { 35 | [super prepareForReuse]; 36 | self.photoImageView.image = nil; 37 | [self.photoImageView removeFromSuperview]; 38 | [self.zoomingScrollView removeFromSuperview]; 39 | self.zoomingScrollView = nil; 40 | self.photoImageView = nil; 41 | self.photoBrowser = nil; 42 | self.asset = nil; 43 | } 44 | 45 | #pragma mark - set 46 | - (void)setAsset:(DNAsset *)asset { 47 | if (_asset != asset) { 48 | _asset = asset; 49 | [self displayImage]; 50 | } 51 | } 52 | 53 | // Get and display image 54 | - (void)displayImage { 55 | self.zoomingScrollView.maximumZoomScale = 1; 56 | self.zoomingScrollView.minimumZoomScale = 1; 57 | self.zoomingScrollView.zoomScale = 1; 58 | self.zoomingScrollView.contentSize = CGSizeMake(0, 0); 59 | __weak typeof(self)weakSelf = self; 60 | [DNImagePickerHelper fetchImageWithAsset:self.asset targetSize:self.zoomingScrollView.size needHighQuality:YES imageResutHandler:^(UIImage * _Nonnull image) { 61 | if (!image) { 62 | return; 63 | } 64 | __strong __typeof(weakSelf) strongSelf = weakSelf; 65 | strongSelf.photoImageView.image = image; 66 | strongSelf.photoImageView.hidden = NO; 67 | CGRect photoImageViewFrame; 68 | photoImageViewFrame.origin = CGPointZero; 69 | photoImageViewFrame.size = image.size; 70 | strongSelf.photoImageView.frame = photoImageViewFrame; 71 | strongSelf.zoomingScrollView.contentSize = photoImageViewFrame.size; 72 | 73 | // Set zoom to minimum zoom 74 | [strongSelf setMaxMinZoomScalesForCurrentBounds]; 75 | [strongSelf setNeedsLayout]; 76 | }]; 77 | } 78 | 79 | 80 | #pragma mark - get 81 | - (DNTapDetectingImageView *)photoImageView 82 | { 83 | if (!_photoImageView) { 84 | _photoImageView = [[DNTapDetectingImageView alloc] initWithFrame:CGRectZero]; 85 | _photoImageView.tapDelegate = self; 86 | _photoImageView.contentMode = UIViewContentModeCenter; 87 | _photoImageView.backgroundColor = [UIColor blackColor]; 88 | [self.zoomingScrollView addSubview:_photoImageView]; 89 | } 90 | return _photoImageView; 91 | } 92 | 93 | - (UIScrollView *)zoomingScrollView 94 | { 95 | if (!_zoomingScrollView) { 96 | _zoomingScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(10, 0, self.frame.size.width-20, self.frame.size.height)]; 97 | _zoomingScrollView.delegate = self; 98 | _zoomingScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth; 99 | _zoomingScrollView.showsHorizontalScrollIndicator = NO; 100 | _zoomingScrollView.showsVerticalScrollIndicator = NO; 101 | _zoomingScrollView.decelerationRate = UIScrollViewDecelerationRateFast; 102 | [self addSubview:_zoomingScrollView]; 103 | } 104 | return _zoomingScrollView; 105 | } 106 | 107 | #pragma mark - Setup 108 | - (CGFloat)initialZoomScaleWithMinScale { 109 | CGFloat zoomScale = self.zoomingScrollView.minimumZoomScale; 110 | // Zoom image to fill if the aspect ratios are fairly similar 111 | CGSize boundsSize = self.zoomingScrollView.bounds.size; 112 | CGSize imageSize = self.photoImageView.image.size; 113 | CGFloat boundsAR = boundsSize.width / boundsSize.height; 114 | CGFloat imageAR = imageSize.width / imageSize.height; 115 | CGFloat xScale = boundsSize.width / imageSize.width; // the scale needed to perfectly fit the image width-wise 116 | CGFloat yScale = boundsSize.height / imageSize.height; // the scale needed to perfectly fit the image height-wise 117 | // Zooms standard portrait images on a 3.5in screen but not on a 4in screen. 118 | if (ABS(boundsAR - imageAR) < 0.17) { 119 | zoomScale = MAX(xScale, yScale); 120 | // Ensure we don't zoom in or out too far, just in case 121 | zoomScale = MIN(MAX(self.zoomingScrollView.minimumZoomScale, zoomScale), self.zoomingScrollView.maximumZoomScale); 122 | } 123 | return zoomScale; 124 | } 125 | 126 | - (void)setMaxMinZoomScalesForCurrentBounds { 127 | // Reset 128 | self.zoomingScrollView.maximumZoomScale = 1; 129 | self.zoomingScrollView.minimumZoomScale = 1; 130 | self.zoomingScrollView.zoomScale = 1; 131 | 132 | // Bail if no image 133 | if (!_photoImageView.image) return; 134 | 135 | // Reset position 136 | _photoImageView.frame = CGRectMake(0, 0, _photoImageView.frame.size.width, _photoImageView.frame.size.height); 137 | 138 | // Sizes 139 | CGSize boundsSize = self.zoomingScrollView.bounds.size; 140 | CGSize imageSize = _photoImageView.image.size; 141 | 142 | // Calculate Min 143 | CGFloat xScale = boundsSize.width / imageSize.width; // the scale needed to perfectly fit the image width-wise 144 | CGFloat yScale = boundsSize.height / imageSize.height; // the scale needed to perfectly fit the image height-wise 145 | CGFloat minScale = MIN(xScale, yScale); // use minimum of these to allow the image to become fully visible 146 | 147 | // Calculate Max 148 | CGFloat maxScale = 1.5; 149 | if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { 150 | // Let them go a bit bigger on a bigger screen! 151 | maxScale = 4; 152 | } 153 | 154 | // Image is smaller than screen so no zooming! 155 | if (xScale >= 1 && yScale >= 1) { 156 | minScale = 1.0; 157 | } 158 | 159 | // Set min/max zoom 160 | self.zoomingScrollView.maximumZoomScale = maxScale; 161 | self.zoomingScrollView.minimumZoomScale = minScale; 162 | 163 | // Initial zoom 164 | self.zoomingScrollView.zoomScale = [self initialZoomScaleWithMinScale]; 165 | 166 | // If we're zooming to fill then centralise 167 | if (self.zoomingScrollView.zoomScale != minScale) { 168 | // Centralise 169 | self.zoomingScrollView.contentOffset = CGPointMake((imageSize.width * self.zoomingScrollView.zoomScale - boundsSize.width) / 2.0, 170 | (imageSize.height * self.zoomingScrollView.zoomScale - boundsSize.height) / 2.0); 171 | // Disable scrolling initially until the first pinch to fix issues with swiping on an initally zoomed in photo 172 | self.zoomingScrollView.scrollEnabled = NO; 173 | } 174 | 175 | // Layout 176 | [self setNeedsLayout]; 177 | 178 | } 179 | 180 | #pragma mark - Layout 181 | 182 | - (void)layoutSubviews { 183 | // Super 184 | [super layoutSubviews]; 185 | 186 | // Center the image as it becomes smaller than the size of the screen 187 | CGSize boundsSize = self.zoomingScrollView.bounds.size; 188 | CGRect frameToCenter = _photoImageView.frame; 189 | 190 | // Horizontally 191 | if (frameToCenter.size.width < boundsSize.width) { 192 | frameToCenter.origin.x = floorf((boundsSize.width - frameToCenter.size.width) / 2.0); 193 | } else { 194 | frameToCenter.origin.x = 0; 195 | } 196 | 197 | // Vertically 198 | if (frameToCenter.size.height < boundsSize.height) { 199 | frameToCenter.origin.y = floorf((boundsSize.height - frameToCenter.size.height) / 2.0); 200 | } else { 201 | frameToCenter.origin.y = 0; 202 | } 203 | 204 | // Center 205 | if (!CGRectEqualToRect(_photoImageView.frame, frameToCenter)) 206 | _photoImageView.frame = frameToCenter; 207 | 208 | } 209 | 210 | #pragma mark - UIScrollViewDelegate 211 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { 212 | return self.photoImageView; 213 | } 214 | 215 | - (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { 216 | self.zoomingScrollView.scrollEnabled = YES; // reset 217 | } 218 | 219 | - (void)scrollViewDidZoom:(UIScrollView *)scrollView { 220 | [self setNeedsLayout]; 221 | [self layoutIfNeeded]; 222 | } 223 | 224 | #pragma mark - Tap Detection 225 | - (void)handleSingleTap:(CGPoint)touchPoint { 226 | [self.photoBrowser performSelector:@selector(toggleControls) withObject:nil afterDelay:0.2]; 227 | } 228 | 229 | - (void)handleDoubleTap:(CGPoint)touchPoint { 230 | 231 | // Cancel any single tap handling 232 | [NSObject cancelPreviousPerformRequestsWithTarget:self.photoBrowser]; 233 | // Zoom 234 | if (self.zoomingScrollView.zoomScale != self.zoomingScrollView.minimumZoomScale && self.zoomingScrollView.zoomScale != [self initialZoomScaleWithMinScale]) { 235 | 236 | // Zoom out 237 | [self.zoomingScrollView setZoomScale:self.zoomingScrollView.minimumZoomScale animated:YES]; 238 | 239 | } else { 240 | 241 | // Zoom in to twice the size 242 | CGFloat newZoomScale = ((self.zoomingScrollView.maximumZoomScale + self.zoomingScrollView.minimumZoomScale) / 2); 243 | CGFloat xsize = self.zoomingScrollView.bounds.size.width / newZoomScale; 244 | CGFloat ysize = self.zoomingScrollView.bounds.size.height / newZoomScale; 245 | [self.zoomingScrollView zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES]; 246 | 247 | } 248 | } 249 | 250 | // Image View 251 | - (void)imageView:(UIImageView *)imageView singleTapDetected:(UITouch *)touch { 252 | [self handleSingleTap:[touch locationInView:imageView]]; 253 | } 254 | - (void)imageView:(UIImageView *)imageView doubleTapDetected:(UITouch *)touch { 255 | [self handleDoubleTap:[touch locationInView:imageView]]; 256 | } 257 | 258 | @end 259 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Views/DNAssetsViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNAssetsViewCell.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/11. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNAssetsViewCell.h" 10 | #import "DNImagePicker.h" 11 | 12 | @interface DNAssetsViewCell () 13 | @property (nonatomic, strong, nonnull) UIImageView *imageView; 14 | @property (nonatomic, strong, nonnull) UIButton *checkButton; 15 | @property (nonatomic, strong, nonnull) UIImageView *checkImageView; 16 | 17 | @end 18 | 19 | @implementation DNAssetsViewCell 20 | 21 | - (instancetype)initWithFrame:(CGRect)frame { 22 | self = [super initWithFrame:frame]; 23 | if (self) { 24 | [self setTranslatesAutoresizingMaskIntoConstraints:NO]; 25 | [self imageView]; 26 | [self checkButton]; 27 | [self checkImageView]; 28 | [self addContentConstraint]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)addContentConstraint { 34 | NSLayoutConstraint *imageConstraintsBottom = [NSLayoutConstraint 35 | constraintWithItem:self.imageView 36 | attribute:NSLayoutAttributeBottom 37 | relatedBy:NSLayoutRelationEqual 38 | toItem:self.contentView 39 | attribute:NSLayoutAttributeBottom 40 | multiplier:1.0f 41 | constant:0]; 42 | 43 | NSLayoutConstraint *imageConstraintsleading = [NSLayoutConstraint 44 | constraintWithItem:self.imageView 45 | attribute:NSLayoutAttributeLeading 46 | relatedBy:NSLayoutRelationEqual 47 | toItem:self.contentView 48 | attribute:NSLayoutAttributeLeading 49 | multiplier:1.0 50 | constant:0]; 51 | 52 | NSLayoutConstraint *imageContraintsTop = [NSLayoutConstraint 53 | constraintWithItem:self.imageView 54 | attribute:NSLayoutAttributeTop 55 | relatedBy:NSLayoutRelationEqual 56 | toItem:self.contentView 57 | attribute:NSLayoutAttributeTop 58 | multiplier:1.0 59 | constant:0]; 60 | 61 | NSLayoutConstraint *imageViewConstraintTrailing = [NSLayoutConstraint 62 | constraintWithItem:self.imageView 63 | attribute:NSLayoutAttributeTrailing 64 | relatedBy:NSLayoutRelationEqual 65 | toItem:self.contentView 66 | attribute:NSLayoutAttributeTrailing 67 | multiplier:1.0 68 | constant:0]; 69 | 70 | [self addConstraints:@[imageConstraintsBottom,imageConstraintsleading,imageContraintsTop,imageViewConstraintTrailing]]; 71 | 72 | NSLayoutConstraint *checkConstraitRight = [NSLayoutConstraint 73 | constraintWithItem:self.checkButton 74 | attribute:NSLayoutAttributeTrailing 75 | relatedBy:NSLayoutRelationEqual 76 | toItem:self.contentView 77 | attribute:NSLayoutAttributeTrailing 78 | multiplier:1.0f 79 | constant:0]; 80 | 81 | NSLayoutConstraint *checkConstraitTop = [NSLayoutConstraint 82 | constraintWithItem:self.checkButton 83 | attribute:NSLayoutAttributeTop 84 | relatedBy:NSLayoutRelationEqual 85 | toItem:self.contentView 86 | attribute:NSLayoutAttributeTop 87 | multiplier:1.0f 88 | constant:0]; 89 | 90 | NSLayoutConstraint *chekBtViewConsraintWidth = [NSLayoutConstraint 91 | constraintWithItem:self.checkButton 92 | attribute:NSLayoutAttributeWidth 93 | relatedBy:NSLayoutRelationEqual 94 | toItem:self.imageView 95 | attribute:NSLayoutAttributeHeight 96 | multiplier:0.5f 97 | constant:0]; 98 | 99 | NSLayoutConstraint *chekBtViewConsraintHeight = [NSLayoutConstraint 100 | constraintWithItem:self.checkButton 101 | attribute:NSLayoutAttributeHeight 102 | relatedBy:NSLayoutRelationEqual 103 | toItem:self.checkButton 104 | attribute:NSLayoutAttributeWidth 105 | multiplier:1.0 106 | constant:0]; 107 | 108 | [self.contentView addConstraints:@[checkConstraitRight,checkConstraitTop,chekBtViewConsraintWidth,chekBtViewConsraintHeight]]; 109 | 110 | NSDictionary *checkImageViewMetric = @{@"sideLength":@25}; 111 | NSString *checkImageViewVFLH = @"H:[_checkImageView(sideLength)]-3-|"; 112 | NSString *checkImageVIewVFLV = @"V:|-3-[_checkImageView(sideLength)]"; 113 | NSArray *checkImageConstraintsH = [NSLayoutConstraint constraintsWithVisualFormat:checkImageViewVFLH options:0 metrics:checkImageViewMetric views:NSDictionaryOfVariableBindings(_checkImageView)]; 114 | NSArray *checkImageConstraintsV = [NSLayoutConstraint constraintsWithVisualFormat:checkImageVIewVFLV options:0 metrics:checkImageViewMetric views:NSDictionaryOfVariableBindings(_checkImageView)]; 115 | 116 | [self.contentView addConstraints:checkImageConstraintsH]; 117 | [self.contentView addConstraints:checkImageConstraintsV]; 118 | } 119 | 120 | 121 | - (void)fillWithAsset:(nonnull DNAsset *)asset isSelected:(BOOL)seleted { 122 | self.isSelected = seleted; 123 | if (self.asset) { 124 | [DNImagePickerHelper cancelFetchWithAssets:self.asset]; 125 | } 126 | self.asset = asset; 127 | 128 | if (self.asset.cacheImage) { 129 | self.imageView.image = self.asset.cacheImage; 130 | return; 131 | } 132 | 133 | __weak typeof(self) wSelf = self; 134 | CGFloat kThumbSizeLength = ceil(([[UIScreen mainScreen] bounds].size.width -10)/4); 135 | [DNImagePickerHelper fetchImageWithAsset:self.asset 136 | targetSize:CGSizeMake(kThumbSizeLength, kThumbSizeLength) 137 | imageResutHandler:^(UIImage * _Nonnull image) { 138 | __strong typeof(wSelf) sSelf = wSelf; 139 | if (image) { 140 | sSelf.asset.cacheImage = image; 141 | sSelf.imageView.image = image; 142 | } else { 143 | sSelf.imageView.image = [UIImage imageNamed:@"assets_placeholder_picture"]; 144 | } 145 | }]; 146 | } 147 | 148 | - (void)setIsSelected:(BOOL)isSelected { 149 | _isSelected = isSelected; 150 | self.checkButton.selected = _isSelected; 151 | [self updateCheckImageView]; 152 | } 153 | 154 | - (void)updateCheckImageView { 155 | if (self.checkButton.selected) { 156 | self.checkImageView.image = [UIImage imageNamed:@"photo_check_selected"]; 157 | 158 | [UIView animateWithDuration:0.2 animations:^{ 159 | self.checkImageView.transform = CGAffineTransformMakeScale(1.2, 1.2); 160 | } 161 | completion:^(BOOL finished){ 162 | [UIView animateWithDuration:0.2 animations:^{ 163 | self.checkImageView.transform = CGAffineTransformMakeScale(1.0, 1.0); 164 | }]; 165 | }]; 166 | } else { 167 | self.checkImageView.image = [UIImage imageNamed:@"photo_check_default"]; 168 | } 169 | } 170 | 171 | - (void)checkButtonAction:(id)sender { 172 | if (self.checkButton.selected) { 173 | if (self.delegate && [self.delegate respondsToSelector:@selector(didDeselectItemAssetsViewCell:)]) { 174 | [self.delegate didDeselectItemAssetsViewCell:self]; 175 | } 176 | } else { 177 | if (self.delegate && [self.delegate respondsToSelector:@selector(didSelectItemAssetsViewCell:)]) { 178 | [self.delegate didSelectItemAssetsViewCell:self]; 179 | } 180 | } 181 | } 182 | 183 | - (void)prepareForReuse { 184 | _isSelected = NO; 185 | _delegate = nil; 186 | } 187 | 188 | #pragma mark - Getter 189 | - (UIImageView *)imageView { 190 | if (!_imageView) { 191 | _imageView = [[UIImageView alloc] initWithFrame:CGRectZero]; 192 | [_imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; 193 | [self.contentView addSubview:_imageView]; 194 | } 195 | return _imageView; 196 | } 197 | 198 | - (UIButton *)checkButton { 199 | if (!_checkButton) { 200 | _checkButton = [UIButton buttonWithType:UIButtonTypeCustom]; 201 | 202 | [_checkButton addTarget:self action:@selector(checkButtonAction:) forControlEvents:UIControlEventTouchUpInside]; 203 | [_checkButton setTranslatesAutoresizingMaskIntoConstraints:NO]; 204 | [self.contentView addSubview:_checkButton]; 205 | } 206 | return _checkButton; 207 | } 208 | 209 | - (UIImageView *)checkImageView { 210 | if (!_checkImageView) { 211 | _checkImageView = [UIImageView new]; 212 | _checkImageView.contentMode = UIViewContentModeScaleAspectFit; 213 | [_checkImageView setTranslatesAutoresizingMaskIntoConstraints:NO]; 214 | [self.contentView addSubview:_checkImageView]; 215 | } 216 | return _checkImageView; 217 | } 218 | 219 | @end 220 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 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 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/DNImagePickerHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNImagePickerHelper.m 3 | // DNImagePicker 4 | // 5 | // Created by Ding Xiao on 16/8/23. 6 | // Copyright © 2016年 Dennis. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DNImagePickerHelper.h" 11 | #import "DNImageFetchOperation.h" 12 | #import "DNAlbum.h" 13 | #import "DNAsset.h" 14 | 15 | NSString * const DNImagePickerPhotoLibraryChangedNotification = @"DNImagePickerPhotoLibraryChangedNotification"; 16 | static NSString* const kDNImagePickerStoredGroupKey = @"com.dennis.kDNImagePickerStoredGroup"; 17 | 18 | static dispatch_queue_t imageFetchQueue() { 19 | static dispatch_queue_t queue = nil; 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | queue = dispatch_queue_create("com.awesomedennis.dnimageFetchQueue", DISPATCH_QUEUE_SERIAL); 23 | }); 24 | return queue; 25 | } 26 | 27 | @interface DNImagePickerHelper () 28 | @property (nonatomic, strong) NSOperationQueue *imageFetchQueue; 29 | @property (nonatomic, strong) NSMutableDictionary *fetchImageOperationDics; 30 | @end 31 | 32 | @implementation DNImagePickerHelper 33 | 34 | + (instancetype)sharedHelper { 35 | static dispatch_once_t once; 36 | static id instance; 37 | dispatch_once(&once, ^{ 38 | instance = [self new]; 39 | }); 40 | return instance; 41 | } 42 | 43 | - (instancetype)init { 44 | self = [super init]; 45 | if (self) { 46 | _imageFetchQueue = [NSOperationQueue new]; 47 | _imageFetchQueue.maxConcurrentOperationCount = 8; 48 | _imageFetchQueue.name = @"com.awesomedennis.dnnimagefetchOperationQueue"; 49 | _fetchImageOperationDics = [NSMutableDictionary dictionary]; 50 | } 51 | return self; 52 | } 53 | 54 | #pragma mark - 55 | #pragma mark - PHPhotoLibraryChangeObserver 56 | - (void)photoLibraryDidChange:(PHChange *)changeInstance { 57 | dispatch_async(dispatch_get_main_queue(), ^{ 58 | [[NSNotificationCenter defaultCenter] postNotificationName:DNImagePickerPhotoLibraryChangedNotification object:nil]; 59 | }); 60 | } 61 | 62 | #pragma mark - 63 | #pragma mark - public 64 | 65 | + (DNAlbumAuthorizationStatus)authorizationStatus { 66 | return (DNAlbumAuthorizationStatus)[PHPhotoLibrary authorizationStatus]; 67 | } 68 | 69 | + (void)requestAlbumListWithCompleteHandler:(void (^)(NSArray *))completeHandelr { 70 | dispatch_block_t block = ^{ 71 | NSMutableArray *albums = [NSMutableArray arrayWithArray:[self fetchAlbumsResults]]; 72 | if (!albums) { 73 | completeHandelr(nil); 74 | return; 75 | } 76 | 77 | PHFetchOptions *userAlbumsOptions = [[PHFetchOptions alloc] init]; 78 | userAlbumsOptions.predicate = [NSPredicate predicateWithFormat:@"mediaType = %@",@(PHAssetMediaTypeImage)]; 79 | userAlbumsOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; 80 | 81 | NSMutableArray *list = [NSMutableArray array]; 82 | for (PHFetchResult *result in albums) { 83 | [result enumerateObjectsUsingBlock:^(PHAssetCollection *obj, NSUInteger idx, BOOL * _Nonnull stop) { 84 | PHFetchResult *assetResults = [PHAsset fetchAssetsInAssetCollection:obj options:userAlbumsOptions]; 85 | NSInteger count = 0; 86 | switch (obj.assetCollectionType) { 87 | case PHAssetCollectionTypeAlbum: 88 | case PHAssetCollectionTypeSmartAlbum: 89 | count = assetResults.count; 90 | break; 91 | default: 92 | count = 0; 93 | break; 94 | } 95 | 96 | if (count > 0) { 97 | @autoreleasepool { 98 | DNAlbum *album = [DNAlbum albumWithAssetCollection:obj results:assetResults]; 99 | [list addObject:album]; 100 | } 101 | } 102 | }]; 103 | } 104 | dispatch_async(dispatch_get_main_queue(), ^{ 105 | if (completeHandelr) { 106 | completeHandelr([list copy]); 107 | } 108 | }); 109 | }; 110 | dispatch_async(imageFetchQueue(), block); 111 | } 112 | 113 | + (void)requestCurrentAblumWithCompleteHandler:(void (^)(DNAlbum *))completeHandler { 114 | void(^callBack)(DNAlbum *) = ^(DNAlbum * album){ 115 | dispatch_async(dispatch_get_main_queue(), ^{ 116 | completeHandler(album); 117 | }); 118 | }; 119 | 120 | dispatch_async(imageFetchQueue(), ^{ 121 | DNAlbum *album = [[DNAlbum alloc] init]; 122 | NSString *identifier = [DNImagePickerHelper albumIdentifier]; 123 | if (!identifier || identifier.length <= 0) { 124 | callBack(album); 125 | return; 126 | } 127 | 128 | PHFetchResult *result = [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[identifier] options:nil]; 129 | 130 | if (result.count <= 0) { 131 | callBack(album); 132 | return; 133 | } 134 | 135 | PHFetchOptions *options = [[PHFetchOptions alloc] init]; 136 | options.predicate = [NSPredicate predicateWithFormat:@"mediaType = %@",@(PHAssetMediaTypeImage)]; 137 | options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]; 138 | PHAssetCollection *collection = result.firstObject; 139 | 140 | PHFetchResult *requestReslut = [PHAsset fetchAssetsInAssetCollection:collection options:options]; 141 | album.albumTitle = collection.localizedTitle; 142 | album.results = requestReslut; 143 | album.count = requestReslut.count; 144 | album.identifier = collection.localIdentifier; 145 | callBack(album); 146 | }); 147 | } 148 | 149 | + (void)fetchImageAssetsInAlbum:(DNAlbum *)album completeHandler:(void (^)(NSArray *))completeHandler { 150 | dispatch_async(imageFetchQueue(), ^{ 151 | NSArray *array = [self fetchImageAssetsViaCollectionResults:album.results]; 152 | dispatch_async(dispatch_get_main_queue(), ^{ 153 | if (completeHandler) { 154 | completeHandler(array); 155 | } 156 | }); 157 | }); 158 | } 159 | 160 | + (void)fetchImageSizeWithAsset:(DNAsset *)asset 161 | imageSizeResultHandler:(void (^)(CGFloat imageSize, NSString * sizeString))handler { 162 | if (!asset.asset) { 163 | handler(0,@"0M"); 164 | return; 165 | } 166 | [[PHImageManager defaultManager] requestImageDataForAsset:asset.asset 167 | options:nil 168 | resultHandler:^(NSData *imageData, 169 | NSString *dataUTI, 170 | UIImageOrientation orientation, 171 | NSDictionary *info) { 172 | NSString *string = @"0M"; 173 | CGFloat imageSize = 0.0; 174 | if (!imageData) { 175 | handler(imageSize, string); 176 | return; 177 | } 178 | imageSize = imageData.length; 179 | if (imageSize > 1024*1024) { 180 | CGFloat size = imageSize/(1024*2024); 181 | string = [NSString stringWithFormat:@"%.1fM",size]; 182 | } else { 183 | CGFloat size = imageSize/1024; 184 | string = [NSString stringWithFormat:@"%.1fK",size]; 185 | } 186 | handler(imageSize, string); 187 | }]; 188 | } 189 | 190 | 191 | + (void)fetchImageWithAsset:(DNAsset *)asset 192 | targetSize:(CGSize)targetSize 193 | imageResutHandler:(void (^)(UIImage *))handler { 194 | return [self fetchImageWithAsset:asset targetSize:targetSize needHighQuality:NO imageResutHandler:handler]; 195 | } 196 | 197 | + (void)fetchImageWithAsset:(DNAsset *)asset 198 | targetSize:(CGSize)targetSize 199 | needHighQuality:(BOOL)isHighQuality 200 | imageResutHandler:(void (^)(UIImage *image))handler { 201 | if (!asset) { 202 | return; 203 | } 204 | 205 | DNImagePickerHelper *helper = [DNImagePickerHelper sharedHelper]; 206 | DNImageFetchOperation *operation = [[DNImageFetchOperation alloc] initWithAsset:asset.asset]; 207 | __weak typeof(helper) whelper = helper; 208 | [operation fetchImageWithTargetSize:targetSize needHighQuality:isHighQuality imageResutHandler:^(UIImage * _Nonnull image) { 209 | __strong typeof(whelper) shelper = whelper; 210 | [shelper.fetchImageOperationDics removeObjectForKey:asset.assetIdentifier]; 211 | handler(image); 212 | }]; 213 | [helper.imageFetchQueue addOperation:operation]; 214 | [helper.fetchImageOperationDics setObject:operation forKey:asset.assetIdentifier]; 215 | } 216 | 217 | + (void)cancelFetchWithAssets:(DNAsset *)asset { 218 | if (!asset) { 219 | return; 220 | } 221 | DNImagePickerHelper *helper = [DNImagePickerHelper sharedHelper]; 222 | DNImageFetchOperation *operation = [helper.fetchImageOperationDics objectForKey:asset.assetIdentifier]; 223 | if (operation) { 224 | [operation cancel]; 225 | } 226 | [helper.fetchImageOperationDics removeObjectForKey:asset.assetIdentifier]; 227 | } 228 | 229 | #pragma mark - 230 | #pragma mark - priviate 231 | 232 | /** 233 | * fetch `PHAsset` array via CollectionResults 234 | * 235 | * @param results collection fetch results 236 | * 237 | * @return `DNAsset` array in collection 238 | */ 239 | + (NSArray *)fetchImageAssetsViaCollectionResults:(PHFetchResult *)results { 240 | NSMutableArray *array = [NSMutableArray arrayWithCapacity:results.count]; 241 | if (!results) { 242 | return array; 243 | } 244 | 245 | [results enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 246 | @autoreleasepool { 247 | DNAsset *asset = [DNAsset assetWithPHAsset:obj]; 248 | [array addObject:asset]; 249 | } 250 | }]; 251 | 252 | return [array copy]; 253 | } 254 | 255 | + (NSArray *)fetchAlbumsResults { 256 | PHFetchOptions *userAlbumsOptions = [[PHFetchOptions alloc] init]; 257 | userAlbumsOptions.predicate = [NSPredicate predicateWithFormat:@"estimatedAssetCount > 0"]; 258 | userAlbumsOptions.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"startDate" ascending:YES]]; 259 | 260 | NSMutableArray *albumsArray = [NSMutableArray array]; 261 | [albumsArray addObject: 262 | [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum 263 | subtype:PHAssetCollectionSubtypeAlbumRegular 264 | options:nil]]; 265 | [albumsArray addObject: 266 | [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum 267 | subtype:PHAssetCollectionSubtypeAny 268 | options:userAlbumsOptions]]; 269 | return albumsArray; 270 | } 271 | 272 | + (void)saveAblumIdentifier:(NSString *)identifier { 273 | if (identifier.length <= 0) return; 274 | [[NSUserDefaults standardUserDefaults] setObject:identifier forKey:kDNImagePickerStoredGroupKey]; 275 | [[NSUserDefaults standardUserDefaults] synchronize]; 276 | } 277 | 278 | + (NSString *)albumIdentifier { 279 | return [[NSUserDefaults standardUserDefaults] objectForKey:kDNImagePickerStoredGroupKey]; 280 | } 281 | 282 | @end 283 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNImageFlowViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNImageFlowViewController.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/11. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNImageFlowViewController.h" 10 | #import "DNImagePickerController.h" 11 | #import "DNPhotoBrowser.h" 12 | #import "UIViewController+DNImagePicker.h" 13 | #import "UIView+DNImagePicker.h" 14 | #import "UIColor+Hex.h" 15 | #import "DNAssetsViewCell.h" 16 | #import "DNSendButton.h" 17 | #import "DNImagePickerHelper.h" 18 | #import "DNAlbum.h" 19 | #import "DNAsset.h" 20 | 21 | static NSUInteger const kDNImageFlowMaxSeletedNumber = 9; 22 | 23 | @interface DNImageFlowViewController () 24 | 25 | @property (nonatomic, strong) DNAlbum *album; 26 | @property (nonatomic, copy) NSString *albumIdentifier; 27 | 28 | @property (nonatomic, strong) UICollectionView *imageFlowCollectionView; 29 | @property (nonatomic, strong) DNSendButton *sendButton; 30 | 31 | @property (nonatomic, strong) NSMutableArray *assetsArray; 32 | @property (nonatomic, strong) NSMutableArray *selectedAssetsArray; 33 | 34 | @property (nonatomic, strong) UIActivityIndicatorView *indicatorView; 35 | 36 | @property (nonatomic, assign) BOOL isFullImage; 37 | @end 38 | 39 | static NSString* const dnAssetsViewCellReuseIdentifier = @"DNAssetsViewCell"; 40 | 41 | @implementation DNImageFlowViewController 42 | 43 | - (instancetype)initWithAlbumIdentifier:(NSString *)albumIdentifier { 44 | self = [super init]; 45 | if (self) { 46 | _assetsArray = [NSMutableArray array]; 47 | _selectedAssetsArray = [NSMutableArray array]; 48 | _albumIdentifier = albumIdentifier; 49 | } 50 | return self; 51 | } 52 | 53 | - (instancetype)initWithAblum:(DNAlbum *)album { 54 | self = [super init]; 55 | if (self) { 56 | _assetsArray = [NSMutableArray array]; 57 | _selectedAssetsArray = [NSMutableArray array]; 58 | _album = album; 59 | 60 | } 61 | return self; 62 | } 63 | 64 | - (void)viewDidLoad { 65 | [super viewDidLoad]; 66 | [self setupView]; 67 | [self setupData]; 68 | } 69 | 70 | - (void)viewWillAppear:(BOOL)animated { 71 | [super viewWillAppear:animated]; 72 | self.navigationController.toolbarHidden = NO; 73 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadData) name:DNImagePickerPhotoLibraryChangedNotification object:nil]; 74 | } 75 | 76 | - (void)viewWillDisappear:(BOOL)animated { 77 | self.navigationController.toolbarHidden = YES; 78 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 79 | } 80 | 81 | - (void)setupData { 82 | 83 | if (!self.album && self.albumIdentifier.length > 0) { 84 | __weak typeof(self) wSelf = self; 85 | [DNImagePickerHelper requestCurrentAblumWithCompleteHandler:^(DNAlbum *album) { 86 | __strong typeof(wSelf) sSelf = wSelf; 87 | sSelf.album = album; 88 | sSelf.title = sSelf.album.albumTitle; 89 | [sSelf loadData]; 90 | }]; 91 | } else { 92 | self.title = self.album.albumTitle; 93 | [self loadData]; 94 | } 95 | } 96 | 97 | - (void)setupView { 98 | self.view.backgroundColor = [UIColor whiteColor]; 99 | [self createBarButtonItemAtPosition:DNImagePickerNavigationBarPositionLeft 100 | statusNormalImage:[UIImage imageNamed:@"back_normal"] 101 | statusHighlightImage:[UIImage imageNamed:@"back_highlight"] 102 | action:@selector(backButtonAction)]; 103 | [self createBarButtonItemAtPosition:DNImagePickerNavigationBarPositionRight 104 | text:NSLocalizedStringFromTable(@"cancel", @"DNImagePicker", @"取消") 105 | action:@selector(cancelAction)]; 106 | 107 | [self imageFlowCollectionView]; 108 | 109 | UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedStringFromTable(@"preview", @"DNImagePicker", @"预览") 110 | style:UIBarButtonItemStylePlain 111 | target:self 112 | action:@selector(previewAction)]; 113 | [item1 setTintColor:[UIColor blackColor]]; 114 | item1.enabled = NO; 115 | 116 | UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 117 | 118 | UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithCustomView:self.sendButton]; 119 | 120 | 121 | UIBarButtonItem *item4 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; 122 | item4.width = -10; 123 | 124 | [self setToolbarItems:@[item1,item2,item3,item4] animated:NO]; 125 | } 126 | 127 | - (void)loadData { 128 | if (!self.assetsArray.count) { 129 | [self.indicatorView startAnimating]; 130 | } 131 | __weak typeof(self) wSelf = self; 132 | [DNImagePickerHelper fetchImageAssetsInAlbum:self.album completeHandler:^(NSArray * imageArray) { 133 | __strong typeof(wSelf) sSelf = wSelf; 134 | [sSelf.indicatorView stopAnimating]; 135 | [sSelf.assetsArray removeAllObjects]; 136 | [sSelf.assetsArray addObjectsFromArray:imageArray]; 137 | [self.imageFlowCollectionView reloadData]; 138 | [self scrollerToBottom:NO]; 139 | }]; 140 | } 141 | 142 | #pragma mark - helpmethods 143 | - (void)scrollerToBottom:(BOOL)animated { 144 | NSInteger rows = [self.imageFlowCollectionView numberOfItemsInSection:0] - 1; 145 | [self.imageFlowCollectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:rows inSection:0] 146 | atScrollPosition:UICollectionViewScrollPositionBottom 147 | animated:animated]; 148 | } 149 | 150 | - (DNImagePickerController *)dnImagePickerController { 151 | if (!self.navigationController 152 | || 153 | ![self.navigationController isKindOfClass:[DNImagePickerController class]]) 154 | { 155 | NSAssert(false, @"check the navigation controller"); 156 | } 157 | return (DNImagePickerController *)self.navigationController; 158 | } 159 | 160 | - (void)removeAssetsObject:(DNAsset *)asset { 161 | if ([self.selectedAssetsArray containsObject:asset]) { 162 | [self.selectedAssetsArray removeObject:asset]; 163 | } 164 | } 165 | 166 | - (void)addAssetsObject:(DNAsset *)asset { 167 | [self.selectedAssetsArray addObject:asset]; 168 | } 169 | 170 | #pragma mark - priviate methods 171 | - (void)sendImages { 172 | [DNImagePickerHelper saveAblumIdentifier:self.album.identifier]; 173 | 174 | DNImagePickerController *imagePicker = [self dnImagePickerController]; 175 | if (imagePicker && [imagePicker.imagePickerDelegate respondsToSelector:@selector(dnImagePickerController:sendImages:isFullImage:)]) { 176 | [imagePicker.imagePickerDelegate dnImagePickerController:imagePicker 177 | sendImages:self.selectedAssetsArray 178 | isFullImage:self.isFullImage]; 179 | } 180 | [self.navigationController dismissViewControllerAnimated:YES completion:nil];} 181 | 182 | - (void)browserPhotoAsstes:(NSArray *)assets pageIndex:(NSInteger)page { 183 | DNPhotoBrowser *browser = [[DNPhotoBrowser alloc] initWithPhotos:assets 184 | currentIndex:page 185 | fullImage:self.isFullImage]; 186 | browser.delegate = self; 187 | browser.hidesBottomBarWhenPushed = YES; 188 | [self.navigationController pushViewController:browser animated:YES]; 189 | } 190 | 191 | - (BOOL)seletedAssets:(DNAsset *)asset { 192 | if ([self.selectedAssetsArray containsObject:asset]) { 193 | return NO; 194 | } 195 | UIBarButtonItem *firstItem = self.toolbarItems.firstObject; 196 | firstItem.enabled = YES; 197 | if (self.selectedAssetsArray.count >= kDNImageFlowMaxSeletedNumber) { 198 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedStringFromTable(@"alertTitle", @"DNImagePicker", nil) 199 | message:NSLocalizedStringFromTable(@"alertContent", @"DNImagePicker", nil) 200 | delegate:self 201 | cancelButtonTitle:NSLocalizedStringFromTable(@"alertButton", @"DNImagePicker", nil) 202 | otherButtonTitles:nil, nil]; 203 | [alert show]; 204 | return NO; 205 | } else { 206 | [self addAssetsObject:asset]; 207 | self.sendButton.badgeValue = [NSString stringWithFormat:@"%@",@(self.selectedAssetsArray.count)]; 208 | return YES; 209 | } 210 | } 211 | 212 | - (void)deseletedAssets:(DNAsset *)asset { 213 | [self removeAssetsObject:asset]; 214 | self.sendButton.badgeValue = [NSString stringWithFormat:@"%@",@(self.selectedAssetsArray.count)]; 215 | if (self.selectedAssetsArray.count < 1) { 216 | UIBarButtonItem *firstItem = self.toolbarItems.firstObject; 217 | firstItem.enabled = NO; 218 | } 219 | } 220 | 221 | #pragma mark - getter/setter 222 | 223 | - (UICollectionView *)imageFlowCollectionView { 224 | if (!_imageFlowCollectionView) { 225 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 226 | layout.minimumLineSpacing = 2.0; 227 | layout.minimumInteritemSpacing = 2.0; 228 | layout.scrollDirection = UICollectionViewScrollDirectionVertical; 229 | _imageFlowCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height) collectionViewLayout:layout]; 230 | _imageFlowCollectionView.backgroundColor = [UIColor clearColor]; 231 | [_imageFlowCollectionView registerClass:[DNAssetsViewCell class] forCellWithReuseIdentifier:dnAssetsViewCellReuseIdentifier]; 232 | _imageFlowCollectionView.alwaysBounceVertical = YES; 233 | _imageFlowCollectionView.delegate = self; 234 | _imageFlowCollectionView.dataSource = self; 235 | _imageFlowCollectionView.showsHorizontalScrollIndicator = YES; 236 | [self.view addSubview:_imageFlowCollectionView]; 237 | } 238 | 239 | return _imageFlowCollectionView; 240 | } 241 | 242 | - (DNSendButton *)sendButton { 243 | if (!_sendButton) { 244 | _sendButton = [[DNSendButton alloc] initWithFrame:CGRectZero]; 245 | [_sendButton addTaget:self action:@selector(sendButtonAction:)]; 246 | } 247 | return _sendButton; 248 | } 249 | 250 | - (UIActivityIndicatorView *)indicatorView { 251 | if (!_indicatorView) { 252 | _indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 253 | _indicatorView.hidesWhenStopped = YES; 254 | _indicatorView.centerX = CGRectGetWidth(self.view.bounds)/2; 255 | _indicatorView.centerY = CGRectGetHeight(self.view.bounds)/2; 256 | [self.view addSubview:_indicatorView]; 257 | } 258 | return _indicatorView; 259 | } 260 | 261 | #pragma mark - ui action 262 | - (void)backButtonAction { 263 | [self.navigationController popViewControllerAnimated:YES]; 264 | } 265 | 266 | - (void)sendButtonAction:(id)sender { 267 | if (self.selectedAssetsArray.count > 0) { 268 | [self sendImages]; 269 | } 270 | } 271 | 272 | - (void)previewAction { 273 | [self browserPhotoAsstes:self.selectedAssetsArray pageIndex:0]; 274 | } 275 | 276 | - (void)cancelAction { 277 | DNImagePickerController *navController = [self dnImagePickerController]; 278 | if (navController && [navController.imagePickerDelegate respondsToSelector:@selector(dnImagePickerControllerDidCancel:)]) { 279 | [navController.imagePickerDelegate dnImagePickerControllerDidCancel:navController]; 280 | } 281 | } 282 | 283 | #pragma mark - DNAssetsViewCellDelegate 284 | - (void)didSelectItemAssetsViewCell:(DNAssetsViewCell *)assetsCell { 285 | assetsCell.isSelected = [self seletedAssets:assetsCell.asset]; 286 | } 287 | 288 | - (void)didDeselectItemAssetsViewCell:(DNAssetsViewCell *)assetsCell { 289 | assetsCell.isSelected = NO; 290 | [self deseletedAssets:assetsCell.asset]; 291 | } 292 | 293 | #pragma mark - UICollectionView delegate and Datasource 294 | - (NSInteger)collectionView:(UICollectionView *)collectionView 295 | numberOfItemsInSection:(NSInteger)section { 296 | return self.assetsArray.count; 297 | } 298 | 299 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView 300 | cellForItemAtIndexPath:(NSIndexPath *)indexPath { 301 | DNAssetsViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:dnAssetsViewCellReuseIdentifier forIndexPath:indexPath]; 302 | DNAsset *asset = self.assetsArray[indexPath.row]; 303 | cell.delegate = self; 304 | [cell fillWithAsset:asset isSelected:[self.selectedAssetsArray containsObject:asset]]; 305 | 306 | return cell; 307 | } 308 | 309 | - (void)collectionView:(UICollectionView *)collectionView 310 | didSelectItemAtIndexPath:(NSIndexPath *)indexPath { 311 | [self browserPhotoAsstes:self.assetsArray pageIndex:indexPath.row]; 312 | } 313 | 314 | #define kSizeThumbnailCollectionView ([UIScreen mainScreen].bounds.size.width-10)/4 315 | #pragma mark - UICollectionViewDelegateFlowLayout 316 | - (CGSize)collectionView:(UICollectionView *)collectionView 317 | layout:(UICollectionViewLayout *)collectionViewLayout 318 | sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 319 | CGSize size = CGSizeMake(kSizeThumbnailCollectionView, kSizeThumbnailCollectionView); 320 | return size; 321 | } 322 | 323 | - (UIEdgeInsets)collectionView:(UICollectionView *)collectionView 324 | layout:(UICollectionViewLayout*)collectionViewLayout 325 | insetForSectionAtIndex:(NSInteger)section { 326 | return UIEdgeInsetsMake(2, 2, 2, 2); 327 | } 328 | 329 | #pragma mark - DNPhotoBrowserDelegate 330 | - (void)sendImagesFromPhotobrowser:(DNPhotoBrowser *)photoBrowser currentAsset:(DNAsset *)asset { 331 | if (self.selectedAssetsArray.count <= 0) { 332 | [self seletedAssets:asset]; 333 | [self.imageFlowCollectionView reloadData]; 334 | } 335 | [self sendImages]; 336 | } 337 | 338 | - (NSUInteger)seletedPhotosNumberInPhotoBrowser:(DNPhotoBrowser *)photoBrowser { 339 | return self.selectedAssetsArray.count; 340 | } 341 | 342 | - (BOOL)photoBrowser:(DNPhotoBrowser *)photoBrowser currentPhotoAssetIsSeleted:(DNAsset *)asset{ 343 | return [self.selectedAssetsArray containsObject:asset]; 344 | } 345 | 346 | - (BOOL)photoBrowser:(DNPhotoBrowser *)photoBrowser seletedAsset:(DNAsset *)asset { 347 | BOOL seleted = [self seletedAssets:asset]; 348 | [self.imageFlowCollectionView reloadData]; 349 | return seleted; 350 | } 351 | 352 | - (void)photoBrowser:(DNPhotoBrowser *)photoBrowser deseletedAsset:(DNAsset *)asset { 353 | [self deseletedAssets:asset]; 354 | [self.imageFlowCollectionView reloadData]; 355 | } 356 | 357 | - (void)photoBrowser:(DNPhotoBrowser *)photoBrowser seleteFullImage:(BOOL)fullImage { 358 | self.isFullImage = fullImage; 359 | } 360 | 361 | @end 362 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker/Classes/Controllers/DNPhotoBrowser.m: -------------------------------------------------------------------------------- 1 | // 2 | // DNPhotoBrowserViewController.m 3 | // ImagePicker 4 | // 5 | // Created by DingXiao on 15/2/28. 6 | // Copyright (c) 2015年 Dennis. All rights reserved. 7 | // 8 | 9 | #import "DNPhotoBrowser.h" 10 | #import "UIViewController+DNImagePicker.h" 11 | #import "UIView+DNImagePicker.h" 12 | #import "DNSendButton.h" 13 | #import "DNFullImageButton.h" 14 | #import "DNBrowserCell.h" 15 | #import "DNAsset.h" 16 | #import "DNImagePickerHelper.h" 17 | 18 | #pragma clang diagnostic push 19 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 20 | 21 | 22 | @interface DNPhotoBrowser () 23 | { 24 | BOOL _statusBarShouldBeHidden; 25 | BOOL _didSavePreviousStateOfNavBar; 26 | BOOL _viewIsActive; 27 | BOOL _viewHasAppearedInitially; 28 | // Appearance 29 | BOOL _previousNavBarHidden; 30 | BOOL _previousNavBarTranslucent; 31 | UIBarStyle _previousNavBarStyle; 32 | UIColor *_previousNavBarTintColor; 33 | UIColor *_previousNavBarBarTintColor; 34 | UIBarButtonItem *_previousViewControllerBackButton; 35 | UIImage *_previousNavigationBarBackgroundImageDefault; 36 | UIImage *_previousNavigationBarBackgroundImageLandscapePhone; 37 | } 38 | 39 | @property (nonatomic, strong) UICollectionView *browserCollectionView; 40 | @property (nonatomic, strong) UIToolbar *toolbar; 41 | @property (nonatomic, strong) UIButton *checkButton; 42 | @property (nonatomic, strong) DNSendButton *sendButton; 43 | @property (nonatomic, strong) DNFullImageButton *fullImageButton; 44 | 45 | @property (nonatomic, strong) NSMutableArray *photoDataSources; 46 | @property (nonatomic, assign) NSInteger currentIndex; 47 | 48 | @property (nonatomic, getter=isFullImage) BOOL fullImage; 49 | 50 | @end 51 | 52 | @implementation DNPhotoBrowser 53 | 54 | - (instancetype)initWithPhotos:(NSArray *)photosArray 55 | currentIndex:(NSInteger)index 56 | fullImage:(BOOL)isFullImage { 57 | self = [super init]; 58 | if (self) { 59 | _photoDataSources = [[NSMutableArray alloc] initWithArray:photosArray]; 60 | _currentIndex = index; 61 | _fullImage = isFullImage; 62 | } 63 | return self; 64 | } 65 | 66 | - (void)viewDidLoad { 67 | [super viewDidLoad]; 68 | [self setupView]; 69 | [self updateSelestedNumber]; 70 | [self updateNavigationBarAndToolBar]; 71 | } 72 | - (void)viewWillAppear:(BOOL)animated { 73 | 74 | // Super 75 | [super viewWillAppear:animated]; 76 | 77 | // Navigation bar appearance 78 | if (!_viewIsActive && [self.navigationController.viewControllers objectAtIndex:0] != self) { 79 | [self storePreviousNavBarAppearance]; 80 | } 81 | [self setNavBarAppearance:animated]; 82 | 83 | // Initial appearance 84 | if (!_viewHasAppearedInitially) { 85 | _viewHasAppearedInitially = YES; 86 | } 87 | 88 | //scroll to the current offset 89 | [self.browserCollectionView setContentOffset:CGPointMake(self.browserCollectionView.frame.size.width * self.currentIndex,0)]; 90 | } 91 | 92 | - (void)viewWillDisappear:(BOOL)animated { 93 | // Check that we're being popped for good 94 | if ([self.navigationController.viewControllers objectAtIndex:0] != self && 95 | ![self.navigationController.viewControllers containsObject:self]) { 96 | 97 | _viewIsActive = NO; 98 | [self restorePreviousNavBarAppearance:animated]; 99 | } 100 | 101 | [self.navigationController.navigationBar.layer removeAllAnimations]; 102 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 103 | [self setControlsHidden:NO animated:NO]; 104 | 105 | // Super 106 | [super viewWillDisappear:animated]; 107 | } 108 | 109 | - (UIStatusBarStyle)preferredStatusBarStyle { 110 | return UIStatusBarStyleDefault; 111 | } 112 | 113 | - (void)viewDidAppear:(BOOL)animated { 114 | [super viewDidAppear:animated]; 115 | _viewIsActive = YES; 116 | } 117 | 118 | - (void)viewDidDisappear:(BOOL)animated { 119 | _viewIsActive = NO; 120 | [super viewDidDisappear:animated]; 121 | } 122 | 123 | #pragma mark - priviate 124 | - (void)setupView { 125 | self.automaticallyAdjustsScrollViewInsets = NO; 126 | self.view.clipsToBounds = YES; 127 | [self browserCollectionView]; 128 | [self toolbar]; 129 | [self setupBarButtonItems]; 130 | [self createBarButtonItemAtPosition:DNImagePickerNavigationBarPositionLeft 131 | statusNormalImage:[UIImage imageNamed:@"back_normal"] 132 | statusHighlightImage:[UIImage imageNamed:@"back_highlight"] 133 | action:@selector(backButtonAction)]; 134 | UIBarButtonItem *rightButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.checkButton]; 135 | self.navigationItem.rightBarButtonItem = rightButtonItem; 136 | } 137 | 138 | - (void)setupData 139 | { 140 | self.photoDataSources = [NSMutableArray new]; 141 | } 142 | 143 | - (void)setupBarButtonItems 144 | { 145 | UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithCustomView:self.fullImageButton]; 146 | UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 147 | UIBarButtonItem *item3 = [[UIBarButtonItem alloc] initWithCustomView:self.sendButton]; 148 | UIBarButtonItem *item4 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; 149 | item4.width = -10; 150 | 151 | [self.toolbar setItems:@[item1,item2,item3,item4]]; 152 | } 153 | 154 | - (void)updateNavigationBarAndToolBar { 155 | NSUInteger totalNumber = self.photoDataSources.count; 156 | self.title = [NSString stringWithFormat:@"%@/%@",@(self.currentIndex+1),@(totalNumber)]; 157 | BOOL isSeleted = NO; 158 | if ([self.delegate respondsToSelector:@selector(photoBrowser:currentPhotoAssetIsSeleted:)]) { 159 | isSeleted = [self.delegate photoBrowser:self currentPhotoAssetIsSeleted:[self.photoDataSources objectAtIndex:self.currentIndex]]; 160 | } 161 | self.checkButton.selected = isSeleted; 162 | self.fullImageButton.selected = self.isFullImage; 163 | 164 | if (self.isFullImage) { 165 | __weak typeof(self) wSelf = self; 166 | [DNImagePickerHelper fetchImageSizeWithAsset:self.photoDataSources[self.currentIndex] imageSizeResultHandler:^(CGFloat imageSize, NSString *sizeString) { 167 | __strong typeof(wSelf) sSelf = wSelf; 168 | sSelf.fullImageButton.text = sizeString; 169 | }]; 170 | } 171 | } 172 | 173 | - (void)updateSelestedNumber 174 | { 175 | NSUInteger selectedNumber = 0; 176 | if ([self.delegate respondsToSelector:@selector(seletedPhotosNumberInPhotoBrowser:)]) { 177 | selectedNumber = [self.delegate seletedPhotosNumberInPhotoBrowser:self]; 178 | } 179 | self.sendButton.badgeValue = [NSString stringWithFormat:@"%@",@(selectedNumber)]; 180 | } 181 | 182 | #pragma mark - Nav Bar Appearance 183 | - (void)setNavBarAppearance:(BOOL)animated { 184 | [self.navigationController setNavigationBarHidden:NO animated:animated]; 185 | UINavigationBar *navBar = self.navigationController.navigationBar; 186 | navBar.tintColor = [UIColor whiteColor]; 187 | if ([navBar respondsToSelector:@selector(setBarTintColor:)]) { 188 | navBar.barTintColor = nil; 189 | navBar.shadowImage = nil; 190 | } 191 | navBar.translucent = YES; 192 | navBar.barStyle = UIBarStyleBlackTranslucent; 193 | if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { 194 | [navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault]; 195 | [navBar setBackgroundImage:nil forBarMetrics:UIBarMetricsCompact];; 196 | } 197 | } 198 | 199 | 200 | - (void)storePreviousNavBarAppearance { 201 | _didSavePreviousStateOfNavBar = YES; 202 | if ([UINavigationBar instancesRespondToSelector:@selector(barTintColor)]) { 203 | _previousNavBarBarTintColor = self.navigationController.navigationBar.barTintColor; 204 | } 205 | _previousNavBarTranslucent = self.navigationController.navigationBar.translucent; 206 | _previousNavBarTintColor = self.navigationController.navigationBar.tintColor; 207 | _previousNavBarHidden = self.navigationController.navigationBarHidden; 208 | _previousNavBarStyle = self.navigationController.navigationBar.barStyle; 209 | if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { 210 | _previousNavigationBarBackgroundImageDefault = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]; 211 | _previousNavigationBarBackgroundImageLandscapePhone = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsCompact]; 212 | } 213 | } 214 | 215 | - (void)restorePreviousNavBarAppearance:(BOOL)animated { 216 | if (_didSavePreviousStateOfNavBar) { 217 | [self.navigationController setNavigationBarHidden:_previousNavBarHidden animated:animated]; 218 | UINavigationBar *navBar = self.navigationController.navigationBar; 219 | navBar.tintColor = _previousNavBarTintColor; 220 | navBar.translucent = _previousNavBarTranslucent; 221 | if ([UINavigationBar instancesRespondToSelector:@selector(barTintColor)]) { 222 | navBar.barTintColor = _previousNavBarBarTintColor; 223 | } 224 | navBar.barStyle = _previousNavBarStyle; 225 | if ([[UINavigationBar class] respondsToSelector:@selector(appearance)]) { 226 | [navBar setBackgroundImage:_previousNavigationBarBackgroundImageDefault forBarMetrics:UIBarMetricsDefault]; 227 | [navBar setBackgroundImage:_previousNavigationBarBackgroundImageLandscapePhone forBarMetrics:UIBarMetricsCompact]; 228 | } 229 | // Restore back button if we need to 230 | if (_previousViewControllerBackButton) { 231 | UIViewController *previousViewController = [self.navigationController topViewController]; // We've disappeared so previous is now top 232 | previousViewController.navigationItem.backBarButtonItem = _previousViewControllerBackButton; 233 | _previousViewControllerBackButton = nil; 234 | } 235 | } 236 | } 237 | 238 | #pragma mark - ui actions 239 | - (void)checkButtonAction { 240 | if (self.checkButton.selected) { 241 | if (self.delegate && [self.delegate respondsToSelector:@selector(photoBrowser:deseletedAsset:)]) { 242 | [self.delegate photoBrowser:self deseletedAsset:self.photoDataSources[self.currentIndex]]; 243 | self.checkButton.selected = NO; 244 | } 245 | } else { 246 | if (self.delegate && [self.delegate respondsToSelector:@selector(photoBrowser:seletedAsset:)]) { 247 | self.checkButton.selected = [self.delegate photoBrowser:self seletedAsset:self.photoDataSources[self.currentIndex]]; 248 | } 249 | } 250 | 251 | [self updateSelestedNumber]; 252 | } 253 | 254 | - (void)backButtonAction { 255 | [self.navigationController popViewControllerAnimated:YES]; 256 | } 257 | 258 | - (void)sendButtonAction { 259 | if ([self.delegate respondsToSelector:@selector(sendImagesFromPhotobrowser:currentAsset:)]) { 260 | [self.delegate sendImagesFromPhotobrowser:self currentAsset:self.photoDataSources[self.currentIndex]]; 261 | } 262 | } 263 | 264 | - (void)fullImageButtonAction { 265 | self.fullImageButton.selected = !self.fullImageButton.selected; 266 | self.fullImage = self.fullImageButton.selected; 267 | if ([self.delegate respondsToSelector:@selector(photoBrowser:seleteFullImage:)]) { 268 | [self.delegate photoBrowser:self seleteFullImage:self.isFullImage]; 269 | } 270 | if (self.fullImageButton.selected) { 271 | [self updateNavigationBarAndToolBar]; 272 | BOOL success = [self.delegate photoBrowser:self seletedAsset:self.photoDataSources[self.currentIndex]]; 273 | if (success) { 274 | [self updateSelestedNumber]; 275 | [self updateNavigationBarAndToolBar]; 276 | } 277 | } 278 | } 279 | 280 | #pragma mark - get/set 281 | - (UIButton *)checkButton { 282 | if (!_checkButton) { 283 | _checkButton = [UIButton buttonWithType:UIButtonTypeCustom]; 284 | _checkButton.frame = CGRectMake(0, 0, 25, 25); 285 | [_checkButton setBackgroundImage:[UIImage imageNamed:@"photo_check_selected"] forState:UIControlStateSelected]; 286 | [_checkButton setBackgroundImage:[UIImage imageNamed:@"photo_check_default"] forState:UIControlStateNormal]; 287 | [_checkButton addTarget:self action:@selector(checkButtonAction) forControlEvents:UIControlEventTouchUpInside]; 288 | } 289 | return _checkButton; 290 | } 291 | 292 | - (DNFullImageButton *)fullImageButton { 293 | if (!_fullImageButton) { 294 | _fullImageButton = [[DNFullImageButton alloc] initWithFrame:CGRectZero]; 295 | [_fullImageButton addTarget:self action:@selector(fullImageButtonAction)]; 296 | _fullImageButton.selected = self.isFullImage; 297 | } 298 | return _fullImageButton; 299 | } 300 | 301 | - (DNSendButton *)sendButton { 302 | if (!_sendButton) { 303 | _sendButton = [[DNSendButton alloc] initWithFrame:CGRectZero]; 304 | [_sendButton addTaget:self action:@selector(sendButtonAction)]; 305 | } 306 | return _sendButton; 307 | } 308 | 309 | - (UIToolbar *)toolbar { 310 | if (!_toolbar) { 311 | CGFloat height = 44; 312 | _toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height - height, self.view.bounds.size.width, height)]; 313 | if ([[UIToolbar class] respondsToSelector:@selector(appearance)]) { 314 | [_toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault]; 315 | [_toolbar setBackgroundImage:nil forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsCompact]; 316 | } 317 | _toolbar.barStyle = UIBarStyleBlackTranslucent; 318 | _toolbar.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth; 319 | [self.view addSubview:_toolbar]; 320 | } 321 | return _toolbar; 322 | } 323 | 324 | - (UICollectionView *)browserCollectionView { 325 | if (!_browserCollectionView) { 326 | UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; 327 | layout.minimumInteritemSpacing = 0; 328 | layout.minimumLineSpacing = 0; 329 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 330 | 331 | _browserCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(-10, 0, self.view.bounds.size.width+20, self.view.bounds.size.height+1) collectionViewLayout:layout]; 332 | _browserCollectionView.backgroundColor = [UIColor blackColor]; 333 | [_browserCollectionView registerClass:[DNBrowserCell class] forCellWithReuseIdentifier:NSStringFromClass([DNBrowserCell class])]; 334 | _browserCollectionView.delegate = self; 335 | _browserCollectionView.dataSource = self; 336 | _browserCollectionView.pagingEnabled = YES; 337 | _browserCollectionView.showsHorizontalScrollIndicator = NO; 338 | _browserCollectionView.showsVerticalScrollIndicator = NO; 339 | [self.view addSubview:_browserCollectionView]; 340 | } 341 | return _browserCollectionView; 342 | } 343 | 344 | #pragma mark - UICollectionViewDataSource 345 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 346 | return [self.photoDataSources count]; 347 | } 348 | 349 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 350 | DNBrowserCell *cell = (DNBrowserCell *)[collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([DNBrowserCell class]) forIndexPath:indexPath]; 351 | cell.asset = [self.photoDataSources objectAtIndex:indexPath.row]; 352 | cell.photoBrowser = self; 353 | return cell; 354 | } 355 | 356 | #pragma mark - UICollectionViewDelegateFlowLayout 357 | - (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { 358 | return CGSizeMake(self.view.bounds.size.width+20, self.view.bounds.size.height); 359 | } 360 | 361 | #pragma mark - scrollerViewDelegate 362 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView { 363 | CGFloat offsetX = scrollView.contentOffset.x; 364 | CGFloat itemWidth = CGRectGetWidth(self.browserCollectionView.frame); 365 | CGFloat currentPageOffset = itemWidth * self.currentIndex; 366 | CGFloat deltaOffset = offsetX - currentPageOffset; 367 | if (fabs(deltaOffset) >= itemWidth/2 ) { 368 | [self.fullImageButton shouldAnimating:YES]; 369 | } else { 370 | [self.fullImageButton shouldAnimating:NO]; 371 | } 372 | } 373 | 374 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { 375 | CGFloat offsetX = scrollView.contentOffset.x; 376 | CGFloat itemWidth = CGRectGetWidth(self.browserCollectionView.frame); 377 | if (offsetX >= 0){ 378 | NSInteger page = offsetX / itemWidth; 379 | [self didScrollToPage:page]; 380 | } 381 | 382 | [self.fullImageButton shouldAnimating:NO]; 383 | } 384 | 385 | - (void)didScrollToPage:(NSInteger)page { 386 | self.currentIndex = page; 387 | [self updateNavigationBarAndToolBar]; 388 | } 389 | 390 | #pragma mark - Control Hiding / Showing 391 | // Fades all controls slide and fade 392 | - (void)setControlsHidden:(BOOL)hidden animated:(BOOL)animated{ 393 | // Force visible 394 | if (!self.photoDataSources || !self.photoDataSources.count) 395 | hidden = NO; 396 | // Animations & positions 397 | CGFloat animatonOffset = 20; 398 | CGFloat animationDuration = (animated ? 0.35 : 0); 399 | 400 | // Status bar 401 | if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { 402 | // Hide status bar 403 | _statusBarShouldBeHidden = hidden; 404 | [UIView animateWithDuration:animationDuration animations:^(void) { 405 | [self setNeedsStatusBarAppearanceUpdate]; 406 | } completion:^(BOOL finished) {}]; 407 | } 408 | 409 | CGRect frame = CGRectIntegral(CGRectMake(0, self.view.bounds.size.height - 44, self.view.bounds.size.width, 44)); 410 | 411 | // Pre-appear animation positions for iOS 7 sliding 412 | if ([self areControlsHidden] && !hidden && animated) { 413 | // Toolbar 414 | self.toolbar.frame = CGRectOffset(frame, 0, animatonOffset); 415 | } 416 | 417 | [UIView animateWithDuration:animationDuration animations:^(void) { 418 | CGFloat alpha = hidden ? 0 : 1; 419 | // Nav bar slides up on it's own on iOS 7 420 | [self.navigationController.navigationBar setAlpha:alpha]; 421 | // Toolbar 422 | self.toolbar.frame = frame; 423 | if (hidden) self.toolbar.frame = CGRectOffset(self.toolbar.frame, 0, animatonOffset); 424 | self.toolbar.alpha = alpha; 425 | 426 | } completion:^(BOOL finished) {}]; 427 | } 428 | 429 | - (BOOL)prefersStatusBarHidden { 430 | return _statusBarShouldBeHidden; 431 | } 432 | 433 | - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { 434 | return UIStatusBarAnimationSlide; 435 | } 436 | 437 | - (BOOL)areControlsHidden { return (_toolbar.alpha == 0); } 438 | - (void)hideControls { [self setControlsHidden:YES animated:YES]; } 439 | - (void)toggleControls { [self setControlsHidden:![self areControlsHidden] animated:YES]; } 440 | @end 441 | #pragma clang diagnostic pop 442 | -------------------------------------------------------------------------------- /DNImagePicker/DNImagePicker.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 24D077EA216F4BF2004E397A /* UIColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = 24D077E9216F4BF2004E397A /* UIColor+Hex.m */; }; 11 | 24EBD7FA216CB58700B020FA /* DNImageFetchOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 24EBD7F9216CB58700B020FA /* DNImageFetchOperation.m */; }; 12 | 952600B21D2B9D4100080227 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600B11D2B9D4100080227 /* main.m */; }; 13 | 952600B51D2B9D4100080227 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600B41D2B9D4100080227 /* AppDelegate.m */; }; 14 | 952600B81D2B9D4100080227 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600B71D2B9D4100080227 /* ViewController.m */; }; 15 | 952600BB1D2B9D4100080227 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 952600B91D2B9D4100080227 /* Main.storyboard */; }; 16 | 952600BD1D2B9D4100080227 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 952600BC1D2B9D4100080227 /* Assets.xcassets */; }; 17 | 952600C01D2B9D4100080227 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 952600BE1D2B9D4100080227 /* LaunchScreen.storyboard */; }; 18 | 952600D41D2BA05700080227 /* DNImagePickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600CD1D2BA05700080227 /* DNImagePickerController.m */; }; 19 | 952600D51D2BA05700080227 /* DNAlbumTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600CF1D2BA05700080227 /* DNAlbumTableViewController.m */; }; 20 | 952600D61D2BA05700080227 /* DNImageFlowViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600D11D2BA05700080227 /* DNImageFlowViewController.m */; }; 21 | 952600D71D2BA05700080227 /* DNPhotoBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600D31D2BA05700080227 /* DNPhotoBrowser.m */; }; 22 | 952600EA1D2BA26400080227 /* DNBrowserCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600DC1D2BA26400080227 /* DNBrowserCell.m */; }; 23 | 952600EB1D2BA26400080227 /* DNTapDetectingImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600DE1D2BA26400080227 /* DNTapDetectingImageView.m */; }; 24 | 952600EC1D2BA26400080227 /* DNAssetsViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600E01D2BA26400080227 /* DNAssetsViewCell.m */; }; 25 | 952600ED1D2BA26400080227 /* DNSendButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600E21D2BA26400080227 /* DNSendButton.m */; }; 26 | 952600EE1D2BA26400080227 /* DNFullImageButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600E41D2BA26400080227 /* DNFullImageButton.m */; }; 27 | 952600EF1D2BA26400080227 /* DNBadgeLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600E61D2BA26400080227 /* DNBadgeLabel.m */; }; 28 | 952600F01D2BA26400080227 /* DNUnAuthorizedTipsView.m in Sources */ = {isa = PBXBuildFile; fileRef = 952600E81D2BA26400080227 /* DNUnAuthorizedTipsView.m */; }; 29 | 952600F21D2BA28000080227 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952600F11D2BA28000080227 /* AssetsLibrary.framework */; }; 30 | 952600F41D2BA29100080227 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 952600F31D2BA29100080227 /* Photos.framework */; }; 31 | 952601031D2BAF6D00080227 /* imageResources.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 952601011D2BAF6D00080227 /* imageResources.xcassets */; }; 32 | 952601051D2BAF7700080227 /* DNImagePicker.strings in Resources */ = {isa = PBXBuildFile; fileRef = 952601071D2BAF7700080227 /* DNImagePicker.strings */; }; 33 | 952601111D2BB7F700080227 /* UIViewController+DNImagePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 9526010A1D2BB7F700080227 /* UIViewController+DNImagePicker.m */; }; 34 | 952601141D2BB7F700080227 /* UIView+DNImagePicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 952601101D2BB7F700080227 /* UIView+DNImagePicker.m */; }; 35 | 9526011C1D2BBB4A00080227 /* InfoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 952601171D2BBB4A00080227 /* InfoViewController.m */; }; 36 | 9526011D1D2BBB4A00080227 /* CollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 952601191D2BBB4A00080227 /* CollectionViewController.m */; }; 37 | 9526011E1D2BBB4A00080227 /* CollectionViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 9526011B1D2BBB4A00080227 /* CollectionViewCell.m */; }; 38 | 952601211D2BBBA500080227 /* DNAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 952601201D2BBBA500080227 /* DNAsset.m */; }; 39 | 9526012A1D2D112500080227 /* DNAlbum.m in Sources */ = {isa = PBXBuildFile; fileRef = 952601291D2D112500080227 /* DNAlbum.m */; }; 40 | 95A147311D6C15A900E80455 /* DNImagePickerHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 95A147301D6C15A900E80455 /* DNImagePickerHelper.m */; }; 41 | 95BE232A1D73490700EDBAF3 /* DNAlbumCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 95BE23291D73490700EDBAF3 /* DNAlbumCell.m */; }; 42 | /* End PBXBuildFile section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 24D077E8216F4BF2004E397A /* UIColor+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+Hex.h"; sourceTree = ""; }; 46 | 24D077E9216F4BF2004E397A /* UIColor+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+Hex.m"; sourceTree = ""; }; 47 | 24EBD7F8216CB58700B020FA /* DNImageFetchOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DNImageFetchOperation.h; path = Controllers/DNImageFetchOperation.h; sourceTree = ""; }; 48 | 24EBD7F9216CB58700B020FA /* DNImageFetchOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = DNImageFetchOperation.m; path = Controllers/DNImageFetchOperation.m; sourceTree = ""; }; 49 | 952600AD1D2B9D4100080227 /* DNImagePicker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DNImagePicker.app; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 952600B11D2B9D4100080227 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | 952600B31D2B9D4100080227 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = ../DNImagePicker/AppDelegate.h; sourceTree = ""; }; 52 | 952600B41D2B9D4100080227 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = ../DNImagePicker/AppDelegate.m; sourceTree = ""; }; 53 | 952600B61D2B9D4100080227 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ViewController.h; path = ../DNImagePicker/ViewController.h; sourceTree = ""; }; 54 | 952600B71D2B9D4100080227 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ViewController.m; path = ../DNImagePicker/ViewController.m; sourceTree = ""; }; 55 | 952600BA1D2B9D4100080227 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 56 | 952600BC1D2B9D4100080227 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../DNImagePicker/Assets.xcassets; sourceTree = ""; }; 57 | 952600BF1D2B9D4100080227 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 58 | 952600C11D2B9D4100080227 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../DNImagePicker/Info.plist; sourceTree = ""; }; 59 | 952600CC1D2BA05700080227 /* DNImagePickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNImagePickerController.h; sourceTree = ""; }; 60 | 952600CD1D2BA05700080227 /* DNImagePickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNImagePickerController.m; sourceTree = ""; }; 61 | 952600CE1D2BA05700080227 /* DNAlbumTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNAlbumTableViewController.h; sourceTree = ""; }; 62 | 952600CF1D2BA05700080227 /* DNAlbumTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNAlbumTableViewController.m; sourceTree = ""; }; 63 | 952600D01D2BA05700080227 /* DNImageFlowViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNImageFlowViewController.h; sourceTree = ""; }; 64 | 952600D11D2BA05700080227 /* DNImageFlowViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNImageFlowViewController.m; sourceTree = ""; }; 65 | 952600D21D2BA05700080227 /* DNPhotoBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNPhotoBrowser.h; sourceTree = ""; }; 66 | 952600D31D2BA05700080227 /* DNPhotoBrowser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNPhotoBrowser.m; sourceTree = ""; }; 67 | 952600DB1D2BA26400080227 /* DNBrowserCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBrowserCell.h; sourceTree = ""; }; 68 | 952600DC1D2BA26400080227 /* DNBrowserCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNBrowserCell.m; sourceTree = ""; }; 69 | 952600DD1D2BA26400080227 /* DNTapDetectingImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNTapDetectingImageView.h; sourceTree = ""; }; 70 | 952600DE1D2BA26400080227 /* DNTapDetectingImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNTapDetectingImageView.m; sourceTree = ""; }; 71 | 952600DF1D2BA26400080227 /* DNAssetsViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNAssetsViewCell.h; sourceTree = ""; }; 72 | 952600E01D2BA26400080227 /* DNAssetsViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNAssetsViewCell.m; sourceTree = ""; }; 73 | 952600E11D2BA26400080227 /* DNSendButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSendButton.h; sourceTree = ""; }; 74 | 952600E21D2BA26400080227 /* DNSendButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSendButton.m; sourceTree = ""; }; 75 | 952600E31D2BA26400080227 /* DNFullImageButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNFullImageButton.h; sourceTree = ""; }; 76 | 952600E41D2BA26400080227 /* DNFullImageButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNFullImageButton.m; sourceTree = ""; }; 77 | 952600E51D2BA26400080227 /* DNBadgeLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBadgeLabel.h; sourceTree = ""; }; 78 | 952600E61D2BA26400080227 /* DNBadgeLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNBadgeLabel.m; sourceTree = ""; }; 79 | 952600E71D2BA26400080227 /* DNUnAuthorizedTipsView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNUnAuthorizedTipsView.h; sourceTree = ""; }; 80 | 952600E81D2BA26400080227 /* DNUnAuthorizedTipsView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNUnAuthorizedTipsView.m; sourceTree = ""; }; 81 | 952600F11D2BA28000080227 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 82 | 952600F31D2BA29100080227 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 83 | 952601011D2BAF6D00080227 /* imageResources.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = imageResources.xcassets; sourceTree = ""; }; 84 | 952601061D2BAF7700080227 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/DNImagePicker.strings; sourceTree = ""; }; 85 | 952601081D2BAFB200080227 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/DNImagePicker.strings"; sourceTree = ""; }; 86 | 952601091D2BB7F700080227 /* UIViewController+DNImagePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+DNImagePicker.h"; sourceTree = ""; }; 87 | 9526010A1D2BB7F700080227 /* UIViewController+DNImagePicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+DNImagePicker.m"; sourceTree = ""; }; 88 | 9526010F1D2BB7F700080227 /* UIView+DNImagePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+DNImagePicker.h"; sourceTree = ""; }; 89 | 952601101D2BB7F700080227 /* UIView+DNImagePicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+DNImagePicker.m"; sourceTree = ""; }; 90 | 952601161D2BBB4A00080227 /* InfoViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InfoViewController.h; sourceTree = ""; }; 91 | 952601171D2BBB4A00080227 /* InfoViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InfoViewController.m; sourceTree = ""; }; 92 | 952601181D2BBB4A00080227 /* CollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionViewController.h; sourceTree = ""; }; 93 | 952601191D2BBB4A00080227 /* CollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionViewController.m; sourceTree = ""; }; 94 | 9526011A1D2BBB4A00080227 /* CollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionViewCell.h; sourceTree = ""; }; 95 | 9526011B1D2BBB4A00080227 /* CollectionViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CollectionViewCell.m; sourceTree = ""; }; 96 | 9526011F1D2BBBA500080227 /* DNAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNAsset.h; sourceTree = ""; }; 97 | 952601201D2BBBA500080227 /* DNAsset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNAsset.m; sourceTree = ""; }; 98 | 952601221D2CD7C600080227 /* DNImagePicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNImagePicker.h; sourceTree = ""; }; 99 | 952601281D2D112500080227 /* DNAlbum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNAlbum.h; sourceTree = ""; }; 100 | 952601291D2D112500080227 /* DNAlbum.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNAlbum.m; sourceTree = ""; }; 101 | 95A1472F1D6C15A900E80455 /* DNImagePickerHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNImagePickerHelper.h; sourceTree = ""; }; 102 | 95A147301D6C15A900E80455 /* DNImagePickerHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNImagePickerHelper.m; sourceTree = ""; }; 103 | 95BE23281D73490700EDBAF3 /* DNAlbumCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNAlbumCell.h; sourceTree = ""; }; 104 | 95BE23291D73490700EDBAF3 /* DNAlbumCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNAlbumCell.m; sourceTree = ""; }; 105 | /* End PBXFileReference section */ 106 | 107 | /* Begin PBXFrameworksBuildPhase section */ 108 | 952600AA1D2B9D4100080227 /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | 952600F41D2BA29100080227 /* Photos.framework in Frameworks */, 113 | 952600F21D2BA28000080227 /* AssetsLibrary.framework in Frameworks */, 114 | ); 115 | runOnlyForDeploymentPostprocessing = 0; 116 | }; 117 | /* End PBXFrameworksBuildPhase section */ 118 | 119 | /* Begin PBXGroup section */ 120 | 952600A41D2B9D4100080227 = { 121 | isa = PBXGroup; 122 | children = ( 123 | 952600C71D2B9D8400080227 /* DNImagePickerDemo */, 124 | 952600AF1D2B9D4100080227 /* DNImagePicker */, 125 | 952600AE1D2B9D4100080227 /* Products */, 126 | 952600F31D2BA29100080227 /* Photos.framework */, 127 | 952600F11D2BA28000080227 /* AssetsLibrary.framework */, 128 | ); 129 | sourceTree = ""; 130 | }; 131 | 952600AE1D2B9D4100080227 /* Products */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 952600AD1D2B9D4100080227 /* DNImagePicker.app */, 135 | ); 136 | name = Products; 137 | sourceTree = ""; 138 | }; 139 | 952600AF1D2B9D4100080227 /* DNImagePicker */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 952601221D2CD7C600080227 /* DNImagePicker.h */, 143 | 952600CA1D2B9F6F00080227 /* Support */, 144 | 952600C91D2B9F5100080227 /* Resources */, 145 | 952600C81D2B9F3700080227 /* Classes */, 146 | ); 147 | path = DNImagePicker; 148 | sourceTree = ""; 149 | }; 150 | 952600B01D2B9D4100080227 /* Supporting Files */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 952600B11D2B9D4100080227 /* main.m */, 154 | ); 155 | name = "Supporting Files"; 156 | path = ../DNImagePicker; 157 | sourceTree = ""; 158 | }; 159 | 952600C71D2B9D8400080227 /* DNImagePickerDemo */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 952600B31D2B9D4100080227 /* AppDelegate.h */, 163 | 952600B41D2B9D4100080227 /* AppDelegate.m */, 164 | 952600B61D2B9D4100080227 /* ViewController.h */, 165 | 952600B71D2B9D4100080227 /* ViewController.m */, 166 | 952601161D2BBB4A00080227 /* InfoViewController.h */, 167 | 952601171D2BBB4A00080227 /* InfoViewController.m */, 168 | 952601181D2BBB4A00080227 /* CollectionViewController.h */, 169 | 952601191D2BBB4A00080227 /* CollectionViewController.m */, 170 | 9526011A1D2BBB4A00080227 /* CollectionViewCell.h */, 171 | 9526011B1D2BBB4A00080227 /* CollectionViewCell.m */, 172 | 952600B91D2B9D4100080227 /* Main.storyboard */, 173 | 952600BC1D2B9D4100080227 /* Assets.xcassets */, 174 | 952600BE1D2B9D4100080227 /* LaunchScreen.storyboard */, 175 | 952600C11D2B9D4100080227 /* Info.plist */, 176 | 952600B01D2B9D4100080227 /* Supporting Files */, 177 | ); 178 | path = DNImagePickerDemo; 179 | sourceTree = ""; 180 | }; 181 | 952600C81D2B9F3700080227 /* Classes */ = { 182 | isa = PBXGroup; 183 | children = ( 184 | 952601241D2CDBAC00080227 /* Managers */, 185 | 952601151D2BB93C00080227 /* Models */, 186 | 952600D81D2BA17900080227 /* Views */, 187 | 952600CB1D2BA00700080227 /* Controllers */, 188 | ); 189 | path = Classes; 190 | sourceTree = ""; 191 | }; 192 | 952600C91D2B9F5100080227 /* Resources */ = { 193 | isa = PBXGroup; 194 | children = ( 195 | 952601011D2BAF6D00080227 /* imageResources.xcassets */, 196 | 952601071D2BAF7700080227 /* DNImagePicker.strings */, 197 | ); 198 | path = Resources; 199 | sourceTree = ""; 200 | }; 201 | 952600CA1D2B9F6F00080227 /* Support */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 24D077E8216F4BF2004E397A /* UIColor+Hex.h */, 205 | 24D077E9216F4BF2004E397A /* UIColor+Hex.m */, 206 | 952601091D2BB7F700080227 /* UIViewController+DNImagePicker.h */, 207 | 9526010A1D2BB7F700080227 /* UIViewController+DNImagePicker.m */, 208 | 9526010F1D2BB7F700080227 /* UIView+DNImagePicker.h */, 209 | 952601101D2BB7F700080227 /* UIView+DNImagePicker.m */, 210 | ); 211 | path = Support; 212 | sourceTree = ""; 213 | }; 214 | 952600CB1D2BA00700080227 /* Controllers */ = { 215 | isa = PBXGroup; 216 | children = ( 217 | 952600CC1D2BA05700080227 /* DNImagePickerController.h */, 218 | 952600CD1D2BA05700080227 /* DNImagePickerController.m */, 219 | 952600CE1D2BA05700080227 /* DNAlbumTableViewController.h */, 220 | 952600CF1D2BA05700080227 /* DNAlbumTableViewController.m */, 221 | 952600D01D2BA05700080227 /* DNImageFlowViewController.h */, 222 | 952600D11D2BA05700080227 /* DNImageFlowViewController.m */, 223 | 952600D21D2BA05700080227 /* DNPhotoBrowser.h */, 224 | 952600D31D2BA05700080227 /* DNPhotoBrowser.m */, 225 | ); 226 | path = Controllers; 227 | sourceTree = ""; 228 | }; 229 | 952600D81D2BA17900080227 /* Views */ = { 230 | isa = PBXGroup; 231 | children = ( 232 | 95BE23281D73490700EDBAF3 /* DNAlbumCell.h */, 233 | 95BE23291D73490700EDBAF3 /* DNAlbumCell.m */, 234 | 952600DB1D2BA26400080227 /* DNBrowserCell.h */, 235 | 952600DC1D2BA26400080227 /* DNBrowserCell.m */, 236 | 952600DD1D2BA26400080227 /* DNTapDetectingImageView.h */, 237 | 952600DE1D2BA26400080227 /* DNTapDetectingImageView.m */, 238 | 952600DF1D2BA26400080227 /* DNAssetsViewCell.h */, 239 | 952600E01D2BA26400080227 /* DNAssetsViewCell.m */, 240 | 952600E11D2BA26400080227 /* DNSendButton.h */, 241 | 952600E21D2BA26400080227 /* DNSendButton.m */, 242 | 952600E31D2BA26400080227 /* DNFullImageButton.h */, 243 | 952600E41D2BA26400080227 /* DNFullImageButton.m */, 244 | 952600E51D2BA26400080227 /* DNBadgeLabel.h */, 245 | 952600E61D2BA26400080227 /* DNBadgeLabel.m */, 246 | 952600E71D2BA26400080227 /* DNUnAuthorizedTipsView.h */, 247 | 952600E81D2BA26400080227 /* DNUnAuthorizedTipsView.m */, 248 | ); 249 | path = Views; 250 | sourceTree = ""; 251 | }; 252 | 952601151D2BB93C00080227 /* Models */ = { 253 | isa = PBXGroup; 254 | children = ( 255 | 9526011F1D2BBBA500080227 /* DNAsset.h */, 256 | 952601201D2BBBA500080227 /* DNAsset.m */, 257 | 952601281D2D112500080227 /* DNAlbum.h */, 258 | 952601291D2D112500080227 /* DNAlbum.m */, 259 | ); 260 | path = Models; 261 | sourceTree = ""; 262 | }; 263 | 952601241D2CDBAC00080227 /* Managers */ = { 264 | isa = PBXGroup; 265 | children = ( 266 | 95A1472F1D6C15A900E80455 /* DNImagePickerHelper.h */, 267 | 95A147301D6C15A900E80455 /* DNImagePickerHelper.m */, 268 | 24EBD7F8216CB58700B020FA /* DNImageFetchOperation.h */, 269 | 24EBD7F9216CB58700B020FA /* DNImageFetchOperation.m */, 270 | ); 271 | name = Managers; 272 | sourceTree = ""; 273 | }; 274 | /* End PBXGroup section */ 275 | 276 | /* Begin PBXNativeTarget section */ 277 | 952600AC1D2B9D4100080227 /* DNImagePicker */ = { 278 | isa = PBXNativeTarget; 279 | buildConfigurationList = 952600C41D2B9D4100080227 /* Build configuration list for PBXNativeTarget "DNImagePicker" */; 280 | buildPhases = ( 281 | 952600A91D2B9D4100080227 /* Sources */, 282 | 952600AA1D2B9D4100080227 /* Frameworks */, 283 | 952600AB1D2B9D4100080227 /* Resources */, 284 | ); 285 | buildRules = ( 286 | ); 287 | dependencies = ( 288 | ); 289 | name = DNImagePicker; 290 | productName = DNImagePicker; 291 | productReference = 952600AD1D2B9D4100080227 /* DNImagePicker.app */; 292 | productType = "com.apple.product-type.application"; 293 | }; 294 | /* End PBXNativeTarget section */ 295 | 296 | /* Begin PBXProject section */ 297 | 952600A51D2B9D4100080227 /* Project object */ = { 298 | isa = PBXProject; 299 | attributes = { 300 | LastUpgradeCheck = 1000; 301 | ORGANIZATIONNAME = Dennis; 302 | TargetAttributes = { 303 | 952600AC1D2B9D4100080227 = { 304 | CreatedOnToolsVersion = 7.3.1; 305 | DevelopmentTeam = 7RQERF84NY; 306 | }; 307 | }; 308 | }; 309 | buildConfigurationList = 952600A81D2B9D4100080227 /* Build configuration list for PBXProject "DNImagePicker" */; 310 | compatibilityVersion = "Xcode 3.2"; 311 | developmentRegion = English; 312 | hasScannedForEncodings = 0; 313 | knownRegions = ( 314 | en, 315 | Base, 316 | "zh-Hans", 317 | ); 318 | mainGroup = 952600A41D2B9D4100080227; 319 | productRefGroup = 952600AE1D2B9D4100080227 /* Products */; 320 | projectDirPath = ""; 321 | projectRoot = ""; 322 | targets = ( 323 | 952600AC1D2B9D4100080227 /* DNImagePicker */, 324 | ); 325 | }; 326 | /* End PBXProject section */ 327 | 328 | /* Begin PBXResourcesBuildPhase section */ 329 | 952600AB1D2B9D4100080227 /* Resources */ = { 330 | isa = PBXResourcesBuildPhase; 331 | buildActionMask = 2147483647; 332 | files = ( 333 | 952600C01D2B9D4100080227 /* LaunchScreen.storyboard in Resources */, 334 | 952601051D2BAF7700080227 /* DNImagePicker.strings in Resources */, 335 | 952601031D2BAF6D00080227 /* imageResources.xcassets in Resources */, 336 | 952600BD1D2B9D4100080227 /* Assets.xcassets in Resources */, 337 | 952600BB1D2B9D4100080227 /* Main.storyboard in Resources */, 338 | ); 339 | runOnlyForDeploymentPostprocessing = 0; 340 | }; 341 | /* End PBXResourcesBuildPhase section */ 342 | 343 | /* Begin PBXSourcesBuildPhase section */ 344 | 952600A91D2B9D4100080227 /* Sources */ = { 345 | isa = PBXSourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 952600EB1D2BA26400080227 /* DNTapDetectingImageView.m in Sources */, 349 | 9526012A1D2D112500080227 /* DNAlbum.m in Sources */, 350 | 952600D61D2BA05700080227 /* DNImageFlowViewController.m in Sources */, 351 | 952600EC1D2BA26400080227 /* DNAssetsViewCell.m in Sources */, 352 | 952600D71D2BA05700080227 /* DNPhotoBrowser.m in Sources */, 353 | 952600EF1D2BA26400080227 /* DNBadgeLabel.m in Sources */, 354 | 952600B81D2B9D4100080227 /* ViewController.m in Sources */, 355 | 952600ED1D2BA26400080227 /* DNSendButton.m in Sources */, 356 | 952601211D2BBBA500080227 /* DNAsset.m in Sources */, 357 | 9526011D1D2BBB4A00080227 /* CollectionViewController.m in Sources */, 358 | 952600EE1D2BA26400080227 /* DNFullImageButton.m in Sources */, 359 | 952600D51D2BA05700080227 /* DNAlbumTableViewController.m in Sources */, 360 | 95BE232A1D73490700EDBAF3 /* DNAlbumCell.m in Sources */, 361 | 952600B51D2B9D4100080227 /* AppDelegate.m in Sources */, 362 | 952600B21D2B9D4100080227 /* main.m in Sources */, 363 | 952601141D2BB7F700080227 /* UIView+DNImagePicker.m in Sources */, 364 | 952601111D2BB7F700080227 /* UIViewController+DNImagePicker.m in Sources */, 365 | 952600D41D2BA05700080227 /* DNImagePickerController.m in Sources */, 366 | 24EBD7FA216CB58700B020FA /* DNImageFetchOperation.m in Sources */, 367 | 952600EA1D2BA26400080227 /* DNBrowserCell.m in Sources */, 368 | 9526011C1D2BBB4A00080227 /* InfoViewController.m in Sources */, 369 | 24D077EA216F4BF2004E397A /* UIColor+Hex.m in Sources */, 370 | 9526011E1D2BBB4A00080227 /* CollectionViewCell.m in Sources */, 371 | 952600F01D2BA26400080227 /* DNUnAuthorizedTipsView.m in Sources */, 372 | 95A147311D6C15A900E80455 /* DNImagePickerHelper.m in Sources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | /* End PBXSourcesBuildPhase section */ 377 | 378 | /* Begin PBXVariantGroup section */ 379 | 952600B91D2B9D4100080227 /* Main.storyboard */ = { 380 | isa = PBXVariantGroup; 381 | children = ( 382 | 952600BA1D2B9D4100080227 /* Base */, 383 | ); 384 | name = Main.storyboard; 385 | path = ../DNImagePicker; 386 | sourceTree = ""; 387 | }; 388 | 952600BE1D2B9D4100080227 /* LaunchScreen.storyboard */ = { 389 | isa = PBXVariantGroup; 390 | children = ( 391 | 952600BF1D2B9D4100080227 /* Base */, 392 | ); 393 | name = LaunchScreen.storyboard; 394 | path = ../DNImagePicker; 395 | sourceTree = ""; 396 | }; 397 | 952601071D2BAF7700080227 /* DNImagePicker.strings */ = { 398 | isa = PBXVariantGroup; 399 | children = ( 400 | 952601061D2BAF7700080227 /* en */, 401 | 952601081D2BAFB200080227 /* zh-Hans */, 402 | ); 403 | name = DNImagePicker.strings; 404 | sourceTree = ""; 405 | }; 406 | /* End PBXVariantGroup section */ 407 | 408 | /* Begin XCBuildConfiguration section */ 409 | 952600C21D2B9D4100080227 /* Debug */ = { 410 | isa = XCBuildConfiguration; 411 | buildSettings = { 412 | ALWAYS_SEARCH_USER_PATHS = NO; 413 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 414 | CLANG_ANALYZER_NONNULL = YES; 415 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 416 | CLANG_CXX_LIBRARY = "libc++"; 417 | CLANG_ENABLE_MODULES = YES; 418 | CLANG_ENABLE_OBJC_ARC = YES; 419 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 420 | CLANG_WARN_BOOL_CONVERSION = YES; 421 | CLANG_WARN_COMMA = YES; 422 | CLANG_WARN_CONSTANT_CONVERSION = YES; 423 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 424 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 425 | CLANG_WARN_EMPTY_BODY = YES; 426 | CLANG_WARN_ENUM_CONVERSION = YES; 427 | CLANG_WARN_INFINITE_RECURSION = YES; 428 | CLANG_WARN_INT_CONVERSION = YES; 429 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 430 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 431 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 432 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 433 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 434 | CLANG_WARN_STRICT_PROTOTYPES = YES; 435 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 439 | COPY_PHASE_STRIP = NO; 440 | DEBUG_INFORMATION_FORMAT = dwarf; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | ENABLE_TESTABILITY = YES; 443 | GCC_C_LANGUAGE_STANDARD = gnu99; 444 | GCC_DYNAMIC_NO_PIC = NO; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_OPTIMIZATION_LEVEL = 0; 447 | GCC_PREPROCESSOR_DEFINITIONS = ( 448 | "DEBUG=1", 449 | "$(inherited)", 450 | ); 451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 452 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 453 | GCC_WARN_UNDECLARED_SELECTOR = YES; 454 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 455 | GCC_WARN_UNUSED_FUNCTION = YES; 456 | GCC_WARN_UNUSED_VARIABLE = YES; 457 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 458 | MTL_ENABLE_DEBUG_INFO = YES; 459 | ONLY_ACTIVE_ARCH = YES; 460 | SDKROOT = iphoneos; 461 | }; 462 | name = Debug; 463 | }; 464 | 952600C31D2B9D4100080227 /* Release */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | ALWAYS_SEARCH_USER_PATHS = NO; 468 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 469 | CLANG_ANALYZER_NONNULL = YES; 470 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 471 | CLANG_CXX_LIBRARY = "libc++"; 472 | CLANG_ENABLE_MODULES = YES; 473 | CLANG_ENABLE_OBJC_ARC = YES; 474 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 475 | CLANG_WARN_BOOL_CONVERSION = YES; 476 | CLANG_WARN_COMMA = YES; 477 | CLANG_WARN_CONSTANT_CONVERSION = YES; 478 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 479 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 480 | CLANG_WARN_EMPTY_BODY = YES; 481 | CLANG_WARN_ENUM_CONVERSION = YES; 482 | CLANG_WARN_INFINITE_RECURSION = YES; 483 | CLANG_WARN_INT_CONVERSION = YES; 484 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 485 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 486 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 487 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 488 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 489 | CLANG_WARN_STRICT_PROTOTYPES = YES; 490 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 491 | CLANG_WARN_UNREACHABLE_CODE = YES; 492 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 493 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 494 | COPY_PHASE_STRIP = NO; 495 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 496 | ENABLE_NS_ASSERTIONS = NO; 497 | ENABLE_STRICT_OBJC_MSGSEND = YES; 498 | GCC_C_LANGUAGE_STANDARD = gnu99; 499 | GCC_NO_COMMON_BLOCKS = YES; 500 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 501 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 502 | GCC_WARN_UNDECLARED_SELECTOR = YES; 503 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 504 | GCC_WARN_UNUSED_FUNCTION = YES; 505 | GCC_WARN_UNUSED_VARIABLE = YES; 506 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 507 | MTL_ENABLE_DEBUG_INFO = NO; 508 | SDKROOT = iphoneos; 509 | VALIDATE_PRODUCT = YES; 510 | }; 511 | name = Release; 512 | }; 513 | 952600C51D2B9D4100080227 /* Debug */ = { 514 | isa = XCBuildConfiguration; 515 | buildSettings = { 516 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 517 | CODE_SIGN_IDENTITY = "iPhone Developer"; 518 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 519 | DEVELOPMENT_TEAM = 7RQERF84NY; 520 | INFOPLIST_FILE = DNImagePicker/Info.plist; 521 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 522 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 523 | PRODUCT_BUNDLE_IDENTIFIER = com.awesomedennis.DNImagePickeraaa; 524 | PRODUCT_NAME = "$(TARGET_NAME)"; 525 | PROVISIONING_PROFILE = ""; 526 | }; 527 | name = Debug; 528 | }; 529 | 952600C61D2B9D4100080227 /* Release */ = { 530 | isa = XCBuildConfiguration; 531 | buildSettings = { 532 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 533 | CODE_SIGN_IDENTITY = "iPhone Developer"; 534 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 535 | DEVELOPMENT_TEAM = 7RQERF84NY; 536 | INFOPLIST_FILE = DNImagePicker/Info.plist; 537 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 538 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 539 | PRODUCT_BUNDLE_IDENTIFIER = com.awesomedennis.DNImagePickeraaa; 540 | PRODUCT_NAME = "$(TARGET_NAME)"; 541 | PROVISIONING_PROFILE = ""; 542 | }; 543 | name = Release; 544 | }; 545 | /* End XCBuildConfiguration section */ 546 | 547 | /* Begin XCConfigurationList section */ 548 | 952600A81D2B9D4100080227 /* Build configuration list for PBXProject "DNImagePicker" */ = { 549 | isa = XCConfigurationList; 550 | buildConfigurations = ( 551 | 952600C21D2B9D4100080227 /* Debug */, 552 | 952600C31D2B9D4100080227 /* Release */, 553 | ); 554 | defaultConfigurationIsVisible = 0; 555 | defaultConfigurationName = Release; 556 | }; 557 | 952600C41D2B9D4100080227 /* Build configuration list for PBXNativeTarget "DNImagePicker" */ = { 558 | isa = XCConfigurationList; 559 | buildConfigurations = ( 560 | 952600C51D2B9D4100080227 /* Debug */, 561 | 952600C61D2B9D4100080227 /* Release */, 562 | ); 563 | defaultConfigurationIsVisible = 0; 564 | defaultConfigurationName = Release; 565 | }; 566 | /* End XCConfigurationList section */ 567 | }; 568 | rootObject = 952600A51D2B9D4100080227 /* Project object */; 569 | } 570 | --------------------------------------------------------------------------------