From 6801acb951cdda481e294f8e7cb03d6b23f0f6d6 Mon Sep 17 00:00:00 2001 From: Vahagn Mkrtchyan Date: Mon, 15 Aug 2016 23:14:54 +0400 Subject: [PATCH] iOS 8 Support --- .../project.pbxproj | 174 +++++++++++++----- .../contents.xcworkspacedata | 10 + .../Athlee-Onboarding/AppDelegate.swift | 1 + .../Base.lproj/Main.storyboard | 12 +- .../Athlee-Onboarding/DataModel.swift | 1 + .../OnboardingViewController.swift | 1 + Example/Athlee-Onboarding/Podfile | 10 + Example/Athlee-Onboarding/Podfile.lock | 19 ++ OnboardingKit.podspec | 4 +- Source/Anchor.swift | 166 +++++++++++++++++ Source/OnboardingView.swift | 56 ++++-- Source/PageControlView.swift | 34 ++-- Source/PageItemView.swift | 50 +++-- Source/PageView.swift | 148 ++++++++++----- 14 files changed, 547 insertions(+), 139 deletions(-) create mode 100644 Example/Athlee-Onboarding/Athlee-Onboarding.xcworkspace/contents.xcworkspacedata create mode 100644 Example/Athlee-Onboarding/Podfile create mode 100644 Example/Athlee-Onboarding/Podfile.lock create mode 100644 Source/Anchor.swift diff --git a/Example/Athlee-Onboarding/Athlee-Onboarding.xcodeproj/project.pbxproj b/Example/Athlee-Onboarding/Athlee-Onboarding.xcodeproj/project.pbxproj index 0855479..a1946f3 100644 --- a/Example/Athlee-Onboarding/Athlee-Onboarding.xcodeproj/project.pbxproj +++ b/Example/Athlee-Onboarding/Athlee-Onboarding.xcodeproj/project.pbxproj @@ -7,23 +7,16 @@ objects = { /* Begin PBXBuildFile section */ - 040D629F1D2DE93B003F8D8E /* CGRect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 040D629E1D2DE93B003F8D8E /* CGRect.swift */; }; - 040D62A11D2DE959003F8D8E /* CompletionObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 040D62A01D2DE959003F8D8E /* CompletionObject.swift */; }; 044DE4991D2DE19300968E90 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 044DE4981D2DE19300968E90 /* Assets.xcassets */; }; 044DE49C1D2DE1B400968E90 /* DataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE49A1D2DE1B400968E90 /* DataModel.swift */; }; 044DE49D1D2DE1B400968E90 /* DeviceTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE49B1D2DE1B400968E90 /* DeviceTarget.swift */; }; 044DE49F1D2DE1BB00968E90 /* OnboardingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE49E1D2DE1BB00968E90 /* OnboardingViewController.swift */; }; - 044DE4A81D2DE21F00968E90 /* OnboardingConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A11D2DE21F00968E90 /* OnboardingConfiguration.swift */; }; - 044DE4A91D2DE21F00968E90 /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A21D2DE21F00968E90 /* OnboardingView.swift */; }; - 044DE4AA1D2DE21F00968E90 /* OnboardingViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A31D2DE21F00968E90 /* OnboardingViewDataSource.swift */; }; - 044DE4AB1D2DE21F00968E90 /* OnboardingViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A41D2DE21F00968E90 /* OnboardingViewDelegate.swift */; }; - 044DE4AC1D2DE21F00968E90 /* PageControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A51D2DE21F00968E90 /* PageControlView.swift */; }; - 044DE4AD1D2DE21F00968E90 /* PageItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A61D2DE21F00968E90 /* PageItemView.swift */; }; - 044DE4AE1D2DE21F00968E90 /* PageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044DE4A71D2DE21F00968E90 /* PageView.swift */; }; 04ED1B521D2DE0850027C2E0 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED1B511D2DE0850027C2E0 /* AppDelegate.swift */; }; 04ED1B571D2DE0850027C2E0 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04ED1B551D2DE0850027C2E0 /* Main.storyboard */; }; 04ED1B5C1D2DE0850027C2E0 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 04ED1B5A1D2DE0850027C2E0 /* LaunchScreen.storyboard */; }; 04ED1B671D2DE0860027C2E0 /* Athlee_OnboardingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04ED1B661D2DE0850027C2E0 /* Athlee_OnboardingTests.swift */; }; + 0A1450A46C9383CB57865B43 /* Pods_Athlee_OnboardingTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43BE41427EF870546655C1B2 /* Pods_Athlee_OnboardingTests.framework */; }; + 330B9E0A1E845689149EF478 /* Pods_Athlee_Onboarding.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2C9BFA9BBF68A04C488C7F0B /* Pods_Athlee_Onboarding.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -37,19 +30,10 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 040D629E1D2DE93B003F8D8E /* CGRect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGRect.swift; sourceTree = ""; }; - 040D62A01D2DE959003F8D8E /* CompletionObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompletionObject.swift; sourceTree = ""; }; 044DE4981D2DE19300968E90 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 044DE49A1D2DE1B400968E90 /* DataModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataModel.swift; sourceTree = ""; }; 044DE49B1D2DE1B400968E90 /* DeviceTarget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceTarget.swift; sourceTree = ""; }; 044DE49E1D2DE1BB00968E90 /* OnboardingViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingViewController.swift; sourceTree = ""; }; - 044DE4A11D2DE21F00968E90 /* OnboardingConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingConfiguration.swift; sourceTree = ""; }; - 044DE4A21D2DE21F00968E90 /* OnboardingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = ""; }; - 044DE4A31D2DE21F00968E90 /* OnboardingViewDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingViewDataSource.swift; sourceTree = ""; }; - 044DE4A41D2DE21F00968E90 /* OnboardingViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardingViewDelegate.swift; sourceTree = ""; }; - 044DE4A51D2DE21F00968E90 /* PageControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageControlView.swift; sourceTree = ""; }; - 044DE4A61D2DE21F00968E90 /* PageItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageItemView.swift; sourceTree = ""; }; - 044DE4A71D2DE21F00968E90 /* PageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageView.swift; sourceTree = ""; }; 04ED1B4E1D2DE0850027C2E0 /* Athlee-Onboarding.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Athlee-Onboarding.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 04ED1B511D2DE0850027C2E0 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 04ED1B561D2DE0850027C2E0 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -58,6 +42,12 @@ 04ED1B621D2DE0850027C2E0 /* Athlee-OnboardingTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Athlee-OnboardingTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 04ED1B661D2DE0850027C2E0 /* Athlee_OnboardingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Athlee_OnboardingTests.swift; sourceTree = ""; }; 04ED1B681D2DE0860027C2E0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2C9BFA9BBF68A04C488C7F0B /* Pods_Athlee_Onboarding.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Athlee_Onboarding.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3543B87E02A45ABB4134504C /* Pods-Athlee-Onboarding.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Athlee-Onboarding.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Athlee-Onboarding/Pods-Athlee-Onboarding.debug.xcconfig"; sourceTree = ""; }; + 43BE41427EF870546655C1B2 /* Pods_Athlee_OnboardingTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Athlee_OnboardingTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7C93DF902F661D08A8347396 /* Pods-Athlee-Onboarding.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Athlee-Onboarding.release.xcconfig"; path = "Pods/Target Support Files/Pods-Athlee-Onboarding/Pods-Athlee-Onboarding.release.xcconfig"; sourceTree = ""; }; + AB2C84A837CAFD705DA5E16C /* Pods-Athlee-OnboardingTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Athlee-OnboardingTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Athlee-OnboardingTests/Pods-Athlee-OnboardingTests.release.xcconfig"; sourceTree = ""; }; + C7B4B729A6FF099FA381F6E1 /* Pods-Athlee-OnboardingTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Athlee-OnboardingTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Athlee-OnboardingTests/Pods-Athlee-OnboardingTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -65,6 +55,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 330B9E0A1E845689149EF478 /* Pods_Athlee_Onboarding.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -72,27 +63,22 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0A1450A46C9383CB57865B43 /* Pods_Athlee_OnboardingTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 044DE4A01D2DE21F00968E90 /* Source */ = { + 029E5614525F10F652573B4F /* Pods */ = { isa = PBXGroup; children = ( - 044DE4A11D2DE21F00968E90 /* OnboardingConfiguration.swift */, - 044DE4A21D2DE21F00968E90 /* OnboardingView.swift */, - 044DE4A31D2DE21F00968E90 /* OnboardingViewDataSource.swift */, - 044DE4A41D2DE21F00968E90 /* OnboardingViewDelegate.swift */, - 044DE4A51D2DE21F00968E90 /* PageControlView.swift */, - 044DE4A61D2DE21F00968E90 /* PageItemView.swift */, - 044DE4A71D2DE21F00968E90 /* PageView.swift */, - 040D629E1D2DE93B003F8D8E /* CGRect.swift */, - 040D62A01D2DE959003F8D8E /* CompletionObject.swift */, - ); - name = Source; - path = ../../Source; + 3543B87E02A45ABB4134504C /* Pods-Athlee-Onboarding.debug.xcconfig */, + 7C93DF902F661D08A8347396 /* Pods-Athlee-Onboarding.release.xcconfig */, + C7B4B729A6FF099FA381F6E1 /* Pods-Athlee-OnboardingTests.debug.xcconfig */, + AB2C84A837CAFD705DA5E16C /* Pods-Athlee-OnboardingTests.release.xcconfig */, + ); + name = Pods; sourceTree = ""; }; 044DE4AF1D2DE23400968E90 /* Application */ = { @@ -107,10 +93,11 @@ 04ED1B451D2DE0850027C2E0 = { isa = PBXGroup; children = ( - 044DE4A01D2DE21F00968E90 /* Source */, 04ED1B501D2DE0850027C2E0 /* Athlee-Onboarding */, 04ED1B651D2DE0850027C2E0 /* Athlee-OnboardingTests */, 04ED1B4F1D2DE0850027C2E0 /* Products */, + 029E5614525F10F652573B4F /* Pods */, + 37BB9CB1B60009A32E4915C0 /* Frameworks */, ); sourceTree = ""; }; @@ -194,6 +181,15 @@ name = Storyboards; sourceTree = ""; }; + 37BB9CB1B60009A32E4915C0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 2C9BFA9BBF68A04C488C7F0B /* Pods_Athlee_Onboarding.framework */, + 43BE41427EF870546655C1B2 /* Pods_Athlee_OnboardingTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -201,9 +197,12 @@ isa = PBXNativeTarget; buildConfigurationList = 04ED1B6B1D2DE0860027C2E0 /* Build configuration list for PBXNativeTarget "Athlee-Onboarding" */; buildPhases = ( + E7D51D9C7607102474279EF2 /* [CP] Check Pods Manifest.lock */, 04ED1B4A1D2DE0850027C2E0 /* Sources */, 04ED1B4B1D2DE0850027C2E0 /* Frameworks */, 04ED1B4C1D2DE0850027C2E0 /* Resources */, + 816AA3088A140479B6C012E1 /* [CP] Embed Pods Frameworks */, + BD488DBD26354F84179123B7 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -218,9 +217,12 @@ isa = PBXNativeTarget; buildConfigurationList = 04ED1B6E1D2DE0860027C2E0 /* Build configuration list for PBXNativeTarget "Athlee-OnboardingTests" */; buildPhases = ( + B69F19D7DD82080813B79B8B /* [CP] Check Pods Manifest.lock */, 04ED1B5E1D2DE0850027C2E0 /* Sources */, 04ED1B5F1D2DE0850027C2E0 /* Frameworks */, 04ED1B601D2DE0850027C2E0 /* Resources */, + EBAD7B0F8F069CC8FF33D162 /* [CP] Embed Pods Frameworks */, + A56D3886D44BDAD81149DAF8 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -290,24 +292,108 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 816AA3088A140479B6C012E1 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Athlee-Onboarding/Pods-Athlee-Onboarding-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A56D3886D44BDAD81149DAF8 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Athlee-OnboardingTests/Pods-Athlee-OnboardingTests-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + B69F19D7DD82080813B79B8B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + BD488DBD26354F84179123B7 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Athlee-Onboarding/Pods-Athlee-Onboarding-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; + E7D51D9C7607102474279EF2 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + EBAD7B0F8F069CC8FF33D162 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Athlee-OnboardingTests/Pods-Athlee-OnboardingTests-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 04ED1B4A1D2DE0850027C2E0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 044DE4AB1D2DE21F00968E90 /* OnboardingViewDelegate.swift in Sources */, 04ED1B521D2DE0850027C2E0 /* AppDelegate.swift in Sources */, 044DE49D1D2DE1B400968E90 /* DeviceTarget.swift in Sources */, 044DE49C1D2DE1B400968E90 /* DataModel.swift in Sources */, - 044DE4A91D2DE21F00968E90 /* OnboardingView.swift in Sources */, - 040D62A11D2DE959003F8D8E /* CompletionObject.swift in Sources */, 044DE49F1D2DE1BB00968E90 /* OnboardingViewController.swift in Sources */, - 044DE4A81D2DE21F00968E90 /* OnboardingConfiguration.swift in Sources */, - 040D629F1D2DE93B003F8D8E /* CGRect.swift in Sources */, - 044DE4AA1D2DE21F00968E90 /* OnboardingViewDataSource.swift in Sources */, - 044DE4AE1D2DE21F00968E90 /* PageView.swift in Sources */, - 044DE4AD1D2DE21F00968E90 /* PageItemView.swift in Sources */, - 044DE4AC1D2DE21F00968E90 /* PageControlView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -434,9 +520,11 @@ }; 04ED1B6C1D2DE0860027C2E0 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 3543B87E02A45ABB4134504C /* Pods-Athlee-Onboarding.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "Athlee-Onboarding/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-Onboarding"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -445,9 +533,11 @@ }; 04ED1B6D1D2DE0860027C2E0 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 7C93DF902F661D08A8347396 /* Pods-Athlee-Onboarding.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "Athlee-Onboarding/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.athlee.Athlee-Onboarding"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -456,6 +546,7 @@ }; 04ED1B6F1D2DE0860027C2E0 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = C7B4B729A6FF099FA381F6E1 /* Pods-Athlee-OnboardingTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = "Athlee-OnboardingTests/Info.plist"; @@ -468,6 +559,7 @@ }; 04ED1B701D2DE0860027C2E0 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = AB2C84A837CAFD705DA5E16C /* Pods-Athlee-OnboardingTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; INFOPLIST_FILE = "Athlee-OnboardingTests/Info.plist"; diff --git a/Example/Athlee-Onboarding/Athlee-Onboarding.xcworkspace/contents.xcworkspacedata b/Example/Athlee-Onboarding/Athlee-Onboarding.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..ae09fe6 --- /dev/null +++ b/Example/Athlee-Onboarding/Athlee-Onboarding.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Example/Athlee-Onboarding/Athlee-Onboarding/AppDelegate.swift b/Example/Athlee-Onboarding/Athlee-Onboarding/AppDelegate.swift index e2dea46..55611f3 100644 --- a/Example/Athlee-Onboarding/Athlee-Onboarding/AppDelegate.swift +++ b/Example/Athlee-Onboarding/Athlee-Onboarding/AppDelegate.swift @@ -7,6 +7,7 @@ // import UIKit +import OnboardingKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { diff --git a/Example/Athlee-Onboarding/Athlee-Onboarding/Base.lproj/Main.storyboard b/Example/Athlee-Onboarding/Athlee-Onboarding/Base.lproj/Main.storyboard index 1c1affc..302171c 100644 --- a/Example/Athlee-Onboarding/Athlee-Onboarding/Base.lproj/Main.storyboard +++ b/Example/Athlee-Onboarding/Athlee-Onboarding/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - - + + @@ -18,10 +18,6 @@ - - - - + + + + diff --git a/Example/Athlee-Onboarding/Athlee-Onboarding/DataModel.swift b/Example/Athlee-Onboarding/Athlee-Onboarding/DataModel.swift index 8b7c046..b6060e6 100644 --- a/Example/Athlee-Onboarding/Athlee-Onboarding/DataModel.swift +++ b/Example/Athlee-Onboarding/Athlee-Onboarding/DataModel.swift @@ -7,6 +7,7 @@ // import UIKit +import OnboardingKit public final class DataModel: NSObject, OnboardingViewDelegate, OnboardingViewDataSource { diff --git a/Example/Athlee-Onboarding/Athlee-Onboarding/OnboardingViewController.swift b/Example/Athlee-Onboarding/Athlee-Onboarding/OnboardingViewController.swift index 86f10f5..7951b34 100644 --- a/Example/Athlee-Onboarding/Athlee-Onboarding/OnboardingViewController.swift +++ b/Example/Athlee-Onboarding/Athlee-Onboarding/OnboardingViewController.swift @@ -7,6 +7,7 @@ // import UIKit +import OnboardingKit public final class OnboardingViewController: UIViewController { diff --git a/Example/Athlee-Onboarding/Podfile b/Example/Athlee-Onboarding/Podfile new file mode 100644 index 0000000..4648f9a --- /dev/null +++ b/Example/Athlee-Onboarding/Podfile @@ -0,0 +1,10 @@ +use_frameworks! + +target 'Athlee-Onboarding' do + pod 'OnboardingKit', :path => '../../' + + target 'Athlee-OnboardingTests' do + inherit! :search_paths + + end +end diff --git a/Example/Athlee-Onboarding/Podfile.lock b/Example/Athlee-Onboarding/Podfile.lock new file mode 100644 index 0000000..17d7a43 --- /dev/null +++ b/Example/Athlee-Onboarding/Podfile.lock @@ -0,0 +1,19 @@ +PODS: + - OnboardingKit (0.0.2): + - TZStackView + - TZStackView (1.2.0) + +DEPENDENCIES: + - OnboardingKit (from `../../`) + +EXTERNAL SOURCES: + OnboardingKit: + :path: ../../ + +SPEC CHECKSUMS: + OnboardingKit: c37eb2110ca3d8f40fc2ad78e54965b04216a66c + TZStackView: 4b82373b4aabe4d99adf739a34e1bc6755149272 + +PODFILE CHECKSUM: 4428256f7d1d2fab9e9f0fbe4e8ec9cda004ba00 + +COCOAPODS: 1.0.1 diff --git a/OnboardingKit.podspec b/OnboardingKit.podspec index 1c99fdc..3e5328f 100644 --- a/OnboardingKit.podspec +++ b/OnboardingKit.podspec @@ -16,9 +16,11 @@ Pod::Spec.new do |s| s.author = { "Eugene Mozharovsky" => "mozharovsky@live.com" } s.social_media_url = "http://twitter.com/dottieyottie" s.platform = :ios, "9.0" - s.ios.deployment_target = "9.0" + s.ios.deployment_target = "8.0" s.source = { :git => "https://github.com/Athlee/OnboardingKit.git", :tag => s.version } s.source_files = "Source/*.swift" s.requires_arc = true + s.dependency 'TZStackView' + end diff --git a/Source/Anchor.swift b/Source/Anchor.swift new file mode 100644 index 0000000..a10c442 --- /dev/null +++ b/Source/Anchor.swift @@ -0,0 +1,166 @@ +// +// Anchor.swift +// AnchorTest +// +// Created by Jonathan Wight on 7/10/15. +// Copyright © 2015 schwa.io. All rights reserved. +// + +#if os(OSX) + import AppKit + internal typealias View = NSView +#elseif os(iOS) + import UIKit + internal typealias View = UIView +#endif + +public extension View { + var anchors:Anchors { + return Anchors(item:self) + } +} + +public struct Anchors { + internal let item:View + + internal init(item:View) { + self.item = item + } + + public var leadingAnchor: LayoutXAxisAnchor { + return LayoutXAxisAnchor(item:item, attribute:.Leading) + } + public var trailingAnchor: LayoutXAxisAnchor { + return LayoutXAxisAnchor(item:item, attribute:.Trailing) + } + public var leftAnchor: LayoutXAxisAnchor { + return LayoutXAxisAnchor(item:item, attribute:.Left) + } + public var rightAnchor: LayoutXAxisAnchor { + return LayoutXAxisAnchor(item:item, attribute:.Right) + } + public var topAnchor: LayoutYAxisAnchor { + return LayoutYAxisAnchor(item:item, attribute:.Top) + } + public var bottomAnchor: LayoutYAxisAnchor { + return LayoutYAxisAnchor(item:item, attribute:.Bottom) + } + public var widthAnchor: LayoutDimension { + return LayoutDimension(item:item, attribute:.Width) + } + public var heightAnchor: LayoutDimension { + return LayoutDimension(item:item, attribute:.Height) + } + public var centerXAnchor: LayoutXAxisAnchor { + return LayoutXAxisAnchor(item:item, attribute:.CenterX) + } + public var centerYAnchor: LayoutYAxisAnchor { + return LayoutYAxisAnchor(item:item, attribute:.CenterY) + } +} + + +// MARK: - + +/* + An NSLayoutAnchor represents an edge or dimension of a layout item. Its concrete subclasses allow concise creation of constraints. The idea is that instead of invoking +[NSLayoutConstraint constraintWithItem: attribute: relatedBy: toItem: attribute: multiplier: constant:] directly, you can instead do something like this: + + [myView.topAnchor constraintEqualToAnchor:otherView.topAnchor constant:10]; + + The -constraint* methods are available in multiple flavors to support use of different relations and omission of unused options. + + */ + +public class LayoutAnchor { + + internal var item:View + internal var attribute:NSLayoutAttribute + + internal init(item:View, attribute:NSLayoutAttribute) { + self.item = item + self.attribute = attribute + } + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor. + public func constraintEqualToAnchor(anchor: LayoutAnchor) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .Equal, toItem: anchor.item, attribute: anchor.attribute, multiplier: 1.0, constant: 0.0) + } + + public func constraintGreaterThanOrEqualToAnchor(anchor: LayoutAnchor) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .GreaterThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: 1.0, constant: 0.0) + } + + public func constraintLessThanOrEqualToAnchor(anchor: LayoutAnchor) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .LessThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: 1.0, constant: 0.0) + } + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor + constant. + public func constraintEqualToAnchor(anchor: LayoutAnchor, constant c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .Equal, toItem: anchor.item, attribute: anchor.attribute, multiplier: 1.0, constant: c) + } + + public func constraintGreaterThanOrEqualToAnchor(anchor: LayoutAnchor, constant c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .GreaterThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: 1.0, constant: c) + } + + public func constraintLessThanOrEqualToAnchor(anchor: LayoutAnchor, constant c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .LessThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: 1.0, constant: c) + } +} + +// MARK: - + +// Axis-specific subclasses for location anchors: top/bottom, leading/trailing, baseline, etc. +public class LayoutXAxisAnchor : LayoutAnchor { +} + +public class LayoutYAxisAnchor : LayoutAnchor { +} + +// MARK: - + +/* + This layout anchor subclass is used for sizes (width & height). + */ + +public class LayoutDimension : LayoutAnchor { + + // These methods return an inactive constraint of the form thisVariable = constant. + public func constraintEqualToConstant(c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .Equal, toItem: nil, attribute:.NotAnAttribute, multiplier: 1.0, constant: c) + } + + public func constraintGreaterThanOrEqualToConstant(c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .GreaterThanOrEqual, toItem: nil, attribute:.NotAnAttribute, multiplier: 1.0, constant: c) + } + + public func constraintLessThanOrEqualToConstant(c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .LessThanOrEqual, toItem: nil, attribute:.NotAnAttribute, multiplier: 1.0, constant: c) + } + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier. + public func constraintEqualToAnchor(anchor: LayoutDimension, multiplier m: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .Equal, toItem: anchor.item, attribute: anchor.attribute, multiplier: m, constant: 0) + } + + public func constraintGreaterThanOrEqualToAnchor(anchor: LayoutDimension, multiplier m: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .GreaterThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: m, constant: 0) + } + + public func constraintLessThanOrEqualToAnchor(anchor: LayoutDimension, multiplier m: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .LessThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: m, constant: 0) + } + + // These methods return an inactive constraint of the form thisAnchor = otherAnchor * multiplier + constant. + public func constraintEqualToAnchor(anchor: LayoutDimension, multiplier m: CGFloat, constant c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .Equal, toItem: anchor.item, attribute: anchor.attribute, multiplier: m, constant: c) + } + + public func constraintGreaterThanOrEqualToAnchor(anchor: LayoutDimension, multiplier m: CGFloat, constant c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .GreaterThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: m, constant: c) + } + + public func constraintLessThanOrEqualToAnchor(anchor: LayoutDimension, multiplier m: CGFloat, constant c: CGFloat) -> NSLayoutConstraint { + return NSLayoutConstraint(item: item, attribute: attribute, relatedBy: .LessThanOrEqual, toItem: anchor.item, attribute: anchor.attribute, multiplier: m, constant: c) + } +} \ No newline at end of file diff --git a/Source/OnboardingView.swift b/Source/OnboardingView.swift index 54edaf0..424d08b 100644 --- a/Source/OnboardingView.swift +++ b/Source/OnboardingView.swift @@ -75,16 +75,29 @@ public final class OnboardingView: UIView { insertSubview(pageControlView, atIndex: Int.max) pageControlView.translatesAutoresizingMaskIntoConstraints = false - bottomPageControlViewAnchor = pageControlView.bottomAnchor.constraintEqualToAnchor(bottomAnchor, constant: -bottomPageControlViewOffset)! - - let pageControlViewAnchors = [ - pageControlView.leadingAnchor.constraintEqualToAnchor(leadingAnchor, constant: 8), - pageControlView.trailingAnchor.constraintEqualToAnchor(trailingAnchor, constant: -8), - bottomPageControlViewAnchor, - pageControlView.heightAnchor.constraintEqualToConstant(PageControlView.radiusExpanded) - ].flatMap { $0 } + if #available(iOS 9.0, *) { + bottomPageControlViewAnchor = pageControlView.bottomAnchor.constraintEqualToAnchor(bottomAnchor, constant: -bottomPageControlViewOffset)! + } else { + bottomPageControlViewAnchor = pageControlView.anchors.bottomAnchor.constraintEqualToAnchor(anchors.bottomAnchor, constant: -bottomPageControlViewOffset) + } - NSLayoutConstraint.activateConstraints(pageControlViewAnchors) + if #available(iOS 9.0, *) { + let pageControlViewAnchors = [ + pageControlView.leadingAnchor.constraintEqualToAnchor(leadingAnchor, constant: 8), + pageControlView.trailingAnchor.constraintEqualToAnchor(trailingAnchor, constant: -8), + bottomPageControlViewAnchor, + pageControlView.heightAnchor.constraintEqualToConstant(PageControlView.radiusExpanded) + ].flatMap { $0 } + NSLayoutConstraint.activateConstraints(pageControlViewAnchors) + } else { + let pageControlViewAnchors = [ + pageControlView.anchors.leadingAnchor.constraintEqualToAnchor(anchors.leadingAnchor, constant: 8), + pageControlView.anchors.trailingAnchor.constraintEqualToAnchor(anchors.trailingAnchor, constant: -8), + bottomPageControlViewAnchor, + pageControlView.anchors.heightAnchor.constraintEqualToConstant(PageControlView.radiusExpanded) + ].flatMap { $0 } + NSLayoutConstraint.activateConstraints(pageControlViewAnchors) + } // Add resture recognizers addRecognizers() @@ -119,14 +132,23 @@ public final class OnboardingView: UIView { pageView.translatesAutoresizingMaskIntoConstraints = false - let anchors = [ - pageView.leadingAnchor.constraintEqualToAnchor(leadingAnchor), - pageView.trailingAnchor.constraintEqualToAnchor(trailingAnchor), - pageView.topAnchor.constraintEqualToAnchor(topAnchor), - pageView.bottomAnchor.constraintEqualToAnchor(bottomAnchor) - ].flatMap { $0 } - - NSLayoutConstraint.activateConstraints(anchors) + if #available(iOS 9.0, *) { + let anchors = [ + pageView.leadingAnchor.constraintEqualToAnchor(leadingAnchor), + pageView.trailingAnchor.constraintEqualToAnchor(trailingAnchor), + pageView.topAnchor.constraintEqualToAnchor(topAnchor), + pageView.bottomAnchor.constraintEqualToAnchor(bottomAnchor) + ].flatMap { $0 } + NSLayoutConstraint.activateConstraints(anchors) + } else { + let _anchors = [ + pageView.anchors.leadingAnchor.constraintEqualToAnchor(anchors.leadingAnchor), + pageView.anchors.trailingAnchor.constraintEqualToAnchor(anchors.trailingAnchor), + pageView.anchors.topAnchor.constraintEqualToAnchor(anchors.topAnchor), + pageView.anchors.bottomAnchor.constraintEqualToAnchor(anchors.bottomAnchor) + ].flatMap { $0 } + NSLayoutConstraint.activateConstraints(_anchors) + } pageView.configuration = config diff --git a/Source/PageControlView.swift b/Source/PageControlView.swift index b668eff..501bb6f 100644 --- a/Source/PageControlView.swift +++ b/Source/PageControlView.swift @@ -7,6 +7,7 @@ // import UIKit +import TZStackView public final class PageControlView: UIView { @@ -45,7 +46,7 @@ public final class PageControlView: UIView { public var items: [PageItemView] = [] - private var stackView = UIStackView() + private var stackView = TZStackView() private var stackViewCenterXAnchor: NSLayoutConstraint! private var stackViewWidthAnchor: NSLayoutConstraint! @@ -89,17 +90,26 @@ public final class PageControlView: UIView { let height = PageControlView.radiusExpanded * 2 stackView.translatesAutoresizingMaskIntoConstraints = false - stackViewCenterXAnchor = stackView.centerXAnchor.constraintEqualToAnchor(centerXAnchor)! - stackViewWidthAnchor = stackView.widthAnchor.constraintEqualToConstant(width)! + stackViewCenterXAnchor = stackView.anchors.centerXAnchor.constraintEqualToAnchor(anchors.centerXAnchor) + stackViewWidthAnchor = stackView.anchors.widthAnchor.constraintEqualToConstant(width) - let anchors = [ - stackViewWidthAnchor, - stackView.heightAnchor.constraintEqualToConstant(height), - stackViewCenterXAnchor, - stackView.centerYAnchor.constraintEqualToAnchor(centerYAnchor) - ].flatMap { $0 } - - NSLayoutConstraint.activateConstraints(anchors) + if #available(iOS 9.0, *) { + let anchors = [ + stackViewWidthAnchor, + stackView.heightAnchor.constraintEqualToConstant(height), + stackViewCenterXAnchor, + stackView.centerYAnchor.constraintEqualToAnchor(centerYAnchor) + ].flatMap { $0 } + NSLayoutConstraint.activateConstraints(anchors) + } else { + let _anchors = [ + stackViewWidthAnchor, + stackView.anchors.heightAnchor.constraintEqualToConstant(height), + stackViewCenterXAnchor, + stackView.anchors.centerYAnchor.constraintEqualToAnchor(anchors.centerYAnchor) + ].flatMap { $0 } + NSLayoutConstraint.activateConstraints(_anchors) + } for _ in 0..