├── .gitignore ├── Documentation ├── README.md └── gifs │ ├── image_carousel.gif │ └── simple_picker.gif ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── Sources │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── CarouselCell.swift │ ├── CarouselPresenter.swift │ ├── CarouselViewController.swift │ ├── Info.plist │ ├── Resources │ └── Images.xcassets │ │ ├── Contents.json │ │ ├── bingsu.imageset │ │ ├── Contents.json │ │ └── bingsu.png │ │ ├── candle.imageset │ │ ├── Contents.json │ │ └── candle.png │ │ ├── duck.imageset │ │ ├── Contents.json │ │ └── duck.png │ │ ├── heart.imageset │ │ ├── Contents.json │ │ └── heart.png │ │ └── rooftop.imageset │ │ ├── Contents.json │ │ └── rooftop.png │ ├── SimplePickerCell.swift │ ├── SimplePickerPresenter.swift │ └── SimplePickerViewController.swift ├── LICENSE ├── Pickme.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Pickme.xcscheme ├── README.md ├── Sources ├── Configuration.swift ├── Delegate.swift ├── Layout.swift ├── LayoutAttributes.swift ├── Pickme.swift └── Presenter.swift └── Support ├── Info.plist └── Pickme.h /.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 | .DS_Store 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xcuserstate 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | 29 | ## Playgrounds 30 | timeline.xctimeline 31 | playground.xcworkspace 32 | 33 | # Swift Package Manager 34 | # 35 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 36 | # Packages/ 37 | .build/ 38 | 39 | # CocoaPods 40 | # 41 | # We recommend against adding the Pods directory to your .gitignore. However 42 | # you should judge for yourself, the pros and cons are mentioned at: 43 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 44 | # 45 | # Pods/ 46 | 47 | # Carthage 48 | # 49 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 50 | # Carthage/Checkouts 51 | 52 | Carthage/Build 53 | 54 | # fastlane 55 | # 56 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 57 | # screenshots whenever they are needed. 58 | # For more information about the recommended setup visit: 59 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 60 | 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | -------------------------------------------------------------------------------- /Documentation/README.md: -------------------------------------------------------------------------------- 1 | # Presenter 2 | `Presenter` is a simple protocol defined as: 3 | ```swift 4 | public protocol Presenter { 5 | associatedtype CellType 6 | associatedtype ModelType 7 | 8 | func render(cell: CellType, with: ModelType, at: IndexPath) 9 | } 10 | ``` 11 | 12 | # Configuration 13 | Pickme can be configured by using `Configuration` object. 14 | ```swift 15 | public struct Configuration { 16 | 17 | // Minimum scale for the item 18 | public var minScale: CGFloat = 1.0 19 | 20 | // Maximum scale for the item 21 | public var maxScale: CGFloat = 2.0 22 | 23 | // Spacing between each items 24 | public var itemSpacing: CGFloat = 10.0 25 | 26 | // Size of each item 27 | public var itemSize: CGSize = CGSize(width: 50, height: 50) 28 | 29 | // Cell identifier of collection view cell 30 | public var cellIdentifier: String = "Cell" 31 | 32 | // Hide scrollbar for collection view 33 | public var hideScrollbar: Bool = true 34 | 35 | // Defines how many cells participate in scaling 36 | public var flowDistance: CGFloat = 50.0 37 | } 38 | ``` 39 | 40 | `flowDistance` parameter is an important configuration parameter that defines how your items will be scaled. It is the distance from center of collection view on either side. The item will participate in scaling, only if its center lies with in flowDistance from center of collection view. 41 | 42 | 43 | # API 44 | ### Initializers 45 | Pickme can be initialized in following ways: 46 | 47 | ```swift 48 | // Initialize with default configuration 49 | Pickme(with: collectionView, items: ["a", "b"], presenter: CustomPresenter()) 50 | ``` 51 | 52 | ```swift 53 | // Initialize with configuration block 54 | Pickme(with: collectionView, items: ["a", "b"], presenter: CustomPresenter()) { config in 55 | config.itemSpacing = 15.0 56 | config.itemSize = CGSize(width: 50.0, height: 50.0) 57 | config.flowDistance = 50.0 58 | } 59 | ``` 60 | 61 | ```swift 62 | // Initialize with existing configuration 63 | Pickme(with: collectionView, items: ["a", "b"], presenter: CustomPresenter(), configuration: configuarion) 64 | ``` 65 | 66 | ### `reload(withItems:)` 67 | Reloads table view with new items 68 | 69 | ### `selectItem(at:animation:)` 70 | Selects the item at index with optional animation. Default value for animation is `true`. 71 | 72 | ### `selectedIndex` 73 | Get the index of selected item 74 | -------------------------------------------------------------------------------- /Documentation/gifs/image_carousel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Documentation/gifs/image_carousel.gif -------------------------------------------------------------------------------- /Documentation/gifs/simple_picker.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Documentation/gifs/simple_picker.gif -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7CB99AC61CCBC6DF00E667DC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB99ABD1CCBC6DF00E667DC /* AppDelegate.swift */; }; 11 | 7CB99AC71CCBC6DF00E667DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7CB99ABE1CCBC6DF00E667DC /* Assets.xcassets */; }; 12 | 7CB99ACD1CCBC71700E667DC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7CB99AC01CCBC6DF00E667DC /* LaunchScreen.storyboard */; }; 13 | 7CB99ACE1CCBC71B00E667DC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7CB99AC21CCBC6DF00E667DC /* Main.storyboard */; }; 14 | 7CB99ADB1CCBCB6200E667DC /* Pickme.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7CB99AD61CCBC75800E667DC /* Pickme.framework */; }; 15 | 7CB99ADC1CCBCB6200E667DC /* Pickme.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7CB99AD61CCBC75800E667DC /* Pickme.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | 7CEB9CE71CCE8F1500ADB223 /* CarouselViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CEB9CE61CCE8F1500ADB223 /* CarouselViewController.swift */; }; 17 | 7CEB9CEA1CCE8F6800ADB223 /* CarouselCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CEB9CE91CCE8F6800ADB223 /* CarouselCell.swift */; }; 18 | 7CEB9CEC1CCE908C00ADB223 /* SimplePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CEB9CEB1CCE908C00ADB223 /* SimplePickerViewController.swift */; }; 19 | 7CEB9CEF1CCE90CE00ADB223 /* SimplePickerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CEB9CEE1CCE90CE00ADB223 /* SimplePickerCell.swift */; }; 20 | BA1C20D41E687B210049F426 /* CarouselPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA1C20D31E687B210049F426 /* CarouselPresenter.swift */; }; 21 | BA1C20DA1E687C630049F426 /* SimplePickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA1C20D91E687C630049F426 /* SimplePickerPresenter.swift */; }; 22 | BA1C20DC1E68842C0049F426 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BA1C20DB1E68842C0049F426 /* Images.xcassets */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXContainerItemProxy section */ 26 | 7CB99AD51CCBC75800E667DC /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = 7CB99AD11CCBC75700E667DC /* Pickme.xcodeproj */; 29 | proxyType = 2; 30 | remoteGlobalIDString = 7C7FAA361CCBC16400258044; 31 | remoteInfo = Pickme; 32 | }; 33 | 7CB99ADD1CCBCB6200E667DC /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 7CB99AD11CCBC75700E667DC /* Pickme.xcodeproj */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 7C7FAA351CCBC16400258044; 38 | remoteInfo = Pickme; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXCopyFilesBuildPhase section */ 43 | 7CB99ADF1CCBCB6200E667DC /* Embed Frameworks */ = { 44 | isa = PBXCopyFilesBuildPhase; 45 | buildActionMask = 2147483647; 46 | dstPath = ""; 47 | dstSubfolderSpec = 10; 48 | files = ( 49 | 7CB99ADC1CCBCB6200E667DC /* Pickme.framework in Embed Frameworks */, 50 | ); 51 | name = "Embed Frameworks"; 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXCopyFilesBuildPhase section */ 55 | 56 | /* Begin PBXFileReference section */ 57 | 7CB99AA81CCBC6B300E667DC /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 7CB99ABD1CCBC6DF00E667DC /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = Sources/AppDelegate.swift; sourceTree = ""; }; 59 | 7CB99ABE1CCBC6DF00E667DC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Sources/Assets.xcassets; sourceTree = ""; }; 60 | 7CB99AC11CCBC6DF00E667DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; }; 61 | 7CB99AC31CCBC6DF00E667DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; 62 | 7CB99AC41CCBC6DF00E667DC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Sources/Info.plist; sourceTree = ""; }; 63 | 7CB99AD11CCBC75700E667DC /* Pickme.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Pickme.xcodeproj; path = ../Pickme.xcodeproj; sourceTree = ""; }; 64 | 7CEB9CE61CCE8F1500ADB223 /* CarouselViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CarouselViewController.swift; path = Sources/CarouselViewController.swift; sourceTree = ""; }; 65 | 7CEB9CE91CCE8F6800ADB223 /* CarouselCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CarouselCell.swift; path = Sources/CarouselCell.swift; sourceTree = ""; }; 66 | 7CEB9CEB1CCE908C00ADB223 /* SimplePickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimplePickerViewController.swift; path = Sources/SimplePickerViewController.swift; sourceTree = ""; }; 67 | 7CEB9CEE1CCE90CE00ADB223 /* SimplePickerCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimplePickerCell.swift; path = Sources/SimplePickerCell.swift; sourceTree = ""; }; 68 | BA1C20D31E687B210049F426 /* CarouselPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CarouselPresenter.swift; path = Sources/CarouselPresenter.swift; sourceTree = ""; }; 69 | BA1C20D91E687C630049F426 /* SimplePickerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SimplePickerPresenter.swift; path = Sources/SimplePickerPresenter.swift; sourceTree = ""; }; 70 | BA1C20DB1E68842C0049F426 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Sources/Resources/Images.xcassets; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 7CB99AA51CCBC6B300E667DC /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | 7CB99ADB1CCBCB6200E667DC /* Pickme.framework in Frameworks */, 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | /* End PBXFrameworksBuildPhase section */ 83 | 84 | /* Begin PBXGroup section */ 85 | 7CB99A9F1CCBC6B300E667DC = { 86 | isa = PBXGroup; 87 | children = ( 88 | 7CB99ACC1CCBC6E600E667DC /* Sources */, 89 | 7CB99AD01CCBC74C00E667DC /* Libraries */, 90 | 7CB99ACF1CCBC73300E667DC /* Support */, 91 | 7CB99AA91CCBC6B300E667DC /* Products */, 92 | ); 93 | sourceTree = ""; 94 | }; 95 | 7CB99AA91CCBC6B300E667DC /* Products */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 7CB99AA81CCBC6B300E667DC /* Example.app */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | 7CB99ACC1CCBC6E600E667DC /* Sources */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 7CB99AC21CCBC6DF00E667DC /* Main.storyboard */, 107 | 7CEB9CE81CCE8F1900ADB223 /* Carousel */, 108 | 7CEB9CED1CCE909300ADB223 /* Simple Picker */, 109 | BA1C20DB1E68842C0049F426 /* Images.xcassets */, 110 | ); 111 | name = Sources; 112 | sourceTree = ""; 113 | }; 114 | 7CB99ACF1CCBC73300E667DC /* Support */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 7CB99ABE1CCBC6DF00E667DC /* Assets.xcassets */, 118 | 7CB99AC01CCBC6DF00E667DC /* LaunchScreen.storyboard */, 119 | 7CB99ABD1CCBC6DF00E667DC /* AppDelegate.swift */, 120 | 7CB99AC41CCBC6DF00E667DC /* Info.plist */, 121 | ); 122 | name = Support; 123 | sourceTree = ""; 124 | }; 125 | 7CB99AD01CCBC74C00E667DC /* Libraries */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 7CB99AD11CCBC75700E667DC /* Pickme.xcodeproj */, 129 | ); 130 | name = Libraries; 131 | sourceTree = ""; 132 | }; 133 | 7CB99AD21CCBC75700E667DC /* Products */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | 7CB99AD61CCBC75800E667DC /* Pickme.framework */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | 7CEB9CE81CCE8F1900ADB223 /* Carousel */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 7CEB9CE61CCE8F1500ADB223 /* CarouselViewController.swift */, 145 | BA1C20D31E687B210049F426 /* CarouselPresenter.swift */, 146 | 7CEB9CE91CCE8F6800ADB223 /* CarouselCell.swift */, 147 | ); 148 | name = Carousel; 149 | sourceTree = ""; 150 | }; 151 | 7CEB9CED1CCE909300ADB223 /* Simple Picker */ = { 152 | isa = PBXGroup; 153 | children = ( 154 | 7CEB9CEB1CCE908C00ADB223 /* SimplePickerViewController.swift */, 155 | BA1C20D91E687C630049F426 /* SimplePickerPresenter.swift */, 156 | 7CEB9CEE1CCE90CE00ADB223 /* SimplePickerCell.swift */, 157 | ); 158 | name = "Simple Picker"; 159 | sourceTree = ""; 160 | }; 161 | /* End PBXGroup section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | 7CB99AA71CCBC6B300E667DC /* Example */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 7CB99ABA1CCBC6B300E667DC /* Build configuration list for PBXNativeTarget "Example" */; 167 | buildPhases = ( 168 | 7CB99AA41CCBC6B300E667DC /* Sources */, 169 | 7CB99AA51CCBC6B300E667DC /* Frameworks */, 170 | 7CB99AA61CCBC6B300E667DC /* Resources */, 171 | 7CB99ADF1CCBCB6200E667DC /* Embed Frameworks */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | 7CB99ADE1CCBCB6200E667DC /* PBXTargetDependency */, 177 | ); 178 | name = Example; 179 | productName = Example; 180 | productReference = 7CB99AA81CCBC6B300E667DC /* Example.app */; 181 | productType = "com.apple.product-type.application"; 182 | }; 183 | /* End PBXNativeTarget section */ 184 | 185 | /* Begin PBXProject section */ 186 | 7CB99AA01CCBC6B300E667DC /* Project object */ = { 187 | isa = PBXProject; 188 | attributes = { 189 | LastSwiftUpdateCheck = 0730; 190 | LastUpgradeCheck = 0910; 191 | ORGANIZATIONNAME = "Bhargav Gurlanka"; 192 | TargetAttributes = { 193 | 7CB99AA71CCBC6B300E667DC = { 194 | CreatedOnToolsVersion = 7.3; 195 | LastSwiftMigration = 0910; 196 | }; 197 | }; 198 | }; 199 | buildConfigurationList = 7CB99AA31CCBC6B300E667DC /* Build configuration list for PBXProject "Example" */; 200 | compatibilityVersion = "Xcode 3.2"; 201 | developmentRegion = English; 202 | hasScannedForEncodings = 0; 203 | knownRegions = ( 204 | en, 205 | Base, 206 | ); 207 | mainGroup = 7CB99A9F1CCBC6B300E667DC; 208 | productRefGroup = 7CB99AA91CCBC6B300E667DC /* Products */; 209 | projectDirPath = ""; 210 | projectReferences = ( 211 | { 212 | ProductGroup = 7CB99AD21CCBC75700E667DC /* Products */; 213 | ProjectRef = 7CB99AD11CCBC75700E667DC /* Pickme.xcodeproj */; 214 | }, 215 | ); 216 | projectRoot = ""; 217 | targets = ( 218 | 7CB99AA71CCBC6B300E667DC /* Example */, 219 | ); 220 | }; 221 | /* End PBXProject section */ 222 | 223 | /* Begin PBXReferenceProxy section */ 224 | 7CB99AD61CCBC75800E667DC /* Pickme.framework */ = { 225 | isa = PBXReferenceProxy; 226 | fileType = wrapper.framework; 227 | path = Pickme.framework; 228 | remoteRef = 7CB99AD51CCBC75800E667DC /* PBXContainerItemProxy */; 229 | sourceTree = BUILT_PRODUCTS_DIR; 230 | }; 231 | /* End PBXReferenceProxy section */ 232 | 233 | /* Begin PBXResourcesBuildPhase section */ 234 | 7CB99AA61CCBC6B300E667DC /* Resources */ = { 235 | isa = PBXResourcesBuildPhase; 236 | buildActionMask = 2147483647; 237 | files = ( 238 | 7CB99AC71CCBC6DF00E667DC /* Assets.xcassets in Resources */, 239 | BA1C20DC1E68842C0049F426 /* Images.xcassets in Resources */, 240 | 7CB99ACD1CCBC71700E667DC /* LaunchScreen.storyboard in Resources */, 241 | 7CB99ACE1CCBC71B00E667DC /* Main.storyboard in Resources */, 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | }; 245 | /* End PBXResourcesBuildPhase section */ 246 | 247 | /* Begin PBXSourcesBuildPhase section */ 248 | 7CB99AA41CCBC6B300E667DC /* Sources */ = { 249 | isa = PBXSourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | 7CEB9CEA1CCE8F6800ADB223 /* CarouselCell.swift in Sources */, 253 | BA1C20D41E687B210049F426 /* CarouselPresenter.swift in Sources */, 254 | 7CB99AC61CCBC6DF00E667DC /* AppDelegate.swift in Sources */, 255 | 7CEB9CEF1CCE90CE00ADB223 /* SimplePickerCell.swift in Sources */, 256 | BA1C20DA1E687C630049F426 /* SimplePickerPresenter.swift in Sources */, 257 | 7CEB9CE71CCE8F1500ADB223 /* CarouselViewController.swift in Sources */, 258 | 7CEB9CEC1CCE908C00ADB223 /* SimplePickerViewController.swift in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | /* End PBXSourcesBuildPhase section */ 263 | 264 | /* Begin PBXTargetDependency section */ 265 | 7CB99ADE1CCBCB6200E667DC /* PBXTargetDependency */ = { 266 | isa = PBXTargetDependency; 267 | name = Pickme; 268 | targetProxy = 7CB99ADD1CCBCB6200E667DC /* PBXContainerItemProxy */; 269 | }; 270 | /* End PBXTargetDependency section */ 271 | 272 | /* Begin PBXVariantGroup section */ 273 | 7CB99AC01CCBC6DF00E667DC /* LaunchScreen.storyboard */ = { 274 | isa = PBXVariantGroup; 275 | children = ( 276 | 7CB99AC11CCBC6DF00E667DC /* Base */, 277 | ); 278 | name = LaunchScreen.storyboard; 279 | path = Sources/Base.lproj; 280 | sourceTree = ""; 281 | }; 282 | 7CB99AC21CCBC6DF00E667DC /* Main.storyboard */ = { 283 | isa = PBXVariantGroup; 284 | children = ( 285 | 7CB99AC31CCBC6DF00E667DC /* Base */, 286 | ); 287 | name = Main.storyboard; 288 | path = Sources/Base.lproj; 289 | sourceTree = ""; 290 | }; 291 | /* End PBXVariantGroup section */ 292 | 293 | /* Begin XCBuildConfiguration section */ 294 | 7CB99AB81CCBC6B300E667DC /* Debug */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ALWAYS_SEARCH_USER_PATHS = NO; 298 | CLANG_ANALYZER_NONNULL = YES; 299 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 300 | CLANG_CXX_LIBRARY = "libc++"; 301 | CLANG_ENABLE_MODULES = YES; 302 | CLANG_ENABLE_OBJC_ARC = YES; 303 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 304 | CLANG_WARN_BOOL_CONVERSION = YES; 305 | CLANG_WARN_COMMA = YES; 306 | CLANG_WARN_CONSTANT_CONVERSION = YES; 307 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 308 | CLANG_WARN_EMPTY_BODY = YES; 309 | CLANG_WARN_ENUM_CONVERSION = YES; 310 | CLANG_WARN_INFINITE_RECURSION = YES; 311 | CLANG_WARN_INT_CONVERSION = YES; 312 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 313 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 314 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 315 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 316 | CLANG_WARN_STRICT_PROTOTYPES = YES; 317 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 318 | CLANG_WARN_UNREACHABLE_CODE = YES; 319 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 320 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 321 | COPY_PHASE_STRIP = NO; 322 | DEBUG_INFORMATION_FORMAT = dwarf; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | ENABLE_TESTABILITY = YES; 325 | GCC_C_LANGUAGE_STANDARD = gnu99; 326 | GCC_DYNAMIC_NO_PIC = NO; 327 | GCC_NO_COMMON_BLOCKS = YES; 328 | GCC_OPTIMIZATION_LEVEL = 0; 329 | GCC_PREPROCESSOR_DEFINITIONS = ( 330 | "DEBUG=1", 331 | "$(inherited)", 332 | ); 333 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 334 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 335 | GCC_WARN_UNDECLARED_SELECTOR = YES; 336 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 337 | GCC_WARN_UNUSED_FUNCTION = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 340 | MTL_ENABLE_DEBUG_INFO = YES; 341 | ONLY_ACTIVE_ARCH = YES; 342 | SDKROOT = iphoneos; 343 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 344 | TARGETED_DEVICE_FAMILY = "1,2"; 345 | }; 346 | name = Debug; 347 | }; 348 | 7CB99AB91CCBC6B300E667DC /* Release */ = { 349 | isa = XCBuildConfiguration; 350 | buildSettings = { 351 | ALWAYS_SEARCH_USER_PATHS = NO; 352 | CLANG_ANALYZER_NONNULL = YES; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 358 | CLANG_WARN_BOOL_CONVERSION = YES; 359 | CLANG_WARN_COMMA = YES; 360 | CLANG_WARN_CONSTANT_CONVERSION = YES; 361 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INFINITE_RECURSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 367 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 368 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 369 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 370 | CLANG_WARN_STRICT_PROTOTYPES = YES; 371 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 372 | CLANG_WARN_UNREACHABLE_CODE = YES; 373 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 374 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 375 | COPY_PHASE_STRIP = NO; 376 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 377 | ENABLE_NS_ASSERTIONS = NO; 378 | ENABLE_STRICT_OBJC_MSGSEND = YES; 379 | GCC_C_LANGUAGE_STANDARD = gnu99; 380 | GCC_NO_COMMON_BLOCKS = YES; 381 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 382 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 383 | GCC_WARN_UNDECLARED_SELECTOR = YES; 384 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 385 | GCC_WARN_UNUSED_FUNCTION = YES; 386 | GCC_WARN_UNUSED_VARIABLE = YES; 387 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 388 | MTL_ENABLE_DEBUG_INFO = NO; 389 | SDKROOT = iphoneos; 390 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 391 | TARGETED_DEVICE_FAMILY = "1,2"; 392 | VALIDATE_PRODUCT = YES; 393 | }; 394 | name = Release; 395 | }; 396 | 7CB99ABB1CCBC6B300E667DC /* Debug */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 400 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 401 | CLANG_ENABLE_MODULES = YES; 402 | INFOPLIST_FILE = Sources/Info.plist; 403 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 404 | PRODUCT_BUNDLE_IDENTIFIER = com.housing.iphone.mainapp; 405 | PRODUCT_NAME = "$(TARGET_NAME)"; 406 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 407 | SWIFT_VERSION = 4.0; 408 | }; 409 | name = Debug; 410 | }; 411 | 7CB99ABC1CCBC6B300E667DC /* Release */ = { 412 | isa = XCBuildConfiguration; 413 | buildSettings = { 414 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 415 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 416 | CLANG_ENABLE_MODULES = YES; 417 | INFOPLIST_FILE = Sources/Info.plist; 418 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 419 | PRODUCT_BUNDLE_IDENTIFIER = com.housing.iphone.mainapp; 420 | PRODUCT_NAME = "$(TARGET_NAME)"; 421 | SWIFT_VERSION = 4.0; 422 | }; 423 | name = Release; 424 | }; 425 | /* End XCBuildConfiguration section */ 426 | 427 | /* Begin XCConfigurationList section */ 428 | 7CB99AA31CCBC6B300E667DC /* Build configuration list for PBXProject "Example" */ = { 429 | isa = XCConfigurationList; 430 | buildConfigurations = ( 431 | 7CB99AB81CCBC6B300E667DC /* Debug */, 432 | 7CB99AB91CCBC6B300E667DC /* Release */, 433 | ); 434 | defaultConfigurationIsVisible = 0; 435 | defaultConfigurationName = Release; 436 | }; 437 | 7CB99ABA1CCBC6B300E667DC /* Build configuration list for PBXNativeTarget "Example" */ = { 438 | isa = XCConfigurationList; 439 | buildConfigurations = ( 440 | 7CB99ABB1CCBC6B300E667DC /* Debug */, 441 | 7CB99ABC1CCBC6B300E667DC /* Release */, 442 | ); 443 | defaultConfigurationIsVisible = 0; 444 | defaultConfigurationName = Release; 445 | }; 446 | /* End XCConfigurationList section */ 447 | }; 448 | rootObject = 7CB99AA01CCBC6B300E667DC /* Project object */; 449 | } 450 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Sources/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Bhargav Gurlanka on 4/23/16. 6 | // Copyright © 2016 Bhargav Gurlanka. 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 throttle down OpenGL ES frame rates. 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 inactive 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 | -------------------------------------------------------------------------------- /Example/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /Example/Sources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Sources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Sources/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 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 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | -------------------------------------------------------------------------------- /Example/Sources/CarouselCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CarouselCell.swift 3 | // Example 4 | // 5 | // Created by Bhargav Gurlanka on 4/25/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Pickme 11 | 12 | class CarouselCell: UICollectionViewCell { 13 | 14 | @IBOutlet weak var imageView: UIImageView! 15 | 16 | override func awakeFromNib() { 17 | backgroundColor = .lightGray 18 | layer.contentsScale = UIScreen.main.scale 19 | layer.masksToBounds = false 20 | layer.shadowOpacity = 0.75; 21 | layer.shadowRadius = 5.0; 22 | layer.shadowOffset = .zero; 23 | 24 | layer.borderWidth = 1 25 | layer.borderColor = UIColor.white.cgColor 26 | clipsToBounds = true 27 | } 28 | 29 | override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { 30 | super.apply(layoutAttributes) 31 | 32 | guard let attr = layoutAttributes as? LayoutAttributes else { 33 | return 34 | } 35 | 36 | alpha = 0.5 + (attr.scaleFactor - 1.0) / 2 37 | 38 | layer.shadowPath = UIBezierPath(rect: bounds).cgPath 39 | layer.cornerRadius = bounds.height/2 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Example/Sources/CarouselPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CarouselPresenter 3 | // Example 4 | // 5 | // Created by Gurlanka, Bhargav (Agoda) on 02/03/17. 6 | // Copyright © 2017 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Pickme 11 | 12 | struct CarouselPresenter: Presenter { 13 | func render(cell: CarouselCell, with image: UIImage, at: IndexPath) { 14 | cell.imageView.image = image 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/Sources/CarouselViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CarouselViewController.swift 3 | // Example 4 | // 5 | // Created by Bhargav Gurlanka on 4/25/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Pickme 11 | 12 | final class CarouselViewController: UIViewController, Delegate { 13 | 14 | @IBOutlet weak var collectionView: UICollectionView! 15 | var picker: Pickme! 16 | let items = [ 17 | #imageLiteral(resourceName: "bingsu"), 18 | #imageLiteral(resourceName: "candle"), 19 | #imageLiteral(resourceName: "duck"), 20 | #imageLiteral(resourceName: "heart"), 21 | #imageLiteral(resourceName: "rooftop") 22 | ] 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | 27 | picker = Pickme(with: collectionView, items: items, presenter: CarouselPresenter()) { config in 28 | config.itemSpacing = 10.0 29 | config.itemSize = CGSize(width: 100.0, height: 100.0) 30 | config.flowDistance = 200.0 31 | } 32 | 33 | picker.selectItem(at: 3, animation: false) 34 | 35 | picker.delegate = self 36 | } 37 | 38 | override func didReceiveMemoryWarning() { 39 | super.didReceiveMemoryWarning() 40 | print("Received memory warning...!") 41 | } 42 | 43 | func itemSelected(atIndex index: Int) { 44 | print(items[index]); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Example/Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/bingsu.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "bingsu.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/bingsu.imageset/bingsu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Example/Sources/Resources/Images.xcassets/bingsu.imageset/bingsu.png -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/candle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "candle.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/candle.imageset/candle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Example/Sources/Resources/Images.xcassets/candle.imageset/candle.png -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/duck.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "duck.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/duck.imageset/duck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Example/Sources/Resources/Images.xcassets/duck.imageset/duck.png -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/heart.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "heart.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/heart.imageset/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Example/Sources/Resources/Images.xcassets/heart.imageset/heart.png -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/rooftop.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "rooftop.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/Sources/Resources/Images.xcassets/rooftop.imageset/rooftop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bhargavg/Pickme/f9f3254e180241fefde2875830a3f6b25be97971/Example/Sources/Resources/Images.xcassets/rooftop.imageset/rooftop.png -------------------------------------------------------------------------------- /Example/Sources/SimplePickerCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimplePickerCell.swift 3 | // Example 4 | // 5 | // Created by Bhargav Gurlanka on 4/25/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Pickme 11 | 12 | class SimplePickerCell: UICollectionViewCell { 13 | 14 | @IBOutlet weak var label: UILabel! 15 | 16 | func render(_ model: String, at: IndexPath) { 17 | label.text = model 18 | } 19 | 20 | override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { 21 | super.apply(layoutAttributes) 22 | 23 | guard let attr = layoutAttributes as? LayoutAttributes else { 24 | return 25 | } 26 | 27 | label.alpha = 0.5 + (attr.scaleFactor - 1.0) / 2 28 | 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Example/Sources/SimplePickerPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimplePickerPresenter.swift 3 | // Example 4 | // 5 | // Created by Gurlanka, Bhargav (Agoda) on 02/03/17. 6 | // Copyright © 2017 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Pickme 11 | 12 | struct SimplePickerPresenter: Presenter { 13 | func render(cell: SimplePickerCell, with model: String, at: IndexPath) { 14 | cell.label.text = model 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/Sources/SimplePickerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SimplePickerViewController.swift 3 | // Example 4 | // 5 | // Created by Bhargav Gurlanka on 4/25/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Pickme 11 | 12 | class SimplePickerViewController: UIViewController { 13 | 14 | @IBOutlet weak var collectionView: UICollectionView! 15 | var picker: Pickme! 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | let items = (10...99).map(String.init) 21 | 22 | picker = Pickme(with: collectionView, items: items, presenter: SimplePickerPresenter()) 23 | 24 | picker.selectItem(at: 5) 25 | } 26 | 27 | override func didReceiveMemoryWarning() { 28 | super.didReceiveMemoryWarning() 29 | print("Received memory warning...!") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Bhargav 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pickme.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7C47CA0E1CCDF376002CF603 /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C47CA0D1CCDF376002CF603 /* Delegate.swift */; }; 11 | 7CB99AE11CCBCE6B00E667DC /* Pickme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB99AE01CCBCE6B00E667DC /* Pickme.swift */; }; 12 | 7CB99AE31CCCEA7E00E667DC /* LayoutAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB99AE21CCCEA7E00E667DC /* LayoutAttributes.swift */; }; 13 | 7CB99AE71CCCEAD500E667DC /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB99AE61CCCEAD500E667DC /* Configuration.swift */; }; 14 | 7CB99AE91CCCEAFD00E667DC /* Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7CB99AE81CCCEAFD00E667DC /* Layout.swift */; }; 15 | BA1C20D21E68789C0049F426 /* Presenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA1C20D11E68789C0049F426 /* Presenter.swift */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 7C47CA0D1CCDF376002CF603 /* Delegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Delegate.swift; path = Sources/Delegate.swift; sourceTree = SOURCE_ROOT; }; 20 | 7C7FAA361CCBC16400258044 /* Pickme.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pickme.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | 7C7FAA391CCBC16400258044 /* Pickme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Pickme.h; path = Support/Pickme.h; sourceTree = ""; }; 22 | 7C7FAA3B1CCBC16400258044 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Support/Info.plist; sourceTree = ""; }; 23 | 7CB99AE01CCBCE6B00E667DC /* Pickme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Pickme.swift; path = Sources/Pickme.swift; sourceTree = SOURCE_ROOT; }; 24 | 7CB99AE21CCCEA7E00E667DC /* LayoutAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LayoutAttributes.swift; path = Sources/LayoutAttributes.swift; sourceTree = SOURCE_ROOT; }; 25 | 7CB99AE61CCCEAD500E667DC /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Configuration.swift; path = Sources/Configuration.swift; sourceTree = SOURCE_ROOT; }; 26 | 7CB99AE81CCCEAFD00E667DC /* Layout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Layout.swift; path = Sources/Layout.swift; sourceTree = SOURCE_ROOT; }; 27 | BA1C20D11E68789C0049F426 /* Presenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Presenter.swift; path = Sources/Presenter.swift; sourceTree = SOURCE_ROOT; }; 28 | /* End PBXFileReference section */ 29 | 30 | /* Begin PBXFrameworksBuildPhase section */ 31 | 7C7FAA321CCBC16400258044 /* Frameworks */ = { 32 | isa = PBXFrameworksBuildPhase; 33 | buildActionMask = 2147483647; 34 | files = ( 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 7C7FAA2C1CCBC16400258044 = { 42 | isa = PBXGroup; 43 | children = ( 44 | 7C7FAA381CCBC16400258044 /* Sources */, 45 | 7C7FAA411CCBC1D100258044 /* Support */, 46 | 7C7FAA371CCBC16400258044 /* Products */, 47 | ); 48 | sourceTree = ""; 49 | }; 50 | 7C7FAA371CCBC16400258044 /* Products */ = { 51 | isa = PBXGroup; 52 | children = ( 53 | 7C7FAA361CCBC16400258044 /* Pickme.framework */, 54 | ); 55 | name = Products; 56 | sourceTree = ""; 57 | }; 58 | 7C7FAA381CCBC16400258044 /* Sources */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 7CB99AE01CCBCE6B00E667DC /* Pickme.swift */, 62 | BA1C20D11E68789C0049F426 /* Presenter.swift */, 63 | 7CB99AE61CCCEAD500E667DC /* Configuration.swift */, 64 | 7CB99AE81CCCEAFD00E667DC /* Layout.swift */, 65 | 7CB99AE21CCCEA7E00E667DC /* LayoutAttributes.swift */, 66 | 7C47CA0D1CCDF376002CF603 /* Delegate.swift */, 67 | ); 68 | name = Sources; 69 | sourceTree = ""; 70 | }; 71 | 7C7FAA411CCBC1D100258044 /* Support */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 7C7FAA391CCBC16400258044 /* Pickme.h */, 75 | 7C7FAA3B1CCBC16400258044 /* Info.plist */, 76 | ); 77 | name = Support; 78 | sourceTree = ""; 79 | }; 80 | /* End PBXGroup section */ 81 | 82 | /* Begin PBXHeadersBuildPhase section */ 83 | 7C7FAA331CCBC16400258044 /* Headers */ = { 84 | isa = PBXHeadersBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | ); 88 | runOnlyForDeploymentPostprocessing = 0; 89 | }; 90 | /* End PBXHeadersBuildPhase section */ 91 | 92 | /* Begin PBXNativeTarget section */ 93 | 7C7FAA351CCBC16400258044 /* Pickme */ = { 94 | isa = PBXNativeTarget; 95 | buildConfigurationList = 7C7FAA3E1CCBC16400258044 /* Build configuration list for PBXNativeTarget "Pickme" */; 96 | buildPhases = ( 97 | 7C7FAA311CCBC16400258044 /* Sources */, 98 | 7C7FAA321CCBC16400258044 /* Frameworks */, 99 | 7C7FAA331CCBC16400258044 /* Headers */, 100 | 7C7FAA341CCBC16400258044 /* Resources */, 101 | ); 102 | buildRules = ( 103 | ); 104 | dependencies = ( 105 | ); 106 | name = Pickme; 107 | productName = Pickme; 108 | productReference = 7C7FAA361CCBC16400258044 /* Pickme.framework */; 109 | productType = "com.apple.product-type.framework"; 110 | }; 111 | /* End PBXNativeTarget section */ 112 | 113 | /* Begin PBXProject section */ 114 | 7C7FAA2D1CCBC16400258044 /* Project object */ = { 115 | isa = PBXProject; 116 | attributes = { 117 | LastUpgradeCheck = 1000; 118 | ORGANIZATIONNAME = "Bhargav Gurlanka"; 119 | TargetAttributes = { 120 | 7C7FAA351CCBC16400258044 = { 121 | CreatedOnToolsVersion = 7.3; 122 | LastSwiftMigration = ""; 123 | }; 124 | }; 125 | }; 126 | buildConfigurationList = 7C7FAA301CCBC16400258044 /* Build configuration list for PBXProject "Pickme" */; 127 | compatibilityVersion = "Xcode 3.2"; 128 | developmentRegion = English; 129 | hasScannedForEncodings = 0; 130 | knownRegions = ( 131 | en, 132 | ); 133 | mainGroup = 7C7FAA2C1CCBC16400258044; 134 | productRefGroup = 7C7FAA371CCBC16400258044 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | 7C7FAA351CCBC16400258044 /* Pickme */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | 7C7FAA341CCBC16400258044 /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXResourcesBuildPhase section */ 152 | 153 | /* Begin PBXSourcesBuildPhase section */ 154 | 7C7FAA311CCBC16400258044 /* Sources */ = { 155 | isa = PBXSourcesBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | 7C47CA0E1CCDF376002CF603 /* Delegate.swift in Sources */, 159 | BA1C20D21E68789C0049F426 /* Presenter.swift in Sources */, 160 | 7CB99AE31CCCEA7E00E667DC /* LayoutAttributes.swift in Sources */, 161 | 7CB99AE11CCBCE6B00E667DC /* Pickme.swift in Sources */, 162 | 7CB99AE91CCCEAFD00E667DC /* Layout.swift in Sources */, 163 | 7CB99AE71CCCEAD500E667DC /* Configuration.swift in Sources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXSourcesBuildPhase section */ 168 | 169 | /* Begin XCBuildConfiguration section */ 170 | 7C7FAA3C1CCBC16400258044 /* Debug */ = { 171 | isa = XCBuildConfiguration; 172 | buildSettings = { 173 | ALWAYS_SEARCH_USER_PATHS = NO; 174 | CLANG_ANALYZER_NONNULL = YES; 175 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 176 | CLANG_CXX_LIBRARY = "libc++"; 177 | CLANG_ENABLE_MODULES = YES; 178 | CLANG_ENABLE_OBJC_ARC = YES; 179 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 180 | CLANG_WARN_BOOL_CONVERSION = YES; 181 | CLANG_WARN_COMMA = YES; 182 | CLANG_WARN_CONSTANT_CONVERSION = YES; 183 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 184 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 185 | CLANG_WARN_EMPTY_BODY = YES; 186 | CLANG_WARN_ENUM_CONVERSION = YES; 187 | CLANG_WARN_INFINITE_RECURSION = YES; 188 | CLANG_WARN_INT_CONVERSION = YES; 189 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 190 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 191 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 192 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 193 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 194 | CLANG_WARN_STRICT_PROTOTYPES = YES; 195 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 196 | CLANG_WARN_UNREACHABLE_CODE = YES; 197 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 198 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 199 | COPY_PHASE_STRIP = NO; 200 | CURRENT_PROJECT_VERSION = 1; 201 | DEBUG_INFORMATION_FORMAT = dwarf; 202 | ENABLE_STRICT_OBJC_MSGSEND = YES; 203 | ENABLE_TESTABILITY = YES; 204 | GCC_C_LANGUAGE_STANDARD = gnu99; 205 | GCC_DYNAMIC_NO_PIC = NO; 206 | GCC_NO_COMMON_BLOCKS = YES; 207 | GCC_OPTIMIZATION_LEVEL = 0; 208 | GCC_PREPROCESSOR_DEFINITIONS = ( 209 | "DEBUG=1", 210 | "$(inherited)", 211 | ); 212 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 213 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 214 | GCC_WARN_UNDECLARED_SELECTOR = YES; 215 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 216 | GCC_WARN_UNUSED_FUNCTION = YES; 217 | GCC_WARN_UNUSED_VARIABLE = YES; 218 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 219 | MTL_ENABLE_DEBUG_INFO = YES; 220 | ONLY_ACTIVE_ARCH = YES; 221 | SDKROOT = iphoneos; 222 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 223 | TARGETED_DEVICE_FAMILY = "1,2"; 224 | VERSIONING_SYSTEM = "apple-generic"; 225 | VERSION_INFO_PREFIX = ""; 226 | }; 227 | name = Debug; 228 | }; 229 | 7C7FAA3D1CCBC16400258044 /* Release */ = { 230 | isa = XCBuildConfiguration; 231 | buildSettings = { 232 | ALWAYS_SEARCH_USER_PATHS = NO; 233 | CLANG_ANALYZER_NONNULL = YES; 234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 235 | CLANG_CXX_LIBRARY = "libc++"; 236 | CLANG_ENABLE_MODULES = YES; 237 | CLANG_ENABLE_OBJC_ARC = YES; 238 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 239 | CLANG_WARN_BOOL_CONVERSION = YES; 240 | CLANG_WARN_COMMA = YES; 241 | CLANG_WARN_CONSTANT_CONVERSION = YES; 242 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 243 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 244 | CLANG_WARN_EMPTY_BODY = YES; 245 | CLANG_WARN_ENUM_CONVERSION = YES; 246 | CLANG_WARN_INFINITE_RECURSION = YES; 247 | CLANG_WARN_INT_CONVERSION = YES; 248 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 249 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 250 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 251 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 252 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 253 | CLANG_WARN_STRICT_PROTOTYPES = YES; 254 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 255 | CLANG_WARN_UNREACHABLE_CODE = YES; 256 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 257 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 258 | COPY_PHASE_STRIP = NO; 259 | CURRENT_PROJECT_VERSION = 1; 260 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 261 | ENABLE_NS_ASSERTIONS = NO; 262 | ENABLE_STRICT_OBJC_MSGSEND = YES; 263 | GCC_C_LANGUAGE_STANDARD = gnu99; 264 | GCC_NO_COMMON_BLOCKS = YES; 265 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 266 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 267 | GCC_WARN_UNDECLARED_SELECTOR = YES; 268 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 269 | GCC_WARN_UNUSED_FUNCTION = YES; 270 | GCC_WARN_UNUSED_VARIABLE = YES; 271 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 272 | MTL_ENABLE_DEBUG_INFO = NO; 273 | SDKROOT = iphoneos; 274 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 275 | TARGETED_DEVICE_FAMILY = "1,2"; 276 | VALIDATE_PRODUCT = YES; 277 | VERSIONING_SYSTEM = "apple-generic"; 278 | VERSION_INFO_PREFIX = ""; 279 | }; 280 | name = Release; 281 | }; 282 | 7C7FAA3F1CCBC16400258044 /* Debug */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | CLANG_ENABLE_MODULES = YES; 286 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 287 | DEFINES_MODULE = YES; 288 | DYLIB_COMPATIBILITY_VERSION = 1; 289 | DYLIB_CURRENT_VERSION = 1; 290 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 291 | INFOPLIST_FILE = "$(SRCROOT)/Support/Info.plist"; 292 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.bhargavg.Pickme; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SKIP_INSTALL = YES; 297 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 298 | SWIFT_VERSION = 4.2; 299 | }; 300 | name = Debug; 301 | }; 302 | 7C7FAA401CCBC16400258044 /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | CLANG_ENABLE_MODULES = YES; 306 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 307 | DEFINES_MODULE = YES; 308 | DYLIB_COMPATIBILITY_VERSION = 1; 309 | DYLIB_CURRENT_VERSION = 1; 310 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 311 | INFOPLIST_FILE = "$(SRCROOT)/Support/Info.plist"; 312 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 313 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 314 | PRODUCT_BUNDLE_IDENTIFIER = com.bhargavg.Pickme; 315 | PRODUCT_NAME = "$(TARGET_NAME)"; 316 | SKIP_INSTALL = YES; 317 | SWIFT_VERSION = 4.2; 318 | }; 319 | name = Release; 320 | }; 321 | /* End XCBuildConfiguration section */ 322 | 323 | /* Begin XCConfigurationList section */ 324 | 7C7FAA301CCBC16400258044 /* Build configuration list for PBXProject "Pickme" */ = { 325 | isa = XCConfigurationList; 326 | buildConfigurations = ( 327 | 7C7FAA3C1CCBC16400258044 /* Debug */, 328 | 7C7FAA3D1CCBC16400258044 /* Release */, 329 | ); 330 | defaultConfigurationIsVisible = 0; 331 | defaultConfigurationName = Release; 332 | }; 333 | 7C7FAA3E1CCBC16400258044 /* Build configuration list for PBXNativeTarget "Pickme" */ = { 334 | isa = XCConfigurationList; 335 | buildConfigurations = ( 336 | 7C7FAA3F1CCBC16400258044 /* Debug */, 337 | 7C7FAA401CCBC16400258044 /* Release */, 338 | ); 339 | defaultConfigurationIsVisible = 0; 340 | defaultConfigurationName = Release; 341 | }; 342 | /* End XCConfigurationList section */ 343 | }; 344 | rootObject = 7C7FAA2D1CCBC16400258044 /* Project object */; 345 | } 346 | -------------------------------------------------------------------------------- /Pickme.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Pickme.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Pickme.xcodeproj/xcshareddata/xcschemes/Pickme.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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pickme [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 2 | Pickme turns your boring `UICollectionView` into an awesome 3D picker view. 3 | 4 | ## Talk is cheap, show me GIFS 💫 ✨ 5 | 6 | ### [Image Carousel](Example/Sources/CarouselViewController.swift): 7 | ![Image Carousel](Documentation/gifs/image_carousel.gif) 8 | 9 | ### [Simple Picker](Example/Sources/SimplePickerViewController.swift): 10 | ![Simple Picker](Documentation/gifs/simple_picker.gif) 11 | 12 | ## Documentation 13 | You can find more documentation [here](/Documentation/README.md) 14 | 15 | ## Todo: 16 | - [ ] CocoaPods Support 17 | - [ ] SwiftPM Support 18 | - [ ] Watch, TvOS Targets 19 | 20 | ## Contribution 21 | Found a bug? Want a new feature? Please feel free to report any issue or raise a Pull Request. 22 | -------------------------------------------------------------------------------- /Sources/Configuration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Configuration.swift 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 4/24/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct Configuration { 12 | public var minScale: CGFloat 13 | public var maxScale: CGFloat 14 | public var itemSpacing: CGFloat 15 | public var itemSize: CGSize 16 | public var cellIdentifier: String 17 | public var hideScrollbar: Bool 18 | public var flowDistance: CGFloat 19 | 20 | public init() { 21 | minScale = 1.0 22 | maxScale = 2.0 23 | itemSpacing = 10.0 24 | itemSize = CGSize(width: 50, height: 50) 25 | cellIdentifier = "Cell" 26 | hideScrollbar = true 27 | flowDistance = 50.0 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Delegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Delegate.swift 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 4/25/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol Delegate: class { 12 | func itemSelected(atIndex index: Int) 13 | } 14 | -------------------------------------------------------------------------------- /Sources/Layout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Layout.swift 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 4/24/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | final class Layout: UICollectionViewFlowLayout { 13 | 14 | var selectedIndexPath: IndexPath? 15 | var cachedAttributes = [LayoutAttributes]() 16 | var contentSize = CGSize() 17 | let config: Configuration 18 | weak var delegate: Delegate? 19 | 20 | init(configuration: Configuration) { 21 | config = configuration 22 | super.init() 23 | scrollDirection = .horizontal 24 | } 25 | 26 | required init?(coder aDecoder: NSCoder) { 27 | fatalError("init(coder:) has not been implemented") 28 | } 29 | 30 | override class var layoutAttributesClass : AnyClass { 31 | return LayoutAttributes.self 32 | } 33 | 34 | override func prepare() { 35 | guard let collectionView = collectionView, 36 | let delegate = collectionView.delegate as? UICollectionViewDelegateFlowLayout, 37 | let dataSource = collectionView.dataSource else { 38 | return 39 | } 40 | 41 | let itemsCount = dataSource.collectionView(collectionView, numberOfItemsInSection: 0) 42 | let sectionInset = delegate.collectionView!(collectionView, layout: self, insetForSectionAt: 0) 43 | let itemSpacing = config.itemSpacing 44 | var itemsWidth = CGFloat() 45 | 46 | let attributes: [LayoutAttributes] = (0.. UICollectionViewLayoutAttributes? { 69 | let row = indexPath.row 70 | return row < cachedAttributes.count ? cachedAttributes[row] : nil 71 | } 72 | 73 | override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 74 | guard let collectionView = collectionView else { 75 | return nil 76 | } 77 | 78 | let attributes = cachedAttributes.filter{ $0.frame.intersects(rect) } 79 | 80 | let modifiedAttributes: [UICollectionViewLayoutAttributes] = attributes.map { attr in 81 | let attribute = attr.copy() as! LayoutAttributes 82 | 83 | let distance = (collectionView.center.x + collectionView.contentOffset.x) - attribute.center.x 84 | let absDistance = abs(distance) 85 | 86 | let factor = 1.0 - min(absDistance / config.flowDistance, 1.0) 87 | let normalizedScale = config.minScale + ((config.maxScale - config.minScale) * factor) 88 | 89 | attribute.transform = CGAffineTransform(scaleX: normalizedScale, y: normalizedScale) 90 | attribute.zIndex = Int(20 * normalizedScale) 91 | attribute.scaleFactor = normalizedScale 92 | 93 | return attribute 94 | } 95 | 96 | return modifiedAttributes 97 | } 98 | 99 | override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint { 100 | let collectionViewSize = self.collectionView!.bounds.size 101 | let proposedContentOffsetCenterX = proposedContentOffset.x + collectionViewSize.width * 0.5 102 | 103 | let proposedRect = self.collectionView!.bounds 104 | 105 | // Comment out if you want the collectionview simply stop at the center of an item while scrolling freely 106 | // let proposedRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionViewSize.width, height: collectionViewSize.height) 107 | 108 | var candidateAttributes: UICollectionViewLayoutAttributes? 109 | for attributes in self.layoutAttributesForElements(in: proposedRect)! { 110 | // == Skip comparison with non-cell items (headers and footers) == // 111 | if attributes.representedElementCategory != .cell { 112 | continue 113 | } 114 | 115 | 116 | // Get collectionView current scroll position 117 | let currentOffset = self.collectionView!.contentOffset 118 | 119 | // Don't even bother with items on opposite direction 120 | // You'll get at least one, or else the fallback got your back 121 | if (attributes.center.x < (currentOffset.x + collectionViewSize.width * 0.5) && velocity.x > 0) || (attributes.center.x > (currentOffset.x + collectionViewSize.width * 0.5) && velocity.x < 0) { 122 | continue 123 | } 124 | 125 | 126 | // First good item in the loop 127 | if candidateAttributes == nil { 128 | candidateAttributes = attributes 129 | continue 130 | } 131 | 132 | 133 | // Save constants to improve readability 134 | let lastCenterOffset = candidateAttributes!.center.x - proposedContentOffsetCenterX 135 | let centerOffset = attributes.center.x - proposedContentOffsetCenterX 136 | 137 | if fabsf( Float(centerOffset) ) < fabsf( Float(lastCenterOffset) ) { 138 | candidateAttributes = attributes 139 | } 140 | } 141 | 142 | if let attributes = candidateAttributes { 143 | selectedIndexPath = attributes.indexPath 144 | // Great, we have a candidate 145 | 146 | if let delegate = delegate, 147 | let row = selectedIndexPath?.row { 148 | delegate.itemSelected(atIndex: row) 149 | } 150 | 151 | return CGPoint(x: attributes.center.x - collectionViewSize.width * 0.5, y: proposedContentOffset.y) 152 | } else { 153 | // Fallback 154 | selectedIndexPath = nil 155 | return super.targetContentOffset(forProposedContentOffset: proposedContentOffset) 156 | } 157 | } 158 | 159 | override var collectionViewContentSize : CGSize { 160 | return contentSize 161 | } 162 | 163 | override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { 164 | return true 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /Sources/LayoutAttributes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutAttributes.swift 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 4/24/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public final class LayoutAttributes: UICollectionViewLayoutAttributes { 12 | 13 | public var scaleFactor: CGFloat = 0 14 | 15 | override public func copy(with zone: NSZone?) -> Any { 16 | let copy = super.copy(with: zone) as! LayoutAttributes 17 | copy.scaleFactor = scaleFactor 18 | return copy 19 | } 20 | 21 | override public func isEqual(_ object: Any?) -> Bool { 22 | guard let attribute = object as? LayoutAttributes, super.isEqual(object) else { 23 | return false 24 | } 25 | 26 | return attribute.scaleFactor == scaleFactor 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Pickme.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pickme.swift 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 4/23/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | open class Pickme: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout where PresenterType.CellType == CellType, PresenterType.ModelType == ModelType{ 13 | 14 | let config: Configuration 15 | weak var collectionView: UICollectionView? 16 | var items: [ModelType] 17 | public weak var delegate: Delegate? 18 | let presenter: PresenterType 19 | open fileprivate(set) var selectedIndex: Int 20 | 21 | convenience public init(with view: UICollectionView, items: [ModelType], presenter: PresenterType, configurator: (inout Configuration) -> ()) { 22 | var configuration = Configuration() 23 | configurator(&configuration) 24 | self.init(with: view, items: items, presenter: presenter, configuration: configuration) 25 | } 26 | 27 | public init(with view: UICollectionView, items models: [ModelType], presenter: PresenterType, configuration: Configuration = Configuration()) { 28 | self.config = configuration 29 | self.collectionView = view 30 | self.items = models 31 | self.selectedIndex = 0 32 | self.presenter = presenter 33 | 34 | super.init() 35 | 36 | let layout = Layout(configuration: config) 37 | layout.delegate = self; 38 | 39 | collectionView?.collectionViewLayout = layout 40 | collectionView?.delegate = self 41 | collectionView?.dataSource = self 42 | 43 | if config.hideScrollbar { 44 | collectionView?.showsHorizontalScrollIndicator = false 45 | } 46 | } 47 | 48 | open func reload(withItems newItems: [ModelType]) { 49 | items = newItems 50 | collectionView?.reloadData() 51 | } 52 | 53 | open func selectItem(at index: Int, animation: Bool = true) { 54 | let indexPath = IndexPath(item: index, section: 0) 55 | collectionView?.layoutIfNeeded() // Trigger the layout 56 | collectionView?.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: animation) 57 | selectedIndex = index 58 | } 59 | 60 | public func numberOfSections(in collectionView: UICollectionView) -> Int { 61 | return 1 62 | } 63 | 64 | public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 65 | return items.count 66 | } 67 | 68 | public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 69 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: config.cellIdentifier, for: indexPath) 70 | let model = items[indexPath.row] 71 | 72 | if let cell = cell as? CellType { 73 | presenter.render(cell: cell, with: model, at: indexPath) 74 | } 75 | 76 | return cell 77 | } 78 | 79 | public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 80 | self.selectItem(at: indexPath.row) 81 | } 82 | 83 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 84 | return config.itemSize 85 | } 86 | 87 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 88 | let inset = (collectionView.frame.size.width - config.itemSize.width)/2 89 | return UIEdgeInsets(top: 0, left: inset, bottom: 0, right: inset) 90 | } 91 | 92 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 93 | return config.itemSpacing 94 | } 95 | } 96 | 97 | 98 | extension Pickme: Delegate { 99 | public func itemSelected(atIndex index: Int) { 100 | selectedIndex = index 101 | delegate?.itemSelected(atIndex: index) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Sources/Presenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Presenter.swift 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 02/03/17. 6 | // Copyright © 2017 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol Presenter { 12 | associatedtype CellType 13 | associatedtype ModelType 14 | 15 | func render(cell: CellType, with: ModelType, at: IndexPath) 16 | } 17 | -------------------------------------------------------------------------------- /Support/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 | 0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Support/Pickme.h: -------------------------------------------------------------------------------- 1 | // 2 | // Pickme.h 3 | // Pickme 4 | // 5 | // Created by Bhargav Gurlanka on 4/23/16. 6 | // Copyright © 2016 Bhargav Gurlanka. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Pickme. 12 | FOUNDATION_EXPORT double PickmeVersionNumber; 13 | 14 | //! Project version string for Pickme. 15 | FOUNDATION_EXPORT const unsigned char PickmeVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | --------------------------------------------------------------------------------