├── .DS_Store ├── ZYQAssetPickerController ├── .DS_Store ├── ZYQAssetPicker.Bundle │ └── Images │ │ ├── AssetsPickerChecked@2x.png │ │ ├── AssetsPickerLocked@2x.png │ │ ├── AssetsPickerVideo@2x.png │ │ └── AssetsPickerChecked~iOS6@2x.png ├── ZYQAssetPickerController.h └── ZYQAssetPickerController.m ├── ZYQAssetPickerControllerDemo ├── ZYQAssetPickerControllerDemo │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── zh-Hans.lproj │ │ └── InfoPlist.strings │ ├── Images.xcassets │ │ ├── LaunchImage.launchimage │ │ │ ├── Default.png │ │ │ ├── Default-1.png │ │ │ ├── Default-2.png │ │ │ ├── Default-3.png │ │ │ ├── Default-4.png │ │ │ ├── Default-5.png │ │ │ ├── Default-6.png │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── MainViewController.h │ ├── AppDelegate.h │ ├── main.m │ ├── ZYQAssetPickerControllerDemo-Prefix.pch │ ├── ZYQAssetPickerControllerDemo-Info.plist │ ├── AppDelegate.m │ └── MainViewController.m ├── .DS_Store ├── ZYQAssetPickerControllerDemoTests │ ├── zh-Hans.lproj │ │ └── InfoPlist.strings │ ├── ZYQAssetPickerControllerDemoTests-Info.plist │ ├── ZYQAssetPickerControllerDemoTests.m │ └── en.lproj │ │ └── InfoPlist.strings └── ZYQAssetPickerControllerDemo.xcodeproj │ ├── xcuserdata │ ├── apple.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── ZYQAssetPickerControllerDemo.xcscheme │ ├── zhaoyiqi.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── ZYQAssetPickerControllerDemo.xcscheme │ ├── admin.xcuserdatad │ │ └── xcschemes │ │ │ ├── xcschememanagement.plist │ │ │ └── ZYQAssetPickerControllerDemo.xcscheme │ └── heroims.xcuserdatad │ │ ├── xcschemes │ │ ├── xcschememanagement.plist │ │ └── ZYQAssetPickerControllerDemo.xcscheme │ │ └── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ ├── admin.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── apple.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ │ ├── heroims.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ │ └── zhaoyiqi.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── ZYQAssetPickerControllerDemo.xccheckout │ └── project.pbxproj ├── .gitignore ├── README.md └── ZYQAssetPickerController.podspec /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/.DS_Store -------------------------------------------------------------------------------- /ZYQAssetPickerController/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerController/.DS_Store -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/.DS_Store -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemoTests/zh-Hans.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerChecked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerChecked@2x.png -------------------------------------------------------------------------------- /ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerLocked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerLocked@2x.png -------------------------------------------------------------------------------- /ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerVideo@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerVideo@2x.png -------------------------------------------------------------------------------- /ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerChecked~iOS6@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerController/ZYQAssetPicker.Bundle/Images/AssetsPickerChecked~iOS6@2x.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/apple.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/zhaoyiqi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-1.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-2.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-3.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-4.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-5.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Default-6.png -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/heroims.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/heroims.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/zhaoyiqi.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heroims/ZYQAssetPickerController/HEAD/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/zhaoyiqi.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac OS X Finder 2 | .DS_Store 3 | 4 | # Xcode per-user config 5 | *.mode1 6 | *.mode1v3 7 | *.mode2v3 8 | *.perspective 9 | *.perspectivev3 10 | *.pbxuser 11 | xcuserdata 12 | *.xccheckout 13 | 14 | # Build products 15 | build/ 16 | *.o 17 | *.LinkFileList 18 | *.hmap 19 | 20 | # Automatic backup files 21 | *~.nib/ 22 | *.swp 23 | *~ 24 | *.dat 25 | *.dep 26 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/MainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.h 3 | // ZYQAssetPickerControllerDemo 4 | // 5 | // Created by Zhao Yiqi on 13-12-26. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MainViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ZYQAssetPickerControllerDemo 4 | // 5 | // Created by Zhao Yiqi on 13-12-25. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "MainViewController.h" 12 | 13 | @interface AppDelegate : UIResponder 14 | 15 | @property (strong, nonatomic) UIWindow *window; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ZYQAssetPickerControllerDemo 4 | // 5 | // Created by Zhao Yiqi on 13-12-25. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcuserdata/heroims.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ZYQAssetPickerController 2 | ======================== 3 | [![](http://i.imgur.com/Yv6RIjd.gif?1)](http://i.imgur.com/Yv6RIjd.gif?1) 4 | ## Minimum Requirement 5 | iOS 6.0 6 | 7 | ## Installation 8 | 9 | ### via CocoaPods 10 | Install CocoaPods if you do not have it:- 11 | ```` 12 | $ [sudo] gem install cocoapods 13 | $ pod setup 14 | ```` 15 | Create Podfile:- 16 | ```` 17 | $ edit Podfile 18 | platform :ios, '5.0' 19 | pod 'ZYQAssetPickerController', '~> 1.2.0' 20 | $ pod install 21 | ```` 22 | Use the Xcode workspace instead of the project from now on. 23 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZYQAssetPickerControllerDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D8E6C4C4186B21AC0057C549 16 | 17 | primary 18 | 19 | 20 | D8E6C4DF186B21AD0057C549 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZYQAssetPickerControllerDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D8E6C4C4186B21AC0057C549 16 | 17 | primary 18 | 19 | 20 | D8E6C4DF186B21AD0057C549 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/heroims.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZYQAssetPickerControllerDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D8E6C4C4186B21AC0057C549 16 | 17 | primary 18 | 19 | 20 | D8E6C4DF186B21AD0057C549 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/zhaoyiqi.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ZYQAssetPickerControllerDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D8E6C4C4186B21AC0057C549 16 | 17 | primary 18 | 19 | 20 | D8E6C4DF186B21AD0057C549 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemoTests/ZYQAssetPickerControllerDemoTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ZYQAssetPickerController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'ZYQAssetPickerController' 3 | s.version = '1.3.1' 4 | s.summary = 'A clone of the UIImagePickerController using the Assets Library Framework allowing for multiple asset selection' 5 | s.homepage = 'https://github.com/heroims/ZYQAssetPickerController' 6 | s.license = { :type => 'MIT', :file => 'README.md' } 7 | s.author = { 'heroims' => 'heroims@163.com' } 8 | s.source = { :git => 'https://github.com/heroims/ZYQAssetPickerController.git', :tag => "#{s.version}" } 9 | s.platform = :ios, '5.0' 10 | s.source_files = 'ZYQAssetPickerController/*.{h,m}' 11 | s.resources = 'ZYQAssetPickerController/*.Bundle' 12 | s.frameworks = ['AssetsLibrary'] 13 | s.requires_arc = true 14 | end 15 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemoTests/ZYQAssetPickerControllerDemoTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZYQAssetPickerControllerDemoTests.m 3 | // ZYQAssetPickerControllerDemoTests 4 | // 5 | // Created by Zhao Yiqi on 13-12-25. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZYQAssetPickerControllerDemoTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation ZYQAssetPickerControllerDemoTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemoTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | /* Navigation bar buttons */ 3 | "取消" = "Cancel"; 4 | "完成" = "Done"; 5 | 6 | /* Title */ 7 | "相簿" = "Photos"; 8 | 9 | /* No. of selected */ 10 | "已选择 %ld 张照片 " = "%ld Photo Selected"; 11 | "已选择 %ld 张照片" = "%ld Photos Selected"; 12 | "已选择 %ld 部视频 " = "%ld Video Selected"; 13 | "已选择 %ld 部视频" = "%ld Videos Selected"; 14 | "已选择 %ld 个项目" = "%ld Items Selected"; 15 | 16 | /* Library Footer */ 17 | "%ld 张照片" = "%ld Photos"; 18 | "%ld 部视频" = "%ld Videos"; 19 | "%ld 张照片, %ld 部视频" = "%ld Photos, %ld Videos"; 20 | 21 | /* Message if privacy is not granted */ 22 | "此应用无法使用您的照片或视频。" = "This app does not have access to your photos or videos."; 23 | "你可以在「隐私设置」中启用存取。" = "You can enable access in Privacy Settings."; 24 | 25 | /* Message if no assets */ 26 | "没有照片或视频。" = "No Photos or Videos"; 27 | "您可以使用 iTunes 将照片和视频\n同步到 iPhone。" = "You can sync photos and videos onto your iPhone using iTunes."; -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/heroims.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 18 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace/xcshareddata/ZYQAssetPickerControllerDemo.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 89D42853-7356-475E-97E3-1E2B853226CD 9 | IDESourceControlProjectName 10 | ZYQAssetPickerControllerDemo 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 8A606363-E623-47A1-8E96-45EDC0DCD34E 14 | https://github.com/heroims/ZYQAssetPickerController.git 15 | 16 | IDESourceControlProjectPath 17 | ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 8A606363-E623-47A1-8E96-45EDC0DCD34E 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/heroims/ZYQAssetPickerController.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 8A606363-E623-47A1-8E96-45EDC0DCD34E 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 8A606363-E623-47A1-8E96-45EDC0DCD34E 36 | IDESourceControlWCCName 37 | ZYQAssetPickerController 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIcons 12 | 13 | CFBundleIcons~ipad 14 | 15 | CFBundleIdentifier 16 | $(PRODUCT_BUNDLE_IDENTIFIER) 17 | CFBundleInfoDictionaryVersion 18 | 6.0 19 | CFBundleName 20 | ${PRODUCT_NAME} 21 | CFBundlePackageType 22 | APPL 23 | CFBundleShortVersionString 24 | 1.0 25 | CFBundleSignature 26 | ???? 27 | CFBundleVersion 28 | 1.0 29 | LSRequiresIPhoneOS 30 | 31 | NSPhotoLibraryAddUsageDescription 32 | 33 | NSPhotoLibraryUsageDescription 34 | 35 | UIRequiredDeviceCapabilities 36 | 37 | armv7 38 | 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | UISupportedInterfaceOrientations~ipad 46 | 47 | UIInterfaceOrientationPortrait 48 | UIInterfaceOrientationPortraitUpsideDown 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ZYQAssetPickerControllerDemo 4 | // 5 | // Created by Zhao Yiqi on 13-12-25. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 16 | // Override point for customization after application launch. 17 | self.window.backgroundColor = [UIColor whiteColor]; 18 | self.window.rootViewController=[[MainViewController alloc] init]; 19 | [self.window makeKeyAndVisible]; 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application 24 | { 25 | // 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. 26 | // 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. 27 | } 28 | 29 | - (void)applicationDidEnterBackground:(UIApplication *)application 30 | { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | - (void)applicationWillEnterForeground:(UIApplication *)application 36 | { 37 | // 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. 38 | } 39 | 40 | - (void)applicationDidBecomeActive:(UIApplication *)application 41 | { 42 | // 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. 43 | } 44 | 45 | - (void)applicationWillTerminate:(UIApplication *)application 46 | { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/ZYQAssetPickerControllerDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "2436h", 7 | "filename" : "Default-6.png", 8 | "minimum-system-version" : "11.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "736h", 16 | "filename" : "Default.png", 17 | "minimum-system-version" : "8.0", 18 | "orientation" : "portrait", 19 | "scale" : "3x" 20 | }, 21 | { 22 | "orientation" : "landscape", 23 | "idiom" : "iphone", 24 | "extent" : "full-screen", 25 | "minimum-system-version" : "8.0", 26 | "subtype" : "736h", 27 | "scale" : "3x" 28 | }, 29 | { 30 | "extent" : "full-screen", 31 | "idiom" : "iphone", 32 | "subtype" : "667h", 33 | "filename" : "Default-1.png", 34 | "minimum-system-version" : "8.0", 35 | "orientation" : "portrait", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "orientation" : "portrait", 40 | "idiom" : "iphone", 41 | "filename" : "Default-3.png", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | }, 46 | { 47 | "extent" : "full-screen", 48 | "idiom" : "iphone", 49 | "subtype" : "retina4", 50 | "filename" : "Default-2.png", 51 | "minimum-system-version" : "7.0", 52 | "orientation" : "portrait", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "orientation" : "portrait", 57 | "idiom" : "ipad", 58 | "extent" : "full-screen", 59 | "minimum-system-version" : "7.0", 60 | "scale" : "1x" 61 | }, 62 | { 63 | "orientation" : "landscape", 64 | "idiom" : "ipad", 65 | "extent" : "full-screen", 66 | "minimum-system-version" : "7.0", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "orientation" : "portrait", 71 | "idiom" : "ipad", 72 | "extent" : "full-screen", 73 | "minimum-system-version" : "7.0", 74 | "scale" : "2x" 75 | }, 76 | { 77 | "orientation" : "landscape", 78 | "idiom" : "ipad", 79 | "extent" : "full-screen", 80 | "minimum-system-version" : "7.0", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "orientation" : "portrait", 85 | "idiom" : "iphone", 86 | "extent" : "full-screen", 87 | "scale" : "1x" 88 | }, 89 | { 90 | "orientation" : "portrait", 91 | "idiom" : "iphone", 92 | "filename" : "Default-4.png", 93 | "extent" : "full-screen", 94 | "scale" : "2x" 95 | }, 96 | { 97 | "orientation" : "portrait", 98 | "idiom" : "iphone", 99 | "filename" : "Default-5.png", 100 | "extent" : "full-screen", 101 | "subtype" : "retina4", 102 | "scale" : "2x" 103 | }, 104 | { 105 | "orientation" : "portrait", 106 | "idiom" : "ipad", 107 | "extent" : "to-status-bar", 108 | "scale" : "1x" 109 | }, 110 | { 111 | "orientation" : "portrait", 112 | "idiom" : "ipad", 113 | "extent" : "full-screen", 114 | "scale" : "1x" 115 | }, 116 | { 117 | "orientation" : "landscape", 118 | "idiom" : "ipad", 119 | "extent" : "to-status-bar", 120 | "scale" : "1x" 121 | }, 122 | { 123 | "orientation" : "landscape", 124 | "idiom" : "ipad", 125 | "extent" : "full-screen", 126 | "scale" : "1x" 127 | }, 128 | { 129 | "orientation" : "portrait", 130 | "idiom" : "ipad", 131 | "extent" : "to-status-bar", 132 | "scale" : "2x" 133 | }, 134 | { 135 | "orientation" : "portrait", 136 | "idiom" : "ipad", 137 | "extent" : "full-screen", 138 | "scale" : "2x" 139 | }, 140 | { 141 | "orientation" : "landscape", 142 | "idiom" : "ipad", 143 | "extent" : "to-status-bar", 144 | "scale" : "2x" 145 | }, 146 | { 147 | "orientation" : "landscape", 148 | "idiom" : "ipad", 149 | "extent" : "full-screen", 150 | "scale" : "2x" 151 | } 152 | ], 153 | "info" : { 154 | "version" : 1, 155 | "author" : "xcode" 156 | } 157 | } -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/ZYQAssetPickerControllerDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/heroims.xcuserdatad/xcschemes/ZYQAssetPickerControllerDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/xcuserdata/zhaoyiqi.xcuserdatad/xcschemes/ZYQAssetPickerControllerDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo/MainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainViewController.m 3 | // ZYQAssetPickerControllerDemo 4 | // 5 | // Created by Zhao Yiqi on 13-12-26. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import "MainViewController.h" 10 | #import "ZYQAssetPickerController.h" 11 | 12 | @interface MainViewController (){ 13 | UIButton *btn; 14 | 15 | UIScrollView *src; 16 | 17 | UIPageControl *pageControl; 18 | } 19 | 20 | @end 21 | 22 | @implementation MainViewController 23 | 24 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 25 | { 26 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 27 | if (self) { 28 | // Custom initialization 29 | } 30 | return self; 31 | } 32 | 33 | - (void)viewDidLoad 34 | { 35 | [super viewDidLoad]; 36 | 37 | 38 | btn=[[UIButton alloc] init]; 39 | btn.frame=CGRectMake(60., self.view.frame.size.height-80, self.view.frame.size.width-120, 60); 40 | [btn setTitle:@"Open" forState:UIControlStateNormal]; 41 | [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 42 | [self.view addSubview:btn]; 43 | [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside]; 44 | 45 | 46 | src=[[UIScrollView alloc] initWithFrame:CGRectMake(20, 20, self.view.frame.size.width-40, self.view.frame.size.height-120)]; 47 | src.pagingEnabled=YES; 48 | src.backgroundColor=[UIColor lightGrayColor]; 49 | src.delegate=self; 50 | [self.view addSubview:src]; 51 | 52 | pageControl=[[UIPageControl alloc] initWithFrame:CGRectMake(src.frame.origin.x, src.frame.origin.y+src.frame.size.height-20, src.frame.size.width, 20)]; 53 | [self.view addSubview:pageControl]; 54 | // Do any additional setup after loading the view. 55 | } 56 | 57 | -(void)btnClick:(id)sender{ 58 | 59 | ZYQAssetPickerController *picker = [[ZYQAssetPickerController alloc] init]; 60 | 61 | picker.maximumNumberOfSelection = 5; 62 | picker.assetsFilter = ZYQAssetsFilterAllAssets; 63 | picker.showEmptyGroups=NO; 64 | picker.delegate=self; 65 | picker.timeDescSort = NO; 66 | picker.scrollBottom=YES; 67 | picker.selectionFilter = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { 68 | 69 | if ([(ZYQAsset*)evaluatedObject mediaType]==ZYQAssetMediaTypeVideo) { 70 | NSTimeInterval duration = [(ZYQAsset*)evaluatedObject duration]; 71 | return duration >= 5; 72 | } else { 73 | return YES; 74 | } 75 | 76 | 77 | }]; 78 | picker.modalPresentationStyle=UIModalPresentationFullScreen; 79 | [self presentViewController:picker animated:YES completion:NULL]; 80 | 81 | } 82 | 83 | - (void)didReceiveMemoryWarning 84 | { 85 | [super didReceiveMemoryWarning]; 86 | // Dispose of any resources that can be recreated. 87 | } 88 | 89 | #pragma mark - ZYQAssetPickerController Delegate 90 | -(void)assetPickerController:(ZYQAssetPickerController *)picker didFinishPickingAssets:(NSArray *)assets{ 91 | [src.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 92 | src.contentSize=CGSizeMake(assets.count*src.frame.size.width, src.frame.size.height); 93 | pageControl.numberOfPages=assets.count; 94 | for (int i=0; i 10 | #import 11 | #import 12 | 13 | typedef enum ZYQAssetsFilter:NSInteger{ 14 | ZYQAssetsFilterAllPhotos=0, 15 | ZYQAssetsFilterAllVideos, 16 | ZYQAssetsFilterAllAssets 17 | }ZYQAssetsFilter; 18 | 19 | #pragma mark - ZYQAssetsGroup 20 | typedef void (^ZYQAssetsGroupEnumerationResultsBlock)(id obj, NSUInteger index, BOOL *stop); 21 | 22 | @interface ZYQAssetsGroup : NSObject 23 | 24 | @property(nonatomic,strong)id originAssetGroup; 25 | @property(nonatomic,strong)id originFetchResult; 26 | 27 | @property(nonatomic,strong)NSString *groupName; 28 | @property(nonatomic,assign,readonly)NSInteger count; 29 | @property(nonatomic,copy)void(^getThumbnail)(UIImage *result); 30 | 31 | - (void)enumerateObjectsUsingBlock:(ZYQAssetsGroupEnumerationResultsBlock)enumerationBlock; 32 | 33 | @end 34 | 35 | #pragma mark - ZYQAsset 36 | 37 | typedef NS_ENUM(NSInteger, ZYQAssetMediaType) { 38 | ZYQAssetMediaTypeUnknown = 0, 39 | ZYQAssetMediaTypeImage = 1, 40 | ZYQAssetMediaTypeVideo = 2, 41 | ZYQAssetMediaTypeAudio = 3, 42 | }; 43 | 44 | @interface ZYQAsset : NSObject 45 | 46 | @property(nonatomic,strong)id originAsset; 47 | @property(nonatomic,copy)void(^getThumbnail)(UIImage *result); 48 | @property(nonatomic,copy)void(^getFullScreenImage)(UIImage *result); 49 | @property(nonatomic,copy)void(^getOriginImage)(UIImage *result); 50 | @property(nonatomic,copy)void(^getExportSession)(AVAssetExportSession *result); 51 | @property(nonatomic,assign,readonly)NSTimeInterval duration; 52 | @property(nonatomic,assign,readonly)ZYQAssetMediaType mediaType; 53 | @property(nonatomic,retain,readonly)NSDate *modificationDate; 54 | @property(nonatomic,assign,readonly)CGSize size; 55 | 56 | -(void)setGetThumbnail:(void (^)(UIImage *))getThumbnail fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler; 57 | 58 | -(void)setGetFullScreenImage:(void (^)(UIImage *))getFullScreenImage fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler; 59 | 60 | -(void)setGetOriginImage:(void (^)(UIImage *))getOriginImage fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler; 61 | 62 | -(void)setGetExportSession:(void (^)(AVAssetExportSession *))getExportSession exportPreset:(NSString *)exportPreset fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler; 63 | 64 | @end 65 | 66 | #pragma mark - ZYQAssetPickerController 67 | 68 | @protocol ZYQAssetPickerControllerDelegate; 69 | 70 | @interface ZYQAssetPickerController : UINavigationController 71 | 72 | @property (nonatomic, weak) id delegate; 73 | 74 | @property (nonatomic, assign) ZYQAssetsFilter assetsFilter; 75 | 76 | @property (nonatomic, copy, readonly) NSArray *indexPathsForSelectedItems; 77 | 78 | @property (nonatomic, assign) NSInteger maximumNumberOfSelection; 79 | @property (nonatomic, assign) NSInteger minimumNumberOfSelection; 80 | 81 | @property (nonatomic, strong) NSPredicate *selectionFilter; 82 | /** 83 | 是否根据时间降序排列, 84 | 默认:NO 85 | NO:时间较早拍摄的的照片,展示时排列在上面 86 | YES:时间较早拍摄的的照片,展示时排列在最下面,(用户进入相册可以看到最新照片) 87 | */ 88 | @property (nonatomic, assign) BOOL timeDescSort; 89 | 90 | @property (nonatomic, assign) BOOL scrollBottom; 91 | 92 | @property (nonatomic, assign) BOOL showCancelButton; 93 | 94 | @property (nonatomic, assign) BOOL showEmptyGroups; 95 | 96 | @property (nonatomic, assign) BOOL isFinishDismissViewController; 97 | 98 | @end 99 | 100 | @protocol ZYQAssetPickerControllerDelegate 101 | 102 | -(void)assetPickerController:(ZYQAssetPickerController *)picker didFinishPickingAssets:(NSArray *)assets; 103 | 104 | @optional 105 | 106 | -(void)assetPickerControllerDidCancel:(ZYQAssetPickerController *)picker; 107 | 108 | -(void)assetPickerController:(ZYQAssetPickerController *)picker didSelectAsset:(ZYQAsset*)asset; 109 | 110 | -(void)assetPickerController:(ZYQAssetPickerController *)picker didDeselectAsset:(ZYQAsset*)asset; 111 | 112 | -(void)assetPickerControllerDidMaximum:(ZYQAssetPickerController *)picker; 113 | 114 | -(void)assetPickerControllerDidMinimum:(ZYQAssetPickerController *)picker; 115 | 116 | @end 117 | 118 | #pragma mark - ZYQAssetViewController 119 | 120 | @interface ZYQAssetViewController : UITableViewController 121 | 122 | @property (nonatomic, strong) ZYQAssetsGroup *assetsGroup; 123 | @property (nonatomic, strong) NSMutableArray *indexPathsForSelectedItems; 124 | 125 | @end 126 | 127 | #pragma mark - ZYQVideoTitleView 128 | 129 | @interface ZYQVideoTitleView : UILabel 130 | 131 | @end 132 | 133 | #pragma mark - ZYQTapAssetView 134 | 135 | @protocol ZYQTapAssetViewDelegate 136 | 137 | -(void)touchSelect:(BOOL)select; 138 | -(BOOL)shouldTap:(BOOL)select; 139 | 140 | @end 141 | 142 | @interface ZYQTapAssetView : UIView 143 | 144 | @property (nonatomic, assign) BOOL selected; 145 | @property (nonatomic, assign) BOOL disabled; 146 | @property (nonatomic, weak) id delegate; 147 | 148 | @end 149 | 150 | #pragma mark - ZYQAssetView 151 | 152 | @protocol ZYQAssetViewDelegate 153 | 154 | -(BOOL)shouldSelectAsset:(ZYQAsset*)asset select:(BOOL)select; 155 | -(void)tapSelectHandle:(BOOL)select asset:(ZYQAsset*)asset; 156 | 157 | @end 158 | 159 | @interface ZYQAssetView : UIView 160 | 161 | - (void)bind:(ZYQAsset*)asset selectionFilter:(NSPredicate*)selectionFilter isSeleced:(BOOL)isSeleced; 162 | 163 | @end 164 | 165 | #pragma mark - ZYQAssetViewCell 166 | 167 | @protocol ZYQAssetViewCellDelegate; 168 | 169 | @interface ZYQAssetViewCell : UITableViewCell 170 | 171 | @property(nonatomic,weak)id delegate; 172 | 173 | - (void)bind:(NSArray *)assets selectionFilter:(NSPredicate*)selectionFilter minimumInteritemSpacing:(float)minimumInteritemSpacing minimumLineSpacing:(float)minimumLineSpacing columns:(int)columns assetViewX:(float)assetViewX; 174 | 175 | @end 176 | 177 | @protocol ZYQAssetViewCellDelegate 178 | 179 | - (BOOL)shouldSelectAsset:(ZYQAsset*)asset select:(BOOL)select; 180 | - (void)didSelectAsset:(ZYQAsset*)asset; 181 | - (void)didDeselectAsset:(ZYQAsset*)asset; 182 | 183 | @end 184 | 185 | #pragma mark - ZYQAssetGroupViewCell 186 | 187 | @interface ZYQAssetGroupViewCell : UITableViewCell 188 | 189 | - (void)bind:(ZYQAssetsGroup*)assetsGroup; 190 | 191 | @end 192 | 193 | #pragma mark - ZYQAssetGroupViewController 194 | 195 | @interface ZYQAssetGroupViewController : UITableViewController 196 | 197 | @end 198 | 199 | -------------------------------------------------------------------------------- /ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D8446D4F18702A3B00375761 /* ZYQAssetPicker.Bundle in Resources */ = {isa = PBXBuildFile; fileRef = D8446D4C18702A3B00375761 /* ZYQAssetPicker.Bundle */; }; 11 | D8446D5018702A3B00375761 /* ZYQAssetPickerController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8446D4E18702A3B00375761 /* ZYQAssetPickerController.m */; }; 12 | D8C4C4201D03E1ED00137782 /* Photos.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8C4C41F1D03E1ED00137782 /* Photos.framework */; }; 13 | D8E6C4C9186B21AC0057C549 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C4C8186B21AC0057C549 /* Foundation.framework */; }; 14 | D8E6C4CB186B21AC0057C549 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C4CA186B21AC0057C549 /* CoreGraphics.framework */; }; 15 | D8E6C4CD186B21AC0057C549 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C4CC186B21AC0057C549 /* UIKit.framework */; }; 16 | D8E6C4D3186B21AC0057C549 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D8E6C4D1186B21AC0057C549 /* InfoPlist.strings */; }; 17 | D8E6C4D5186B21AC0057C549 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D8E6C4D4186B21AC0057C549 /* main.m */; }; 18 | D8E6C4D9186B21AC0057C549 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D8E6C4D8186B21AC0057C549 /* AppDelegate.m */; }; 19 | D8E6C4E2186B21AD0057C549 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C4E1186B21AD0057C549 /* XCTest.framework */; }; 20 | D8E6C4E3186B21AD0057C549 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C4C8186B21AC0057C549 /* Foundation.framework */; }; 21 | D8E6C4E4186B21AD0057C549 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C4CC186B21AC0057C549 /* UIKit.framework */; }; 22 | D8E6C4EC186B21AD0057C549 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D8E6C4EA186B21AD0057C549 /* InfoPlist.strings */; }; 23 | D8E6C4EE186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D8E6C4ED186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.m */; }; 24 | D8E6C500186B47410057C549 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D8E6C4FF186B47410057C549 /* MainViewController.m */; }; 25 | D8E6C52D187013650057C549 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E6C52C187013650057C549 /* AssetsLibrary.framework */; }; 26 | D8F0F1CE1AB196FA0036D030 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D8F0F1CD1AB196FA0036D030 /* Images.xcassets */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | D8E6C4E5186B21AD0057C549 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = D8E6C4BD186B21AC0057C549 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = D8E6C4C4186B21AC0057C549; 35 | remoteInfo = ZYQAssetPickerControllerDemo; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | D8446D4C18702A3B00375761 /* ZYQAssetPicker.Bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = ZYQAssetPicker.Bundle; sourceTree = ""; }; 41 | D8446D4D18702A3B00375761 /* ZYQAssetPickerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYQAssetPickerController.h; sourceTree = ""; }; 42 | D8446D4E18702A3B00375761 /* ZYQAssetPickerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYQAssetPickerController.m; sourceTree = ""; }; 43 | D86038BA18732B460046A5F9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; 44 | D86038BB18732B460046A5F9 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; 45 | D8C4C41F1D03E1ED00137782 /* Photos.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Photos.framework; path = System/Library/Frameworks/Photos.framework; sourceTree = SDKROOT; }; 46 | D8E6C4C5186B21AC0057C549 /* ZYQAssetPickerControllerDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZYQAssetPickerControllerDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | D8E6C4C8186B21AC0057C549 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 48 | D8E6C4CA186B21AC0057C549 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 49 | D8E6C4CC186B21AC0057C549 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 50 | D8E6C4D0186B21AC0057C549 /* ZYQAssetPickerControllerDemo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ZYQAssetPickerControllerDemo-Info.plist"; sourceTree = ""; }; 51 | D8E6C4D2186B21AC0057C549 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 52 | D8E6C4D4186B21AC0057C549 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 53 | D8E6C4D6186B21AC0057C549 /* ZYQAssetPickerControllerDemo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ZYQAssetPickerControllerDemo-Prefix.pch"; sourceTree = ""; }; 54 | D8E6C4D7186B21AC0057C549 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 55 | D8E6C4D8186B21AC0057C549 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 56 | D8E6C4E0186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ZYQAssetPickerControllerDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | D8E6C4E1186B21AD0057C549 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 58 | D8E6C4E9186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "ZYQAssetPickerControllerDemoTests-Info.plist"; sourceTree = ""; }; 59 | D8E6C4EB186B21AD0057C549 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 60 | D8E6C4ED186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ZYQAssetPickerControllerDemoTests.m; sourceTree = ""; }; 61 | D8E6C4FE186B47410057C549 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = ""; }; 62 | D8E6C4FF186B47410057C549 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = ""; }; 63 | D8E6C52C187013650057C549 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; 64 | D8F0F1CD1AB196FA0036D030 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | D8E6C4C2186B21AC0057C549 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | D8C4C4201D03E1ED00137782 /* Photos.framework in Frameworks */, 73 | D8E6C52D187013650057C549 /* AssetsLibrary.framework in Frameworks */, 74 | D8E6C4CB186B21AC0057C549 /* CoreGraphics.framework in Frameworks */, 75 | D8E6C4CD186B21AC0057C549 /* UIKit.framework in Frameworks */, 76 | D8E6C4C9186B21AC0057C549 /* Foundation.framework in Frameworks */, 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | D8E6C4DD186B21AD0057C549 /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | D8E6C4E2186B21AD0057C549 /* XCTest.framework in Frameworks */, 85 | D8E6C4E4186B21AD0057C549 /* UIKit.framework in Frameworks */, 86 | D8E6C4E3186B21AD0057C549 /* Foundation.framework in Frameworks */, 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | /* End PBXFrameworksBuildPhase section */ 91 | 92 | /* Begin PBXGroup section */ 93 | D8446D4B18702A3B00375761 /* ZYQAssetPickerController */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | D8446D4C18702A3B00375761 /* ZYQAssetPicker.Bundle */, 97 | D8446D4D18702A3B00375761 /* ZYQAssetPickerController.h */, 98 | D8446D4E18702A3B00375761 /* ZYQAssetPickerController.m */, 99 | ); 100 | name = ZYQAssetPickerController; 101 | path = ../../ZYQAssetPickerController; 102 | sourceTree = ""; 103 | }; 104 | D8E6C4BC186B21AC0057C549 = { 105 | isa = PBXGroup; 106 | children = ( 107 | D8E6C4CE186B21AC0057C549 /* ZYQAssetPickerControllerDemo */, 108 | D8E6C4E7186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests */, 109 | D8E6C4C7186B21AC0057C549 /* Frameworks */, 110 | D8E6C4C6186B21AC0057C549 /* Products */, 111 | ); 112 | sourceTree = ""; 113 | }; 114 | D8E6C4C6186B21AC0057C549 /* Products */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | D8E6C4C5186B21AC0057C549 /* ZYQAssetPickerControllerDemo.app */, 118 | D8E6C4E0186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.xctest */, 119 | ); 120 | name = Products; 121 | sourceTree = ""; 122 | }; 123 | D8E6C4C7186B21AC0057C549 /* Frameworks */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | D8C4C41F1D03E1ED00137782 /* Photos.framework */, 127 | D8E6C52C187013650057C549 /* AssetsLibrary.framework */, 128 | D8E6C4C8186B21AC0057C549 /* Foundation.framework */, 129 | D8E6C4CA186B21AC0057C549 /* CoreGraphics.framework */, 130 | D8E6C4CC186B21AC0057C549 /* UIKit.framework */, 131 | D8E6C4E1186B21AD0057C549 /* XCTest.framework */, 132 | ); 133 | name = Frameworks; 134 | sourceTree = ""; 135 | }; 136 | D8E6C4CE186B21AC0057C549 /* ZYQAssetPickerControllerDemo */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | D8446D4B18702A3B00375761 /* ZYQAssetPickerController */, 140 | D8E6C4D7186B21AC0057C549 /* AppDelegate.h */, 141 | D8E6C4D8186B21AC0057C549 /* AppDelegate.m */, 142 | D8E6C4FE186B47410057C549 /* MainViewController.h */, 143 | D8E6C4FF186B47410057C549 /* MainViewController.m */, 144 | D8F0F1CD1AB196FA0036D030 /* Images.xcassets */, 145 | D8E6C4CF186B21AC0057C549 /* Supporting Files */, 146 | ); 147 | path = ZYQAssetPickerControllerDemo; 148 | sourceTree = ""; 149 | }; 150 | D8E6C4CF186B21AC0057C549 /* Supporting Files */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | D8E6C4D0186B21AC0057C549 /* ZYQAssetPickerControllerDemo-Info.plist */, 154 | D8E6C4D1186B21AC0057C549 /* InfoPlist.strings */, 155 | D8E6C4D4186B21AC0057C549 /* main.m */, 156 | D8E6C4D6186B21AC0057C549 /* ZYQAssetPickerControllerDemo-Prefix.pch */, 157 | ); 158 | name = "Supporting Files"; 159 | sourceTree = ""; 160 | }; 161 | D8E6C4E7186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | D8E6C4ED186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.m */, 165 | D8E6C4E8186B21AD0057C549 /* Supporting Files */, 166 | ); 167 | path = ZYQAssetPickerControllerDemoTests; 168 | sourceTree = ""; 169 | }; 170 | D8E6C4E8186B21AD0057C549 /* Supporting Files */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | D8E6C4E9186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests-Info.plist */, 174 | D8E6C4EA186B21AD0057C549 /* InfoPlist.strings */, 175 | ); 176 | name = "Supporting Files"; 177 | sourceTree = ""; 178 | }; 179 | /* End PBXGroup section */ 180 | 181 | /* Begin PBXNativeTarget section */ 182 | D8E6C4C4186B21AC0057C549 /* ZYQAssetPickerControllerDemo */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = D8E6C4F1186B21AD0057C549 /* Build configuration list for PBXNativeTarget "ZYQAssetPickerControllerDemo" */; 185 | buildPhases = ( 186 | D8E6C4C1186B21AC0057C549 /* Sources */, 187 | D8E6C4C2186B21AC0057C549 /* Frameworks */, 188 | D8E6C4C3186B21AC0057C549 /* Resources */, 189 | ); 190 | buildRules = ( 191 | ); 192 | dependencies = ( 193 | ); 194 | name = ZYQAssetPickerControllerDemo; 195 | productName = ZYQAssetPickerControllerDemo; 196 | productReference = D8E6C4C5186B21AC0057C549 /* ZYQAssetPickerControllerDemo.app */; 197 | productType = "com.apple.product-type.application"; 198 | }; 199 | D8E6C4DF186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests */ = { 200 | isa = PBXNativeTarget; 201 | buildConfigurationList = D8E6C4F4186B21AD0057C549 /* Build configuration list for PBXNativeTarget "ZYQAssetPickerControllerDemoTests" */; 202 | buildPhases = ( 203 | D8E6C4DC186B21AD0057C549 /* Sources */, 204 | D8E6C4DD186B21AD0057C549 /* Frameworks */, 205 | D8E6C4DE186B21AD0057C549 /* Resources */, 206 | ); 207 | buildRules = ( 208 | ); 209 | dependencies = ( 210 | D8E6C4E6186B21AD0057C549 /* PBXTargetDependency */, 211 | ); 212 | name = ZYQAssetPickerControllerDemoTests; 213 | productName = ZYQAssetPickerControllerDemoTests; 214 | productReference = D8E6C4E0186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.xctest */; 215 | productType = "com.apple.product-type.bundle.unit-test"; 216 | }; 217 | /* End PBXNativeTarget section */ 218 | 219 | /* Begin PBXProject section */ 220 | D8E6C4BD186B21AC0057C549 /* Project object */ = { 221 | isa = PBXProject; 222 | attributes = { 223 | LastUpgradeCheck = 0700; 224 | ORGANIZATIONNAME = heroims; 225 | TargetAttributes = { 226 | D8E6C4C4186B21AC0057C549 = { 227 | DevelopmentTeam = YDDJ83LVSQ; 228 | ProvisioningStyle = Automatic; 229 | }; 230 | D8E6C4DF186B21AD0057C549 = { 231 | TestTargetID = D8E6C4C4186B21AC0057C549; 232 | }; 233 | }; 234 | }; 235 | buildConfigurationList = D8E6C4C0186B21AC0057C549 /* Build configuration list for PBXProject "ZYQAssetPickerControllerDemo" */; 236 | compatibilityVersion = "Xcode 3.2"; 237 | developmentRegion = English; 238 | hasScannedForEncodings = 0; 239 | knownRegions = ( 240 | English, 241 | en, 242 | "zh-Hans", 243 | ); 244 | mainGroup = D8E6C4BC186B21AC0057C549; 245 | productRefGroup = D8E6C4C6186B21AC0057C549 /* Products */; 246 | projectDirPath = ""; 247 | projectRoot = ""; 248 | targets = ( 249 | D8E6C4C4186B21AC0057C549 /* ZYQAssetPickerControllerDemo */, 250 | D8E6C4DF186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests */, 251 | ); 252 | }; 253 | /* End PBXProject section */ 254 | 255 | /* Begin PBXResourcesBuildPhase section */ 256 | D8E6C4C3186B21AC0057C549 /* Resources */ = { 257 | isa = PBXResourcesBuildPhase; 258 | buildActionMask = 2147483647; 259 | files = ( 260 | D8F0F1CE1AB196FA0036D030 /* Images.xcassets in Resources */, 261 | D8E6C4D3186B21AC0057C549 /* InfoPlist.strings in Resources */, 262 | D8446D4F18702A3B00375761 /* ZYQAssetPicker.Bundle in Resources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | D8E6C4DE186B21AD0057C549 /* Resources */ = { 267 | isa = PBXResourcesBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | D8E6C4EC186B21AD0057C549 /* InfoPlist.strings in Resources */, 271 | ); 272 | runOnlyForDeploymentPostprocessing = 0; 273 | }; 274 | /* End PBXResourcesBuildPhase section */ 275 | 276 | /* Begin PBXSourcesBuildPhase section */ 277 | D8E6C4C1186B21AC0057C549 /* Sources */ = { 278 | isa = PBXSourcesBuildPhase; 279 | buildActionMask = 2147483647; 280 | files = ( 281 | D8E6C4D9186B21AC0057C549 /* AppDelegate.m in Sources */, 282 | D8E6C4D5186B21AC0057C549 /* main.m in Sources */, 283 | D8E6C500186B47410057C549 /* MainViewController.m in Sources */, 284 | D8446D5018702A3B00375761 /* ZYQAssetPickerController.m in Sources */, 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | }; 288 | D8E6C4DC186B21AD0057C549 /* Sources */ = { 289 | isa = PBXSourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | D8E6C4EE186B21AD0057C549 /* ZYQAssetPickerControllerDemoTests.m in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXSourcesBuildPhase section */ 297 | 298 | /* Begin PBXTargetDependency section */ 299 | D8E6C4E6186B21AD0057C549 /* PBXTargetDependency */ = { 300 | isa = PBXTargetDependency; 301 | target = D8E6C4C4186B21AC0057C549 /* ZYQAssetPickerControllerDemo */; 302 | targetProxy = D8E6C4E5186B21AD0057C549 /* PBXContainerItemProxy */; 303 | }; 304 | /* End PBXTargetDependency section */ 305 | 306 | /* Begin PBXVariantGroup section */ 307 | D8E6C4D1186B21AC0057C549 /* InfoPlist.strings */ = { 308 | isa = PBXVariantGroup; 309 | children = ( 310 | D8E6C4D2186B21AC0057C549 /* en */, 311 | D86038BA18732B460046A5F9 /* zh-Hans */, 312 | ); 313 | name = InfoPlist.strings; 314 | sourceTree = ""; 315 | }; 316 | D8E6C4EA186B21AD0057C549 /* InfoPlist.strings */ = { 317 | isa = PBXVariantGroup; 318 | children = ( 319 | D8E6C4EB186B21AD0057C549 /* en */, 320 | D86038BB18732B460046A5F9 /* zh-Hans */, 321 | ); 322 | name = InfoPlist.strings; 323 | sourceTree = ""; 324 | }; 325 | /* End PBXVariantGroup section */ 326 | 327 | /* Begin XCBuildConfiguration section */ 328 | D8E6C4EF186B21AD0057C549 /* Debug */ = { 329 | isa = XCBuildConfiguration; 330 | buildSettings = { 331 | ALWAYS_SEARCH_USER_PATHS = NO; 332 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 333 | CLANG_CXX_LIBRARY = "libc++"; 334 | CLANG_ENABLE_MODULES = YES; 335 | CLANG_ENABLE_OBJC_ARC = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_CONSTANT_CONVERSION = YES; 338 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 339 | CLANG_WARN_EMPTY_BODY = YES; 340 | CLANG_WARN_ENUM_CONVERSION = YES; 341 | CLANG_WARN_INT_CONVERSION = YES; 342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 343 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 344 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 345 | COPY_PHASE_STRIP = NO; 346 | ENABLE_TESTABILITY = YES; 347 | GCC_C_LANGUAGE_STANDARD = gnu99; 348 | GCC_DYNAMIC_NO_PIC = NO; 349 | GCC_OPTIMIZATION_LEVEL = 0; 350 | GCC_PREPROCESSOR_DEFINITIONS = ( 351 | "DEBUG=1", 352 | "$(inherited)", 353 | ); 354 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 355 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 356 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 357 | GCC_WARN_UNDECLARED_SELECTOR = YES; 358 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 359 | GCC_WARN_UNUSED_FUNCTION = YES; 360 | GCC_WARN_UNUSED_VARIABLE = YES; 361 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 362 | ONLY_ACTIVE_ARCH = YES; 363 | SDKROOT = iphoneos; 364 | TARGETED_DEVICE_FAMILY = "1,2"; 365 | }; 366 | name = Debug; 367 | }; 368 | D8E6C4F0186B21AD0057C549 /* Release */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 373 | CLANG_CXX_LIBRARY = "libc++"; 374 | CLANG_ENABLE_MODULES = YES; 375 | CLANG_ENABLE_OBJC_ARC = YES; 376 | CLANG_WARN_BOOL_CONVERSION = YES; 377 | CLANG_WARN_CONSTANT_CONVERSION = YES; 378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 379 | CLANG_WARN_EMPTY_BODY = YES; 380 | CLANG_WARN_ENUM_CONVERSION = YES; 381 | CLANG_WARN_INT_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 384 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 385 | COPY_PHASE_STRIP = YES; 386 | ENABLE_NS_ASSERTIONS = NO; 387 | GCC_C_LANGUAGE_STANDARD = gnu99; 388 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 389 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 390 | GCC_WARN_UNDECLARED_SELECTOR = YES; 391 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 392 | GCC_WARN_UNUSED_FUNCTION = YES; 393 | GCC_WARN_UNUSED_VARIABLE = YES; 394 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 395 | SDKROOT = iphoneos; 396 | TARGETED_DEVICE_FAMILY = "1,2"; 397 | VALIDATE_PRODUCT = YES; 398 | }; 399 | name = Release; 400 | }; 401 | D8E6C4F2186B21AD0057C549 /* Debug */ = { 402 | isa = XCBuildConfiguration; 403 | buildSettings = { 404 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 405 | CODE_SIGN_IDENTITY = "Apple Development"; 406 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 407 | CODE_SIGN_STYLE = Automatic; 408 | DEVELOPMENT_TEAM = YDDJ83LVSQ; 409 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 410 | GCC_PREFIX_HEADER = "ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Prefix.pch"; 411 | INFOPLIST_FILE = "ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Info.plist"; 412 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 413 | PRODUCT_BUNDLE_IDENTIFIER = ZYQ.ZYQAssetPickerControllerDemo; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | PROVISIONING_PROFILE = ""; 416 | PROVISIONING_PROFILE_SPECIFIER = ""; 417 | WRAPPER_EXTENSION = app; 418 | }; 419 | name = Debug; 420 | }; 421 | D8E6C4F3186B21AD0057C549 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 425 | CODE_SIGN_IDENTITY = "iPhone Developer: 幻影 灵异 (33FX7C95LQ)"; 426 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 427 | CODE_SIGN_STYLE = Manual; 428 | DEVELOPMENT_TEAM = ""; 429 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 430 | GCC_PREFIX_HEADER = "ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Prefix.pch"; 431 | INFOPLIST_FILE = "ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Info.plist"; 432 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 433 | PRODUCT_BUNDLE_IDENTIFIER = ZYQ.ZYQAssetPickerControllerDemo; 434 | PRODUCT_NAME = "$(TARGET_NAME)"; 435 | PROVISIONING_PROFILE = ""; 436 | PROVISIONING_PROFILE_SPECIFIER = ""; 437 | WRAPPER_EXTENSION = app; 438 | }; 439 | name = Release; 440 | }; 441 | D8E6C4F5186B21AD0057C549 /* Debug */ = { 442 | isa = XCBuildConfiguration; 443 | buildSettings = { 444 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ZYQAssetPickerControllerDemo.app/ZYQAssetPickerControllerDemo"; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(SDKROOT)/Developer/Library/Frameworks", 447 | "$(inherited)", 448 | "$(DEVELOPER_FRAMEWORKS_DIR)", 449 | ); 450 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 451 | GCC_PREFIX_HEADER = "ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Prefix.pch"; 452 | GCC_PREPROCESSOR_DEFINITIONS = ( 453 | "DEBUG=1", 454 | "$(inherited)", 455 | ); 456 | INFOPLIST_FILE = "ZYQAssetPickerControllerDemoTests/ZYQAssetPickerControllerDemoTests-Info.plist"; 457 | PRODUCT_BUNDLE_IDENTIFIER = "ZYQ.${PRODUCT_NAME:rfc1034identifier}"; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | TEST_HOST = "$(BUNDLE_LOADER)"; 460 | WRAPPER_EXTENSION = xctest; 461 | }; 462 | name = Debug; 463 | }; 464 | D8E6C4F6186B21AD0057C549 /* Release */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/ZYQAssetPickerControllerDemo.app/ZYQAssetPickerControllerDemo"; 468 | FRAMEWORK_SEARCH_PATHS = ( 469 | "$(SDKROOT)/Developer/Library/Frameworks", 470 | "$(inherited)", 471 | "$(DEVELOPER_FRAMEWORKS_DIR)", 472 | ); 473 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 474 | GCC_PREFIX_HEADER = "ZYQAssetPickerControllerDemo/ZYQAssetPickerControllerDemo-Prefix.pch"; 475 | INFOPLIST_FILE = "ZYQAssetPickerControllerDemoTests/ZYQAssetPickerControllerDemoTests-Info.plist"; 476 | PRODUCT_BUNDLE_IDENTIFIER = "ZYQ.${PRODUCT_NAME:rfc1034identifier}"; 477 | PRODUCT_NAME = "$(TARGET_NAME)"; 478 | TEST_HOST = "$(BUNDLE_LOADER)"; 479 | WRAPPER_EXTENSION = xctest; 480 | }; 481 | name = Release; 482 | }; 483 | /* End XCBuildConfiguration section */ 484 | 485 | /* Begin XCConfigurationList section */ 486 | D8E6C4C0186B21AC0057C549 /* Build configuration list for PBXProject "ZYQAssetPickerControllerDemo" */ = { 487 | isa = XCConfigurationList; 488 | buildConfigurations = ( 489 | D8E6C4EF186B21AD0057C549 /* Debug */, 490 | D8E6C4F0186B21AD0057C549 /* Release */, 491 | ); 492 | defaultConfigurationIsVisible = 0; 493 | defaultConfigurationName = Release; 494 | }; 495 | D8E6C4F1186B21AD0057C549 /* Build configuration list for PBXNativeTarget "ZYQAssetPickerControllerDemo" */ = { 496 | isa = XCConfigurationList; 497 | buildConfigurations = ( 498 | D8E6C4F2186B21AD0057C549 /* Debug */, 499 | D8E6C4F3186B21AD0057C549 /* Release */, 500 | ); 501 | defaultConfigurationIsVisible = 0; 502 | defaultConfigurationName = Release; 503 | }; 504 | D8E6C4F4186B21AD0057C549 /* Build configuration list for PBXNativeTarget "ZYQAssetPickerControllerDemoTests" */ = { 505 | isa = XCConfigurationList; 506 | buildConfigurations = ( 507 | D8E6C4F5186B21AD0057C549 /* Debug */, 508 | D8E6C4F6186B21AD0057C549 /* Release */, 509 | ); 510 | defaultConfigurationIsVisible = 0; 511 | defaultConfigurationName = Release; 512 | }; 513 | /* End XCConfigurationList section */ 514 | }; 515 | rootObject = D8E6C4BD186B21AC0057C549 /* Project object */; 516 | } 517 | -------------------------------------------------------------------------------- /ZYQAssetPickerController/ZYQAssetPickerController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZYQAssetPickerController.m 3 | // ZYQAssetPickerControllerDemo 4 | // 5 | // Created by Zhao Yiqi on 13-12-25. 6 | // Copyright (c) 2013年 heroims. All rights reserved. 7 | // 8 | 9 | #import "ZYQAssetPickerController.h" 10 | 11 | #define IS_IOS7 ([[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending) 12 | #define IS_IOS8 ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] != NSOrderedAscending) 13 | 14 | #define kThumbnailLength 78.0f 15 | #define kThumbnailSize CGSizeMake(kThumbnailLength, kThumbnailLength) 16 | #define kPopoverContentSize CGSizeMake(320, 480) 17 | 18 | #pragma mark - 19 | 20 | @interface NSDate (TimeInterval) 21 | 22 | + (NSDateComponents *)componetsWithTimeInterval:(NSTimeInterval)timeInterval; 23 | + (NSString *)timeDescriptionOfTimeInterval:(NSTimeInterval)timeInterval; 24 | 25 | @end 26 | 27 | @implementation NSDate (TimeInterval) 28 | 29 | + (NSDateComponents *)componetsWithTimeInterval:(NSTimeInterval)timeInterval 30 | { 31 | NSCalendar *calendar = [NSCalendar currentCalendar]; 32 | 33 | NSDate *date1 = [[NSDate alloc] init]; 34 | NSDate *date2 = [[NSDate alloc] initWithTimeInterval:timeInterval sinceDate:date1]; 35 | 36 | unsigned int unitFlags = 37 | NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour | 38 | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear; 39 | 40 | return [calendar components:unitFlags 41 | fromDate:date1 42 | toDate:date2 43 | options:0]; 44 | } 45 | 46 | + (NSString *)timeDescriptionOfTimeInterval:(NSTimeInterval)timeInterval 47 | { 48 | NSString *newTime; 49 | if (timeInterval < 10) { 50 | newTime = [NSString stringWithFormat:@"0:0%zd",(NSInteger)timeInterval]; 51 | } else if (timeInterval < 60) { 52 | newTime = [NSString stringWithFormat:@"0:%zd",(NSInteger)timeInterval]; 53 | } else { 54 | NSInteger min = timeInterval / 60; 55 | NSInteger sec = timeInterval - (min * 60); 56 | if (sec < 10) { 57 | newTime = [NSString stringWithFormat:@"%zd:0%zd",min,sec]; 58 | } else { 59 | newTime = [NSString stringWithFormat:@"%zd:%zd",min,sec]; 60 | } 61 | } 62 | return newTime; 63 | } 64 | 65 | @end 66 | 67 | #pragma mark - ZYQAssetsGroup 68 | 69 | @interface ZYQAssetsGroup(){ 70 | UIImage *_cacheThumbnail; 71 | } 72 | 73 | @end 74 | 75 | @implementation ZYQAssetsGroup : NSObject 76 | 77 | -(NSString*)groupName{ 78 | if (_originAssetGroup) { 79 | if ([_originAssetGroup isKindOfClass:[PHCollection class]]) { 80 | return [(PHCollection*)_originAssetGroup localizedTitle]; 81 | } 82 | else if([_originAssetGroup isKindOfClass:[ALAssetsGroup class]]){ 83 | return [(ALAssetsGroup*)_originAssetGroup valueForProperty:ALAssetsGroupPropertyName]; 84 | } 85 | } 86 | return nil; 87 | } 88 | 89 | -(NSInteger)count{ 90 | if (_originAssetGroup) { 91 | if ([_originAssetGroup isKindOfClass:[PHCollection class]]) { 92 | if (!_originFetchResult) { 93 | PHFetchOptions *fetchOptionsAlbums=[[PHFetchOptions alloc] init]; 94 | 95 | _originFetchResult=[PHCollection fetchCollectionsInCollectionList:_originAssetGroup options:fetchOptionsAlbums]; 96 | } 97 | return [(PHFetchResult*)_originFetchResult count]; 98 | } 99 | else if([_originAssetGroup isKindOfClass:[ALAssetsGroup class]]){ 100 | return [(ALAssetsGroup*)_originAssetGroup numberOfAssets]; 101 | } 102 | } 103 | return 0; 104 | } 105 | 106 | -(void)setGetThumbnail:(void (^)(UIImage *))getThumbnail{ 107 | _getThumbnail=getThumbnail; 108 | 109 | if (_originAssetGroup) { 110 | if (_cacheThumbnail) { 111 | _getThumbnail(_cacheThumbnail); 112 | return; 113 | } 114 | 115 | if ([_originAssetGroup isKindOfClass:[ALAssetsGroup class]]) { 116 | 117 | CGImageRef posterImage = [(ALAssetsGroup*)_originAssetGroup posterImage]; 118 | size_t height = CGImageGetHeight(posterImage); 119 | float scale = height / kThumbnailLength; 120 | 121 | _cacheThumbnail = [UIImage imageWithCGImage:posterImage scale:scale orientation:UIImageOrientationUp]; 122 | 123 | _getThumbnail(_cacheThumbnail); 124 | } 125 | else if ([_originAssetGroup isKindOfClass:[PHCollection class]]){ 126 | if (!_originFetchResult) { 127 | PHFetchOptions *fetchOptionsAlbums=[[PHFetchOptions alloc] init]; 128 | 129 | _originFetchResult=[PHCollection fetchCollectionsInCollectionList:_originAssetGroup options:fetchOptionsAlbums]; 130 | } 131 | PHFetchResult *tmpFetchResult=_originFetchResult; 132 | PHAsset *tmpAsset=[tmpFetchResult objectAtIndex:tmpFetchResult.count-1]; 133 | 134 | PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init]; 135 | requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic; 136 | requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact; 137 | [[PHImageManager defaultManager] requestImageForAsset:tmpAsset targetSize:CGSizeMake(200, 200) contentMode:PHImageContentModeAspectFill options:requestOptions resultHandler:^(UIImage *result, NSDictionary *info){ 138 | BOOL downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]; 139 | 140 | //设置BOOL判断,确定返回高清照片 141 | if (downloadFinined) { 142 | float scale = result.size.height / kThumbnailLength; 143 | 144 | _cacheThumbnail=[UIImage imageWithCGImage:result.CGImage scale:scale orientation:UIImageOrientationUp]; 145 | 146 | _getThumbnail(_cacheThumbnail); 147 | 148 | } 149 | }]; 150 | } 151 | } 152 | } 153 | 154 | -(void)enumerateObjectsUsingBlock:(ZYQAssetsGroupEnumerationResultsBlock)enumerationBlock{ 155 | if (_originAssetGroup) { 156 | if ([_originAssetGroup isKindOfClass:[PHCollection class]]) { 157 | if (!_originFetchResult) { 158 | PHFetchOptions *fetchOptionsAlbums=[[PHFetchOptions alloc] init]; 159 | 160 | _originFetchResult=[PHCollection fetchCollectionsInCollectionList:_originAssetGroup options:fetchOptionsAlbums]; 161 | } 162 | return [(PHFetchResult*)_originFetchResult enumerateObjectsUsingBlock:enumerationBlock]; 163 | } 164 | else if([_originAssetGroup isKindOfClass:[ALAssetsGroup class]]){ 165 | return [(ALAssetsGroup*)_originAssetGroup enumerateAssetsUsingBlock:enumerationBlock]; 166 | } 167 | } 168 | } 169 | 170 | @end 171 | #pragma mark - ZYQAsset 172 | @interface ZYQAsset(){ 173 | UIImage *_cacheThumbnail; 174 | UIImage *_cacheFullScreenImage; 175 | UIImage *_cacheOriginImage; 176 | 177 | AVAssetExportSession *_cacheExportSession; 178 | } 179 | 180 | @end 181 | 182 | @implementation ZYQAsset : NSObject 183 | 184 | -(void)setGetThumbnail:(void (^)(UIImage *))getThumbnail fromNetwokProgressHandler:(void (^)(double, NSError *, BOOL *, NSDictionary *))progressHandler{ 185 | _getThumbnail=getThumbnail; 186 | 187 | if (_originAsset) { 188 | if (_cacheThumbnail) { 189 | _getThumbnail(_cacheThumbnail); 190 | return; 191 | } 192 | 193 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 194 | _cacheThumbnail=[UIImage imageWithCGImage:[(ALAsset*)_originAsset thumbnail]]; 195 | _getThumbnail(_cacheThumbnail); 196 | } 197 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 198 | PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init]; 199 | requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic; 200 | requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact; 201 | requestOptions.progressHandler = ^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) { 202 | if (progressHandler) { 203 | progressHandler(progress,error,stop,info); 204 | } 205 | }; 206 | [[PHImageManager defaultManager] requestImageForAsset:_originAsset targetSize:CGSizeMake(200, 200) contentMode:PHImageContentModeAspectFill options:requestOptions resultHandler:^(UIImage *result, NSDictionary *info){ 207 | BOOL downloadFinined = NO; 208 | 209 | downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];//设置BOOL判断,确定返回高清照片 210 | 211 | if (downloadFinined) { 212 | _cacheThumbnail=result; 213 | _getThumbnail(_cacheThumbnail); 214 | } 215 | }]; 216 | } 217 | } 218 | } 219 | 220 | -(void)setGetExportSession:(void (^)(AVAssetExportSession *))getExportSession exportPreset:(NSString *)exportPreset fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler{ 221 | 222 | _getExportSession=getExportSession; 223 | 224 | if (_originAsset) { 225 | if (_cacheExportSession) { 226 | _getExportSession(_cacheExportSession); 227 | return; 228 | } 229 | 230 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 231 | 232 | AVURLAsset *avasset=[AVURLAsset URLAssetWithURL:[(ALAsset*)_originAsset defaultRepresentation].url options:nil]; 233 | _cacheExportSession = [[AVAssetExportSession alloc] initWithAsset:avasset presetName:exportPreset]; 234 | _getExportSession(_cacheExportSession); 235 | } 236 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 237 | PHVideoRequestOptions *requestOptions = [[PHVideoRequestOptions alloc] init]; 238 | requestOptions.deliveryMode = PHVideoRequestOptionsDeliveryModeMediumQualityFormat; 239 | requestOptions.networkAccessAllowed=YES; 240 | 241 | requestOptions.progressHandler = ^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) { 242 | if (progressHandler) { 243 | progressHandler(progress,error,stop,info); 244 | } 245 | }; 246 | 247 | [[PHImageManager defaultManager] requestExportSessionForVideo:_originAsset options:requestOptions exportPreset:exportPreset resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) { 248 | 249 | _cacheExportSession=exportSession; 250 | _getExportSession(_cacheExportSession); 251 | }]; 252 | } 253 | } 254 | 255 | } 256 | 257 | -(void)setGetFullScreenImage:(void (^)(UIImage *))getFullScreenImage fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler{ 258 | _getFullScreenImage=getFullScreenImage; 259 | 260 | if (_originAsset) { 261 | if (_cacheFullScreenImage) { 262 | _getFullScreenImage(_cacheFullScreenImage); 263 | return; 264 | } 265 | 266 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 267 | _cacheFullScreenImage=[UIImage imageWithCGImage:[(ALAsset*)_originAsset defaultRepresentation].fullScreenImage]; 268 | _getFullScreenImage(_cacheFullScreenImage); 269 | } 270 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 271 | PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init]; 272 | requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic; 273 | requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact; 274 | 275 | CGFloat photoWidth = [UIScreen mainScreen].bounds.size.width; 276 | 277 | CGFloat aspectRatio = ((PHAsset*)_originAsset).pixelWidth / (CGFloat)((PHAsset*)_originAsset).pixelHeight; 278 | CGFloat multiple = [UIScreen mainScreen].scale; 279 | CGFloat pixelWidth = photoWidth * multiple; 280 | CGFloat pixelHeight = pixelWidth / aspectRatio; 281 | 282 | requestOptions.networkAccessAllowed=YES; 283 | 284 | 285 | requestOptions.progressHandler = ^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) { 286 | if (progressHandler) { 287 | progressHandler(progress,error,stop,info); 288 | } 289 | }; 290 | 291 | [[PHImageManager defaultManager] requestImageForAsset:_originAsset targetSize:CGSizeMake(pixelWidth, pixelHeight) contentMode:PHImageContentModeAspectFill options:requestOptions resultHandler:^(UIImage *result, NSDictionary *info){ 292 | BOOL downloadFinined = NO; 293 | 294 | downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];//设置BOOL判断,确定返回高清照片 295 | 296 | if (downloadFinined) { 297 | _cacheFullScreenImage=result; 298 | _getFullScreenImage(_cacheFullScreenImage); 299 | } 300 | }]; 301 | } 302 | } 303 | 304 | } 305 | 306 | -(void)setGetOriginImage:(void (^)(UIImage *))getOriginImage fromNetwokProgressHandler:(void (^)(double ,NSError * , BOOL *, NSDictionary *))progressHandler{ 307 | _getOriginImage=getOriginImage; 308 | 309 | if (_originAsset) { 310 | if (_cacheOriginImage) { 311 | _getOriginImage(_cacheOriginImage); 312 | return; 313 | } 314 | 315 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 316 | ALAssetRepresentation *image_representation=[(ALAsset*)_originAsset defaultRepresentation]; 317 | Byte * buffer = (Byte*)malloc(image_representation.size); 318 | NSUInteger length = [image_representation getBytes:buffer fromOffset: 0.0 length:image_representation.size error:nil]; 319 | 320 | if (length != 0) { 321 | NSData *adata = [[NSData alloc] initWithBytesNoCopy:buffer length:image_representation.size freeWhenDone:YES]; 322 | _cacheOriginImage = [UIImage imageWithData:adata]; 323 | } 324 | 325 | _getOriginImage(_cacheOriginImage); 326 | } 327 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 328 | PHImageRequestOptions *requestOptions = [[PHImageRequestOptions alloc] init]; 329 | requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic; 330 | requestOptions.resizeMode = PHImageRequestOptionsResizeModeExact; 331 | 332 | requestOptions.networkAccessAllowed=YES; 333 | 334 | requestOptions.progressHandler = ^(double progress, NSError * _Nullable error, BOOL * _Nonnull stop, NSDictionary * _Nullable info) { 335 | if (progressHandler) { 336 | progressHandler(progress,error,stop,info); 337 | } 338 | }; 339 | 340 | [[PHImageManager defaultManager] requestImageForAsset:_originAsset targetSize:CGSizeMake(((PHAsset*)_originAsset).pixelWidth, ((PHAsset*)_originAsset).pixelHeight) contentMode:PHImageContentModeAspectFill options:requestOptions resultHandler:^(UIImage *result, NSDictionary *info){ 341 | BOOL downloadFinined = NO; 342 | 343 | downloadFinined = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue];//设置BOOL判断,确定返回高清照片 344 | 345 | if (downloadFinined) { 346 | _cacheFullScreenImage=result; 347 | _getFullScreenImage(_cacheFullScreenImage); 348 | } 349 | }]; 350 | } 351 | } 352 | } 353 | 354 | -(void)setGetExportSession:(void (^)(AVAssetExportSession *))getExportSession{ 355 | [self setGetExportSession:getExportSession exportPreset:AVAssetExportPresetMediumQuality fromNetwokProgressHandler:nil]; 356 | } 357 | 358 | -(void)setGetThumbnail:(void (^)(UIImage *))getThumbnail{ 359 | [self setGetThumbnail:getThumbnail fromNetwokProgressHandler:nil]; 360 | } 361 | 362 | -(void)setGetFullScreenImage:(void (^)(UIImage *))getFullScreenImage{ 363 | [self setGetFullScreenImage:getFullScreenImage fromNetwokProgressHandler:nil]; 364 | } 365 | 366 | -(void)setGetOriginImage:(void (^)(UIImage *))getOriginImage{ 367 | [self setGetOriginImage:getOriginImage fromNetwokProgressHandler:nil]; 368 | } 369 | 370 | 371 | -(NSTimeInterval)duration{ 372 | if (_originAsset) { 373 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 374 | return [[(ALAsset*)_originAsset valueForProperty:ALAssetPropertyDuration] doubleValue]; 375 | } 376 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 377 | return [(PHAsset*)_originAsset duration]; 378 | } 379 | } 380 | return 0; 381 | } 382 | 383 | -(CGSize)size{ 384 | if (_originAsset) { 385 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 386 | return [(ALAsset*)_originAsset defaultRepresentation].dimensions; 387 | } 388 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 389 | return CGSizeMake(((PHAsset*)_originAsset).pixelWidth, ((PHAsset*)_originAsset).pixelHeight); 390 | } 391 | } 392 | return CGSizeMake(0, 0); 393 | 394 | } 395 | -(NSDate*)modificationDate{ 396 | if (_originAsset) { 397 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 398 | return [(ALAsset*)_originAsset valueForProperty:ALAssetPropertyDate]; 399 | } 400 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 401 | return [(PHAsset*)_originAsset modificationDate]; 402 | } 403 | } 404 | return nil; 405 | 406 | } 407 | 408 | -(ZYQAssetMediaType)mediaType{ 409 | if (_originAsset) { 410 | if ([_originAsset isKindOfClass:[ALAsset class]]) { 411 | if ([[(ALAsset*)_originAsset valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypePhoto]) { 412 | return ZYQAssetMediaTypeImage; 413 | } 414 | if ([[(ALAsset*)_originAsset valueForProperty:ALAssetPropertyType] isEqual:ALAssetTypeVideo]) { 415 | return ZYQAssetMediaTypeVideo; 416 | } 417 | } 418 | else if ([_originAsset isKindOfClass:[PHAsset class]]){ 419 | switch ([(PHAsset*)_originAsset mediaType]) { 420 | case PHAssetMediaTypeImage: 421 | return ZYQAssetMediaTypeImage; 422 | case PHAssetMediaTypeVideo: 423 | return ZYQAssetMediaTypeVideo; 424 | case PHAssetMediaTypeAudio: 425 | return ZYQAssetMediaTypeAudio; 426 | default: 427 | break; 428 | } 429 | } 430 | } 431 | return ZYQAssetMediaTypeUnknown; 432 | } 433 | 434 | @end 435 | 436 | #pragma mark - ZYQAssetPickerController 437 | 438 | @interface ZYQAssetPickerController () 439 | 440 | @property (nonatomic, copy) NSArray *indexPathsForSelectedItems; 441 | 442 | @end 443 | 444 | #pragma mark - ZYQVideoTitleView 445 | 446 | @implementation ZYQVideoTitleView 447 | 448 | -(void)drawRect:(CGRect)rect{ 449 | CGFloat colors [] = { 450 | 0.0, 0.0, 0.0, 0.0, 451 | 0.7, 0.7, 0.7, 0.6, 452 | 1.0, 1.0, 1.0, 1.0 453 | }; 454 | 455 | CGFloat locations [] = {0.0, 0.75, 1.0}; 456 | 457 | CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); 458 | CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, locations, 2); 459 | CGColorSpaceRelease(baseSpace); 460 | 461 | CGContextRef context = UIGraphicsGetCurrentContext(); 462 | 463 | CGFloat height = rect.size.height; 464 | CGPoint startPoint = CGPointMake(0, 0); 465 | CGPoint endPoint = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)); 466 | 467 | CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0); 468 | 469 | CGGradientRelease(gradient); 470 | 471 | CGSize titleSize = [self.text sizeWithAttributes:@{NSFontAttributeName:self.font,NSForegroundColorAttributeName:self.textColor}]; 472 | [self.text drawAtPoint:CGPointMake(rect.size.width - titleSize.width - 2 , (height - 12) / 2) withAttributes:@{NSFontAttributeName:self.font,NSForegroundColorAttributeName:self.textColor}]; 473 | 474 | UIImage *videoIcon=[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"ZYQAssetPicker.Bundle/Images/AssetsPickerVideo@2x.png"]]; 475 | 476 | [videoIcon drawAtPoint:CGPointMake(2, (height - videoIcon.size.height) / 2)]; 477 | 478 | } 479 | 480 | @end 481 | 482 | #pragma mark - ZYQTapAssetView 483 | 484 | @interface ZYQTapAssetView () 485 | 486 | @property(nonatomic,retain)UIImageView *selectView; 487 | 488 | @end 489 | 490 | @implementation ZYQTapAssetView 491 | 492 | static UIImage *checkedIcon; 493 | static UIColor *selectedColor; 494 | static UIColor *disabledColor; 495 | 496 | + (void)initialize 497 | { 498 | checkedIcon = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:[NSString stringWithFormat:@"ZYQAssetPicker.Bundle/Images/%@@2x.png",(!IS_IOS7) ? @"AssetsPickerChecked~iOS6" : @"AssetsPickerChecked"]]]; 499 | selectedColor = [UIColor colorWithWhite:1 alpha:0.3]; 500 | disabledColor = [UIColor colorWithWhite:1 alpha:0.9]; 501 | } 502 | 503 | -(id)initWithFrame:(CGRect)frame{ 504 | if (self=[super initWithFrame:frame]) { 505 | _selectView=[[UIImageView alloc] initWithFrame:CGRectMake(frame.size.width-checkedIcon.size.width, frame.size.height-checkedIcon.size.height, checkedIcon.size.width, checkedIcon.size.height)]; 506 | [self addSubview:_selectView]; 507 | } 508 | return self; 509 | } 510 | 511 | -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 512 | if (_disabled) { 513 | return; 514 | } 515 | 516 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(shouldTap:)]) { 517 | if (![_delegate shouldTap:_selected]&&!_selected) { 518 | return; 519 | } 520 | } 521 | 522 | if ((_selected=!_selected)) { 523 | self.backgroundColor=selectedColor; 524 | [_selectView setImage:checkedIcon]; 525 | } 526 | else{ 527 | self.backgroundColor=[UIColor clearColor]; 528 | [_selectView setImage:nil]; 529 | } 530 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(touchSelect:)]) { 531 | [_delegate touchSelect:_selected]; 532 | } 533 | } 534 | 535 | -(void)setDisabled:(BOOL)disabled{ 536 | _disabled=disabled; 537 | if (_disabled) { 538 | self.backgroundColor=disabledColor; 539 | } 540 | else{ 541 | self.backgroundColor=[UIColor clearColor]; 542 | } 543 | } 544 | 545 | -(void)setSelected:(BOOL)selected{ 546 | if (_disabled) { 547 | self.backgroundColor=disabledColor; 548 | [_selectView setImage:nil]; 549 | return; 550 | } 551 | 552 | _selected=selected; 553 | if (_selected) { 554 | self.backgroundColor=selectedColor; 555 | [_selectView setImage:checkedIcon]; 556 | } 557 | else{ 558 | self.backgroundColor=[UIColor clearColor]; 559 | [_selectView setImage:nil]; 560 | } 561 | } 562 | 563 | @end 564 | 565 | #pragma mark - ZYQAssetView 566 | 567 | @interface ZYQAssetView () 568 | 569 | @property (nonatomic, strong) ZYQAsset *asset; 570 | 571 | @property (nonatomic, weak) id delegate; 572 | 573 | @property (nonatomic, retain) UIImageView *imageView; 574 | @property (nonatomic, retain) ZYQVideoTitleView *videoTitle; 575 | @property (nonatomic, retain) ZYQTapAssetView *tapAssetView; 576 | 577 | @end 578 | 579 | @implementation ZYQAssetView 580 | 581 | static UIFont *titleFont = nil; 582 | 583 | static CGFloat titleHeight; 584 | static UIColor *titleColor; 585 | 586 | + (void)initialize 587 | { 588 | titleFont = [UIFont systemFontOfSize:12]; 589 | titleHeight = 20.0f; 590 | titleColor = [UIColor whiteColor]; 591 | } 592 | 593 | - (id)initWithFrame:(CGRect)frame 594 | { 595 | if (self = [super initWithFrame:frame]) 596 | { 597 | self.opaque = YES; 598 | self.isAccessibilityElement = YES; 599 | self.accessibilityTraits = UIAccessibilityTraitImage; 600 | 601 | _imageView=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kThumbnailSize.width, kThumbnailSize.height)]; 602 | [self addSubview:_imageView]; 603 | 604 | _videoTitle=[[ZYQVideoTitleView alloc] initWithFrame:CGRectMake(0, kThumbnailSize.height-20, kThumbnailSize.width, titleHeight)]; 605 | _videoTitle.hidden=YES; 606 | _videoTitle.font=titleFont; 607 | _videoTitle.textColor=titleColor; 608 | _videoTitle.textAlignment=NSTextAlignmentRight; 609 | _videoTitle.backgroundColor=[UIColor colorWithWhite:0 alpha:0.6]; 610 | [self addSubview:_videoTitle]; 611 | 612 | _tapAssetView=[[ZYQTapAssetView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)]; 613 | _tapAssetView.delegate=self; 614 | [self addSubview:_tapAssetView]; 615 | } 616 | 617 | return self; 618 | } 619 | 620 | - (void)bind:(ZYQAsset*)asset selectionFilter:(NSPredicate*)selectionFilter isSeleced:(BOOL)isSeleced 621 | { 622 | self.asset=asset; 623 | 624 | __weak typeof(self) weakSelf=self; 625 | [_asset setGetThumbnail:^(UIImage *result) { 626 | dispatch_async(dispatch_get_main_queue(), ^{ 627 | weakSelf.imageView.image=result; 628 | }); 629 | }]; 630 | 631 | 632 | if (_asset.mediaType==ZYQAssetMediaTypeVideo) { 633 | _videoTitle.hidden=NO; 634 | _videoTitle.text=[NSDate timeDescriptionOfTimeInterval:_asset.duration]; 635 | NSLog(@"%@",_videoTitle.text); 636 | 637 | } 638 | else{ 639 | _videoTitle.hidden=YES; 640 | } 641 | 642 | _tapAssetView.disabled=! [selectionFilter evaluateWithObject:_asset]; 643 | 644 | _tapAssetView.selected=isSeleced; 645 | } 646 | 647 | #pragma mark - ZYQTapAssetView Delegate 648 | 649 | -(BOOL)shouldTap:(BOOL)select{ 650 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(shouldSelectAsset:select:)]) { 651 | return [_delegate shouldSelectAsset:_asset select:select]; 652 | } 653 | return YES; 654 | } 655 | 656 | -(void)touchSelect:(BOOL)select{ 657 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(tapSelectHandle:asset:)]) { 658 | [_delegate tapSelectHandle:select asset:_asset]; 659 | } 660 | } 661 | 662 | @end 663 | 664 | #pragma mark - ZYQAssetViewCell 665 | 666 | @interface ZYQAssetViewCell () 667 | 668 | @end 669 | 670 | @class ZYQAssetViewController; 671 | 672 | @implementation ZYQAssetViewCell 673 | 674 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ 675 | if (self=[super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 676 | [self setSelectionStyle:UITableViewCellSelectionStyleNone]; 677 | } 678 | return self; 679 | } 680 | 681 | - (void)bind:(NSArray *)assets selectionFilter:(NSPredicate*)selectionFilter minimumInteritemSpacing:(float)minimumInteritemSpacing minimumLineSpacing:(float)minimumLineSpacing columns:(int)columns assetViewX:(float)assetViewX{ 682 | 683 | if (self.contentView.subviews.count((NSInteger)self.contentView.subviews.count-1)) { 686 | ZYQAssetView *assetView=[[ZYQAssetView alloc] initWithFrame:CGRectMake(assetViewX+(kThumbnailSize.width+minimumInteritemSpacing)*i, minimumLineSpacing-1, kThumbnailSize.width, kThumbnailSize.height)]; 687 | [assetView bind:assets[i] selectionFilter:selectionFilter isSeleced:[((ZYQAssetViewController*)_delegate).indexPathsForSelectedItems containsObject:assets[i]]]; 688 | assetView.delegate=self; 689 | [self.contentView addSubview:assetView]; 690 | } 691 | else{ 692 | ((ZYQAssetView*)self.contentView.subviews[i]).frame=CGRectMake(assetViewX+(kThumbnailSize.width+minimumInteritemSpacing)*(i), minimumLineSpacing-1, kThumbnailSize.width, kThumbnailSize.height); 693 | [(ZYQAssetView*)self.contentView.subviews[i] bind:assets[i] selectionFilter:selectionFilter isSeleced:[((ZYQAssetViewController*)_delegate).indexPathsForSelectedItems containsObject:assets[i]]]; 694 | } 695 | 696 | } 697 | 698 | } 699 | else{ 700 | for (NSInteger i=self.contentView.subviews.count; i>0; i--) { 701 | if (i>assets.count) { 702 | [((ZYQAssetView*)self.contentView.subviews[i-1]) removeFromSuperview]; 703 | } 704 | else{ 705 | ((ZYQAssetView*)self.contentView.subviews[i-1]).frame=CGRectMake(assetViewX+(kThumbnailSize.width+minimumInteritemSpacing)*(i-1), minimumLineSpacing-1, kThumbnailSize.width, kThumbnailSize.height); 706 | [(ZYQAssetView*)self.contentView.subviews[i-1] bind:assets[i-1] selectionFilter:selectionFilter isSeleced:[((ZYQAssetViewController*)_delegate).indexPathsForSelectedItems containsObject:assets[i-1]]]; 707 | } 708 | } 709 | } 710 | } 711 | 712 | #pragma mark - ZYQAssetView Delegate 713 | 714 | -(BOOL)shouldSelectAsset:(ZYQAsset*)asset select:(BOOL)select{ 715 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(shouldSelectAsset:select:)]) { 716 | return [_delegate shouldSelectAsset:asset select:select]; 717 | } 718 | return YES; 719 | } 720 | 721 | -(void)tapSelectHandle:(BOOL)select asset:(ZYQAsset*)asset{ 722 | if (select) { 723 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(didSelectAsset:)]) { 724 | [_delegate didSelectAsset:asset]; 725 | } 726 | } 727 | else{ 728 | if (_delegate!=nil&&[_delegate respondsToSelector:@selector(didDeselectAsset:)]) { 729 | [_delegate didDeselectAsset:asset]; 730 | } 731 | } 732 | } 733 | 734 | @end 735 | 736 | #pragma mark - ZYQAssetViewController 737 | 738 | @interface ZYQAssetViewController (){ 739 | int columns; 740 | 741 | float minimumInteritemSpacing; 742 | float minimumLineSpacing; 743 | 744 | BOOL unFirst; 745 | } 746 | 747 | @property (nonatomic, strong) NSMutableArray *assets; 748 | @property (nonatomic, assign) NSInteger numberOfPhotos; 749 | @property (nonatomic, assign) NSInteger numberOfVideos; 750 | 751 | @end 752 | 753 | #define kAssetViewCellIdentifier @"AssetViewCellIdentifier" 754 | 755 | @implementation ZYQAssetViewController 756 | 757 | - (id)init 758 | { 759 | if (self = [super init]) 760 | { 761 | _indexPathsForSelectedItems=[[NSMutableArray alloc] init]; 762 | 763 | if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) 764 | { 765 | self.tableView.contentInset=UIEdgeInsetsMake(9.0, 2.0, 0, 2.0); 766 | 767 | minimumInteritemSpacing=3; 768 | minimumLineSpacing=3; 769 | 770 | } 771 | else 772 | { 773 | self.tableView.contentInset=UIEdgeInsetsMake(9.0, 0, 0, 0); 774 | 775 | minimumInteritemSpacing=2; 776 | minimumLineSpacing=2; 777 | } 778 | 779 | if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) 780 | [self setEdgesForExtendedLayout:UIRectEdgeNone]; 781 | 782 | if ([self respondsToSelector:@selector(setContentSizeForViewInPopover:)]) 783 | [self setPreferredContentSize:kPopoverContentSize]; 784 | 785 | } 786 | 787 | [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; 788 | return self; 789 | } 790 | 791 | - (void)viewDidLoad 792 | { 793 | [super viewDidLoad]; 794 | 795 | [self setupViews]; 796 | [self setupButtons]; 797 | } 798 | 799 | - (void)viewWillAppear:(BOOL)animated 800 | { 801 | [super viewWillAppear:animated]; 802 | if (!unFirst) { 803 | columns=floor(self.view.frame.size.width/(kThumbnailSize.width+minimumInteritemSpacing)); 804 | 805 | [self setupAssets]; 806 | 807 | unFirst=YES; 808 | } 809 | } 810 | 811 | 812 | #pragma mark - Rotation 813 | 814 | - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 815 | { 816 | if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) 817 | { 818 | self.tableView.contentInset=UIEdgeInsetsMake(9.0, 0, 0, 0); 819 | 820 | minimumInteritemSpacing=3; 821 | minimumLineSpacing=3; 822 | } 823 | else 824 | { 825 | self.tableView.contentInset=UIEdgeInsetsMake(9.0, 0, 0, 0); 826 | 827 | minimumInteritemSpacing=2; 828 | minimumLineSpacing=2; 829 | } 830 | 831 | columns=floor(self.view.frame.size.width/(kThumbnailSize.width+minimumInteritemSpacing)); 832 | 833 | [self.tableView reloadData]; 834 | } 835 | 836 | #pragma mark - Setup 837 | 838 | - (void)setupViews 839 | { 840 | self.tableView.backgroundColor = [UIColor whiteColor]; 841 | } 842 | 843 | - (void)setupButtons 844 | { 845 | self.navigationItem.rightBarButtonItem = 846 | [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"完成", nil) 847 | style:UIBarButtonItemStylePlain 848 | target:self 849 | action:@selector(finishPickingAssets:)]; 850 | } 851 | 852 | - (void)setupAssets 853 | { 854 | self.title = self.assetsGroup.groupName; 855 | self.numberOfPhotos = 0; 856 | self.numberOfVideos = 0; 857 | 858 | if (!self.assets) 859 | self.assets = [[NSMutableArray alloc] init]; 860 | else 861 | [self.assets removeAllObjects]; 862 | 863 | ZYQAssetPickerController *picker = (ZYQAssetPickerController *)self.navigationController; 864 | 865 | [self.assetsGroup enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 866 | if (obj) 867 | { 868 | ZYQAsset *asset=[[ZYQAsset alloc] init]; 869 | asset.originAsset=obj; 870 | 871 | [self.assets addObject:asset]; 872 | 873 | switch ([asset mediaType]) { 874 | case ZYQAssetMediaTypeImage: 875 | self.numberOfPhotos ++; 876 | break; 877 | case ZYQAssetMediaTypeVideo: 878 | self.numberOfVideos ++; 879 | break; 880 | default: 881 | break; 882 | } 883 | } 884 | 885 | if (self.assetsGroup.count-1 == idx) 886 | { 887 | 888 | dispatch_async(dispatch_get_main_queue(), ^{ 889 | [self.tableView reloadData]; 890 | 891 | if (picker.scrollBottom) { 892 | [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:ceil(self.assets.count*1.0/columns) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:NO]; 893 | } 894 | }); 895 | } 896 | 897 | }]; 898 | 899 | /** 900 | 将数组倒序 901 | */ 902 | if(picker.timeDescSort){ 903 | NSArray *tempArray = [[self.assets reverseObjectEnumerator] allObjects]; 904 | [self.assets removeAllObjects]; 905 | [self.assets addObjectsFromArray:tempArray]; 906 | } 907 | 908 | 909 | 910 | } 911 | 912 | #pragma mark - UITableView DataSource 913 | -(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 914 | 915 | if (indexPath.row==ceil(self.assets.count*1.0/columns)) { 916 | UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:@"cellFooter"]; 917 | 918 | if (cell==nil) { 919 | cell=[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellFooter"]; 920 | cell.textLabel.font=[UIFont systemFontOfSize:18]; 921 | cell.textLabel.backgroundColor=[UIColor clearColor]; 922 | cell.textLabel.textAlignment=NSTextAlignmentCenter; 923 | cell.textLabel.textColor=[UIColor blackColor]; 924 | cell.backgroundColor=[UIColor clearColor]; 925 | [cell setSelectionStyle:UITableViewCellSelectionStyleNone]; 926 | } 927 | 928 | NSString *title; 929 | 930 | if (_numberOfVideos == 0) 931 | title = [NSString stringWithFormat:NSLocalizedString(@"%ld 张照片", nil), (long)_numberOfPhotos]; 932 | else if (_numberOfPhotos == 0) 933 | title = [NSString stringWithFormat:NSLocalizedString(@"%ld 部视频", nil), (long)_numberOfVideos]; 934 | else 935 | title = [NSString stringWithFormat:NSLocalizedString(@"%ld 张照片, %ld 部视频", nil), (long)_numberOfPhotos, (long)_numberOfVideos]; 936 | 937 | cell.textLabel.text=title; 938 | return cell; 939 | } 940 | 941 | 942 | NSMutableArray *tempAssets=[[NSMutableArray alloc] init]; 943 | for (int i=0; i= vc.maximumNumberOfSelection&&!select) { 983 | if (vc.delegate!=nil&&[vc.delegate respondsToSelector:@selector(assetPickerControllerDidMaximum:)]) { 984 | [vc.delegate assetPickerControllerDidMaximum:vc]; 985 | } 986 | } 987 | 988 | return (selectable && _indexPathsForSelectedItems.count < vc.maximumNumberOfSelection); 989 | } 990 | 991 | - (void)didSelectAsset:(id)asset 992 | { 993 | [_indexPathsForSelectedItems addObject:asset]; 994 | 995 | ZYQAssetPickerController *vc = (ZYQAssetPickerController *)self.navigationController; 996 | vc.indexPathsForSelectedItems = _indexPathsForSelectedItems; 997 | 998 | if (vc.delegate!=nil&&[vc.delegate respondsToSelector:@selector(assetPickerController:didSelectAsset:)]) 999 | [vc.delegate assetPickerController:vc didSelectAsset:asset]; 1000 | 1001 | [self setTitleWithSelectedIndexPaths:_indexPathsForSelectedItems]; 1002 | } 1003 | 1004 | - (void)didDeselectAsset:(id)asset 1005 | { 1006 | [_indexPathsForSelectedItems removeObject:asset]; 1007 | 1008 | ZYQAssetPickerController *vc = (ZYQAssetPickerController *)self.navigationController; 1009 | vc.indexPathsForSelectedItems = _indexPathsForSelectedItems; 1010 | 1011 | if (vc.delegate!=nil&&[vc.delegate respondsToSelector:@selector(assetPickerController:didDeselectAsset:)]) 1012 | [vc.delegate assetPickerController:vc didDeselectAsset:asset]; 1013 | 1014 | [self setTitleWithSelectedIndexPaths:_indexPathsForSelectedItems]; 1015 | } 1016 | 1017 | 1018 | #pragma mark - Title 1019 | 1020 | - (void)setTitleWithSelectedIndexPaths:(NSArray *)indexPaths 1021 | { 1022 | if (indexPaths.count == 0) 1023 | { 1024 | self.title = self.assetsGroup.groupName; 1025 | return; 1026 | } 1027 | 1028 | BOOL photosSelected = NO; 1029 | BOOL videoSelected = NO; 1030 | 1031 | for (int i=0; i 1) ? NSLocalizedString(@"已选择 %ld 张照片", nil) : NSLocalizedString(@"已选择 %ld 张照片 ", nil); 1052 | 1053 | else if (videoSelected) 1054 | format = (indexPaths.count > 1) ? NSLocalizedString(@"已选择 %ld 部视频", nil) : NSLocalizedString(@"已选择 %ld 部视频 ", nil); 1055 | 1056 | self.title = [NSString stringWithFormat:format, (long)indexPaths.count]; 1057 | 1058 | } 1059 | 1060 | 1061 | #pragma mark - Actions 1062 | 1063 | - (void)finishPickingAssets:(id)sender 1064 | { 1065 | 1066 | ZYQAssetPickerController *picker = (ZYQAssetPickerController *)self.navigationController; 1067 | 1068 | if (_indexPathsForSelectedItems.count < picker.minimumNumberOfSelection) { 1069 | if (picker.delegate!=nil&&[picker.delegate respondsToSelector:@selector(assetPickerControllerDidMaximum:)]) { 1070 | [picker.delegate assetPickerControllerDidMaximum:picker]; 1071 | } 1072 | } 1073 | 1074 | 1075 | if ([picker.delegate respondsToSelector:@selector(assetPickerController:didFinishPickingAssets:)]) 1076 | [picker.delegate assetPickerController:picker didFinishPickingAssets:_indexPathsForSelectedItems]; 1077 | 1078 | if (picker.isFinishDismissViewController) { 1079 | [picker.presentingViewController dismissViewControllerAnimated:YES completion:NULL]; 1080 | } 1081 | } 1082 | 1083 | @end 1084 | 1085 | #pragma mark - ZYQAssetGroupViewCell 1086 | 1087 | @interface ZYQAssetGroupViewCell () 1088 | 1089 | @property (nonatomic, strong) ZYQAssetsGroup *assetsGroup; 1090 | 1091 | @end 1092 | 1093 | @implementation ZYQAssetGroupViewCell 1094 | 1095 | 1096 | - (void)bind:(ZYQAssetsGroup*)assetsGroup 1097 | { 1098 | self.assetsGroup = assetsGroup; 1099 | 1100 | __weak typeof(self) weakSelf=self; 1101 | 1102 | [_assetsGroup setGetThumbnail:^(UIImage *result) { 1103 | dispatch_async(dispatch_get_main_queue(), ^{ 1104 | weakSelf.imageView.image=result; 1105 | [weakSelf setNeedsLayout]; 1106 | }); 1107 | }]; 1108 | 1109 | self.textLabel.text=_assetsGroup.groupName; 1110 | self.detailTextLabel.text = [NSString stringWithFormat:@"%zi", _assetsGroup.count]; 1111 | self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 1112 | } 1113 | 1114 | - (NSString *)accessibilityLabel 1115 | { 1116 | return [_assetsGroup.groupName stringByAppendingFormat:NSLocalizedString(@"%ld 张照片", nil), (long)_assetsGroup.count]; 1117 | } 1118 | 1119 | @end 1120 | 1121 | 1122 | #pragma mark - ZYQAssetGroupViewController 1123 | 1124 | @interface ZYQAssetGroupViewController() 1125 | 1126 | @property (nonatomic, strong) ALAssetsLibrary *assetsLibrary; 1127 | @property (nonatomic, strong) NSMutableArray *groups; 1128 | 1129 | @end 1130 | 1131 | @implementation ZYQAssetGroupViewController 1132 | 1133 | - (id)init 1134 | { 1135 | if (self = [super initWithStyle:UITableViewStylePlain]) 1136 | { 1137 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 1138 | self.preferredContentSize=kPopoverContentSize; 1139 | #else 1140 | if ([self respondsToSelector:@selector(setContentSizeForViewInPopover:)]) 1141 | [self setContentSizeForViewInPopover:kPopoverContentSize]; 1142 | #endif 1143 | } 1144 | 1145 | return self; 1146 | } 1147 | 1148 | - (void)viewDidLoad 1149 | { 1150 | [super viewDidLoad]; 1151 | [self setupViews]; 1152 | [self setupButtons]; 1153 | [self localize]; 1154 | [self setupGroup]; 1155 | } 1156 | 1157 | 1158 | #pragma mark - Rotation 1159 | 1160 | - (BOOL)shouldAutorotate 1161 | { 1162 | return YES; 1163 | } 1164 | 1165 | - (UIInterfaceOrientationMask)supportedInterfaceOrientations 1166 | { 1167 | return UIInterfaceOrientationMaskAllButUpsideDown; 1168 | } 1169 | 1170 | 1171 | #pragma mark - Setup 1172 | 1173 | - (void)setupViews 1174 | { 1175 | self.tableView.rowHeight = kThumbnailLength + 12; 1176 | self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; 1177 | } 1178 | 1179 | - (void)setupButtons 1180 | { 1181 | ZYQAssetPickerController *picker = (ZYQAssetPickerController *)self.navigationController; 1182 | 1183 | if (picker.showCancelButton) 1184 | { 1185 | self.navigationItem.rightBarButtonItem = 1186 | [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"取消", nil) 1187 | style:UIBarButtonItemStylePlain 1188 | target:self 1189 | action:@selector(dismiss:)]; 1190 | } 1191 | } 1192 | 1193 | - (void)localize 1194 | { 1195 | self.title = NSLocalizedString(@"相簿", nil); 1196 | } 1197 | 1198 | - (void)setupGroup 1199 | { 1200 | if (!self.groups) 1201 | self.groups = [[NSMutableArray alloc] init]; 1202 | else 1203 | [self.groups removeAllObjects]; 1204 | 1205 | 1206 | if (IS_IOS8) { 1207 | __block BOOL showNotAllowed=YES; 1208 | ZYQAssetPickerController *picker = (ZYQAssetPickerController *)self.navigationController; 1209 | 1210 | PHFetchOptions *fetchOptions = [[PHFetchOptions alloc]init]; 1211 | 1212 | PHFetchResult *smartAlbumsFetchResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:fetchOptions]; 1213 | //遍历相机胶卷 1214 | [smartAlbumsFetchResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull collection, NSUInteger idx, BOOL *stop) { 1215 | showNotAllowed=NO; 1216 | PHFetchOptions *fetchOptionsAlbums=[[PHFetchOptions alloc] init]; 1217 | 1218 | switch (picker.assetsFilter) { 1219 | case ZYQAssetsFilterAllVideos: 1220 | fetchOptionsAlbums.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeVideo]; 1221 | break; 1222 | case ZYQAssetsFilterAllPhotos: 1223 | fetchOptionsAlbums.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeImage]; 1224 | break; 1225 | default: 1226 | break; 1227 | } 1228 | PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptionsAlbums]; 1229 | 1230 | 1231 | if (![collection.localizedTitle isEqualToString:@"Videos"]) { 1232 | if (fetchResult.count>0) { 1233 | ZYQAssetsGroup *tmpGroup=[[ZYQAssetsGroup alloc] init]; 1234 | tmpGroup.originAssetGroup=collection; 1235 | tmpGroup.originFetchResult=fetchResult; 1236 | [self.groups addObject:tmpGroup]; 1237 | } 1238 | } 1239 | }]; 1240 | //遍历自建相册 1241 | PHFetchResult *customAlbumsFetchResult = [PHAssetCollection fetchTopLevelUserCollectionsWithOptions:fetchOptions]; 1242 | [customAlbumsFetchResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull collection, NSUInteger idx, BOOL *stop) { 1243 | showNotAllowed=NO; 1244 | 1245 | PHFetchOptions *fetchOptionsAlbums=[[PHFetchOptions alloc] init]; 1246 | 1247 | switch (picker.assetsFilter) { 1248 | case ZYQAssetsFilterAllVideos: 1249 | fetchOptionsAlbums.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeVideo]; 1250 | break; 1251 | case ZYQAssetsFilterAllPhotos: 1252 | fetchOptionsAlbums.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeImage]; 1253 | break; 1254 | default: 1255 | break; 1256 | } 1257 | PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:collection options:fetchOptionsAlbums]; 1258 | 1259 | if (fetchResult.count>0) { 1260 | ZYQAssetsGroup *tmpGroup=[[ZYQAssetsGroup alloc] init]; 1261 | tmpGroup.originAssetGroup=collection; 1262 | tmpGroup.originFetchResult=fetchResult; 1263 | [self.groups addObject:tmpGroup]; 1264 | } 1265 | 1266 | }]; 1267 | 1268 | if (showNotAllowed) { 1269 | [self showNotAllowed]; 1270 | } 1271 | else 1272 | { 1273 | [self reloadData]; 1274 | } 1275 | } 1276 | else{ 1277 | if (!self.assetsLibrary) 1278 | self.assetsLibrary = [self.class defaultAssetsLibrary]; 1279 | 1280 | ZYQAssetPickerController *picker = (ZYQAssetPickerController *)self.navigationController; 1281 | 1282 | ALAssetsFilter *assetsFilter = [ALAssetsFilter allAssets]; 1283 | 1284 | switch (picker.assetsFilter) { 1285 | case ZYQAssetsFilterAllPhotos: 1286 | assetsFilter=[ALAssetsFilter allPhotos]; 1287 | break; 1288 | case ZYQAssetsFilterAllVideos: 1289 | assetsFilter=[ALAssetsFilter allVideos]; 1290 | break; 1291 | default: 1292 | break; 1293 | } 1294 | 1295 | ALAssetsLibraryGroupsEnumerationResultsBlock resultsBlock = ^(ALAssetsGroup *group, BOOL *stop) { 1296 | 1297 | if (group) 1298 | { 1299 | [group setAssetsFilter:assetsFilter]; 1300 | if (group.numberOfAssets > 0 || picker.showEmptyGroups){ 1301 | ZYQAssetsGroup *tmpGroup=[[ZYQAssetsGroup alloc] init]; 1302 | tmpGroup.originAssetGroup=group; 1303 | [self.groups addObject:tmpGroup]; 1304 | } 1305 | } 1306 | else 1307 | { 1308 | [self reloadData]; 1309 | } 1310 | }; 1311 | 1312 | 1313 | ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError *error) { 1314 | 1315 | [self showNotAllowed]; 1316 | 1317 | }; 1318 | 1319 | // Enumerate Camera roll first 1320 | [self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos 1321 | usingBlock:resultsBlock 1322 | failureBlock:failureBlock]; 1323 | 1324 | // Then all other groups 1325 | NSUInteger type = 1326 | ALAssetsGroupLibrary | ALAssetsGroupAlbum | ALAssetsGroupEvent | 1327 | ALAssetsGroupFaces | ALAssetsGroupPhotoStream; 1328 | 1329 | [self.assetsLibrary enumerateGroupsWithTypes:type 1330 | usingBlock:resultsBlock 1331 | failureBlock:failureBlock]; 1332 | } 1333 | 1334 | } 1335 | 1336 | 1337 | #pragma mark - Reload Data 1338 | 1339 | - (void)reloadData 1340 | { 1341 | if (self.groups.count == 0) 1342 | [self showNoAssets]; 1343 | 1344 | [self.tableView reloadData]; 1345 | } 1346 | 1347 | 1348 | #pragma mark - ALAssetsLibrary 1349 | 1350 | + (ALAssetsLibrary *)defaultAssetsLibrary 1351 | { 1352 | static dispatch_once_t pred = 0; 1353 | static ALAssetsLibrary *library = nil; 1354 | dispatch_once(&pred, ^{ 1355 | library = [[ALAssetsLibrary alloc] init]; 1356 | }); 1357 | return library; 1358 | } 1359 | 1360 | 1361 | #pragma mark - Not allowed / No assets 1362 | 1363 | - (void)showNotAllowed 1364 | { 1365 | if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) 1366 | [self setEdgesForExtendedLayout:UIRectEdgeLeft | UIRectEdgeRight | UIRectEdgeBottom]; 1367 | 1368 | self.title = nil; 1369 | 1370 | UIImageView *padlock = [[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"ZYQAssetPicker.Bundle/Images/AssetsPickerLocked@2x.png"]]]; 1371 | padlock.translatesAutoresizingMaskIntoConstraints = NO; 1372 | 1373 | UILabel *title = [UILabel new]; 1374 | title.translatesAutoresizingMaskIntoConstraints = NO; 1375 | title.preferredMaxLayoutWidth = 304.0f; 1376 | 1377 | UILabel *message = [UILabel new]; 1378 | message.translatesAutoresizingMaskIntoConstraints = NO; 1379 | message.preferredMaxLayoutWidth = 304.0f; 1380 | 1381 | title.text = NSLocalizedString(@"此应用无法使用您的照片或视频。", nil); 1382 | title.font = [UIFont boldSystemFontOfSize:17.0]; 1383 | title.textColor = [UIColor colorWithRed:129.0/255.0 green:136.0/255.0 blue:148.0/255.0 alpha:1]; 1384 | title.textAlignment = NSTextAlignmentCenter; 1385 | title.numberOfLines = 5; 1386 | 1387 | message.text = NSLocalizedString(@"你可以在「隐私设置」中启用存取。", nil); 1388 | message.font = [UIFont systemFontOfSize:14.0]; 1389 | message.textColor = [UIColor colorWithRed:129.0/255.0 green:136.0/255.0 blue:148.0/255.0 alpha:1]; 1390 | message.textAlignment = NSTextAlignmentCenter; 1391 | message.numberOfLines = 5; 1392 | 1393 | [title sizeToFit]; 1394 | [message sizeToFit]; 1395 | 1396 | UIView *centerView = [UIView new]; 1397 | centerView.translatesAutoresizingMaskIntoConstraints = NO; 1398 | [centerView addSubview:padlock]; 1399 | [centerView addSubview:title]; 1400 | [centerView addSubview:message]; 1401 | 1402 | NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(padlock, title, message); 1403 | 1404 | [centerView addConstraint:[NSLayoutConstraint constraintWithItem:padlock attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:centerView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1405 | [centerView addConstraint:[NSLayoutConstraint constraintWithItem:title attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:padlock attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1406 | [centerView addConstraint:[NSLayoutConstraint constraintWithItem:message attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:padlock attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1407 | [centerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[padlock]-[title]-[message]|" options:0 metrics:nil views:viewsDictionary]]; 1408 | 1409 | UIView *backgroundView = [UIView new]; 1410 | [backgroundView addSubview:centerView]; 1411 | [backgroundView addConstraint:[NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:backgroundView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1412 | [backgroundView addConstraint:[NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:backgroundView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]; 1413 | 1414 | self.tableView.backgroundView = backgroundView; 1415 | } 1416 | 1417 | - (void)showNoAssets 1418 | { 1419 | if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) 1420 | [self setEdgesForExtendedLayout:UIRectEdgeLeft | UIRectEdgeRight | UIRectEdgeBottom]; 1421 | 1422 | UILabel *title = [UILabel new]; 1423 | title.translatesAutoresizingMaskIntoConstraints = NO; 1424 | title.preferredMaxLayoutWidth = 304.0f; 1425 | UILabel *message = [UILabel new]; 1426 | message.translatesAutoresizingMaskIntoConstraints = NO; 1427 | message.preferredMaxLayoutWidth = 304.0f; 1428 | 1429 | title.text = NSLocalizedString(@"没有照片或视频。", nil); 1430 | title.font = [UIFont systemFontOfSize:26.0]; 1431 | title.textColor = [UIColor colorWithRed:153.0/255.0 green:153.0/255.0 blue:153.0/255.0 alpha:1]; 1432 | title.textAlignment = NSTextAlignmentCenter; 1433 | title.numberOfLines = 5; 1434 | 1435 | message.text = NSLocalizedString(@"您可以使用 iTunes 将照片和视频\n同步到 iPhone。", nil); 1436 | message.font = [UIFont systemFontOfSize:18.0]; 1437 | message.textColor = [UIColor colorWithRed:153.0/255.0 green:153.0/255.0 blue:153.0/255.0 alpha:1]; 1438 | message.textAlignment = NSTextAlignmentCenter; 1439 | message.numberOfLines = 5; 1440 | 1441 | [title sizeToFit]; 1442 | [message sizeToFit]; 1443 | 1444 | UIView *centerView = [UIView new]; 1445 | centerView.translatesAutoresizingMaskIntoConstraints = NO; 1446 | [centerView addSubview:title]; 1447 | [centerView addSubview:message]; 1448 | 1449 | NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(title, message); 1450 | 1451 | [centerView addConstraint:[NSLayoutConstraint constraintWithItem:title attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:centerView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1452 | [centerView addConstraint:[NSLayoutConstraint constraintWithItem:message attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:title attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1453 | [centerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[title]-[message]|" options:0 metrics:nil views:viewsDictionary]]; 1454 | 1455 | UIView *backgroundView = [UIView new]; 1456 | [backgroundView addSubview:centerView]; 1457 | [backgroundView addConstraint:[NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:backgroundView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]]; 1458 | [backgroundView addConstraint:[NSLayoutConstraint constraintWithItem:centerView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:backgroundView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]; 1459 | 1460 | self.tableView.backgroundView = backgroundView; 1461 | } 1462 | 1463 | 1464 | 1465 | #pragma mark - Table view data source 1466 | 1467 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 1468 | { 1469 | return 1; 1470 | } 1471 | 1472 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 1473 | { 1474 | return self.groups.count; 1475 | } 1476 | 1477 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 1478 | { 1479 | static NSString *CellIdentifier = @"Cell"; 1480 | 1481 | ZYQAssetGroupViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 1482 | if (cell == nil) 1483 | { 1484 | cell = [[ZYQAssetGroupViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 1485 | } 1486 | 1487 | [cell bind:[self.groups objectAtIndex:indexPath.row]]; 1488 | 1489 | return cell; 1490 | } 1491 | 1492 | 1493 | #pragma mark - UITableView Delegate 1494 | 1495 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 1496 | { 1497 | return kThumbnailLength + 12; 1498 | } 1499 | 1500 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 1501 | { 1502 | ZYQAssetViewController *vc = [[ZYQAssetViewController alloc] init]; 1503 | vc.assetsGroup = [self.groups objectAtIndex:indexPath.row]; 1504 | 1505 | [self.navigationController pushViewController:vc animated:YES]; 1506 | } 1507 | 1508 | #pragma mark - Actions 1509 | 1510 | - (void)dismiss:(id)sender 1511 | { 1512 | ZYQAssetPickerController *picker = (ZYQAssetPickerController *)self.navigationController; 1513 | 1514 | if ([picker.delegate respondsToSelector:@selector(assetPickerControllerDidCancel:)]) 1515 | [picker.delegate assetPickerControllerDidCancel:picker]; 1516 | 1517 | [picker.presentingViewController dismissViewControllerAnimated:YES completion:NULL]; 1518 | } 1519 | 1520 | @end 1521 | 1522 | #pragma mark - ZYQAssetPickerController 1523 | 1524 | @implementation ZYQAssetPickerController 1525 | 1526 | @dynamic delegate; 1527 | 1528 | - (id)init 1529 | { 1530 | ZYQAssetGroupViewController *groupViewController = [[ZYQAssetGroupViewController alloc] init]; 1531 | 1532 | if (self = [super initWithRootViewController:groupViewController]) 1533 | { 1534 | _maximumNumberOfSelection = 10; 1535 | _minimumNumberOfSelection = 0; 1536 | _assetsFilter = ZYQAssetsFilterAllAssets; 1537 | _showCancelButton = YES; 1538 | _showEmptyGroups = NO; 1539 | _selectionFilter = [NSPredicate predicateWithValue:YES]; 1540 | _isFinishDismissViewController = YES; 1541 | 1542 | #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_7_0 1543 | self.preferredContentSize=kPopoverContentSize; 1544 | #else 1545 | if ([self respondsToSelector:@selector(setContentSizeForViewInPopover:)]) 1546 | [self setContentSizeForViewInPopover:kPopoverContentSize]; 1547 | #endif 1548 | } 1549 | 1550 | return self; 1551 | } 1552 | 1553 | - (void)viewDidLoad 1554 | { 1555 | [super viewDidLoad]; 1556 | } 1557 | 1558 | - (void)didReceiveMemoryWarning 1559 | { 1560 | [super didReceiveMemoryWarning]; 1561 | } 1562 | 1563 | @end 1564 | --------------------------------------------------------------------------------