├── .gitignore ├── .swift-version ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── .travis.yml ├── Demo ├── Demo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── Demo.xcscmblueprint │ └── xcshareddata │ │ └── xcschemes │ │ ├── Demo.xcscheme │ │ └── ImageSlideShow.xcscheme ├── Demo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift └── ImageSlideShow │ ├── ImageSlideShow.h │ └── Info.plist ├── ImageSlideShowSwift.podspec ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── ImageSlideShow │ ├── Classes │ ├── ImageSlideShowNavigationController.swift │ ├── ImageSlideShowViewController.swift │ └── ImageSlideViewController.swift │ ├── Extensions │ └── UIPageViewController+ImageSlideShow.swift │ └── Storyboard │ └── ImageSlideShow.storyboard └── demo.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 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # .travis.yml 2 | 3 | # references: 4 | # * http://www.objc.io/issue-6/travis-ci.html 5 | # * https://github.com/supermarin/xcpretty#usage 6 | 7 | osx_image: xcode8.0 8 | language: objective-c 9 | xcode_sdk: macosx10.11 10 | xcode_scheme: ImageSlideShow 11 | before_install: 12 | - export LANG=en_US.UTF-8 13 | - env 14 | - locale 15 | - brew update 16 | - brew install swiftlint 17 | after_success: 18 | - swiftlint lint --path Sources/SwiftDate 19 | - pod lib lint 20 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 02ECBD2E1ED59FB600E156F7 /* ImageSlideShow.h in Headers */ = {isa = PBXBuildFile; fileRef = 02ECBD2C1ED59FB600E156F7 /* ImageSlideShow.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 02ECBD311ED59FB600E156F7 /* ImageSlideShow.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02ECBD2A1ED59FB600E156F7 /* ImageSlideShow.framework */; }; 12 | 02ECBD321ED59FB600E156F7 /* ImageSlideShow.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 02ECBD2A1ED59FB600E156F7 /* ImageSlideShow.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 13 | 02ECBD371ED59FC000E156F7 /* ImageSlideShowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA4D1DB395F900DCDA5F /* ImageSlideShowViewController.swift */; }; 14 | 02ECBD381ED59FC000E156F7 /* ImageSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA4E1DB395F900DCDA5F /* ImageSlideViewController.swift */; }; 15 | 02ECBD391ED59FC000E156F7 /* ImageSlideShowNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47726AA71DC1F1D300835E1F /* ImageSlideShowNavigationController.swift */; }; 16 | 02ECBD3A1ED59FC000E156F7 /* UIPageViewController+ImageSlideShow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA501DB395F900DCDA5F /* UIPageViewController+ImageSlideShow.swift */; }; 17 | 02ECBD591ED5A20B00E156F7 /* ImageSlideShow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4707EA521DB395F900DCDA5F /* ImageSlideShow.storyboard */; }; 18 | 4707EA3A1DB3959800DCDA5F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA391DB3959800DCDA5F /* AppDelegate.swift */; }; 19 | 4707EA3C1DB3959800DCDA5F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA3B1DB3959800DCDA5F /* ViewController.swift */; }; 20 | 4707EA3F1DB3959800DCDA5F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4707EA3D1DB3959800DCDA5F /* Main.storyboard */; }; 21 | 4707EA411DB3959800DCDA5F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4707EA401DB3959800DCDA5F /* Assets.xcassets */; }; 22 | 4707EA441DB3959800DCDA5F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4707EA421DB3959800DCDA5F /* LaunchScreen.storyboard */; }; 23 | 4707EA531DB395F900DCDA5F /* ImageSlideShowViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA4D1DB395F900DCDA5F /* ImageSlideShowViewController.swift */; }; 24 | 4707EA541DB395F900DCDA5F /* ImageSlideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA4E1DB395F900DCDA5F /* ImageSlideViewController.swift */; }; 25 | 4707EA551DB395F900DCDA5F /* UIPageViewController+ImageSlideShow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4707EA501DB395F900DCDA5F /* UIPageViewController+ImageSlideShow.swift */; }; 26 | 4707EA561DB395F900DCDA5F /* ImageSlideShow.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4707EA521DB395F900DCDA5F /* ImageSlideShow.storyboard */; }; 27 | 47726AA81DC1F1D300835E1F /* ImageSlideShowNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 47726AA71DC1F1D300835E1F /* ImageSlideShowNavigationController.swift */; }; 28 | /* End PBXBuildFile section */ 29 | 30 | /* Begin PBXContainerItemProxy section */ 31 | 02ECBD2F1ED59FB600E156F7 /* PBXContainerItemProxy */ = { 32 | isa = PBXContainerItemProxy; 33 | containerPortal = 4707EA2E1DB3959800DCDA5F /* Project object */; 34 | proxyType = 1; 35 | remoteGlobalIDString = 02ECBD291ED59FB600E156F7; 36 | remoteInfo = ImageSlideShow; 37 | }; 38 | /* End PBXContainerItemProxy section */ 39 | 40 | /* Begin PBXCopyFilesBuildPhase section */ 41 | 02ECBD361ED59FB600E156F7 /* Embed Frameworks */ = { 42 | isa = PBXCopyFilesBuildPhase; 43 | buildActionMask = 2147483647; 44 | dstPath = ""; 45 | dstSubfolderSpec = 10; 46 | files = ( 47 | 02ECBD321ED59FB600E156F7 /* ImageSlideShow.framework in Embed Frameworks */, 48 | ); 49 | name = "Embed Frameworks"; 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXCopyFilesBuildPhase section */ 53 | 54 | /* Begin PBXFileReference section */ 55 | 02ECBD2A1ED59FB600E156F7 /* ImageSlideShow.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ImageSlideShow.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 02ECBD2C1ED59FB600E156F7 /* ImageSlideShow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageSlideShow.h; sourceTree = ""; }; 57 | 02ECBD2D1ED59FB600E156F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 4707EA361DB3959800DCDA5F /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 4707EA391DB3959800DCDA5F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 60 | 4707EA3B1DB3959800DCDA5F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 61 | 4707EA3E1DB3959800DCDA5F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 62 | 4707EA401DB3959800DCDA5F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 63 | 4707EA431DB3959800DCDA5F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 64 | 4707EA451DB3959800DCDA5F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65 | 4707EA4D1DB395F900DCDA5F /* ImageSlideShowViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageSlideShowViewController.swift; sourceTree = ""; }; 66 | 4707EA4E1DB395F900DCDA5F /* ImageSlideViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageSlideViewController.swift; sourceTree = ""; }; 67 | 4707EA501DB395F900DCDA5F /* UIPageViewController+ImageSlideShow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIPageViewController+ImageSlideShow.swift"; sourceTree = ""; }; 68 | 4707EA521DB395F900DCDA5F /* ImageSlideShow.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ImageSlideShow.storyboard; sourceTree = ""; }; 69 | 47726AA71DC1F1D300835E1F /* ImageSlideShowNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageSlideShowNavigationController.swift; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 02ECBD261ED59FB600E156F7 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | 4707EA331DB3959800DCDA5F /* Frameworks */ = { 81 | isa = PBXFrameworksBuildPhase; 82 | buildActionMask = 2147483647; 83 | files = ( 84 | 02ECBD311ED59FB600E156F7 /* ImageSlideShow.framework in Frameworks */, 85 | ); 86 | runOnlyForDeploymentPostprocessing = 0; 87 | }; 88 | /* End PBXFrameworksBuildPhase section */ 89 | 90 | /* Begin PBXGroup section */ 91 | 02ECBD2B1ED59FB600E156F7 /* ImageSlideShow */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 02ECBD2C1ED59FB600E156F7 /* ImageSlideShow.h */, 95 | 02ECBD2D1ED59FB600E156F7 /* Info.plist */, 96 | ); 97 | path = ImageSlideShow; 98 | sourceTree = ""; 99 | }; 100 | 4707EA2D1DB3959800DCDA5F = { 101 | isa = PBXGroup; 102 | children = ( 103 | 4707EA4B1DB395F900DCDA5F /* ImageSlideShow */, 104 | 4707EA381DB3959800DCDA5F /* Demo */, 105 | 02ECBD2B1ED59FB600E156F7 /* ImageSlideShow */, 106 | 4707EA371DB3959800DCDA5F /* Products */, 107 | ); 108 | sourceTree = ""; 109 | }; 110 | 4707EA371DB3959800DCDA5F /* Products */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 4707EA361DB3959800DCDA5F /* Demo.app */, 114 | 02ECBD2A1ED59FB600E156F7 /* ImageSlideShow.framework */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 4707EA381DB3959800DCDA5F /* Demo */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 4707EA391DB3959800DCDA5F /* AppDelegate.swift */, 123 | 4707EA3B1DB3959800DCDA5F /* ViewController.swift */, 124 | 4707EA3D1DB3959800DCDA5F /* Main.storyboard */, 125 | 4707EA401DB3959800DCDA5F /* Assets.xcassets */, 126 | 4707EA421DB3959800DCDA5F /* LaunchScreen.storyboard */, 127 | 4707EA451DB3959800DCDA5F /* Info.plist */, 128 | ); 129 | path = Demo; 130 | sourceTree = ""; 131 | }; 132 | 4707EA4B1DB395F900DCDA5F /* ImageSlideShow */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 4707EA4C1DB395F900DCDA5F /* Classes */, 136 | 4707EA4F1DB395F900DCDA5F /* Extensions */, 137 | 4707EA511DB395F900DCDA5F /* Storyboard */, 138 | ); 139 | name = ImageSlideShow; 140 | path = ../Sources/ImageSlideShow; 141 | sourceTree = ""; 142 | }; 143 | 4707EA4C1DB395F900DCDA5F /* Classes */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 4707EA4D1DB395F900DCDA5F /* ImageSlideShowViewController.swift */, 147 | 4707EA4E1DB395F900DCDA5F /* ImageSlideViewController.swift */, 148 | 47726AA71DC1F1D300835E1F /* ImageSlideShowNavigationController.swift */, 149 | ); 150 | path = Classes; 151 | sourceTree = ""; 152 | }; 153 | 4707EA4F1DB395F900DCDA5F /* Extensions */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 4707EA501DB395F900DCDA5F /* UIPageViewController+ImageSlideShow.swift */, 157 | ); 158 | path = Extensions; 159 | sourceTree = ""; 160 | }; 161 | 4707EA511DB395F900DCDA5F /* Storyboard */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 4707EA521DB395F900DCDA5F /* ImageSlideShow.storyboard */, 165 | ); 166 | path = Storyboard; 167 | sourceTree = ""; 168 | }; 169 | /* End PBXGroup section */ 170 | 171 | /* Begin PBXHeadersBuildPhase section */ 172 | 02ECBD271ED59FB600E156F7 /* Headers */ = { 173 | isa = PBXHeadersBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | 02ECBD2E1ED59FB600E156F7 /* ImageSlideShow.h in Headers */, 177 | ); 178 | runOnlyForDeploymentPostprocessing = 0; 179 | }; 180 | /* End PBXHeadersBuildPhase section */ 181 | 182 | /* Begin PBXNativeTarget section */ 183 | 02ECBD291ED59FB600E156F7 /* ImageSlideShow */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 02ECBD351ED59FB600E156F7 /* Build configuration list for PBXNativeTarget "ImageSlideShow" */; 186 | buildPhases = ( 187 | 02ECBD251ED59FB600E156F7 /* Sources */, 188 | 02ECBD261ED59FB600E156F7 /* Frameworks */, 189 | 02ECBD271ED59FB600E156F7 /* Headers */, 190 | 02ECBD281ED59FB600E156F7 /* Resources */, 191 | ); 192 | buildRules = ( 193 | ); 194 | dependencies = ( 195 | ); 196 | name = ImageSlideShow; 197 | productName = ImageSlideShow; 198 | productReference = 02ECBD2A1ED59FB600E156F7 /* ImageSlideShow.framework */; 199 | productType = "com.apple.product-type.framework"; 200 | }; 201 | 4707EA351DB3959800DCDA5F /* Demo */ = { 202 | isa = PBXNativeTarget; 203 | buildConfigurationList = 4707EA481DB3959800DCDA5F /* Build configuration list for PBXNativeTarget "Demo" */; 204 | buildPhases = ( 205 | 4707EA321DB3959800DCDA5F /* Sources */, 206 | 4707EA331DB3959800DCDA5F /* Frameworks */, 207 | 4707EA341DB3959800DCDA5F /* Resources */, 208 | 02ECBD361ED59FB600E156F7 /* Embed Frameworks */, 209 | ); 210 | buildRules = ( 211 | ); 212 | dependencies = ( 213 | 02ECBD301ED59FB600E156F7 /* PBXTargetDependency */, 214 | ); 215 | name = Demo; 216 | productName = Demo; 217 | productReference = 4707EA361DB3959800DCDA5F /* Demo.app */; 218 | productType = "com.apple.product-type.application"; 219 | }; 220 | /* End PBXNativeTarget section */ 221 | 222 | /* Begin PBXProject section */ 223 | 4707EA2E1DB3959800DCDA5F /* Project object */ = { 224 | isa = PBXProject; 225 | attributes = { 226 | LastSwiftUpdateCheck = 0800; 227 | LastUpgradeCheck = 1020; 228 | ORGANIZATIONNAME = "Dimitri Giani"; 229 | TargetAttributes = { 230 | 02ECBD291ED59FB600E156F7 = { 231 | CreatedOnToolsVersion = 8.3.2; 232 | LastSwiftMigration = 0900; 233 | ProvisioningStyle = Automatic; 234 | }; 235 | 4707EA351DB3959800DCDA5F = { 236 | CreatedOnToolsVersion = 8.0; 237 | DevelopmentTeam = Y36762Y992; 238 | LastSwiftMigration = 0900; 239 | ProvisioningStyle = Automatic; 240 | }; 241 | }; 242 | }; 243 | buildConfigurationList = 4707EA311DB3959800DCDA5F /* Build configuration list for PBXProject "Demo" */; 244 | compatibilityVersion = "Xcode 3.2"; 245 | developmentRegion = en; 246 | hasScannedForEncodings = 0; 247 | knownRegions = ( 248 | en, 249 | Base, 250 | ); 251 | mainGroup = 4707EA2D1DB3959800DCDA5F; 252 | productRefGroup = 4707EA371DB3959800DCDA5F /* Products */; 253 | projectDirPath = ""; 254 | projectRoot = ""; 255 | targets = ( 256 | 4707EA351DB3959800DCDA5F /* Demo */, 257 | 02ECBD291ED59FB600E156F7 /* ImageSlideShow */, 258 | ); 259 | }; 260 | /* End PBXProject section */ 261 | 262 | /* Begin PBXResourcesBuildPhase section */ 263 | 02ECBD281ED59FB600E156F7 /* Resources */ = { 264 | isa = PBXResourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | 02ECBD591ED5A20B00E156F7 /* ImageSlideShow.storyboard in Resources */, 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | 4707EA341DB3959800DCDA5F /* Resources */ = { 272 | isa = PBXResourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | 4707EA441DB3959800DCDA5F /* LaunchScreen.storyboard in Resources */, 276 | 4707EA561DB395F900DCDA5F /* ImageSlideShow.storyboard in Resources */, 277 | 4707EA411DB3959800DCDA5F /* Assets.xcassets in Resources */, 278 | 4707EA3F1DB3959800DCDA5F /* Main.storyboard in Resources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXResourcesBuildPhase section */ 283 | 284 | /* Begin PBXSourcesBuildPhase section */ 285 | 02ECBD251ED59FB600E156F7 /* Sources */ = { 286 | isa = PBXSourcesBuildPhase; 287 | buildActionMask = 2147483647; 288 | files = ( 289 | 02ECBD371ED59FC000E156F7 /* ImageSlideShowViewController.swift in Sources */, 290 | 02ECBD381ED59FC000E156F7 /* ImageSlideViewController.swift in Sources */, 291 | 02ECBD391ED59FC000E156F7 /* ImageSlideShowNavigationController.swift in Sources */, 292 | 02ECBD3A1ED59FC000E156F7 /* UIPageViewController+ImageSlideShow.swift in Sources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | 4707EA321DB3959800DCDA5F /* Sources */ = { 297 | isa = PBXSourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | 47726AA81DC1F1D300835E1F /* ImageSlideShowNavigationController.swift in Sources */, 301 | 4707EA541DB395F900DCDA5F /* ImageSlideViewController.swift in Sources */, 302 | 4707EA3C1DB3959800DCDA5F /* ViewController.swift in Sources */, 303 | 4707EA551DB395F900DCDA5F /* UIPageViewController+ImageSlideShow.swift in Sources */, 304 | 4707EA531DB395F900DCDA5F /* ImageSlideShowViewController.swift in Sources */, 305 | 4707EA3A1DB3959800DCDA5F /* AppDelegate.swift in Sources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | /* End PBXSourcesBuildPhase section */ 310 | 311 | /* Begin PBXTargetDependency section */ 312 | 02ECBD301ED59FB600E156F7 /* PBXTargetDependency */ = { 313 | isa = PBXTargetDependency; 314 | target = 02ECBD291ED59FB600E156F7 /* ImageSlideShow */; 315 | targetProxy = 02ECBD2F1ED59FB600E156F7 /* PBXContainerItemProxy */; 316 | }; 317 | /* End PBXTargetDependency section */ 318 | 319 | /* Begin PBXVariantGroup section */ 320 | 4707EA3D1DB3959800DCDA5F /* Main.storyboard */ = { 321 | isa = PBXVariantGroup; 322 | children = ( 323 | 4707EA3E1DB3959800DCDA5F /* Base */, 324 | ); 325 | name = Main.storyboard; 326 | sourceTree = ""; 327 | }; 328 | 4707EA421DB3959800DCDA5F /* LaunchScreen.storyboard */ = { 329 | isa = PBXVariantGroup; 330 | children = ( 331 | 4707EA431DB3959800DCDA5F /* Base */, 332 | ); 333 | name = LaunchScreen.storyboard; 334 | sourceTree = ""; 335 | }; 336 | /* End PBXVariantGroup section */ 337 | 338 | /* Begin XCBuildConfiguration section */ 339 | 02ECBD331ED59FB600E156F7 /* Debug */ = { 340 | isa = XCBuildConfiguration; 341 | buildSettings = { 342 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 343 | CODE_SIGN_IDENTITY = ""; 344 | CURRENT_PROJECT_VERSION = 1; 345 | DEFINES_MODULE = YES; 346 | DYLIB_COMPATIBILITY_VERSION = 1; 347 | DYLIB_CURRENT_VERSION = 1; 348 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 349 | INFOPLIST_FILE = ImageSlideShow/Info.plist; 350 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 351 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = com.DimitriGian.ImageSlideShow; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | SKIP_INSTALL = YES; 356 | SWIFT_VERSION = 5.0; 357 | VERSIONING_SYSTEM = "apple-generic"; 358 | VERSION_INFO_PREFIX = ""; 359 | }; 360 | name = Debug; 361 | }; 362 | 02ECBD341ED59FB600E156F7 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 366 | CODE_SIGN_IDENTITY = ""; 367 | CURRENT_PROJECT_VERSION = 1; 368 | DEFINES_MODULE = YES; 369 | DYLIB_COMPATIBILITY_VERSION = 1; 370 | DYLIB_CURRENT_VERSION = 1; 371 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 372 | INFOPLIST_FILE = ImageSlideShow/Info.plist; 373 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 374 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 375 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 376 | PRODUCT_BUNDLE_IDENTIFIER = com.DimitriGian.ImageSlideShow; 377 | PRODUCT_NAME = "$(TARGET_NAME)"; 378 | SKIP_INSTALL = YES; 379 | SWIFT_VERSION = 5.0; 380 | VERSIONING_SYSTEM = "apple-generic"; 381 | VERSION_INFO_PREFIX = ""; 382 | }; 383 | name = Release; 384 | }; 385 | 4707EA461DB3959800DCDA5F /* Debug */ = { 386 | isa = XCBuildConfiguration; 387 | buildSettings = { 388 | ALWAYS_SEARCH_USER_PATHS = NO; 389 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 390 | CLANG_ANALYZER_NONNULL = YES; 391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 392 | CLANG_CXX_LIBRARY = "libc++"; 393 | CLANG_ENABLE_MODULES = YES; 394 | CLANG_ENABLE_OBJC_ARC = YES; 395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 396 | CLANG_WARN_BOOL_CONVERSION = YES; 397 | CLANG_WARN_COMMA = YES; 398 | CLANG_WARN_CONSTANT_CONVERSION = YES; 399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 401 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 402 | CLANG_WARN_EMPTY_BODY = YES; 403 | CLANG_WARN_ENUM_CONVERSION = YES; 404 | CLANG_WARN_INFINITE_RECURSION = YES; 405 | CLANG_WARN_INT_CONVERSION = YES; 406 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 407 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 408 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 409 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 411 | CLANG_WARN_STRICT_PROTOTYPES = YES; 412 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 413 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 417 | COPY_PHASE_STRIP = NO; 418 | DEBUG_INFORMATION_FORMAT = dwarf; 419 | ENABLE_STRICT_OBJC_MSGSEND = YES; 420 | ENABLE_TESTABILITY = YES; 421 | GCC_C_LANGUAGE_STANDARD = gnu99; 422 | GCC_DYNAMIC_NO_PIC = NO; 423 | GCC_NO_COMMON_BLOCKS = YES; 424 | GCC_OPTIMIZATION_LEVEL = 0; 425 | GCC_PREPROCESSOR_DEFINITIONS = ( 426 | "DEBUG=1", 427 | "$(inherited)", 428 | ); 429 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 430 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 431 | GCC_WARN_UNDECLARED_SELECTOR = YES; 432 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 433 | GCC_WARN_UNUSED_FUNCTION = YES; 434 | GCC_WARN_UNUSED_VARIABLE = YES; 435 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 436 | MTL_ENABLE_DEBUG_INFO = YES; 437 | ONLY_ACTIVE_ARCH = YES; 438 | SDKROOT = iphoneos; 439 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 440 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 441 | SWIFT_VERSION = 5.0; 442 | TARGETED_DEVICE_FAMILY = "1,2"; 443 | }; 444 | name = Debug; 445 | }; 446 | 4707EA471DB3959800DCDA5F /* Release */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ALWAYS_SEARCH_USER_PATHS = NO; 450 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 451 | CLANG_ANALYZER_NONNULL = YES; 452 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 453 | CLANG_CXX_LIBRARY = "libc++"; 454 | CLANG_ENABLE_MODULES = YES; 455 | CLANG_ENABLE_OBJC_ARC = YES; 456 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 457 | CLANG_WARN_BOOL_CONVERSION = YES; 458 | CLANG_WARN_COMMA = YES; 459 | CLANG_WARN_CONSTANT_CONVERSION = YES; 460 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 461 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 462 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 463 | CLANG_WARN_EMPTY_BODY = YES; 464 | CLANG_WARN_ENUM_CONVERSION = YES; 465 | CLANG_WARN_INFINITE_RECURSION = YES; 466 | CLANG_WARN_INT_CONVERSION = YES; 467 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 468 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 469 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 470 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 471 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 472 | CLANG_WARN_STRICT_PROTOTYPES = YES; 473 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 474 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 475 | CLANG_WARN_UNREACHABLE_CODE = YES; 476 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 477 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 478 | COPY_PHASE_STRIP = NO; 479 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 480 | ENABLE_NS_ASSERTIONS = NO; 481 | ENABLE_STRICT_OBJC_MSGSEND = YES; 482 | GCC_C_LANGUAGE_STANDARD = gnu99; 483 | GCC_NO_COMMON_BLOCKS = YES; 484 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 485 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 486 | GCC_WARN_UNDECLARED_SELECTOR = YES; 487 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 488 | GCC_WARN_UNUSED_FUNCTION = YES; 489 | GCC_WARN_UNUSED_VARIABLE = YES; 490 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 491 | MTL_ENABLE_DEBUG_INFO = NO; 492 | SDKROOT = iphoneos; 493 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 494 | SWIFT_VERSION = 5.0; 495 | TARGETED_DEVICE_FAMILY = "1,2"; 496 | VALIDATE_PRODUCT = YES; 497 | }; 498 | name = Release; 499 | }; 500 | 4707EA491DB3959800DCDA5F /* Debug */ = { 501 | isa = XCBuildConfiguration; 502 | buildSettings = { 503 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 504 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 505 | DEVELOPMENT_TEAM = Y36762Y992; 506 | INFOPLIST_FILE = Demo/Info.plist; 507 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 508 | PRODUCT_BUNDLE_IDENTIFIER = com.dimix.Demo; 509 | PRODUCT_NAME = "$(TARGET_NAME)"; 510 | SWIFT_VERSION = 5.0; 511 | }; 512 | name = Debug; 513 | }; 514 | 4707EA4A1DB3959800DCDA5F /* Release */ = { 515 | isa = XCBuildConfiguration; 516 | buildSettings = { 517 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 518 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 519 | DEVELOPMENT_TEAM = Y36762Y992; 520 | INFOPLIST_FILE = Demo/Info.plist; 521 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 522 | PRODUCT_BUNDLE_IDENTIFIER = com.dimix.Demo; 523 | PRODUCT_NAME = "$(TARGET_NAME)"; 524 | SWIFT_VERSION = 5.0; 525 | }; 526 | name = Release; 527 | }; 528 | /* End XCBuildConfiguration section */ 529 | 530 | /* Begin XCConfigurationList section */ 531 | 02ECBD351ED59FB600E156F7 /* Build configuration list for PBXNativeTarget "ImageSlideShow" */ = { 532 | isa = XCConfigurationList; 533 | buildConfigurations = ( 534 | 02ECBD331ED59FB600E156F7 /* Debug */, 535 | 02ECBD341ED59FB600E156F7 /* Release */, 536 | ); 537 | defaultConfigurationIsVisible = 0; 538 | defaultConfigurationName = Release; 539 | }; 540 | 4707EA311DB3959800DCDA5F /* Build configuration list for PBXProject "Demo" */ = { 541 | isa = XCConfigurationList; 542 | buildConfigurations = ( 543 | 4707EA461DB3959800DCDA5F /* Debug */, 544 | 4707EA471DB3959800DCDA5F /* Release */, 545 | ); 546 | defaultConfigurationIsVisible = 0; 547 | defaultConfigurationName = Release; 548 | }; 549 | 4707EA481DB3959800DCDA5F /* Build configuration list for PBXNativeTarget "Demo" */ = { 550 | isa = XCConfigurationList; 551 | buildConfigurations = ( 552 | 4707EA491DB3959800DCDA5F /* Debug */, 553 | 4707EA4A1DB3959800DCDA5F /* Release */, 554 | ); 555 | defaultConfigurationIsVisible = 0; 556 | defaultConfigurationName = Release; 557 | }; 558 | /* End XCConfigurationList section */ 559 | }; 560 | rootObject = 4707EA2E1DB3959800DCDA5F /* Project object */; 561 | } 562 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/project.xcworkspace/xcshareddata/Demo.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "f268d18c-e996-4b29-9489-9c60d5e3f5bc++8218", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | "f268d18c-e996-4b29-9489-9c60d5e3f5bc++8218" : { 5 | 6 | } 7 | }, 8 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 9 | "f268d18c-e996-4b29-9489-9c60d5e3f5bc++8218" : 9223372036854775807, 10 | "8710737E6E4F06ACEC4FC00188A330F26426543B" : 9223372036854775807 11 | }, 12 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "715DBD8A-EB3F-4F34-8678-6695AAD93A4B", 13 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 14 | "f268d18c-e996-4b29-9489-9c60d5e3f5bc++8218" : "..", 15 | "8710737E6E4F06ACEC4FC00188A330F26426543B" : "ImageSlideShow\/" 16 | }, 17 | "DVTSourceControlWorkspaceBlueprintNameKey" : "Demo", 18 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 19 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Demo\/Demo.xcodeproj", 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 21 | { 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/dimix\/ImageSlideShow", 23 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 24 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8710737E6E4F06ACEC4FC00188A330F26426543B" 25 | }, 26 | { 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "http:\/\/svn.dimitrigiani.it", 28 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Subversion", 29 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "f268d18c-e996-4b29-9489-9c60d5e3f5bc++8218" 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/xcshareddata/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 | -------------------------------------------------------------------------------- /Demo/Demo.xcodeproj/xcshareddata/xcschemes/ImageSlideShow.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 | -------------------------------------------------------------------------------- /Demo/Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Demo 4 | // 5 | // Created by Dimitri Giani on 16/10/2016. 6 | // Copyright © 2016 Dimitri Giani. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool 17 | { 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 | -------------------------------------------------------------------------------- /Demo/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 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Demo/Demo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Demo/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 | 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 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /Demo/Demo/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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | UIViewControllerBasedStatusBarAppearance 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Demo/Demo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Demo 4 | // 5 | // Created by Dimitri Giani on 16/10/2016. 6 | // Copyright © 2016 Dimitri Giani. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // Very bad Class, but just for Demo ;-) 12 | 13 | class Image: NSObject, ImageSlideShowProtocol 14 | { 15 | private let url: URL 16 | let title: String? 17 | 18 | init(title: String, url: URL) { 19 | self.title = title 20 | self.url = url 21 | } 22 | 23 | func slideIdentifier() -> String { 24 | return String(describing: url) 25 | } 26 | 27 | func image(completion: @escaping (_ image: UIImage?, _ error: Error?) -> Void) { 28 | 29 | let session = URLSession(configuration: URLSessionConfiguration.default) 30 | session.dataTask(with: self.url) { data, response, error in 31 | 32 | if let data = data, error == nil 33 | { 34 | let image = UIImage(data: data) 35 | completion(image, nil) 36 | } 37 | else 38 | { 39 | completion(nil, error) 40 | } 41 | 42 | }.resume() 43 | 44 | } 45 | } 46 | 47 | class ViewController: UIViewController { 48 | 49 | fileprivate var images:[Image] = [] 50 | 51 | override func viewDidLoad() { 52 | super.viewDidLoad() 53 | 54 | self.generateImages() 55 | } 56 | 57 | override func didReceiveMemoryWarning() { 58 | super.didReceiveMemoryWarning() 59 | // Dispose of any resources that can be recreated. 60 | } 61 | 62 | fileprivate func generateImages() 63 | { 64 | let scale:Int = Int(UIScreen.main.scale) 65 | let height:Int = Int(view.frame.size.height) * scale 66 | let width:Int = Int(view.frame.size.width) * scale 67 | 68 | images = [ 69 | Image(title: "Image 1", url: URL(string: "https://dummyimage.com/\(width)x\(height)/09a/fff.png&text=Image+1")!), 70 | Image(title: "Image 2", url: URL(string: "https://dummyimage.com/\(600)x\(600)/09b/fff.png&text=Image+2")!), 71 | Image(title: "Image 3", url: URL(string: "https://dummyimage.com/\(width)x\(height)/09c/fff.png&text=Image+3")!), 72 | Image(title: "Image 4", url: URL(string: "https://dummyimage.com/\(600)x\(600)/09d/fff.png&text=Image+4")!), 73 | Image(title: "Image 5", url: URL(string: "https://dummyimage.com/\(width)x\(height)/09e/fff.png&text=Image+5")!), 74 | Image(title: "Image 6", url: URL(string: "https://dummyimage.com/\(width)x\(height)/09f/fff.png&text=Image+6")!), 75 | ] 76 | } 77 | 78 | @IBAction func presentSlideShow(_ sender:AnyObject?) 79 | { 80 | ImageSlideShowViewController.presentFrom(self){ [weak self] controller in 81 | 82 | controller.dismissOnPanGesture = true 83 | controller.slides = self?.images 84 | controller.enableZoom = true 85 | controller.controllerDidDismiss = { 86 | debugPrint("Controller Dismissed") 87 | 88 | debugPrint("last index viewed: \(controller.currentIndex)") 89 | } 90 | 91 | controller.slideShowViewDidLoad = { 92 | debugPrint("Did Load") 93 | } 94 | 95 | controller.slideShowViewWillAppear = { animated in 96 | debugPrint("Will Appear Animated: \(animated)") 97 | } 98 | 99 | controller.slideShowViewDidAppear = { animated in 100 | debugPrint("Did Appear Animated: \(animated)") 101 | } 102 | 103 | } 104 | } 105 | } 106 | 107 | -------------------------------------------------------------------------------- /Demo/ImageSlideShow/ImageSlideShow.h: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSlideShow.h 3 | // ImageSlideShow 4 | // 5 | // Created by Lasse Hansen on 24/05/2017. 6 | // Copyright © 2017 Dimitri Giani. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for ImageSlideShow. 12 | FOUNDATION_EXPORT double ImageSlideShowVersionNumber; 13 | 14 | //! Project version string for ImageSlideShow. 15 | FOUNDATION_EXPORT const unsigned char ImageSlideShowVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Demo/ImageSlideShow/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 | -------------------------------------------------------------------------------- /ImageSlideShowSwift.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ImageSlideShowSwift" 3 | s.version = "0.1.8" 4 | s.summary = "A simple Swift 5 Slideshow for iOS" 5 | s.description = "ImageSlideShow is a simple Slideshow for images (Picture, Photos) for your apps written in Swift 5." 6 | s.homepage = "https://github.com/dimix/ImageSlideShow" 7 | s.screenshots = "https://raw.githubusercontent.com/dimix/ImageSlideShow/master/demo.gif" 8 | s.license = "MIT" 9 | s.author = { "Dimitri Giani" => "dimitri.giani@gmail.com" } 10 | s.platform = :ios, "9.0" 11 | s.ios.deployment_target = "9.3" 12 | s.source = { :git => "https://github.com/dimix/ImageSlideShow.git", :tag => "#{s.version}" } 13 | s.source_files = "Classes", "Sources/ImageSlideShow/**/**/*.{swift}" 14 | s.resources = "Sources/ImageSlideShow/Storyboard/*.{png,jpeg,jpg,storyboard,xib}" 15 | s.framework = "UIKit" 16 | end 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Dimitri Giani 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "ImageSlideShow", 8 | platforms: [ 9 | .iOS(.v10) 10 | ], 11 | products: [ 12 | .library( 13 | name: "ImageSlideShow", 14 | targets: ["ImageSlideShow"]), 15 | ], 16 | dependencies: [], 17 | targets: [ 18 | .target( 19 | name: "ImageSlideShow", 20 | dependencies: [], 21 | resources: [.process("Storyboard")] 22 | ) 23 | ] 24 | ) 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![License](https://img.shields.io/cocoapods/l/ImageSlideShowSwift.svg?style=flat) 2 | ![Platform](https://img.shields.io/badge/platform-ios-lightgray.svg?style=flat) 3 | ![Version](https://img.shields.io/cocoapods/v/ImageSlideShowSwift.svg?style=flat) 4 | ![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat) 5 | 6 | # Swift ImageSlideShow for iOS 7 | ImageSlideShow is a simple Slideshow for images (Picture, Photos) for your iOS apps written in Swift 5. 8 | You can use this class on iPhone and iPad as well. 9 | 10 | ![alt tag](https://raw.githubusercontent.com/dimix/ImageSlideShow/e6e9a62db2b4c82b58d5b298ef6802c0a8125970/demo.gif) 11 | 12 | ## Features 13 | - All in one slideshow with generic protocol to provide images directly from the model 14 | - Pan-gesture-to-dismiss behaviour (like Facebook) 15 | 16 | ## Installation with CocoaPods 17 | 18 | [CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like ImageSlideShow in your projects. You can install it with the following command: 19 | 20 | ```bash 21 | $ gem install cocoapods 22 | ``` 23 | 24 | > CocoaPods 1.0.1+ is required to build ImageSlideShow (along with Swift 5 and Xcode 10). 25 | 26 | #### Podfile 27 | 28 | To integrate ImageSlideShow into your Xcode project using CocoaPods, specify it in your `Podfile`: 29 | 30 | ```ruby 31 | source 'https://github.com/CocoaPods/Specs.git' 32 | platform :ios, '9.0' 33 | 34 | target 'TargetName' do 35 | use_frameworks! 36 | pod 'ImageSlideShowSwift' 37 | end 38 | ``` 39 | 40 | Then, run the following command: 41 | 42 | ```bash 43 | $ pod install 44 | ``` 45 | 46 | ## Installation with Carthage 47 | Currently only iOS is supported. 48 | 49 | 1. Add the following to your [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile): 50 | 51 | ``` 52 | github "dimix/ImageSlideShow" 53 | ``` 54 | 55 | 2. Run `carthage update --platform ios` 56 | 57 | 3. Copy the framework into your project and you are good to go. 58 | 59 | ## How to Use 60 | 61 | #### 1. Import ImageSlideShowSwift module 62 | 63 | ```swift 64 | Import ImageSlideShowSwift 65 | ``` 66 | 67 | ImageSlideShowSwift 68 | #### 2. Instantiate the controller 69 | 70 | ```swift 71 | ImageSlideShowViewController.presentFrom(self){ [weak self] controller in 72 | 73 | controller.dismissOnPanGesture = true 74 | controller.slides = self?.images 75 | controller.enableZoom = true 76 | controller.controllerDidDismiss = { 77 | print("Controller Dismissed") 78 | } 79 | 80 | } 81 | ``` 82 | 83 | You need to provide an array of `[ImageSlideShowProtocol]` objects. 84 | You can use the Demo project to watch details. 85 | 86 | ## Requirements 87 | 88 | Current version is compatible with: 89 | 90 | * Swift 5.0 91 | * XCode 10 92 | * iOS 9 or later 93 | 94 | Are you searching for an old (unsupported) version? Check out: 95 | 96 | * [Swift 2.3](https://github.com/dimix/ImageSlideShow/tree/feature/swift2.3) 97 | * [Swift 3](https://github.com/dimix/ImageSlideShow/tree/tags/0.1.2) 98 | * [Swift 4](https://github.com/dimix/ImageSlideShow/tree/tags/0.1.5) 99 | 100 | ## Credits 101 | 102 | Thanks to Lasse-Hansen for the Carthage support! 103 | -------------------------------------------------------------------------------- /Sources/ImageSlideShow/Classes/ImageSlideShowNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSlideShowNavigationController.swift 3 | // 4 | // Created by Dimitri Giani on 27/10/2016. 5 | // Copyright © 2016 Dimitri Giani. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class ImageSlideShowNavigationController: UINavigationController 11 | { 12 | override var childForStatusBarStyle: UIViewController? 13 | { 14 | return topViewController 15 | } 16 | 17 | override var prefersStatusBarHidden:Bool 18 | { 19 | if let prefersStatusBarHidden = viewControllers.last?.prefersStatusBarHidden 20 | { 21 | return prefersStatusBarHidden 22 | } 23 | 24 | return false 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ImageSlideShow/Classes/ImageSlideShowViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSlideShowViewController.swift 3 | // 4 | // Created by Dimitri Giani on 02/11/15. 5 | // Copyright © 2015 Dimitri Giani. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | public protocol ImageSlideShowProtocol 11 | { 12 | var title: String? { get } 13 | 14 | func slideIdentifier() -> String 15 | func image(completion: @escaping (_ image:UIImage?, _ error:Error?) -> Void) 16 | } 17 | 18 | class ImageSlideShowCache: NSCache 19 | { 20 | override init() 21 | { 22 | super.init() 23 | 24 | NotificationCenter.default.addObserver(self, selector:#selector(NSMutableArray.removeAllObjects), name: UIApplication.didReceiveMemoryWarningNotification, object: nil) 25 | } 26 | 27 | deinit 28 | { 29 | NotificationCenter.default.removeObserver(self); 30 | } 31 | } 32 | 33 | open class ImageSlideShowViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate 34 | { 35 | static var imageSlideShowStoryboard:UIStoryboard = UIStoryboard(name: "ImageSlideShow", bundle: Bundle.module) 36 | 37 | open var slides: [ImageSlideShowProtocol]? 38 | open var initialIndex: Int = 0 39 | open var pageSpacing: CGFloat = 10.0 40 | open var panDismissTolerance: CGFloat = 30.0 41 | open var dismissOnPanGesture: Bool = false 42 | open var enableZoom: Bool = false 43 | open var statusBarStyle: UIStatusBarStyle = .lightContent 44 | open var navigationBarTintColor: UIColor = .white 45 | open var hideNavigationBarOnAction: Bool = true 46 | 47 | // Current index and slide 48 | public var currentIndex: Int { 49 | return _currentIndex 50 | } 51 | public var currentSlide: ImageSlideShowProtocol? { 52 | return slides?[currentIndex] 53 | } 54 | 55 | public var slideShowViewDidLoad: (()->())? 56 | public var slideShowViewWillAppear: ((_ animated: Bool)-> ())? 57 | public var slideShowViewDidAppear: ((_ animated: Bool)-> ())? 58 | 59 | open var controllerDidDismiss:() -> Void = {} 60 | open var stepAnimate:((_ offset:CGFloat, _ viewController:UIViewController) -> Void) = { _,_ in } 61 | open var restoreAnimation:((_ viewController:UIViewController) -> Void) = { _ in } 62 | open var dismissAnimation:((_ viewController:UIViewController, _ panDirection:CGPoint, _ completion: @escaping ()->()) -> Void) = { _,_,_ in } 63 | 64 | fileprivate var originPanViewCenter:CGPoint = .zero 65 | fileprivate var panViewCenter:CGPoint = .zero 66 | fileprivate var navigationBarHidden = false 67 | fileprivate var toggleBarButtonItem:UIBarButtonItem? 68 | fileprivate var _currentIndex: Int = 0 69 | fileprivate let slidesViewControllerCache = ImageSlideShowCache() 70 | 71 | override open var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { 72 | return .fade 73 | } 74 | 75 | override open var preferredStatusBarStyle: UIStatusBarStyle 76 | { 77 | return statusBarStyle 78 | } 79 | 80 | override open var prefersStatusBarHidden: Bool 81 | { 82 | return navigationBarHidden 83 | } 84 | 85 | override open var shouldAutorotate: Bool 86 | { 87 | return true 88 | } 89 | 90 | override open var supportedInterfaceOrientations: UIInterfaceOrientationMask 91 | { 92 | return .all 93 | } 94 | 95 | // MARK: - Class methods 96 | 97 | class func imageSlideShowNavigationController() -> ImageSlideShowNavigationController 98 | { 99 | let controller = ImageSlideShowViewController.imageSlideShowStoryboard.instantiateViewController(withIdentifier: "ImageSlideShowNavigationController") as! ImageSlideShowNavigationController 100 | controller.modalPresentationStyle = .overFullScreen 101 | controller.modalPresentationCapturesStatusBarAppearance = true 102 | 103 | return controller 104 | } 105 | 106 | class func imageSlideShowViewController() -> ImageSlideShowViewController 107 | { 108 | let controller = ImageSlideShowViewController.imageSlideShowStoryboard.instantiateViewController(withIdentifier: "ImageSlideShowViewController") as! ImageSlideShowViewController 109 | controller.modalPresentationStyle = .overCurrentContext 110 | controller.modalPresentationCapturesStatusBarAppearance = true 111 | 112 | return controller 113 | } 114 | 115 | class open func presentFrom(_ viewController:UIViewController, configure:((_ controller: ImageSlideShowViewController) -> ())?) 116 | { 117 | let navController = self.imageSlideShowNavigationController() 118 | if let issViewController = navController.visibleViewController as? ImageSlideShowViewController 119 | { 120 | configure?(issViewController) 121 | 122 | viewController.present(navController, animated: true, completion: nil) 123 | } 124 | } 125 | 126 | required public init?(coder: NSCoder) 127 | { 128 | super.init(coder: coder) 129 | 130 | prepareAnimations() 131 | } 132 | 133 | // MARK: - Instance methods 134 | 135 | override open func viewDidLoad() 136 | { 137 | super.viewDidLoad() 138 | 139 | delegate = self 140 | dataSource = self 141 | 142 | hidesBottomBarWhenPushed = true 143 | 144 | navigationController?.navigationBar.tintColor = navigationBarTintColor 145 | navigationController?.view.backgroundColor = .black 146 | navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(dismiss(sender:))) 147 | 148 | // Manage Gestures 149 | 150 | var gestures = gestureRecognizers 151 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapGesture(gesture:))) 152 | gestures.append(tapGesture) 153 | 154 | if (dismissOnPanGesture) 155 | { 156 | let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGesture(gesture:))) 157 | gestures.append(panGesture) 158 | 159 | // If dismiss on pan lock horizontal direction and disable vertical pan to avoid strange behaviours 160 | 161 | scrollView()?.isDirectionalLockEnabled = true 162 | scrollView()?.alwaysBounceVertical = false 163 | } 164 | 165 | view.gestureRecognizers = gestures 166 | 167 | slideShowViewDidLoad?() 168 | } 169 | 170 | override open func viewWillAppear(_ animated: Bool) 171 | { 172 | super.viewWillAppear(animated) 173 | 174 | setPage(withIndex: initialIndex) 175 | 176 | slideShowViewWillAppear?(animated) 177 | } 178 | 179 | override open func viewDidAppear(_ animated: Bool) 180 | { 181 | super.viewDidAppear(animated) 182 | 183 | slideShowViewDidAppear?(animated) 184 | } 185 | 186 | // MARK: Actions 187 | 188 | @objc open func dismiss(sender:AnyObject?) 189 | { 190 | dismiss(animated: true, completion: nil) 191 | 192 | controllerDidDismiss() 193 | } 194 | 195 | open func goToPage(withIndex index:Int) 196 | { 197 | if index != _currentIndex 198 | { 199 | setPage(withIndex: index) 200 | } 201 | } 202 | 203 | open func goToNextPage() 204 | { 205 | let index = _currentIndex + 1 206 | if index < (slides?.count)! 207 | { 208 | setPage(withIndex: index) 209 | } 210 | } 211 | 212 | open func goToPreviousPage() 213 | { 214 | let index = _currentIndex - 1 215 | if index >= 0 216 | { 217 | setPage(withIndex: index) 218 | } 219 | } 220 | 221 | func setPage(withIndex index:Int) 222 | { 223 | if let viewController = slideViewController(forPageIndex: index) 224 | { 225 | setViewControllers([viewController], direction: (index > _currentIndex ? .forward : .reverse), animated: true, completion: nil) 226 | 227 | _currentIndex = index 228 | 229 | updateSlideBasedUI() 230 | } 231 | } 232 | 233 | func setNavigationBar(visible:Bool) 234 | { 235 | guard hideNavigationBarOnAction else { return } 236 | 237 | navigationBarHidden = !visible 238 | 239 | navigationController?.setNavigationBarHidden(!visible, animated: true) 240 | 241 | UIView.animate(withDuration: 0.23) { self.setNeedsStatusBarAppearanceUpdate() } 242 | } 243 | 244 | // MARK: UIPageViewControllerDataSource 245 | 246 | public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) 247 | { 248 | self.setNavigationBar(visible: false) 249 | } 250 | 251 | public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 252 | { 253 | if completed 254 | { 255 | _currentIndex = indexOfSlideForViewController(viewController: (pageViewController.viewControllers?.last)!) 256 | 257 | updateSlideBasedUI() 258 | } 259 | } 260 | 261 | public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? 262 | { 263 | let index = indexOfSlideForViewController(viewController: viewController) 264 | 265 | if index > 0 266 | { 267 | return slideViewController(forPageIndex: index - 1) 268 | } 269 | else 270 | { 271 | return nil 272 | } 273 | } 274 | 275 | public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? 276 | { 277 | let index = indexOfSlideForViewController(viewController: viewController) 278 | 279 | if let slides = slides, index < slides.count - 1 280 | { 281 | return slideViewController(forPageIndex: index + 1) 282 | } 283 | else 284 | { 285 | return nil 286 | } 287 | } 288 | 289 | // MARK: Accessories 290 | 291 | private func indexOfProtocolObject(inSlideViewController controller: ImageSlideViewController) -> Int? 292 | { 293 | var index = 0 294 | 295 | if let object = controller.slide, 296 | let slides = slides 297 | { 298 | for slide in slides 299 | { 300 | if slide.slideIdentifier() == object.slideIdentifier() 301 | { 302 | return index 303 | } 304 | 305 | index += 1 306 | } 307 | } 308 | 309 | return nil 310 | } 311 | 312 | private func indexOfSlideForViewController(viewController: UIViewController) -> Int 313 | { 314 | guard let viewController = viewController as? ImageSlideViewController else { fatalError("Unexpected view controller type in page view controller.") } 315 | guard let viewControllerIndex = indexOfProtocolObject(inSlideViewController: viewController) else { fatalError("View controller's data item not found.") } 316 | 317 | return viewControllerIndex 318 | } 319 | 320 | private func slideViewController(forPageIndex pageIndex: Int) -> ImageSlideViewController? 321 | { 322 | if let slides = slides, slides.count > 0 323 | { 324 | let slide = slides[pageIndex] 325 | 326 | if let cachedController = slidesViewControllerCache.object(forKey: slide.slideIdentifier() as AnyObject) as? ImageSlideViewController 327 | { 328 | return cachedController 329 | } 330 | else 331 | { 332 | guard let controller = self.storyboard?.instantiateViewController(withIdentifier: "ImageSlideViewController") as? ImageSlideViewController else { fatalError("Unable to instantiate a ImageSlideViewController.") } 333 | controller.slide = slide 334 | controller.enableZoom = enableZoom 335 | controller.willBeginZoom = { 336 | self.setNavigationBar(visible: false) 337 | } 338 | 339 | slidesViewControllerCache.setObject(controller, forKey: slide.slideIdentifier() as AnyObject) 340 | 341 | return controller 342 | } 343 | } 344 | 345 | return nil 346 | } 347 | 348 | private func prepareAnimations() 349 | { 350 | stepAnimate = { step, viewController in 351 | 352 | if let viewController = viewController as? ImageSlideViewController 353 | { 354 | if step == 0 355 | { 356 | viewController.imageView?.layer.shadowRadius = 10 357 | viewController.imageView?.layer.shadowOpacity = 0.3 358 | } 359 | else 360 | { 361 | let alpha = CGFloat(1.0 - step) 362 | 363 | self.navigationController?.navigationBar.alpha = 0.0 364 | self.navigationController?.view.backgroundColor = UIColor.black.withAlphaComponent(max(0.2, alpha * 0.9)) 365 | 366 | let scale = max(0.8, alpha) 367 | 368 | viewController.imageView?.center = self.panViewCenter 369 | viewController.imageView?.transform = CGAffineTransform(scaleX: scale, y: scale) 370 | } 371 | } 372 | } 373 | restoreAnimation = { viewController in 374 | 375 | if let viewController = viewController as? ImageSlideViewController 376 | { 377 | UIView.animate(withDuration: 0.2, 378 | delay: 0.0, 379 | options: .beginFromCurrentState, 380 | animations: { 381 | 382 | self.presentingViewController?.view.transform = .identity 383 | 384 | viewController.imageView?.center = self.originPanViewCenter 385 | viewController.imageView?.transform = CGAffineTransform(scaleX: 1.0, y: 1.0) 386 | viewController.imageView?.layer.shadowRadius = 0 387 | viewController.imageView?.layer.shadowOpacity = 0 388 | 389 | }, completion: nil) 390 | } 391 | } 392 | dismissAnimation = { viewController, panDirection, completion in 393 | 394 | if let viewController = viewController as? ImageSlideViewController 395 | { 396 | let velocity = panDirection.y 397 | 398 | UIView.animate(withDuration: 0.3, 399 | delay: 0.0, 400 | options: .beginFromCurrentState, 401 | animations: { 402 | 403 | self.presentingViewController?.view.transform = .identity 404 | 405 | var frame = viewController.imageView?.frame ?? .zero 406 | frame.origin.y = (velocity > 0 ? self.view.frame.size.height*2 : -self.view.frame.size.height) 407 | viewController.imageView?.transform = .identity 408 | viewController.imageView?.frame = frame 409 | viewController.imageView?.alpha = 0.0 410 | 411 | }, completion: { completed in 412 | 413 | completion() 414 | 415 | }) 416 | } 417 | } 418 | } 419 | 420 | private func updateSlideBasedUI() 421 | { 422 | if let title = currentSlide?.title 423 | { 424 | navigationItem.title = title 425 | } 426 | } 427 | 428 | // MARK: Gestures 429 | 430 | @objc private func tapGesture(gesture:UITapGestureRecognizer) 431 | { 432 | setNavigationBar(visible: navigationBarHidden == true); 433 | } 434 | 435 | @objc private func panGesture(gesture:UIPanGestureRecognizer) 436 | { 437 | let viewController = slideViewController(forPageIndex: currentIndex) 438 | 439 | switch gesture.state 440 | { 441 | case .began: 442 | presentingViewController?.view.transform = CGAffineTransform(scaleX: 0.95, y: 0.95) 443 | 444 | originPanViewCenter = view.center 445 | panViewCenter = view.center 446 | 447 | stepAnimate(0, viewController!) 448 | 449 | case .changed: 450 | let translation = gesture.translation(in: view) 451 | panViewCenter = CGPoint(x: panViewCenter.x + translation.x, y: panViewCenter.y + translation.y) 452 | 453 | gesture.setTranslation(.zero, in: view) 454 | 455 | let distanceX = abs(originPanViewCenter.x - panViewCenter.x) 456 | let distanceY = abs(originPanViewCenter.y - panViewCenter.y) 457 | let distance = max(distanceX, distanceY) 458 | let center = max(originPanViewCenter.x, originPanViewCenter.y) 459 | 460 | let distanceNormalized = max(0, min((distance / center), 1.0)) 461 | 462 | stepAnimate(distanceNormalized, viewController!) 463 | 464 | case .ended, .cancelled, .failed: 465 | let distanceY = abs(originPanViewCenter.y - panViewCenter.y) 466 | 467 | if (distanceY >= panDismissTolerance) 468 | { 469 | UIView.animate(withDuration: 0.3, 470 | delay: 0.0, 471 | options: .beginFromCurrentState, 472 | animations: { () -> Void in 473 | 474 | self.navigationController?.view.alpha = 0.0 475 | }, completion:nil) 476 | 477 | dismissAnimation(viewController!, gesture.velocity(in: gesture.view), { 478 | 479 | self.dismiss(sender: nil) 480 | 481 | }) 482 | } 483 | else 484 | { 485 | UIView.animate(withDuration: 0.2, 486 | delay: 0.0, 487 | options: .beginFromCurrentState, 488 | animations: { () -> Void in 489 | 490 | self.navigationBarHidden = true 491 | self.navigationController?.navigationBar.alpha = 0.0 492 | self.navigationController?.view.backgroundColor = .black 493 | 494 | }, completion: nil) 495 | 496 | restoreAnimation(viewController!) 497 | } 498 | 499 | default: 500 | break; 501 | } 502 | } 503 | } 504 | -------------------------------------------------------------------------------- /Sources/ImageSlideShow/Classes/ImageSlideViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageSlideViewController.swift 3 | // 4 | // Created by Dimitri Giani on 02/11/15. 5 | // Copyright © 2015 Dimitri Giani. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | class ImageSlideViewController: UIViewController, UIScrollViewDelegate 11 | { 12 | @IBOutlet weak var scrollView:UIScrollView? 13 | @IBOutlet weak var imageView:UIImageView? 14 | @IBOutlet weak var loadingIndicatorView:UIActivityIndicatorView? 15 | 16 | var slide:ImageSlideShowProtocol? 17 | var enableZoom = false 18 | 19 | var willBeginZoom:() -> Void = {} 20 | 21 | override func viewDidLoad() 22 | { 23 | super.viewDidLoad() 24 | 25 | if enableZoom 26 | { 27 | scrollView?.maximumZoomScale = 2.0 28 | scrollView?.minimumZoomScale = 1.0 29 | scrollView?.zoomScale = 1.0 30 | } 31 | 32 | scrollView?.isHidden = true 33 | loadingIndicatorView?.startAnimating() 34 | 35 | slide?.image(completion: { (image, error) -> Void in 36 | 37 | DispatchQueue.main.async { 38 | 39 | self.imageView?.image = image 40 | self.loadingIndicatorView?.stopAnimating() 41 | self.scrollView?.isHidden = false 42 | 43 | } 44 | 45 | }) 46 | } 47 | 48 | override func viewDidDisappear(_ animated: Bool) 49 | { 50 | super.viewDidDisappear(animated) 51 | 52 | if enableZoom 53 | { 54 | // Reset zoom scale when the controller is hidden 55 | 56 | scrollView?.zoomScale = 1.0 57 | } 58 | } 59 | 60 | // MARK: UIScrollViewDelegate 61 | 62 | func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) 63 | { 64 | willBeginZoom() 65 | } 66 | 67 | func viewForZooming(in scrollView: UIScrollView) -> UIView? 68 | { 69 | if enableZoom 70 | { 71 | return imageView 72 | } 73 | 74 | return nil 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Sources/ImageSlideShow/Extensions/UIPageViewController+ImageSlideShow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIPageViewController+Extensions.swift 3 | // 4 | // Created by Dimitri Giani on 14/01/16. 5 | // Copyright © 2016 Dimitri Giani. All rights reserved. 6 | // 7 | 8 | import UIKit 9 | 10 | extension UIPageViewController 11 | { 12 | // ScrollView 13 | 14 | func scrollView() -> UIScrollView? 15 | { 16 | for view in view.subviews 17 | { 18 | if let scrollview = view as? UIScrollView 19 | { 20 | return scrollview 21 | } 22 | } 23 | 24 | return nil 25 | } 26 | 27 | func setScrollEnabled(enabled:Bool) 28 | { 29 | scrollView()?.isScrollEnabled = enabled 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/ImageSlideShow/Storyboard/ImageSlideShow.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 | 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 | 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 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dimix/ImageSlideShow/e4aefd924b326c6b1c90c6d371c79d594ccc82fd/demo.gif --------------------------------------------------------------------------------