├── .gitignore ├── .swift-version ├── Demo ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-29.0@1x.png │ │ ├── Icon-29.0@2x.png │ │ ├── Icon-29.0@3x.png │ │ ├── Icon-40.0@1x.png │ │ ├── Icon-40.0@2x.png │ │ ├── Icon-40.0@3x.png │ │ ├── Icon-50.0@1x.png │ │ ├── Icon-50.0@2x.png │ │ ├── Icon-57.0@1x.png │ │ ├── Icon-57.0@2x.png │ │ ├── Icon-60.0@2x.png │ │ ├── Icon-60.0@3x.png │ │ ├── Icon-72.0@1x.png │ │ ├── Icon-72.0@2x.png │ │ ├── Icon-76.0@1x.png │ │ ├── Icon-76.0@2x.png │ │ └── Icon-83.5@2x.png ├── Base.lproj │ └── Main.storyboard ├── Info.plist ├── Launch Screen.storyboard └── ViewController.swift ├── LICENSE ├── README.md ├── WCLImagePickerController.podspec ├── WCLImagePickerController.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── wangchonglei.xcuserdatad │ └── xcschemes │ ├── Demo.xcscheme │ ├── WCLImagePickerController.xcscheme │ └── xcschememanagement.plist ├── WCLImagePickerController ├── Info.plist └── WCLImagePickerController │ ├── Cells │ ├── WCLAblumListCell.swift │ ├── WCLAblumListCell.xib │ ├── photoBrowserCells │ │ ├── WCLPhotoCVCell.swift │ │ ├── WCLPhotoCVCell.xib │ │ └── WCLPhotoCellContext.swift │ └── pickerCells │ │ ├── WCLCameraCVCell.swift │ │ ├── WCLCameraCVCell.xib │ │ ├── WCLPickerCVCell.swift │ │ ├── WCLPickerCVCell.xib │ │ ├── WCLPickerCellContext.swift │ │ ├── WCLSelecteCVCell.swift │ │ └── WCLSelecteCVCell.xib │ ├── Others │ ├── WCLBaseImagePickerController.swift │ ├── WCLError.swift │ ├── WCLImagePickerBundle.swift │ ├── WCLImagePickerNotify.swift │ ├── WCLImagePickerOptions.swift │ ├── WCLImagePikcerDelegate.swift │ ├── WCLNavigationController.swift │ ├── WCLPickerExtension.swift │ └── WCLPickerManager.swift │ ├── ViewControllers │ ├── WCLImagePickerController.swift │ ├── WCLImagePickerController.xib │ ├── WCLPhotoBrowserController.swift │ └── WCLPhotoBrowserController.xib │ ├── Views │ ├── WCLAblumCenterView.swift │ ├── WCLAblumListView.swift │ ├── WCLAblumListView.xib │ ├── WCLLaunchView.swift │ ├── WCLPhotoSelectView.swift │ ├── WCLPhotoSelectView.xib │ ├── WCLSelectView.swift │ └── WCLSelectView.xib │ └── WCLImagePickerController.bundle │ ├── Images │ ├── image_ablumSelectBackGround@2x.png │ ├── image_ablumSelectBackGround@3x.png │ ├── image_buffer@2x.png │ ├── image_buffer@3x.png │ ├── image_camera@2x.png │ ├── image_camera@3x.png │ ├── image_photoAlbum@2x.png │ ├── image_photoAlbum@3x.png │ ├── image_pickerArrow@2x.png │ ├── image_pickerArrow@3x.png │ ├── image_pickerDefault@2x.png │ ├── image_pickerDefault@3x.png │ ├── image_selectPlaceholder@2x.png │ └── image_selectPlaceholder@3x.png │ ├── en.lproj │ └── Localizable.strings │ └── zh.lproj │ └── Localizable.strings └── wcl.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | .DS_Store 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | .build/ 40 | 41 | # CocoaPods 42 | # 43 | # We recommend against adding the Pods directory to your .gitignore. However 44 | # you should judge for yourself, the pros and cons are mentioned at: 45 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 46 | # 47 | # Pods/ 48 | 49 | # Carthage 50 | # 51 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 52 | # Carthage/Checkouts 53 | 54 | Carthage/Build 55 | 56 | # fastlane 57 | # 58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 59 | # screenshots whenever they are needed. 60 | # For more information about the recommended setup visit: 61 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 62 | 63 | fastlane/report.xml 64 | fastlane/Preview.html 65 | fastlane/screenshots 66 | fastlane/test_output 67 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 3.0 2 | -------------------------------------------------------------------------------- /Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Demo 4 | // 5 | // Created by 王崇磊 on 2017/1/10. 6 | // Copyright © 2017年 王崇磊. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Demo/Assets.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 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-29.0@1x.png", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-29.0@2x.png", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "size" : "29x29", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-29.0@3x.png", 29 | "scale" : "3x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-40.0@2x.png", 35 | "scale" : "2x" 36 | }, 37 | { 38 | "size" : "40x40", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-40.0@3x.png", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "size" : "57x57", 45 | "idiom" : "iphone", 46 | "filename" : "Icon-57.0@1x.png", 47 | "scale" : "1x" 48 | }, 49 | { 50 | "size" : "57x57", 51 | "idiom" : "iphone", 52 | "filename" : "Icon-57.0@2x.png", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "size" : "60x60", 57 | "idiom" : "iphone", 58 | "filename" : "Icon-60.0@2x.png", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "size" : "60x60", 63 | "idiom" : "iphone", 64 | "filename" : "Icon-60.0@3x.png", 65 | "scale" : "3x" 66 | }, 67 | { 68 | "idiom" : "ipad", 69 | "size" : "20x20", 70 | "scale" : "1x" 71 | }, 72 | { 73 | "idiom" : "ipad", 74 | "size" : "20x20", 75 | "scale" : "2x" 76 | }, 77 | { 78 | "size" : "29x29", 79 | "idiom" : "ipad", 80 | "filename" : "Icon-29.0@1x.png", 81 | "scale" : "1x" 82 | }, 83 | { 84 | "size" : "29x29", 85 | "idiom" : "ipad", 86 | "filename" : "Icon-29.0@2x.png", 87 | "scale" : "2x" 88 | }, 89 | { 90 | "size" : "40x40", 91 | "idiom" : "ipad", 92 | "filename" : "Icon-40.0@1x.png", 93 | "scale" : "1x" 94 | }, 95 | { 96 | "size" : "40x40", 97 | "idiom" : "ipad", 98 | "filename" : "Icon-40.0@2x.png", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "size" : "50x50", 103 | "idiom" : "ipad", 104 | "filename" : "Icon-50.0@1x.png", 105 | "scale" : "1x" 106 | }, 107 | { 108 | "size" : "50x50", 109 | "idiom" : "ipad", 110 | "filename" : "Icon-50.0@2x.png", 111 | "scale" : "2x" 112 | }, 113 | { 114 | "size" : "72x72", 115 | "idiom" : "ipad", 116 | "filename" : "Icon-72.0@1x.png", 117 | "scale" : "1x" 118 | }, 119 | { 120 | "size" : "72x72", 121 | "idiom" : "ipad", 122 | "filename" : "Icon-72.0@2x.png", 123 | "scale" : "2x" 124 | }, 125 | { 126 | "size" : "76x76", 127 | "idiom" : "ipad", 128 | "filename" : "Icon-76.0@1x.png", 129 | "scale" : "1x" 130 | }, 131 | { 132 | "size" : "76x76", 133 | "idiom" : "ipad", 134 | "filename" : "Icon-76.0@2x.png", 135 | "scale" : "2x" 136 | }, 137 | { 138 | "size" : "83.5x83.5", 139 | "idiom" : "ipad", 140 | "filename" : "Icon-83.5@2x.png", 141 | "scale" : "2x" 142 | } 143 | ], 144 | "info" : { 145 | "version" : 1, 146 | "author" : "xcode" 147 | } 148 | } -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-29.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-29.0@1x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-29.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-29.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-29.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-29.0@3x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-40.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-40.0@1x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-40.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-40.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-40.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-40.0@3x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-50.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-50.0@1x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-50.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-50.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-57.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-57.0@1x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-57.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-57.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-60.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-60.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-60.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-60.0@3x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-72.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-72.0@1x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-72.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-72.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-76.0@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-76.0@1x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-76.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-76.0@2x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/Demo/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png -------------------------------------------------------------------------------- /Demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | zh_CN 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | 25 | NSPhotoLibraryUsageDescription 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Demo/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Demo 4 | // 5 | // Created by 王崇磊 on 2017/1/10. 6 | // Copyright © 2017年 王崇磊. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import WCLImagePickerController 11 | 12 | class ViewController: UIViewController, WCLImagePikcerDelegate { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | // Do any additional setup after loading the view, typically from a nib. 17 | } 18 | 19 | @IBAction func buttonAction(_ sender: Any) { 20 | /// 初始化,直接present出WCLImagePickerController 21 | WCLImagePickerController.present(inVC: self, delegate: self) 22 | /// 或者只初始化WCLImagePickerController.init 23 | /// WCLImagePickerController.init(delegate: self) 24 | } 25 | 26 | func wclImagePickerCancel(_ picker: WCLImagePickerController) { 27 | picker.dismiss(animated: true, completion: nil) 28 | } 29 | 30 | func wclImagePickerComplete(_ picker: WCLImagePickerController, imageArr: [UIImage]) { 31 | picker.dismiss(animated: true, completion: nil) 32 | print(imageArr) 33 | } 34 | 35 | func wclImagePickerError(_ picker: WCLImagePickerController, error: WCLError) { 36 | let al = UIAlertController.init(title: nil, message: error.lcalizable, preferredStyle: .alert) 37 | let cancel = UIAlertAction.init(title: "取消", style: .cancel, handler: nil) 38 | al.addAction(cancel) 39 | picker.present(al, animated: true, completion: nil) 40 | } 41 | 42 | @IBAction func lineChange(_ sender: UISegmentedControl) { 43 | let line = sender.selectedSegmentIndex + 3 44 | WCLImagePickerOptions.photoLineNum = line 45 | } 46 | 47 | 48 | @IBAction func tintColorChange(_ sender: UISegmentedControl) { 49 | let color = [UIColor(red: 49/255, green: 47/255, blue: 47/255, alpha: 1), UIColor.blue, UIColor.yellow][sender.selectedSegmentIndex] 50 | WCLImagePickerOptions.tintColor = color 51 | } 52 | 53 | 54 | @IBAction func hideBottom(_ sender: UISegmentedControl) { 55 | let need = sender.selectedSegmentIndex == 0 ? true : false 56 | WCLImagePickerOptions.isShowSelecView = need 57 | } 58 | 59 | @IBAction func statsBarChange(_ sender: UISegmentedControl) { 60 | if sender.selectedSegmentIndex == 0 { 61 | WCLImagePickerOptions.statusBarStyle = .lightContent 62 | }else { 63 | WCLImagePickerOptions.statusBarStyle = .default 64 | } 65 | } 66 | 67 | @IBAction func maxSelectNum(_ sender: UISegmentedControl) { 68 | let max = [3, 4, 5][sender.selectedSegmentIndex] 69 | WCLImagePickerOptions.maxPhotoSelectNum = max 70 | } 71 | 72 | @IBAction func needCamare(_ sender: UISegmentedControl) { 73 | let need = sender.selectedSegmentIndex == 0 ? true : false 74 | WCLImagePickerOptions.needPickerCamera = need 75 | } 76 | 77 | 78 | override func didReceiveMemoryWarning() { 79 | super.didReceiveMemoryWarning() 80 | // Dispose of any resources that can be recreated. 81 | } 82 | 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | WCLImagePickerController license 3 | ========================= 4 | 5 | The MIT License (MIT) 6 | 7 | Copyright (c) 2017 W_C__L 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # WCLImagePickerController 4 | 5 | ![](https://img.shields.io/badge/Swift-3.0-blue.svg?style=flat) 6 | [![Version](https://img.shields.io/cocoapods/v/WCLImagePickerController.svg?style=flat)](http://cocoapods.org/pods/WCLImagePickerController) 7 | [![Platform](https://img.shields.io/cocoapods/p/WCLImagePickerController.svg?style=flat)](http://cocoapods.org/pods/WCLImagePickerController) 8 | [![License](https://img.shields.io/cocoapods/l/WCLImagePickerController.svg?style=flat)](http://cocoapods.org/pods/WCLImagePickerController) 9 | 10 | `WCLImagePickerController`是一个自定义的图片选择器 11 | 12 | ![wcl.gif](wcl.gif) 13 | 14 | # Demo 15 | 16 | 可以通过[Appetize.io](https://appetize.io/app/hue1a1gmunhh46dtcxuj8ycfd4?device=iphone5s&scale=75&orientation=portrait&osVersion=9.3)运行我的Demo,非常方便~ 17 | 18 | # **Features** 19 | 20 | - [x] 支持多选图片 21 | - [x] 支持图片预览 22 | - [x] 可以高度自定义界面,包括颜色和其他功能 23 | - [x] 支持拍照功能 24 | - [x] 支持本地化(中、英) 25 | 26 | # 安装 27 | 28 | 必须iOS 8.0+ Swift3 29 | 30 | ## CocoaPods 31 | 32 | 如果没有安装你可以用下面的命令安装[CocoaPods](http://cocoapods.org): 33 | 34 | ```shell 35 | $ gem install cocoapods 36 | ``` 37 | 38 | 使用CocoaPods将`WCLImagePickerController`添加到您的`Xcode`项目,在`Podfile`中添加一下代码: 39 | 40 | ```ruby 41 | source 'https://github.com/CocoaPods/Specs.git' 42 | platform :ios, '8.0' 43 | use_frameworks! 44 | 45 | pod 'WCLImagePickerController' 46 | ``` 47 | 48 | 然后,运行以下命令: 49 | 50 | ```shell 51 | $ pod install 52 | ``` 53 | 54 | # 使用 55 | 56 | 首先因为权限问题需要加入照片权限和摄像头的权限: 57 | 58 | 在项目的`info.plist`添加一下字段 59 | 60 | `NSPhotoLibraryUsageDescription`和`NSCameraUsageDescription` 61 | 62 | 可以下载项目查看demo: 63 | 64 | ```swift 65 | // 推出WCLImagePickerController 66 | WCLImagePickerController.present(inVC: self, delegate: self) 67 | 68 | // 实现代理 69 | func wclImagePickerCancel(_ picker: WCLImagePickerController) { 70 | picker.dismiss(animated: true, completion: nil) 71 | } 72 | 73 | func wclImagePickerComplete(_ picker: WCLImagePickerController, imageArr: [UIImage]) { 74 | picker.dismiss(animated: true, completion: nil) 75 | } 76 | 77 | func wclImagePickerError(_ picker: WCLImagePickerController, error: WCLError) { 78 | let al = UIAlertController.init(title: nil, message: error.lcalizable, preferredStyle: .alert) 79 | let cancel = UIAlertAction.init(title: WCLImagePickerBundle.localizedString(key: "取消"), style: .cancel, handler: nil) 80 | al.addAction(cancel) 81 | self.vc?.present(al, animated: true, completion: nil) 82 | } 83 | ``` 84 | 85 | # 自定义 86 | 87 | 以下属性都是可以自定义的,下面是一下默认的配置 88 | 89 | ```swift 90 | public struct WCLImagePickerOptions { 91 | //字体设置,默认苹方字体 92 | static var fontLightName: String = "PingFangSC-Light" 93 | static var fontRegularName: String = "PingFangSC-Regular" 94 | static var fontMediumName: String = "PingFangSC-Medium" 95 | 96 | //MARK: 图片选择器的选项 97 | //是否需要拍照功能 98 | static var needPickerCamera: Bool = true 99 | //相册页每行的照片数,默认每行3张 100 | static var photoLineNum: Int = 3 101 | //相册选择页照片的间隔,默认3,最小为2 102 | static var photoInterval: Int = 3 103 | //相册选择器最大选择的照片数 104 | static var maxPhotoSelectNum: Int = 9 105 | //是否显示selectView 106 | static var isShowSelecView: Bool = true 107 | 108 | //MARK: launchImage的配置 109 | //相册启动图片和启动颜色,二选一,launchImage优先级高 110 | static var launchImage: UIImage? = nil 111 | //没有设置默认用imageTintColor 112 | static var launchColor: UIColor? = nil 113 | 114 | //MARK: 状态栏的样式 115 | static var statusBarStyle: UIStatusBarStyle = .lightContent 116 | 117 | //MARK: 图片的配置 118 | static var imageBuffer: UIImage? = WCLImagePickerBundle.imageFromBundle("image_buffer") 119 | static var ablumSelectBackGround: UIImage? = WCLImagePickerBundle.imageFromBundle("image_ablumSelectBackGround") 120 | static var cameraImage: UIImage? = WCLImagePickerBundle.imageFromBundle("image_camera") 121 | static var pickerArrow: UIImage? = WCLImagePickerBundle.imageFromBundle("image_pickerArrow") 122 | static var pickerDefault: UIImage? = WCLImagePickerBundle.imageFromBundle("image_pickerDefault") 123 | static var selectPlaceholder: UIImage? = WCLImagePickerBundle.imageFromBundle("image_selectPlaceholder") 124 | 125 | //MARK: 颜色的配置 126 | static var tintColor: UIColor = UIColor(red: 49/255, green: 47/255, blue: 47/255, alpha: 1) 127 | //没有设置默认用imageTintColor 128 | static var pickerSelectColor: UIColor? = UIColor(red: 255/255, green: 0/255, blue: 27/255, alpha: 1) 129 | //没有设置默认用imageTintColor 130 | static var selectViewBackColor: UIColor? = nil 131 | } 132 | ``` 133 | 134 | # blog 135 | 136 | [photos框架的相关介绍](http://blog.csdn.net/wang631106979/article/details/54343860) 137 | 138 | -------------------------------------------------------------------------------- /WCLImagePickerController.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint WCLImagePickerController.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | s.name = "WCLImagePickerController" 12 | s.version = "1.0.5" 13 | s.summary = "由swift实现可自定义的图片选择器。" 14 | 15 | s.homepage = "https://github.com/631106979/WCLImagePickerController" 16 | s.license = 'MIT' 17 | s.author = { "W_C__L" => "wangchonglei93@icloud.com" } 18 | s.platform = :ios, "8.0" 19 | s.source = { :git => "https://github.com/631106979/WCLImagePickerController.git", :tag => "1.0.5" } 20 | s.source_files = 'WCLImagePickerController/**/*.{swift,xib}' 21 | s.resources = 'WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle' 22 | s.frameworks = "UIKit", "Photos" 23 | s.requires_arc = true 24 | 25 | end 26 | -------------------------------------------------------------------------------- /WCLImagePickerController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WCLImagePickerController.xcodeproj/xcuserdata/wangchonglei.xcuserdatad/xcschemes/Demo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /WCLImagePickerController.xcodeproj/xcuserdata/wangchonglei.xcuserdatad/xcschemes/WCLImagePickerController.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /WCLImagePickerController.xcodeproj/xcuserdata/wangchonglei.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Demo.xcscheme 8 | 9 | orderHint 10 | 1 11 | 12 | WCLImagePickerController.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | 9717A1B11E2517C90075D33E 21 | 22 | primary 23 | 24 | 25 | 9717A1C01E2518360075D33E 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /WCLImagePickerController/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/WCLAblumListCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLAblumListCell.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLAblumListCell 22 | // @abstract 相册列表的TableViewCell 23 | // @discussion 相册列表的TableViewCell 24 | 25 | import UIKit 26 | 27 | class WCLAblumListCell: UITableViewCell, 28 | WCLCellIdentfier { 29 | 30 | @IBOutlet weak var ablumNameLabel: UILabel! 31 | @IBOutlet weak var ablumImageView: UIImageView! 32 | @IBOutlet weak var selectImageView: UIImageView! 33 | //MARK: Public Methods 34 | 35 | 36 | //MARK: Override 37 | override func awakeFromNib() { 38 | super.awakeFromNib() 39 | // Initialization code 40 | ablumImageView.image = WCLImagePickerOptions.imageBuffer 41 | selectImageView.highlightedImage = WCLImagePickerOptions.ablumSelectBackGround 42 | } 43 | 44 | override func setSelected(_ selected: Bool, animated: Bool) { 45 | super.setSelected(selected, animated: animated) 46 | 47 | // Configure the view for the selected state 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/WCLAblumListCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/photoBrowserCells/WCLPhotoCVCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPhotoCVCell.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPhotoCVCell 22 | // @abstract 图片浏览器的CollectionViewCell 23 | // @discussion 图片浏览器的CollectionViewCell 24 | 25 | import UIKit 26 | 27 | class WCLPhotoCVCell: UICollectionViewCell, 28 | WCLCellIdentfier, 29 | UIScrollViewDelegate { 30 | 31 | @IBOutlet weak var photoSrcollView: UIScrollView! 32 | @IBOutlet weak var photoImageView: UIImageView! 33 | @IBOutlet weak var imageWidth: NSLayoutConstraint! 34 | @IBOutlet weak var imageHeight: NSLayoutConstraint! 35 | @IBOutlet weak var imageTop: NSLayoutConstraint! 36 | @IBOutlet weak var imageRight: NSLayoutConstraint! 37 | @IBOutlet weak var imageBottom: NSLayoutConstraint! 38 | @IBOutlet weak var imageLeft: NSLayoutConstraint! 39 | 40 | deinit { 41 | NotificationCenter.default.removeObserver(self) 42 | } 43 | 44 | override func awakeFromNib() { 45 | NotificationCenter.default.addObserver(self, selector: #selector(zoomChage), name: WCLImagePickerNotify.selectPickerZoom, object: nil) 46 | } 47 | 48 | @objc private func zoomChage() { 49 | photoSrcollView.zoomScale = 1.0 50 | } 51 | 52 | //MARK: UIScrollViewDelegate 53 | func viewForZooming(in scrollView: UIScrollView) -> UIView? { 54 | return photoImageView 55 | } 56 | 57 | func scrollViewDidZoom(_ scrollView: UIScrollView) { 58 | var c = (scrollView.frame.height - photoImageView.frame.height) / 2 59 | if c <= 0 {c = 0} 60 | imageTop.constant = c 61 | imageBottom.constant = c 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/photoBrowserCells/WCLPhotoCVCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/photoBrowserCells/WCLPhotoCellContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPhotoCellContext.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPhotoCellContext 22 | // @abstract PhotoBrowserCell的context 23 | // @discussion PhotoBrowserCell的context 24 | // 25 | 26 | import UIKit 27 | import Photos 28 | 29 | class WCLPhotoCellContext: NSObject { 30 | 31 | private var pickerManager: WCLPickerManager 32 | 33 | init(pickerManager: WCLPickerManager) { 34 | self.pickerManager = pickerManager 35 | super.init() 36 | } 37 | 38 | //MARK: Public Methods 39 | func register(collectionView: UICollectionView) { 40 | collectionView.register(UINib.init(nibName: WCLPhotoCVCell.identfier , bundle: WCLImagePickerBundle.bundle), forCellWithReuseIdentifier: WCLPhotoCVCell.identfier) 41 | } 42 | 43 | func getCell(asset: PHAsset, collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell { 44 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WCLPhotoCVCell.identfier, for: indexPath) as! WCLPhotoCVCell 45 | let size = CGSize(width: collectionView.frame.width, height: collectionView.frame.height) 46 | pickerManager.getPhoto(size, alasset: asset) { (image, info) in 47 | if let image = image { 48 | let size = image.size 49 | let scale = CGFloat(size.width/size.height) 50 | let deviceScale = cell.photoSrcollView.bounds.width/cell.photoSrcollView.bounds.height 51 | if scale >= deviceScale { 52 | cell.imageWidth.constant = cell.photoSrcollView.bounds.width 53 | cell.imageHeight.constant = cell.imageWidth.constant/scale 54 | let interval = cell.photoSrcollView.bounds.height - cell.imageHeight.constant 55 | cell.imageBottom.constant = interval/2 56 | cell.imageTop.constant = interval/2 57 | cell.imageRight.constant = 0 58 | cell.imageLeft.constant = 0 59 | }else { 60 | cell.imageHeight.constant = cell.photoSrcollView.bounds.height 61 | cell.imageWidth.constant = cell.imageHeight.constant*scale 62 | let interval = cell.photoSrcollView.bounds.width - cell.imageWidth.constant 63 | cell.imageRight.constant = interval/2 64 | cell.imageLeft.constant = interval/2 65 | cell.imageTop.constant = 0 66 | cell.imageBottom.constant = 0 67 | } 68 | } 69 | cell.photoImageView.image = image 70 | } 71 | return cell 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLCameraCVCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLCameraCVCell.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLCameraCVCell 22 | // @abstract 图片选择器的摄像的CollectionViewCell 23 | // @discussion 图片选择器的摄像的CollectionViewCell 24 | 25 | import UIKit 26 | 27 | class WCLCameraCVCell: UICollectionViewCell, 28 | WCLCellIdentfier { 29 | 30 | @IBOutlet weak var imageCameraView: UIImageView! 31 | 32 | //MARK: Override 33 | override func awakeFromNib() { 34 | super.awakeFromNib() 35 | // Initialization code 36 | imageCameraView.image = WCLImagePickerOptions.cameraImage 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLCameraCVCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLPickerCVCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPickerCVCell.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPickerCVCell 22 | // @abstract 图片选择器的CollectionViewCell 23 | // @discussion 图片选择器的CollectionViewCell 24 | 25 | import UIKit 26 | 27 | class WCLPickerCVCell: UICollectionViewCell, 28 | WCLCellIdentfier { 29 | 30 | @IBOutlet weak var selectNumBt: UIButton! 31 | @IBOutlet weak var photoImageView: UIImageView! 32 | var selectBlock:(()->Void)? 33 | 34 | //MARK: - Override 35 | override func awakeFromNib() { 36 | super.awakeFromNib() 37 | // Initialization code 38 | selectNumBt.setBackgroundImage(WCLImagePickerOptions.pickerDefault, for: .normal) 39 | 40 | let size = WCLImagePickerOptions.pickerDefault?.size ?? CGSize.zero 41 | UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) 42 | let context = UIGraphicsGetCurrentContext() 43 | if let color = WCLImagePickerOptions.pickerSelectColor { 44 | color.setFill() 45 | }else { 46 | WCLImagePickerOptions.tintColor.setFill() 47 | } 48 | context?.addArc(center: CGPoint.init(x: size.width / 2, y: size.height / 2), radius: size.width / 2, startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: true) 49 | context?.fillPath() 50 | let selectImage = UIGraphicsGetImageFromCurrentImageContext() 51 | UIGraphicsEndImageContext() 52 | selectNumBt.setBackgroundImage(selectImage, for: .selected) 53 | } 54 | 55 | //MARK: - Public Methods 56 | @discardableResult 57 | func animation() -> WCLPickerCVCell { 58 | let animation = CAKeyframeAnimation.init(keyPath: "transform.scale") 59 | animation.duration = 0.35 60 | animation.calculationMode = kCAAnimationCubic 61 | animation.values = [1.0 ,1.4, 0.9, 1.15, 0.95, 1.02, 1.0] 62 | self.selectNumBt.layer.add(animation, forKey: "scaleAnimation") 63 | return self 64 | } 65 | 66 | //MARK: - Target Methods 67 | @IBAction func selectAction(_ sender: UIButton) { 68 | if selectBlock != nil { 69 | selectBlock!() 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLPickerCVCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 36 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLPickerCellContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPickerCellContext.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPickerCellContext 22 | // @abstract 图片选择器cell的Context 23 | // @discussion 图片选择器cell的Context 24 | // 25 | 26 | import UIKit 27 | import Photos 28 | 29 | class WCLPickerCellContext: NSObject { 30 | 31 | private var pickerManager: WCLPickerManager 32 | 33 | //MARK: Initial Methods 34 | init(pickerManager: WCLPickerManager) { 35 | self.pickerManager = pickerManager 36 | super.init() 37 | } 38 | 39 | //MARK: Public Methods 40 | func register(collectionView: UICollectionView) { 41 | collectionView.register(UINib.init(nibName: WCLCameraCVCell.identfier , bundle: WCLImagePickerBundle.bundle), forCellWithReuseIdentifier: WCLCameraCVCell.identfier) 42 | collectionView.register(UINib.init(nibName: WCLPickerCVCell.identfier, bundle: WCLImagePickerBundle.bundle), forCellWithReuseIdentifier: WCLPickerCVCell.identfier) 43 | } 44 | 45 | func getPikcerCellNumber(ablumIndex: Int) -> Int { 46 | var count = pickerManager.getAblumCount(ablumIndex) 47 | if WCLImagePickerOptions.needPickerCamera { 48 | count = count + 1 49 | } 50 | return count 51 | } 52 | 53 | func getPickerCell(_ collectionView: UICollectionView, ablumIndex: Int, photoIndex: Int) -> UICollectionViewCell { 54 | if WCLImagePickerOptions.needPickerCamera && photoIndex == 0 { 55 | return getCameraCell(collectionView, ablumIndex: ablumIndex, cellForItemAtIndexPath: IndexPath(item: photoIndex, section: 0)) 56 | }else { 57 | return getPhotoCell(collectionView, ablumIndex: ablumIndex, cellForItemAtIndexPath: IndexPath(item: photoIndex, section: 0)) 58 | } 59 | } 60 | 61 | //MARK: Private Methods 62 | /** 63 | 返回WCLCameraCVCell,拍照的cell 64 | */ 65 | private func getCameraCell(_ collectionView: UICollectionView, ablumIndex: Int, cellForItemAtIndexPath indexPath: IndexPath) -> UICollectionViewCell { 66 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WCLCameraCVCell.identfier, for: indexPath) 67 | return cell 68 | } 69 | 70 | /** 71 | 返回WCLPickerCVCell,照片的cell 72 | */ 73 | private func getPhotoCell(_ collectionView: UICollectionView, ablumIndex: Int, cellForItemAtIndexPath indexPath: IndexPath) -> UICollectionViewCell { 74 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WCLPickerCVCell.identfier, for: indexPath) as! WCLPickerCVCell 75 | //加载图片 76 | var photoIndexPath = indexPath.row 77 | if WCLImagePickerOptions.needPickerCamera == true { 78 | photoIndexPath = photoIndexPath - 1 79 | } 80 | weak var weakCell = cell 81 | if let photoAsset = pickerManager.getPHAsset(ablumIndex, photoIndex: photoIndexPath) { 82 | pickerManager.getPhotoDefalutSize(ablumIndex, photoIndex: photoIndexPath, resultHandler: { (image, infoDic) in 83 | weakCell?.photoImageView.image = image 84 | }) 85 | //改变状态 86 | if let photoIndex = pickerManager.index(ofSelect: photoAsset) { 87 | weakCell?.selectNumBt.isSelected = true 88 | cell.selectNumBt.setTitle("\(photoIndex+1)", for: .selected) 89 | }else { 90 | weakCell?.selectNumBt.isSelected = false 91 | cell.selectNumBt.setTitle("", for: .normal) 92 | } 93 | setPickerSelectBlock(cell: cell, photoAsset: photoAsset, ablumIndex: ablumIndex, photoIndex: photoIndexPath) 94 | } 95 | return cell 96 | } 97 | 98 | private func setPickerSelectBlock(cell: WCLPickerCVCell, photoAsset: PHAsset, ablumIndex: Int, photoIndex: Int) { 99 | weak var weakCell = cell 100 | //判断selectCV是需要加入还是删除 101 | cell.selectBlock = { [weak self] () in 102 | let selectCount = self?.pickerManager.selectPhotoArr.count ?? 0 103 | if self?.pickerManager.isContains(formSelect: photoAsset) ?? false { 104 | let photoIndex = self?.pickerManager.index(ofSelect: photoAsset) ?? 0 105 | let index = photoIndex 106 | self?.pickerManager.remove(formSelect: photoAsset) 107 | NotificationCenter.default.post(name: WCLImagePickerNotify.deleteSelectCell, object: IndexPath.init(item: index, section: 0)) 108 | NotificationCenter.default.post(name: WCLImagePickerNotify.reloadImagePicker, object: nil) 109 | }else { 110 | if selectCount >= WCLImagePickerOptions.maxPhotoSelectNum { 111 | guard self != nil else { 112 | return 113 | } 114 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noMoreThanImages) 115 | return 116 | }else { 117 | //添加selectCV的cell 118 | self?.pickerManager.append(toSelect: photoAsset) 119 | let selectCount = self?.pickerManager.selectPhotoArr.count ?? 0 120 | weakCell?.selectNumBt.isSelected = true 121 | weakCell?.selectNumBt.setTitle("\(selectCount)", for: .selected) 122 | weakCell?.animation() 123 | NotificationCenter.default.post(name: WCLImagePickerNotify.insertSelectCell, object: IndexPath.init(item: selectCount - 1, section: 0)) 124 | } 125 | } 126 | NotificationCenter.default.post(name: WCLImagePickerNotify.reloadSelectTotalNum, object: nil) 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLSelecteCVCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLSelecteCVCell.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLSelecteCVCell 22 | // @abstract WCLSelecteView的cell 23 | // @discussion WCLSelecteView的cell 24 | // 25 | 26 | import UIKit 27 | 28 | class WCLSelecteCVCell: UICollectionViewCell, 29 | WCLCellIdentfier { 30 | 31 | @IBOutlet weak var selectImageView: UIImageView! 32 | 33 | } 34 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Cells/pickerCells/WCLSelecteCVCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLBaseImagePickerController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLImagePickerController.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLImagePickerController 22 | // @abstract WCLBaseImagePickerController 23 | // @discussion WCLBaseImagePickerController 24 | // 25 | 26 | import UIKit 27 | 28 | internal class WCLBaseImagePickerController: UIImagePickerController { 29 | 30 | override var preferredStatusBarStyle: UIStatusBarStyle { 31 | return WCLImagePickerOptions.statusBarStyle 32 | } 33 | 34 | //MARK: Override 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | // Do any additional setup after loading the view. 38 | } 39 | 40 | override func didReceiveMemoryWarning() { 41 | super.didReceiveMemoryWarning() 42 | // Dispose of any resources that can be recreated. 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLError.swift 3 | // WclImagePickerController 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLError 22 | // @abstract 错误提示 23 | // @discussion 错误提示 24 | // 25 | 26 | import UIKit 27 | 28 | public enum WCLError { 29 | /// 没有相册访问权限 30 | case noAlbumPermissions 31 | /// 没有摄像头访问权限 32 | case noCameraPermissions 33 | /// 超过选择最大数 34 | case noMoreThanImages 35 | public var lcalizable: String? { 36 | if self == .noAlbumPermissions { 37 | return WCLImagePickerBundle.localizedString(key: "没有相册访问权限") 38 | } 39 | if self == .noCameraPermissions { 40 | return WCLImagePickerBundle.localizedString(key: "没有摄像头访问权限") 41 | } 42 | if self == .noMoreThanImages { 43 | return String(format: WCLImagePickerBundle.localizedString(key: "最多选择%d张照片") , WCLImagePickerOptions.maxPhotoSelectNum) 44 | } 45 | return nil 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLImagePickerBundle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLImagePickerBundle.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLImagePickerBundle 22 | // @abstract WCLImagePickerBundle 23 | // @discussion WCLImagePickerBundle 24 | // 25 | 26 | import UIKit 27 | 28 | internal struct WCLImagePickerBundle { 29 | 30 | // 当前的bundle 31 | static var bundle: Bundle { 32 | let bundle = Bundle(for: WCLImagePickerController.self) 33 | return bundle 34 | } 35 | 36 | // 存放资源的bundle 37 | static var wclBundle: Bundle { 38 | let bundle = Bundle(path: self.bundle.path(forResource: "WCLImagePickerController", ofType: "bundle")!) 39 | return bundle! 40 | } 41 | 42 | static func imageFromBundle(_ imageName: String) -> UIImage? { 43 | var imageName = imageName 44 | if UIScreen.main.scale == 2 { 45 | imageName = imageName + "@2x" 46 | }else if UIScreen.main.scale == 3 { 47 | imageName = imageName + "@3x" 48 | } 49 | let bundle = Bundle(path: wclBundle.bundlePath + "/Images") 50 | if let path = bundle?.path(forResource: imageName, ofType: "png") { 51 | let image = UIImage(contentsOfFile: path) 52 | return image 53 | } 54 | return nil 55 | } 56 | 57 | static func localizedString(key: String) -> String { 58 | if let current = Locale.current.languageCode { 59 | var language = "" 60 | switch current { 61 | case "zh": 62 | language = "zh" 63 | default: 64 | language = "en" 65 | } 66 | if let path = wclBundle.path(forResource: language, ofType: "lproj") { 67 | if let bundle = Bundle(path: path) { 68 | let value = bundle.localizedString(forKey: key, value: nil, table: nil) 69 | return Bundle.main.localizedString(forKey: key, value: value, table: nil) 70 | } 71 | } 72 | } 73 | return key 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLImagePickerNotify.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLImagePickerNotify.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLImagePickerNotify 22 | // @abstract WCLImagePicker的通知类 23 | // @discussion WCLImagePicker的通知类 24 | // 25 | 26 | import Foundation 27 | 28 | internal struct WCLImagePickerNotify { 29 | // 刷新imagePicker 30 | static let reloadImagePicker = Notification.Name("WCLReloadImagePickerNotify") 31 | 32 | // 刷新imagePicker的selectView 33 | static let reloadSelect = Notification.Name("WCLReloadSelectPickerNotify") 34 | // 删除imagePicker的selectView的cell 35 | static let deleteSelectCell = Notification.Name("WCLDeleteSelectPickerCellNotofy") 36 | // 插入imagePicker的selectView的cell 37 | static let insertSelectCell = Notification.Name("WCLInsertSelectPickerCellNotofy") 38 | 39 | // 刷新imagePicker的selectView的TotalNum 40 | static let reloadSelectTotalNum = Notification.Name("WCLReloadSelectTotalNumNotofy") 41 | 42 | // imagePicker的error通知 43 | static let imagePickerError = Notification.Name("WCLImagePickerErrorNotify") 44 | 45 | // selectPicker的zoom通知 46 | static let selectPickerZoom = Notification.Name("WCLSelectPickerZoom") 47 | } 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLImagePickerOptions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLImagePickerOptions.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLImagePickerOptions 22 | // @abstract WCLImagePicker的选项类 23 | // @discussion WCLImagePicker的选项类 24 | // 25 | 26 | import UIKit 27 | 28 | public struct WCLImagePickerOptions { 29 | 30 | /// 字体设置,默认苹方字体 31 | public static var fontLightName: String = "PingFangSC-Light" 32 | public static var fontRegularName: String = "PingFangSC-Regular" 33 | public static var fontMediumName: String = "PingFangSC-Medium" 34 | 35 | /// 是否需要拍照功能 36 | public static var needPickerCamera: Bool = true 37 | /// 相册页每行的照片数,默认每行3张 38 | public static var photoLineNum: Int = 3 39 | /// 相册选择页照片的间隔,默认3,最小为2 40 | public static var photoInterval: Int = 3 41 | /// 相册选择器最大选择的照片数 42 | public static var maxPhotoSelectNum: Int = 9 43 | /// 是否显示selectView 44 | public static var isShowSelecView: Bool = true 45 | 46 | /// launchImage的配置 47 | /// 相册启动图片和启动颜色,二选一,launchImage优先级高 48 | public static var launchImage: UIImage? = nil 49 | /// 没有设置默认用imageTintColor 50 | public static var launchColor: UIColor? = nil 51 | 52 | /// 状态栏的样式 53 | public static var statusBarStyle: UIStatusBarStyle = .lightContent 54 | 55 | /// 图片的配置 56 | public static var imageBuffer: UIImage? = WCLImagePickerBundle.imageFromBundle("image_buffer") 57 | public static var ablumSelectBackGround: UIImage? = WCLImagePickerBundle.imageFromBundle("image_ablumSelectBackGround") 58 | public static var cameraImage: UIImage? = WCLImagePickerBundle.imageFromBundle("image_camera") 59 | public static var pickerArrow: UIImage? = WCLImagePickerBundle.imageFromBundle("image_pickerArrow") 60 | public static var pickerDefault: UIImage? = WCLImagePickerBundle.imageFromBundle("image_pickerDefault") 61 | public static var selectPlaceholder: UIImage? = WCLImagePickerBundle.imageFromBundle("image_selectPlaceholder") 62 | 63 | /// 颜色的配置 64 | public static var tintColor: UIColor = UIColor(red: 49/255, green: 47/255, blue: 47/255, alpha: 1) 65 | /// 没有设置默认用imageTintColor 66 | public static var pickerSelectColor: UIColor? = UIColor(red: 255/255, green: 0/255, blue: 27/255, alpha: 1) 67 | /// 没有设置默认用imageTintColor 68 | public static var selectViewBackColor: UIColor? = nil 69 | } 70 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLImagePikcerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLImagePikcerDelegate.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLImagePikcerDelegate 22 | // @abstract WCLImagePikcerVC的Delegate 23 | // @discussion WCLImagePikcerVC的Delegate 24 | // 25 | 26 | import UIKit 27 | 28 | public protocol WCLImagePikcerDelegate: class { 29 | /// 点击取消按钮的回调方法 30 | func wclImagePickerCancel(_ picker: WCLImagePickerController) -> Void 31 | /// 选择完成后的回调方法 32 | func wclImagePickerComplete(_ picker: WCLImagePickerController, imageArr: [UIImage]) -> Void 33 | /// 反馈错误信息的回调方法 34 | func wclImagePickerError(_ picker: WCLImagePickerController, error: WCLError) -> Void 35 | } 36 | 37 | extension WCLImagePikcerDelegate { 38 | public func wclImagePickerCancel(_ picker: WCLImagePickerController) -> Void {} 39 | public func wclImagePickerComplete(_ picker: WCLImagePickerController, imageArr: [UIImage]) -> Void {} 40 | public func wclImagePickerError(_ picker: WCLImagePickerController, error: WCLError) -> Void {} 41 | } 42 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLNavigationController.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLNavigationController 22 | // @abstract WCLNavigationController 23 | // @discussion WCLNavigationController 24 | // 25 | 26 | import UIKit 27 | 28 | public class WCLNavigationController: UINavigationController, 29 | UINavigationControllerDelegate { 30 | 31 | override public var preferredStatusBarStyle: UIStatusBarStyle { 32 | return WCLImagePickerOptions.statusBarStyle 33 | } 34 | 35 | //MARK: Public Methods 36 | 37 | 38 | //MARK: Override 39 | override public func viewDidLoad() { 40 | super.viewDidLoad() 41 | // Do any additional setup after loading the view. 42 | navigationBar.isTranslucent = false 43 | delegate = self 44 | modalPresentationCapturesStatusBarAppearance = true 45 | } 46 | 47 | override public func didReceiveMemoryWarning() { 48 | super.didReceiveMemoryWarning() 49 | // Dispose of any resources that can be recreated. 50 | } 51 | 52 | override public func pushViewController(_ viewController: UIViewController, animated: Bool) { 53 | if self.responds(to: #selector(getter: UINavigationController.interactivePopGestureRecognizer)) { 54 | self.interactivePopGestureRecognizer?.isEnabled = false 55 | } 56 | super.pushViewController(viewController, animated: animated) 57 | } 58 | 59 | //MARK: UINavigationControllerDelegate 60 | public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { 61 | if navigationController.responds(to: #selector(getter: UINavigationController.interactivePopGestureRecognizer)) { 62 | navigationController.interactivePopGestureRecognizer?.isEnabled = true 63 | } 64 | if navigationController.viewControllers.count == 1 { 65 | navigationController.interactivePopGestureRecognizer?.isEnabled = false 66 | navigationController.interactivePopGestureRecognizer?.delegate = nil 67 | } 68 | } 69 | 70 | 71 | //MARK: Initial Methods 72 | convenience init(rootViewController: UIViewController, navBarColor: UIColor) { 73 | self.init(rootViewController: rootViewController) 74 | setNavImage(bgColor: navBarColor, shadowColor: UIColor.clear) 75 | } 76 | 77 | //MARK: Setter Getter Methods 78 | 79 | 80 | //MARK: Privater Methods 81 | /** 82 | 设置navBar的颜色 83 | 84 | - parameter bgColor: 背景色 85 | - parameter shadowColor: 阴影色 86 | 87 | - returns: self 88 | */ 89 | func setNavImage(bgColor: UIColor, shadowColor: UIColor) { 90 | let width = UIScreen.main.bounds.width 91 | let scale = UIScreen.main.scale 92 | 93 | UIGraphicsBeginImageContextWithOptions(CGSize.init(width: width, height: 64), false, scale) 94 | var context = UIGraphicsGetCurrentContext()! 95 | CGContext.setFillColor(context)(bgColor.cgColor) 96 | CGContext.addRect(context)(CGRect.init(x: 0, y: 0, width: width, height: 64)) 97 | CGContext.drawPath(context)(using: .fill) 98 | let bgImage = UIGraphicsGetImageFromCurrentImageContext() 99 | 100 | UIGraphicsBeginImageContextWithOptions(CGSize.init(width: width, height: 1), false, scale) 101 | context = UIGraphicsGetCurrentContext()! 102 | CGContext.setLineWidth(context)(1) 103 | CGContext.setStrokeColor(context)(shadowColor.cgColor) 104 | CGContext.move(context)(to: CGPoint.zero) 105 | CGContext.addLine(context)(to: CGPoint.init(x: width, y: 0)) 106 | CGContext.drawPath(context)(using: .stroke) 107 | let shadowImage = UIGraphicsGetImageFromCurrentImageContext() 108 | 109 | self.navigationBar.setBackgroundImage(bgImage, for: .default) 110 | self.navigationBar.shadowImage = shadowImage 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Others/WCLPickerExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPickerExtension.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPickerExtension 22 | // @abstract WCLPicker的扩展 23 | // @discussion WCLPicker的扩展 24 | // 25 | 26 | import UIKit 27 | 28 | internal extension UIViewController { 29 | 30 | /** 31 | 添加nav右侧按钮 32 | */ 33 | @discardableResult 34 | func addWCLPhotoNavRightButton(_ btName:String) -> UIButton { 35 | let rightBt = UIButton() 36 | rightBt.contentHorizontalAlignment = .right 37 | rightBt.setTitle(btName, for: UIControlState()) 38 | rightBt.setTitleColor(UIColor.white, for: UIControlState()) 39 | rightBt.titleLabel?.font = UIFont.WCLRegularFontOfSize(15) 40 | rightBt.addTarget(self, action: #selector(photoRightAction(_:)), for: .touchUpInside) 41 | rightBt.frame.size = CGSize(width: 16*CGFloat(btName.characters.count), height: 20) 42 | navigationItem.rightBarButtonItem = UIBarButtonItem.init(customView: rightBt) 43 | return rightBt 44 | } 45 | 46 | /** 47 | 添加nav左侧按钮 48 | */ 49 | @discardableResult 50 | func addWCLPhotoNavLeftButton(_ btName:String) -> UIButton { 51 | let leftBt = UIButton() 52 | leftBt.contentHorizontalAlignment = .left 53 | leftBt.setTitle(btName, for: UIControlState()) 54 | leftBt.setTitleColor(UIColor.white, for: UIControlState()) 55 | leftBt.titleLabel?.font = UIFont.WCLRegularFontOfSize(15) 56 | leftBt.frame.size = CGSize(width: 16*CGFloat(btName.characters.count), height: 20) 57 | leftBt.addTarget(self, action: #selector(photoLeftAction(_:)), for: .touchUpInside) 58 | leftBt.sizeToFit() 59 | navigationItem.leftBarButtonItem = UIBarButtonItem.init(customView: leftBt) 60 | return leftBt 61 | } 62 | 63 | /** 64 | 添加nav的titleView 65 | */ 66 | @discardableResult 67 | func setWCLPhotoNavTitle(_ title:String) -> UILabel { 68 | let titleLable = UILabel() 69 | titleLable.text = title 70 | titleLable.textColor = UIColor.white 71 | titleLable.font = UIFont.WCLMediumFontOfSize(17) 72 | titleLable.sizeToFit() 73 | navigationItem.titleView = titleLable 74 | return titleLable 75 | } 76 | 77 | func photoLeftAction(_ sender: UIButton) { 78 | 79 | } 80 | 81 | func photoRightAction(_ sender: UIButton) { 82 | 83 | } 84 | } 85 | 86 | //MARK: 字体 87 | extension UIFont { 88 | /** 89 | 更具系统不同返回light字体 90 | */ 91 | class func WCLLightFontOfSize(_ fontSize:CGFloat) -> UIFont { 92 | return UIFont.init(name: WCLImagePickerOptions.fontLightName, size: fontSize) ?? UIFont.systemFont(ofSize: fontSize) 93 | } 94 | /** 95 | 更具系统不同返回Regular字体 96 | */ 97 | class func WCLRegularFontOfSize(_ fontSize:CGFloat) -> UIFont { 98 | return UIFont.init(name: WCLImagePickerOptions.fontRegularName, size: fontSize) ?? UIFont.systemFont(ofSize: fontSize) 99 | } 100 | /** 101 | 更具系统不同返回Medium字体 102 | */ 103 | class func WCLMediumFontOfSize(_ fontSize:CGFloat) -> UIFont { 104 | return UIFont.init(name: WCLImagePickerOptions.fontMediumName, size: fontSize) ?? UIFont.systemFont(ofSize: fontSize) 105 | } 106 | } 107 | 108 | //MARK: 数组的扩展 109 | extension Array { 110 | subscript (wcl_safe index: Int) -> Element? { 111 | return (0.. Bool { 116 | if (0..]]() 33 | private(set) var selectPhotoArr = [PHAsset]() 34 | 35 | //是否同步请求图片 36 | public var isSynchronous: Bool = false { 37 | didSet{ 38 | self.photoOption.isSynchronous = isSynchronous 39 | } 40 | } 41 | 42 | //pickerCell照片的size 43 | class public var pickerPhotoSize: CGSize { 44 | assert(WCLImagePickerOptions.photoLineNum > 2, "列数最小为2") 45 | let sreenBounds = UIScreen.main.bounds 46 | let screenWidth = sreenBounds.width > sreenBounds.height ? sreenBounds.height : sreenBounds.width 47 | let width = (screenWidth - CGFloat(WCLImagePickerOptions.photoInterval) * (CGFloat(WCLImagePickerOptions.photoLineNum) - 1)) / CGFloat(WCLImagePickerOptions.photoLineNum) 48 | return CGSize(width: width, height: width) 49 | } 50 | 51 | private var photoManage = PHCachingImageManager() 52 | private let photoOption = PHImageRequestOptions() 53 | private let photoCreationDate = "creationDate" 54 | 55 | //MARK: Override 56 | override init() { 57 | super.init() 58 | //图片请求设置成快速获取 59 | self.photoOption.resizeMode = .fast 60 | self.photoOption.deliveryMode = .opportunistic 61 | getPhotoAlbum() 62 | } 63 | 64 | //MARK: Public Methods 65 | /** 66 | 获取相册的title 67 | 68 | - parameter index: 相册的index 69 | 70 | - returns: 相册的title 71 | */ 72 | public func getAblumTitle(_ ablumIndex: Int) -> String { 73 | if let ablum = self.photoAlbums[wcl_safe: ablumIndex] { 74 | if let result = ablum.keys.first { 75 | return "\(result)(\(getAblumCount(ablumIndex)))" 76 | } 77 | } 78 | return "" 79 | } 80 | 81 | //MARK: photo数据的操作 82 | /** 83 | 通过下标返回相册中照片的个数 84 | 85 | - parameter index: 选择的index 86 | 87 | - returns: 相册中照片的个数 88 | */ 89 | public func getAblumCount(_ ablumIndex: Int) -> Int { 90 | if let ablum = self.photoAlbums[wcl_safe: ablumIndex] { 91 | if let result = ablum.values.first { 92 | return result.count 93 | } 94 | } 95 | return 0 96 | } 97 | 98 | /** 99 | 通过下标返回相册的PHFetchResult 100 | 101 | - parameter index: 选择相册的index 102 | 103 | - returns: 相册的PHFetchResult 104 | */ 105 | public func getAblumResult(_ ablumIndex: Int) -> PHFetchResult? { 106 | if let ablum = self.photoAlbums[wcl_safe: ablumIndex] { 107 | if let result = ablum.values.first { 108 | return result 109 | } 110 | } 111 | return nil 112 | } 113 | 114 | /** 115 | 根据index获取PHAsset 116 | 117 | - parameter ablumIndex: 相册的index 118 | - parameter photoIndex: 相册里图片的index 119 | 120 | - returns: PHAsset 121 | */ 122 | public func getPHAsset(_ ablumIndex: Int, photoIndex: Int) -> PHAsset? { 123 | let ablumResult = getAblumResult(ablumIndex) 124 | if ablumResult != nil { 125 | if ablumResult?.count != 0 { 126 | let photoAsset:PHAsset? = ablumResult![photoIndex] 127 | return photoAsset 128 | } 129 | } 130 | return nil 131 | } 132 | 133 | /** 134 | PHAsset是否已经在SelectPhotoArr里 135 | 136 | - parameter alasset: PHAsset对象 137 | 138 | - returns: 返回值 139 | */ 140 | public func isContains(formSelect alasset: PHAsset) -> Bool { 141 | return selectPhotoArr.contains(alasset) 142 | } 143 | 144 | /** 145 | PHAsset在SelectPhotoArr的index 146 | 147 | - parameter alasset: PHAsset对象 148 | 149 | - returns: PHAsset在选择的数组的index 150 | */ 151 | public func index(ofSelect alasset: PHAsset) -> Int? { 152 | return selectPhotoArr.index(of: alasset) 153 | } 154 | 155 | /** 156 | 删除SelectPhotoArr里的PHAsset 157 | 158 | - parameter alasset: PHAsset对象 159 | */ 160 | func remove(formSelect alasset: PHAsset) { 161 | if let index = index(ofSelect: alasset) { 162 | selectPhotoArr.wcl_removeSafe(at: index) 163 | } 164 | } 165 | 166 | /** 167 | 添加PHAsset到SelectPhotoArr 168 | 169 | - parameter alasset: 要添加的PHAsset 170 | */ 171 | public func append(toSelect alasset: PHAsset) { 172 | selectPhotoArr.append(alasset) 173 | } 174 | 175 | //MARK: 通过请求获取photo的数据 176 | /** 177 | 根据index获取photo 178 | 179 | - parameter ablumIndex: 相册的index 180 | - parameter photoIndex: 相册里图片的index 181 | - parameter photoSize: 图片的size 182 | - parameter resultHandler: 返回照片的回调 183 | */ 184 | public func getPhoto(_ ablumIndex: Int, photoIndex: Int, photoSize: CGSize, resultHandler: ((UIImage?, [AnyHashable: Any]?) -> Void)?) { 185 | let photoAsset:PHAsset? = getPHAsset(ablumIndex, photoIndex: photoIndex) 186 | if photoAsset != nil { 187 | let scale = UIScreen.main.scale 188 | let photoScaleSize = CGSize(width: photoSize.width*scale, height: photoSize.height*scale) 189 | self.photoManage.requestImage(for: photoAsset!, targetSize: photoScaleSize, contentMode: .aspectFill, options: self.photoOption, resultHandler: { (image, infoDic) in 190 | if image != nil { 191 | resultHandler?(image, infoDic) 192 | }else { 193 | let image_buffer = WCLImagePickerBundle.imageFromBundle("image-buffer") 194 | resultHandler?(image_buffer, infoDic) 195 | } 196 | }) 197 | } 198 | } 199 | 200 | /** 201 | 根据PHAsset获取photo 202 | 203 | - parameter ablumIndex: 相册的index 204 | - parameter alasset: 相册里图片的PHAsset 205 | - parameter photoSize: 图片的size 206 | - parameter resultHandler: 返回照片的回调 207 | */ 208 | public func getPhoto(_ photoSize: CGSize, alasset: PHAsset?, resultHandler: ((UIImage?, [AnyHashable: Any]?) -> Void)?) { 209 | if alasset != nil { 210 | let scale = UIScreen.main.scale 211 | let photoScaleSize = CGSize(width: photoSize.width*scale, height: photoSize.height*scale) 212 | self.photoManage.requestImage(for: alasset!, targetSize: photoScaleSize, contentMode: .aspectFill, options: self.photoOption, resultHandler: { (image, infoDic) in 213 | if image != nil { 214 | resultHandler?(image, infoDic) 215 | }else { 216 | let image_buffer = WCLImagePickerBundle.imageFromBundle("image-buffer") 217 | resultHandler?(image_buffer, infoDic) 218 | } 219 | }) 220 | } 221 | } 222 | 223 | /** 224 | 根据PHAsset获取photo的元数据 225 | 226 | - parameter alasset: 相册里图片的PHAsset 227 | - parameter resultHandler: 返回照片元数据的回调 228 | */ 229 | public func getPhotoData(alasset: PHAsset?, resultHandler: ((Data?, UIImageOrientation) -> Void)?) { 230 | if alasset != nil { 231 | self.photoManage.requestImageData(for: alasset!, options: nil, resultHandler: { (data, str, orientation, hashable) in 232 | resultHandler?(data, orientation) 233 | }) 234 | } 235 | } 236 | 237 | /** 238 | 获取默认大小的图片 239 | */ 240 | public func getPhotoDefalutSize(_ ablumIndex: Int, photoIndex: Int, resultHandler: ((UIImage?, [AnyHashable: Any]?) -> Void)?) { 241 | getPhoto(ablumIndex, photoIndex: photoIndex, photoSize: WCLPickerManager.pickerPhotoSize, resultHandler: resultHandler) 242 | } 243 | 244 | //MARK: Private Methods 245 | /** 246 | 开始获取获取相册列表 247 | */ 248 | private func getPhotoAlbum() { 249 | //创建一个PHFetchOptions对象检索照片 250 | let options = PHFetchOptions() 251 | //通过创建时间来检索 252 | options.sortDescriptors = [NSSortDescriptor.init(key: photoCreationDate, ascending: false)] 253 | //通过数据类型来检索,这里为只检索照片 254 | options.predicate = NSPredicate.init(format: "mediaType in %@", [PHAssetMediaType.image.rawValue]) 255 | //通过检索条件检索出符合检索条件的所有数据,也就是所有的照片 256 | let allResult = PHAsset.fetchAssets(with: options) 257 | //获取用户创建的相册 258 | let userResult = PHAssetCollection.fetchTopLevelUserCollections(with: nil) 259 | //获取智能相册 260 | let smartResult = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .albumRegular, options: nil) 261 | //将获取的相册加入到相册的数组中 262 | photoAlbums.append([WCLImagePickerBundle.localizedString(key: "全部照片"): allResult]) 263 | 264 | userResult.enumerateObjects(options: .concurrent) { (collection, index, stop) in 265 | let assetcollection = collection as! PHAssetCollection 266 | //通过检索条件从assetcollection中检索出结果 267 | let assetResult = PHAsset.fetchAssets(in: assetcollection, options: options) 268 | if assetResult.count != 0 { 269 | self.photoAlbums.append([assetcollection.localizedTitle!:assetResult]) 270 | } 271 | } 272 | 273 | smartResult.enumerateObjects(options: .concurrent) { (collection, index, stop) in 274 | //通过检索条件从assetcollection中检索出结果 275 | let assetResult = PHAsset.fetchAssets(in: collection, options: options) 276 | if assetResult.count != 0 { 277 | self.photoAlbums.append([collection.localizedTitle!:assetResult]) 278 | } 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/ViewControllers/WCLImagePickerController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLImagePickerController.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLImagePickerController 22 | // @abstract 图片选择器的VC 23 | // @discussion 图片选择器的VC 24 | // 25 | 26 | import UIKit 27 | import Photos 28 | 29 | public class WCLImagePickerController: UIViewController { 30 | 31 | @IBOutlet weak var photoAblumCV: UICollectionView! 32 | fileprivate var centerView: WCLAblumCenterView? 33 | fileprivate var ablumList: WCLAblumListView? 34 | fileprivate var photoSelectView: WCLPhotoSelectView? 35 | fileprivate var pickerManager: WCLPickerManager? 36 | fileprivate var cellContext: WCLPickerCellContext? 37 | fileprivate let pickerView = WCLBaseImagePickerController() 38 | weak var delegate: WCLImagePikcerDelegate? 39 | //选择的相册的index 40 | fileprivate var ablumSelectIndex = 0 41 | //是否是第一次启动 42 | fileprivate var firstLaunch:Bool = true 43 | //View是否DidLoad 44 | fileprivate var isViewDidLoad:Bool = false 45 | //相册启动的view 46 | fileprivate var launchView = WCLLaunchView.init(frame: UIScreen.main.bounds) 47 | 48 | deinit { 49 | NotificationCenter.default.removeObserver(self) 50 | } 51 | 52 | //MARK: Public Methods 53 | /// present出WCLImagePickerController 54 | @discardableResult 55 | class public func present(inVC: UIViewController?, delegate: WCLImagePikcerDelegate) -> (WCLImagePickerController, WCLNavigationController) { 56 | let vc = WCLImagePickerController.init(delegate: delegate) 57 | let nav = WCLNavigationController.init(rootViewController: vc, navBarColor: WCLImagePickerOptions.tintColor) 58 | inVC?.present(nav, animated: true, completion: nil) 59 | return (vc, nav) 60 | } 61 | 62 | 63 | //MARK: Override 64 | public override func viewDidAppear(_ animated: Bool) { 65 | super.viewDidAppear(animated) 66 | isViewDidLoad = true 67 | if firstLaunch == true && PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized { 68 | configPhotoVC() 69 | } 70 | } 71 | 72 | override public func viewDidLoad() { 73 | super.viewDidLoad() 74 | // Do any additional setup after loading the view. 75 | photoAuthorization() 76 | //添加launchView 77 | navigationController?.view.addSubview(launchView) 78 | configNav() 79 | addNotify() 80 | } 81 | 82 | override public func didReceiveMemoryWarning() { 83 | super.didReceiveMemoryWarning() 84 | // Dispose of any resources that can be recreated. 85 | } 86 | 87 | override func photoLeftAction(_ sender: UIButton) { 88 | delegate?.wclImagePickerCancel(self) 89 | } 90 | 91 | override func photoRightAction(_ sender: UIButton) { 92 | var imageArr = [UIImage]() 93 | if pickerManager != nil { 94 | let count = pickerManager!.selectPhotoArr.count 95 | if count == 0 { 96 | delegate?.wclImagePickerComplete(self, imageArr: imageArr) 97 | return 98 | } 99 | for asset in pickerManager!.selectPhotoArr { 100 | pickerManager!.getPhotoData(alasset: asset, resultHandler: { [weak self] (data, orientation) in 101 | if data != nil { 102 | let image = UIImage.init(data: data!) 103 | if image != nil { 104 | imageArr.append(image!) 105 | } 106 | if imageArr.count == count { 107 | DispatchQueue.main.async { 108 | self?.delegate?.wclImagePickerComplete(self!, imageArr: imageArr) 109 | } 110 | } 111 | } 112 | }) 113 | } 114 | } 115 | } 116 | 117 | 118 | //MARK: Initial Methods 119 | public init(delegate: WCLImagePikcerDelegate) { 120 | super.init(nibName: "WCLImagePickerController", bundle: WCLImagePickerBundle.bundle) 121 | self.delegate = delegate 122 | } 123 | 124 | required public init?(coder aDecoder: NSCoder) { 125 | fatalError("init(coder:) has not been implemented") 126 | } 127 | 128 | //MARK: Private Methods 129 | private func addNotify() { 130 | NotificationCenter.default.addObserver(self, selector: #selector(reloadSelect), name: WCLImagePickerNotify.reloadSelect, object: nil) 131 | NotificationCenter.default.addObserver(self, selector: #selector(reloadPhoto), name: WCLImagePickerNotify.reloadImagePicker, object: nil) 132 | NotificationCenter.default.addObserver(self, selector: #selector(imagePickerError(_:)), name: WCLImagePickerNotify.imagePickerError, object: nil) 133 | } 134 | 135 | private func configNav() { 136 | addWCLPhotoNavLeftButton(WCLImagePickerBundle.localizedString(key: "取消")) 137 | addWCLPhotoNavRightButton(WCLImagePickerBundle.localizedString(key: "完成")) 138 | } 139 | 140 | /** 141 | 刷新PhotoCV 142 | */ 143 | private func reloadPhotoCV() { 144 | pickerManager?.isSynchronous = true 145 | photoAblumCV.reloadData() 146 | //保证刷新的时候是同步刷新的,要不会有闪烁 147 | photoAblumCV.performBatchUpdates({ 148 | }, completion: { [weak self] (finished) in 149 | self?.pickerManager?.isSynchronous = false 150 | }) 151 | } 152 | 153 | /** 154 | 相册授权 155 | */ 156 | private func photoAuthorization() { 157 | switch PHPhotoLibrary.authorizationStatus() { 158 | case .denied: 159 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noAlbumPermissions) 160 | break 161 | // 用户拒绝,提示开启 162 | case .notDetermined: 163 | // 尚未请求,立即请求 164 | PHPhotoLibrary.requestAuthorization({ (status) -> Void in 165 | if status == .authorized { 166 | // 用户同意 167 | DispatchQueue.main.async { 168 | self.configPhotoVC() 169 | } 170 | } 171 | }) 172 | break 173 | case .restricted: 174 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noAlbumPermissions) 175 | break 176 | // 用户无法解决的无法访问 177 | case .authorized: 178 | // 用户已授权 179 | configPhotoVC() 180 | break 181 | } 182 | } 183 | 184 | private func configPhotoVC() { 185 | if isViewDidLoad == false { 186 | return 187 | } 188 | if firstLaunch { 189 | launchView.starAnimation() 190 | firstLaunch = false 191 | } 192 | pickerManager = WCLPickerManager() 193 | cellContext = WCLPickerCellContext.init(pickerManager: pickerManager!) 194 | cellContext?.register(collectionView: photoAblumCV) 195 | addSelectView() 196 | addCenterView() 197 | addAblumList() 198 | photoAblumCV.reloadData() 199 | } 200 | 201 | fileprivate func addCenterView() { 202 | centerView = WCLAblumCenterView.init(frame: CGRect(x: 0, y: 0, width: 200, height: 45), selectBlock: { [weak self] (select) in 203 | self?.ablumList?.dropAblbumList(select) 204 | }) 205 | navigationItem.titleView = centerView 206 | centerView!.centerTitle = pickerManager?.getAblumTitle(ablumSelectIndex) 207 | } 208 | 209 | fileprivate func addAblumList() { 210 | ablumList = WCLAblumListView.show(inView: view, pickerManager: pickerManager!) 211 | ablumList?.select = { [weak self] (index) in 212 | self?.ablumSelectIndex = index 213 | self?.centerView?.isSelect = !(self?.centerView?.isSelect ?? false) 214 | self?.photoAblumCV.reloadData() 215 | self?.photoAblumCV.setContentOffset(CGPoint(x: 0, y: 0), animated: false) 216 | self?.centerView?.centerTitle = self?.pickerManager?.getAblumTitle(index) 217 | } 218 | ablumList?.cancle = { [weak self] in 219 | self?.centerView?.isSelect = !(self?.centerView?.isSelect ?? false) 220 | } 221 | } 222 | 223 | fileprivate func addSelectView() { 224 | if WCLImagePickerOptions.isShowSelecView { 225 | let bounds = UIScreen.main.bounds 226 | photoSelectView = WCLPhotoSelectView.init(frame: CGRect.init(origin: CGPoint.init(x: 0, y: bounds.height - 47 - 64), size: CGSize.init(width: bounds.width, height: 47)), pickerManager: pickerManager!) 227 | photoSelectView?.pushBlock = { [weak self] (vc) in 228 | self?.navigationController?.pushViewController(vc, animated: true) 229 | } 230 | photoAblumCV.contentInset = UIEdgeInsetsMake(0, 0, 47, 0) 231 | photoSelectView?.translatesAutoresizingMaskIntoConstraints = false 232 | view.addSubview(photoSelectView!) 233 | photoSelectView?.addConstraint(NSLayoutConstraint(item: photoSelectView!, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1.0, constant: 47)) 234 | view.addConstraint(NSLayoutConstraint(item: photoSelectView!, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1.0, constant: 0)) 235 | view.addConstraint(NSLayoutConstraint(item: photoSelectView!, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1.0, constant: 0)) 236 | view.addConstraint(NSLayoutConstraint(item: photoSelectView!, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: 0)) 237 | 238 | }else { 239 | photoAblumCV.contentInset = UIEdgeInsetsMake(0, 0, 0, 0) 240 | } 241 | } 242 | 243 | fileprivate func imageCamereShow() { 244 | if cameraAuthorization() { 245 | pickerView.navigationBar.barTintColor = WCLImagePickerOptions.tintColor 246 | pickerView.navigationBar.tintColor = UIColor.white 247 | pickerView.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white] 248 | pickerView.delegate = self 249 | pickerView.sourceType = .camera 250 | self.present(pickerView, animated: true, completion: nil) 251 | } 252 | } 253 | 254 | fileprivate func cameraAuthorization() -> Bool { 255 | let mediaType = AVMediaTypeVideo 256 | let authorizationStatus = AVCaptureDevice.authorizationStatus(forMediaType: mediaType) 257 | /// 是否在模拟器 258 | #if (arch(i386) || arch(x86_64)) && os(iOS) 259 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noCameraPermissions) 260 | return false 261 | #else 262 | if authorizationStatus == .restricted || authorizationStatus == .denied { 263 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noCameraPermissions) 264 | AVCaptureDevice.requestAccess(forMediaType: mediaType, completionHandler: { (flag) in 265 | if flag { 266 | self.imageCamereShow() 267 | } 268 | }) 269 | return false 270 | } 271 | return true 272 | #endif 273 | // if TARGET_OS_SIMULATOR != 0 { 274 | // NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noCameraPermissions) 275 | // return false 276 | // } 277 | } 278 | 279 | //MARK: Notification Methods 280 | //刷新选择的相册列表 281 | @objc private func reloadSelect() { 282 | reloadPhotoCV() 283 | photoSelectView?.selectCollectionView.reloadData() 284 | if let pickerManager = pickerManager { 285 | photoSelectView?.imageSelectNum.text = String.init(format: "%d", pickerManager.selectPhotoArr.count) 286 | } 287 | } 288 | 289 | //刷新相册列表 290 | @objc private func reloadPhoto() { 291 | reloadPhotoCV() 292 | } 293 | 294 | //错误提示 295 | @objc private func imagePickerError(_ not: Notification) { 296 | if let error = not.object as? WCLError { 297 | delegate?.wclImagePickerError(self, error: error) 298 | } 299 | } 300 | } 301 | 302 | //MARK: UICollectionView 303 | extension WCLImagePickerController: UICollectionViewDelegate, 304 | UICollectionViewDataSource, 305 | UICollectionViewDelegateFlowLayout { 306 | //MARK: UICollectionViewDelegate 307 | public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 308 | collectionView.deselectItem(at: indexPath, animated: true) 309 | if WCLImagePickerOptions.needPickerCamera && indexPath.row == 0 { 310 | let conut = pickerManager?.selectPhotoArr.count ?? 0 311 | if conut >= WCLImagePickerOptions.maxPhotoSelectNum { 312 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noMoreThanImages) 313 | return 314 | } 315 | imageCamereShow() 316 | return 317 | } 318 | if let result = pickerManager?.getAblumResult(ablumSelectIndex) { 319 | var currentIndex = indexPath.row 320 | if WCLImagePickerOptions.needPickerCamera { 321 | currentIndex = currentIndex - 1 322 | } 323 | let browserVC = WCLPhotoBrowserController.init(pickerManager!, currentIndex: currentIndex, photoResult: result) 324 | navigationController?.pushViewController(browserVC, animated: true) 325 | } 326 | } 327 | 328 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 329 | return WCLPickerManager.pickerPhotoSize 330 | } 331 | 332 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 333 | return CGFloat(WCLImagePickerOptions.photoInterval) 334 | } 335 | 336 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 337 | return CGFloat(WCLImagePickerOptions.photoInterval) 338 | } 339 | 340 | //MARK: UICollectionViewDataSource 341 | public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 342 | guard cellContext != nil else { 343 | return 0 344 | } 345 | return cellContext!.getPikcerCellNumber(ablumIndex: ablumSelectIndex) 346 | } 347 | 348 | public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 349 | guard cellContext != nil else { 350 | let cell = UICollectionViewCell() 351 | return cell 352 | } 353 | return cellContext!.getPickerCell(collectionView, ablumIndex: ablumSelectIndex, photoIndex: indexPath.row) 354 | } 355 | } 356 | 357 | 358 | //MARK: UIImagePickerController 359 | extension WCLImagePickerController: UIImagePickerControllerDelegate, 360 | UINavigationControllerDelegate { 361 | //MARK: UIImagePickerControllerDelegate 362 | public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { 363 | if let image = info[UIImagePickerControllerOriginalImage] as? UIImage { 364 | picker.dismiss(animated: true, completion: { 365 | DispatchQueue.main.async { 366 | self.delegate?.wclImagePickerComplete(self, imageArr: [image]) 367 | } 368 | PHPhotoLibrary.shared().performChanges({ 369 | PHAssetChangeRequest.creationRequestForAsset(from: image) 370 | }, completionHandler: { (flag, error) in 371 | 372 | }) 373 | }) 374 | } 375 | } 376 | 377 | public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { 378 | picker.dismiss(animated: true, completion: nil) 379 | } 380 | } 381 | 382 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/ViewControllers/WCLImagePickerController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/ViewControllers/WCLPhotoBrowserController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPhotoBrowserController.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPhotoBrowserController 22 | // @abstract 相册的图片浏览器的VC 23 | // @discussion 相册的图片浏览器的VC 24 | // 25 | 26 | import UIKit 27 | import Photos 28 | 29 | internal class WCLPhotoBrowserController: UIViewController { 30 | 31 | @IBOutlet weak var photoBrowserView: UICollectionView! 32 | //当前photo的index 33 | var currentIndex:Int = 0 34 | 35 | fileprivate var context: WCLPhotoCellContext? 36 | 37 | fileprivate var pickerManager: WCLPickerManager 38 | //选择的是否是selectAssetArr 39 | fileprivate var isSelect:Bool = false 40 | //选择的照片的数组 41 | fileprivate var selectAssetArr: [PHAsset]? 42 | //相册的PHFetchResult 43 | fileprivate var photoResult: PHFetchResult? 44 | //是否出现过 45 | fileprivate var isViewDidAppear: Bool = false 46 | 47 | fileprivate let selecView = WCLSelectView.initFormNib() 48 | //MARK: Public Methods 49 | 50 | 51 | //MARK: Override 52 | override func viewDidAppear(_ animated: Bool) { 53 | super.viewDidAppear(animated) 54 | isViewDidAppear = true 55 | } 56 | 57 | override func viewDidLoad() { 58 | super.viewDidLoad() 59 | // Do any additional setup after loading the view. 60 | context = WCLPhotoCellContext.init(pickerManager: pickerManager) 61 | context?.register(collectionView: photoBrowserView) 62 | addWCLPhotoNavLeftButton(WCLImagePickerBundle.localizedString(key: "返回")) 63 | countSelectIndex(currentIndex) 64 | 65 | pickerManager.isSynchronous = true 66 | photoBrowserView.performBatchUpdates(nil) { (finish) in 67 | let size = UIScreen.main.bounds.size 68 | self.photoBrowserView.setContentOffset(CGPoint.init(x: (size.width+20)*CGFloat(self.currentIndex), y: 0), animated: false) 69 | self.pickerManager.isSynchronous = false 70 | } 71 | navigationItem.rightBarButtonItem = UIBarButtonItem.init(customView: selecView) 72 | selecView.selectBt.addTarget(self, action: #selector(selectViewAction(_ :)), for: .touchUpInside) 73 | } 74 | 75 | override func photoLeftAction(_ sender: UIButton) { 76 | _ = navigationController?.popViewController(animated: true) 77 | } 78 | 79 | override func didReceiveMemoryWarning() { 80 | super.didReceiveMemoryWarning() 81 | // Dispose of any resources that can be recreated. 82 | } 83 | 84 | 85 | //MARK: Initial Methods 86 | init(_ pickerManager: WCLPickerManager, currentIndex: Int, selectAssetArr: [PHAsset]) { 87 | self.pickerManager = pickerManager 88 | super.init(nibName: "WCLPhotoBrowserController", bundle: WCLImagePickerBundle.bundle) 89 | self.currentIndex = currentIndex 90 | self.selectAssetArr = selectAssetArr 91 | self.isSelect = true 92 | } 93 | 94 | init(_ pickerManager: WCLPickerManager, currentIndex: Int, photoResult: PHFetchResult) { 95 | self.pickerManager = pickerManager 96 | super.init(nibName: "WCLPhotoBrowserController", bundle: WCLImagePickerBundle.bundle) 97 | self.currentIndex = currentIndex 98 | self.photoResult = photoResult 99 | self.isSelect = false 100 | } 101 | 102 | required init?(coder aDecoder: NSCoder) { 103 | fatalError("init(coder:) has not been implemented") 104 | } 105 | 106 | //MARK: Private Methods 107 | fileprivate func countSelectIndex(_ index: Int) { 108 | if isSelect { 109 | setWCLPhotoNavTitle("\(index+1)/\(selectAssetArr!.count)") 110 | selecView.selecrIndex = index+1 111 | }else { 112 | setWCLPhotoNavTitle("\(index+1)/\(photoResult!.count)") 113 | if let alasset = photoResult?[index] { 114 | let aindex = pickerManager.index(ofSelect: alasset) 115 | if aindex == nil { 116 | selecView.selecrIndex = 0 117 | }else { 118 | selecView.selecrIndex = aindex! + 1 119 | } 120 | } 121 | } 122 | } 123 | 124 | 125 | //MARK: Target Methods 126 | @objc private func selectViewAction(_ sender: UIButton) { 127 | defer { 128 | NotificationCenter.default.post(name: WCLImagePickerNotify.reloadSelect, object: nil, userInfo: nil) 129 | } 130 | let index = currentIndex 131 | if sender.isSelected { 132 | //删除 133 | if isSelect { 134 | self.photoBrowserView.performBatchUpdates({ 135 | if let alasset = self.selectAssetArr?[index] { 136 | if self.pickerManager.index(ofSelect: alasset) != nil { 137 | self.pickerManager.remove(formSelect: alasset) 138 | } 139 | } 140 | self.selectAssetArr?.remove(at: index) 141 | if self.currentIndex != 0 { 142 | self.currentIndex = self.currentIndex - 1 143 | } 144 | self.countSelectIndex(self.currentIndex) 145 | self.photoBrowserView.deleteItems(at: [IndexPath.init(row: index, section: 0)]) 146 | }, completion: { (complete) in 147 | if self.pickerManager.selectPhotoArr.count == 0 { 148 | _ = self.navigationController?.popViewController(animated: true) 149 | } 150 | }) 151 | }else { 152 | if let alasset = photoResult?[index] { 153 | if self.pickerManager.index(ofSelect: alasset) != nil { 154 | self.pickerManager.remove(formSelect: alasset) 155 | selecView.selecrIndex = 0 156 | } 157 | } 158 | } 159 | }else { 160 | //添加 161 | if !isSelect { 162 | if pickerManager.selectPhotoArr.count >= WCLImagePickerOptions.maxPhotoSelectNum { 163 | NotificationCenter.default.post(name: WCLImagePickerNotify.imagePickerError, object: WCLError.noMoreThanImages) 164 | return 165 | } 166 | if let alasset = photoResult?[index] { 167 | self.pickerManager.append(toSelect: alasset) 168 | self.selecView.selecrIndex = self.pickerManager.selectPhotoArr.count 169 | } 170 | } 171 | } 172 | } 173 | } 174 | 175 | 176 | //MARK: UICollectionView 177 | extension WCLPhotoBrowserController: UICollectionViewDelegate, 178 | UICollectionViewDataSource, 179 | UICollectionViewDelegateFlowLayout{ 180 | //MARK: UICollectionViewDelegate 181 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 182 | guard isViewDidAppear else { 183 | return 184 | } 185 | let floatIndex:CGFloat = scrollView.contentOffset.x/scrollView.frame.width 186 | let intIndex:Int = Int(scrollView.contentOffset.x/scrollView.frame.width) 187 | if CGFloat(intIndex) == floatIndex { 188 | if intIndex != currentIndex { 189 | NotificationCenter.default.post(name: WCLImagePickerNotify.selectPickerZoom, object: nil) 190 | } 191 | countSelectIndex(intIndex) 192 | currentIndex = intIndex 193 | } 194 | } 195 | 196 | //MARK: UICollectionViewDelegateFlowLayout 197 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 198 | let bounds = UIScreen.main.bounds 199 | return CGSize(width: bounds.width + 20, height: bounds.height - 64) 200 | } 201 | 202 | //MARK: UICollectionViewDataSource 203 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 204 | var asset: PHAsset? 205 | if isSelect { 206 | asset = selectAssetArr![indexPath.row] 207 | }else { 208 | asset = photoResult![indexPath.row] 209 | } 210 | let cell = context!.getCell(asset: asset!, collectionView: collectionView, indexPath: indexPath) 211 | return cell 212 | } 213 | 214 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 215 | if isSelect { 216 | return selectAssetArr!.count 217 | }else { 218 | return photoResult!.count 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/ViewControllers/WCLPhotoBrowserController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLAblumCenterView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLAblumCenterView.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // 22 | // @class WCLAblumCenterView 23 | // @abstract 图片选择器nav上的titleView 24 | // @discussion 图片选择器nav上的titleView 25 | // 26 | 27 | import UIKit 28 | 29 | internal class WCLAblumCenterView: UIView { 30 | 31 | var centerTitle:String? { 32 | didSet { 33 | titleLabel.text = centerTitle 34 | } 35 | } 36 | 37 | var selectBlock:((Bool) ->Void)? 38 | 39 | var isSelect = false { 40 | didSet { 41 | UIView.animate(withDuration: 0.3, animations: { 42 | self.arrowImageView.layer.transform = CATransform3DRotate(self.arrowImageView.layer.transform, CGFloat(Double.pi), 1.0, 0.0, 0.0) 43 | }) 44 | selectBlockAction() 45 | } 46 | } 47 | 48 | private let arrowImageView = UIImageView.init(image: WCLImagePickerOptions.pickerArrow) 49 | private let titleLabel = UILabel() 50 | 51 | //MARK: Override 52 | override init(frame: CGRect) { 53 | super.init(frame: frame) 54 | 55 | titleLabel.textColor = UIColor.white 56 | addSubview(arrowImageView) 57 | addSubview(titleLabel) 58 | //添加约束 59 | arrowImageView.translatesAutoresizingMaskIntoConstraints = false 60 | titleLabel.translatesAutoresizingMaskIntoConstraints = false 61 | addConstraint(NSLayoutConstraint.init(item: titleLabel, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1.0, constant: -11.0)) 62 | addConstraint(NSLayoutConstraint.init(item: titleLabel, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0.0)) 63 | addConstraint(NSLayoutConstraint.init(item: arrowImageView, attribute: .centerY, relatedBy: .equal, toItem: titleLabel, attribute: .centerY, multiplier: 1.0, constant: 0.0)) 64 | addConstraint(NSLayoutConstraint.init(item: arrowImageView, attribute: .left, relatedBy: .equal, toItem: titleLabel, attribute: .right, multiplier: 1.0, constant: 7.0)) 65 | } 66 | 67 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 68 | isSelect = !isSelect 69 | selectBlockAction() 70 | } 71 | 72 | func selectBlockAction() { 73 | if selectBlock != nil { 74 | selectBlock!(isSelect) 75 | } 76 | } 77 | 78 | //MARK: Initial Methods 79 | convenience init(frame: CGRect, selectBlock:@escaping (Bool) ->Void) { 80 | self.init(frame: frame) 81 | self.selectBlock = selectBlock 82 | } 83 | 84 | required init?(coder aDecoder: NSCoder) { 85 | fatalError("init(coder:) has not been implemented") 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLAblumListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLAblumListView.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLAblumListView 22 | // @abstract 相册列表的view 23 | // @discussion 相册列表的view 24 | // 25 | 26 | import UIKit 27 | 28 | internal class WCLAblumListView: UIView, 29 | UITableViewDelegate, 30 | UITableViewDataSource { 31 | //选择的相册的index 32 | var ablumSelectIndex = 0 33 | private var pickerManager: WCLPickerManager? 34 | @IBOutlet weak var ablumTableView: UITableView! 35 | @IBOutlet weak var maskBackView: UIView! 36 | @IBOutlet weak var ablumTableHeight: NSLayoutConstraint! 37 | 38 | var select: ((_ index: Int) -> Void)? 39 | var cancle: (() -> Void)? 40 | 41 | //MARK: Public Methods 42 | func dropAblbumList(_ select:Bool) { 43 | if select { 44 | isUserInteractionEnabled = true 45 | }else { 46 | isUserInteractionEnabled = false 47 | } 48 | UIView.animate(withDuration: 0.35, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .allowUserInteraction, animations: { 49 | if select { 50 | self.ablumTableHeight.constant = self.frame.size.height - 51 51 | self.maskBackView.alpha = 0.7 52 | }else { 53 | self.ablumTableHeight.constant = 0 54 | self.maskBackView.alpha = 0.0 55 | } 56 | self.layoutIfNeeded() 57 | }) { (complete) in 58 | self.ablumTableView.reloadData() 59 | } 60 | } 61 | 62 | //MARK: Override 63 | override func awakeFromNib() { 64 | super.awakeFromNib() 65 | ablumTableView.register(UINib.init(nibName: WCLAblumListCell.identfier, bundle: WCLImagePickerBundle.bundle), forCellReuseIdentifier: WCLAblumListCell.identfier) 66 | let tap = UITapGestureRecognizer.init(target: self, action: #selector(cancleAction)) 67 | maskBackView.addGestureRecognizer(tap) 68 | } 69 | 70 | //MARK: Initial Methods 71 | class func `init`(pickerManager: WCLPickerManager) -> WCLAblumListView { 72 | let view = UINib.init(nibName: "WCLAblumListView", bundle: WCLImagePickerBundle.bundle).instantiate(withOwner: nil, options: nil).first as! WCLAblumListView 73 | view.pickerManager = pickerManager 74 | return view 75 | } 76 | 77 | class func show(inView: UIView, pickerManager: WCLPickerManager) -> WCLAblumListView { 78 | let view = WCLAblumListView.init(pickerManager: pickerManager) 79 | view.frame = inView.bounds 80 | inView.addSubview(view) 81 | view.isUserInteractionEnabled = false 82 | return view 83 | } 84 | 85 | //MARK: private Methods 86 | @objc private func cancleAction() { 87 | cancle?() 88 | } 89 | 90 | //MARK: UITableViewDelegate 91 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 92 | tableView.deselectRow(at: indexPath, animated: true) 93 | select?(indexPath.row) 94 | ablumSelectIndex = indexPath.row 95 | } 96 | 97 | func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 98 | return 90 99 | } 100 | 101 | //MARK: UITableViewDataSource 102 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 103 | //相册的数量 104 | if pickerManager != nil { 105 | return pickerManager!.photoAlbums.count 106 | }else { 107 | return 0 108 | } 109 | } 110 | 111 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 112 | let cell:WCLAblumListCell = tableView.dequeueReusableCell(withIdentifier: WCLAblumListCell.identfier, for: indexPath) as! WCLAblumListCell 113 | cell.ablumNameLabel.text = pickerManager?.getAblumTitle(indexPath.row) 114 | weak var weakCell = cell 115 | pickerManager?.getPhoto(indexPath.row, photoIndex: 0, photoSize: cell.ablumImageView.frame.size, resultHandler: { (image, infoDic) in 116 | weakCell?.ablumImageView.image = image 117 | }) 118 | if (indexPath as NSIndexPath).row == ablumSelectIndex { 119 | cell.selectImageView.isHighlighted = true 120 | }else { 121 | cell.selectImageView.isHighlighted = false 122 | } 123 | return cell 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLAblumListView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLLaunchView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLLaunchView.swift 3 | // WCLLaunchView 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLLaunchView 22 | // @abstract 缓慢展开的启动图 23 | // @discussion 缓慢展开的启动图 24 | // 25 | 26 | import UIKit 27 | 28 | internal class WCLLaunchView: UIView, CAAnimationDelegate { 29 | 30 | fileprivate var topLayer: CALayer = CALayer() 31 | fileprivate var bottomLayer: CALayer = CALayer() 32 | fileprivate var launchImage: UIImage? 33 | //MARK: Public Methods 34 | /** 35 | 展开的动画 36 | */ 37 | func starAnimation() { 38 | //创建一个CABasicAnimation作用于CALayer的anchorPoint 39 | let topAnimation = CABasicAnimation.init(keyPath: "anchorPoint") 40 | //设置移动路径 41 | topAnimation.toValue = NSValue.init(cgPoint: CGPoint(x: 1, y: 1)) 42 | //动画时间 43 | topAnimation.duration = 0.6 44 | //设置代理,方便完成动画后移除当前view 45 | topAnimation.delegate = self 46 | //设置动画速度为匀速 47 | topAnimation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear) 48 | //设置动画结束后不移除点,保持移动后的位置 49 | topAnimation.isRemovedOnCompletion = false 50 | topAnimation.fillMode = kCAFillModeForwards 51 | topLayer.add(topAnimation, forKey: "topAnimation") 52 | 53 | //创建一个CABasicAnimation作用于CALayer的anchorPoint 54 | let bottomAnimation = CABasicAnimation.init(keyPath: "anchorPoint") 55 | //设置移动路径 56 | bottomAnimation.toValue = NSValue.init(cgPoint: CGPoint(x: 0, y: 0)) 57 | //动画时间 58 | bottomAnimation.duration = 0.6 59 | //设置动画速度为匀速 60 | bottomAnimation.timingFunction = CAMediaTimingFunction.init(name: kCAMediaTimingFunctionLinear) 61 | //设置动画结束后不移除点,保持移动后的位置 62 | bottomAnimation.isRemovedOnCompletion = false 63 | bottomAnimation.fillMode = kCAFillModeForwards 64 | bottomLayer.add(bottomAnimation, forKey: "topAnimation") 65 | } 66 | 67 | //MARK: Initial Methods 68 | init(frame: CGRect, launchImage: UIImage?) { 69 | super.init(frame: frame) 70 | self.launchImage = launchImage 71 | configTopShapeLayer() 72 | configBottomShapeLayer() 73 | } 74 | 75 | override init(frame: CGRect) { 76 | super.init(frame: frame) 77 | if WCLImagePickerOptions.launchImage == nil { 78 | launchImage = getDefaultLaunchImage() 79 | }else { 80 | launchImage = WCLImagePickerOptions.launchImage 81 | } 82 | configTopShapeLayer() 83 | configBottomShapeLayer() 84 | } 85 | 86 | required init?(coder aDecoder: NSCoder) { 87 | fatalError("init(coder:) has not been implemented") 88 | } 89 | 90 | //MARK: Private Methods 91 | /** 92 | 绘制上半部分的layer 93 | */ 94 | private func configTopShapeLayer() { 95 | //绘制贝斯尔曲线 96 | let topBezier:UIBezierPath = UIBezierPath() 97 | topBezier.move(to: CGPoint(x: -1, y: -1)) 98 | topBezier.addLine(to: CGPoint(x: bounds.width+1, y: -1)) 99 | topBezier.addCurve(to: CGPoint(x: bounds.width/2.0+1, y: bounds.height/2.0+1), controlPoint1: CGPoint(x: bounds.width+1, y: 0+1), controlPoint2: CGPoint(x: 343.5+1, y: 242.5+1)) 100 | topBezier.addCurve(to: CGPoint(x: -1, y: bounds.height+2), controlPoint1: CGPoint(x: 31.5+2, y: 424.5+2), controlPoint2: CGPoint(x: 0+2, y: bounds.height+2)) 101 | topBezier.addLine(to: CGPoint(x: -1, y: -1)) 102 | topBezier.close() 103 | //创建一个CAShapeLayer,将绘制的贝斯尔曲线的path给CAShapeLayer 104 | let topShape = CAShapeLayer() 105 | topShape.path = topBezier.cgPath 106 | //给topLayer设置contents为启动图 107 | topLayer.contents = launchImage?.cgImage 108 | topLayer.frame = bounds 109 | layer.addSublayer(topLayer) 110 | //将绘制后的CAShapeLayer做为topLayer的mask 111 | topLayer.mask = topShape 112 | } 113 | 114 | /** 115 | 绘制下半部分的layer 116 | */ 117 | private func configBottomShapeLayer() { 118 | let width = bounds.width 119 | let height = bounds.height 120 | //绘制贝斯尔曲线 121 | let bottomBezier:UIBezierPath = UIBezierPath() 122 | bottomBezier.move(to: CGPoint(x: width, y: 0)) 123 | bottomBezier.addCurve(to: CGPoint(x: width/2.0, y: height/2.0), controlPoint1: CGPoint(x: width, y: 0), controlPoint2: CGPoint(x: width * 0.915, y: height * 0.364)) 124 | bottomBezier.addCurve(to: CGPoint(x: 0, y: bounds.height), controlPoint1: CGPoint(x: width * 0.084 , y: height * 0.636), controlPoint2: CGPoint(x: 0, y: bounds.height)) 125 | bottomBezier.addLine(to: CGPoint(x: bounds.width, y: bounds.height)) 126 | bottomBezier.addLine(to: CGPoint(x: bounds.width, y: 0)) 127 | bottomBezier.close() 128 | //创建一个CAShapeLayer,将绘制的贝斯尔曲线的path给CAShapeLayer 129 | let bottomShape = CAShapeLayer() 130 | bottomShape.path = bottomBezier.cgPath 131 | //给bottomLayer设置contents为启动图 132 | bottomLayer.contents = launchImage?.cgImage 133 | bottomLayer.frame = bounds 134 | layer.addSublayer(bottomLayer) 135 | //将绘制后的CAShapeLayer做为bottomLayer的mask 136 | bottomLayer.mask = bottomShape 137 | } 138 | 139 | private func getDefaultLaunchImage() -> UIImage? { 140 | let screen = UIScreen.main 141 | UIGraphicsBeginImageContextWithOptions(screen.bounds.size, true, screen.scale) 142 | if let color = WCLImagePickerOptions.launchColor { 143 | color.setFill() 144 | }else { 145 | WCLImagePickerOptions.tintColor.setFill() 146 | } 147 | UIRectFill(screen.bounds) 148 | if let maskImage = WCLImagePickerBundle.imageFromBundle("image_photoAlbum") { 149 | maskImage.draw(at: CGPoint(x: screen.bounds.size.width/2 - maskImage.size.width/2, y: screen.bounds.size.height/2 - maskImage.size.height/2)) 150 | } 151 | let originImage = UIGraphicsGetImageFromCurrentImageContext() 152 | UIGraphicsEndImageContext() 153 | return originImage 154 | } 155 | 156 | //MRAK: animationDelegate 157 | /** 158 | 动画完成后移除当前view 159 | */ 160 | func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 161 | if flag { 162 | removeFromSuperview() 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLPhotoSelectView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLPhotoSelectView.swift 3 | // WCLImagePickrController-swift 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:http://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLPhotoSelectView 22 | // @abstract 相册中选择的照片的view 23 | // @discussion 相册中选择的照片的view 24 | // 25 | 26 | import UIKit 27 | import Photos 28 | 29 | internal class WCLPhotoSelectView: UIView, 30 | UICollectionViewDelegate, 31 | UICollectionViewDataSource { 32 | 33 | private var pickerManager: WCLPickerManager? 34 | @IBOutlet weak var imageSelectImage: UIImageView! 35 | @IBOutlet weak var imageSelectNum: UILabel! 36 | @IBOutlet weak var selectCollectionView: UICollectionView! 37 | 38 | var pushBlock: ((_: UIViewController) -> Void)? 39 | 40 | deinit { 41 | NotificationCenter.default.removeObserver(self) 42 | } 43 | //MARK: Public Methods 44 | 45 | 46 | //MARK: Override 47 | override func awakeFromNib() { 48 | super.awakeFromNib() 49 | if let color = WCLImagePickerOptions.selectViewBackColor { 50 | backgroundColor = color 51 | }else { 52 | backgroundColor = WCLImagePickerOptions.tintColor 53 | } 54 | selectCollectionView.register(UINib.init(nibName: WCLSelecteCVCell.identfier, bundle: WCLImagePickerBundle.bundle), forCellWithReuseIdentifier: WCLSelecteCVCell.identfier) 55 | NotificationCenter.default.addObserver(self, selector: #selector(reloadSelectTotalNum), name: WCLImagePickerNotify.reloadSelectTotalNum, object: nil) 56 | NotificationCenter.default.addObserver(self, selector: #selector(deleteSelectTotalNum(_ :)), name: WCLImagePickerNotify.deleteSelectCell, object: nil) 57 | NotificationCenter.default.addObserver(self, selector: #selector(insertSelectTotalNum(_ :)), name: WCLImagePickerNotify.insertSelectCell, object: nil) 58 | 59 | let size = CGSize.init(width: 26, height: 26) 60 | UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) 61 | let context = UIGraphicsGetCurrentContext() 62 | if let color = WCLImagePickerOptions.pickerSelectColor { 63 | color.setFill() 64 | }else { 65 | WCLImagePickerOptions.tintColor.setFill() 66 | } 67 | context?.addArc(center: CGPoint.init(x: size.width / 2, y: size.height / 2), radius: size.width / 2, startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: true) 68 | context?.fillPath() 69 | let selectImage = UIGraphicsGetImageFromCurrentImageContext() 70 | UIGraphicsEndImageContext() 71 | imageSelectImage.image = selectImage 72 | } 73 | 74 | override func layoutSubviews() { 75 | super.layoutSubviews() 76 | layoutIfNeeded() 77 | } 78 | 79 | //MARK: Initial Methods 80 | class func `init`(frame: CGRect, pickerManager: WCLPickerManager) -> WCLPhotoSelectView { 81 | let view = UINib.init(nibName: "WCLPhotoSelectView", bundle: WCLImagePickerBundle.bundle).instantiate(withOwner: nil, options: nil).first as! WCLPhotoSelectView 82 | view.frame = frame 83 | view.pickerManager = pickerManager 84 | return view 85 | } 86 | 87 | //MARK: Privater Methods 88 | 89 | 90 | //MARK: UICollectionViewDelegate 91 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 92 | collectionView.deselectItem(at: indexPath, animated: true) 93 | if let count = pickerManager?.selectPhotoArr.count { 94 | if count != indexPath.row { 95 | let browserVC = WCLPhotoBrowserController.init(pickerManager!, currentIndex: indexPath.row, selectAssetArr: pickerManager!.selectPhotoArr) 96 | pushBlock?(browserVC) 97 | } 98 | } 99 | } 100 | 101 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 102 | return CGSize(width: 36, height: 36) 103 | } 104 | 105 | //MARK: UICollectionViewDataSource 106 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 107 | return pickerManager!.selectPhotoArr.count+1 108 | 109 | } 110 | 111 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 112 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: WCLSelecteCVCell.identfier, for: indexPath) as! WCLSelecteCVCell 113 | if let pickerManager = pickerManager { 114 | if indexPath.row == pickerManager.selectPhotoArr.count { 115 | cell.selectImageView.image = WCLImagePickerOptions.selectPlaceholder 116 | }else { 117 | weak var weakCell = cell 118 | let assetArr: [PHAsset] = pickerManager.selectPhotoArr 119 | pickerManager.getPhoto(CGSize(width: 36, height: 36), alasset: assetArr[indexPath.row], resultHandler: { (image, infoDic) in 120 | weakCell?.selectImageView.image = image 121 | }) 122 | } 123 | }else { 124 | cell.selectImageView.image = WCLImagePickerOptions.selectPlaceholder 125 | } 126 | return cell 127 | } 128 | 129 | //MARK: Notification Methods 130 | @objc private func reloadSelectTotalNum() { 131 | if let pickerManager = pickerManager { 132 | imageSelectNum.text = String.init(format: "%d", pickerManager.selectPhotoArr.count) 133 | } 134 | } 135 | 136 | @objc private func deleteSelectTotalNum(_ not: Notification) { 137 | if let index = not.object as? IndexPath { 138 | selectCollectionView.performBatchUpdates({ [weak self] in 139 | self?.selectCollectionView.deleteItems(at: [index]) 140 | }, completion: nil) 141 | } 142 | } 143 | 144 | @objc private func insertSelectTotalNum(_ not: Notification) { 145 | if let index = not.object as? IndexPath { 146 | selectCollectionView.performBatchUpdates({ [weak self] in 147 | self?.selectCollectionView.insertItems(at: [index]) 148 | }, completion: nil) 149 | } 150 | } 151 | } 152 | 153 | 154 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLPhotoSelectView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLSelectView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WCLSelectView.swift 3 | // WarChat 4 | // 5 | // ************************************************** 6 | // * _____ * 7 | // * __ _ __ ___ \ / * 8 | // * \ \/ \/ / / __\ / / * 9 | // * \ _ / | (__ / / * 10 | // * \/ \/ \___/ / /__ * 11 | // * /_____/ * 12 | // * * 13 | // ************************************************** 14 | // Github :https://github.com/631106979 15 | // HomePage:https://imwcl.com 16 | // CSDN :http://blog.csdn.net/wang631106979 17 | // 18 | // Created by 王崇磊 on 16/9/14. 19 | // Copyright © 2016年 王崇磊. All rights reserved. 20 | // 21 | // @class WCLSelectView 22 | // @abstract WCLPhotoBrowserController页面的右上角的选择view 23 | // @discussion WCLPhotoBrowserController页面的右上角的选择view 24 | // 25 | 26 | import UIKit 27 | 28 | internal class WCLSelectView: UIView { 29 | 30 | @IBOutlet weak var selectLabel: UILabel! 31 | @IBOutlet weak var selectBt: UIButton! 32 | 33 | var selecrIndex: Int = 0 { 34 | willSet { 35 | if newValue == 0 { 36 | selectBt.isSelected = false 37 | selectLabel.isHidden = true 38 | }else { 39 | selectBt.isSelected = true 40 | selectLabel.isHidden = false 41 | selectLabel.text = "\(newValue)" 42 | } 43 | } 44 | } 45 | 46 | override func awakeFromNib() { 47 | super.awakeFromNib() 48 | 49 | let size = CGSize.init(width: 22, height: 22) 50 | UIGraphicsBeginImageContextWithOptions(size, false, UIScreen.main.scale) 51 | let context = UIGraphicsGetCurrentContext() 52 | if let color = WCLImagePickerOptions.pickerSelectColor { 53 | color.setFill() 54 | }else { 55 | WCLImagePickerOptions.tintColor.setFill() 56 | } 57 | context?.addArc(center: CGPoint.init(x: size.width / 2, y: size.height / 2), radius: size.width / 2, startAngle: 0, endAngle: CGFloat(Double.pi * 2), clockwise: true) 58 | context?.fillPath() 59 | let selectImage = UIGraphicsGetImageFromCurrentImageContext() 60 | UIGraphicsEndImageContext() 61 | selectBt.setImage(selectImage, for: .selected) 62 | 63 | selectBt.setImage(WCLImagePickerBundle.imageFromBundle("image_pickerDefault"), for: .normal) 64 | } 65 | 66 | //MARK: init Methods 67 | class func initFormNib() -> WCLSelectView { 68 | let view = UINib.init(nibName: "WCLSelectView", bundle: WCLImagePickerBundle.bundle).instantiate(withOwner: nil, options: nil).first as! WCLSelectView 69 | view.selectBt.isSelected = false 70 | view.selectLabel.isHidden = true 71 | return view 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/Views/WCLSelectView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 26 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_ablumSelectBackGround@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_ablumSelectBackGround@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_ablumSelectBackGround@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_ablumSelectBackGround@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_buffer@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_buffer@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_buffer@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_buffer@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_camera@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_camera@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_camera@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_camera@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_photoAlbum@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_photoAlbum@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_photoAlbum@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_photoAlbum@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerArrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerArrow@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerArrow@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerArrow@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerDefault@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerDefault@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerDefault@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_pickerDefault@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_selectPlaceholder@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_selectPlaceholder@2x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_selectPlaceholder@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/Images/image_selectPlaceholder@3x.png -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/zh.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/WCLImagePickerController/WCLImagePickerController/WCLImagePickerController.bundle/zh.lproj/Localizable.strings -------------------------------------------------------------------------------- /wcl.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imwcl/WCLImagePickerController/a5b9328d09d399e6c4384b940f4bcca8fbe53ff7/wcl.gif --------------------------------------------------------------------------------