7 Commits

Author SHA1 Message Date
i.kolpachkov 30defb3edd bump pod version 2018-01-19 02:03:45 +03:00
i.kolpachkov 1fabddd191 update travis config, setup swift version 2018-01-19 01:26:14 +03:00
i.kolpachkov 8d33009aec add demo icon, configure launch storyboard, code cleanup 2018-01-18 20:32:07 +03:00
i.kolpachkov af7ef6e828 update swift format 2018-01-17 11:34:25 +03:00
i.kolpachkov f13ab0900b remove test target 2018-01-15 18:31:19 +03:00
Alex K 2555a951e5 update podspec 2017-11-27 15:35:48 +03:00
Alex K e0042171f0 update podspec and readme 2017-11-27 15:07:23 +03:00
31 changed files with 614 additions and 737 deletions
+1
View File
@@ -0,0 +1 @@
4.0
+7 -2
View File
@@ -1,6 +1,11 @@
osx_image: xcode9
osx_image: xcode9.2
language: objective-c
xcode_project: NavigationStackDemo.xcodeproj
xcode_scheme: NavigationStack
xcode_sdk: iphonesimulator
xcode_sdk: iphonesimulator11.2
# whitelist
branches:
only:
- master
+1 -1
View File
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Navigation-stack'
s.version = '1.0.1'
s.version = '2.0.2'
s.summary = 'Show list of navigationControllers'
s.license = 'MIT'
s.homepage = 'https://github.com/Ramotion/navigation-stack'
+5 -135
View File
@@ -8,8 +8,6 @@
/* Begin PBXBuildFile section */
840D54101C8705FA00555605 /* FirstTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D540F1C8705FA00555605 /* FirstTableViewController.swift */; };
842FF8E11C8707BD0030E758 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B0EF1C80238500B53B4E /* AppDelegate.swift */; };
842FF8E51C8707DA0030E758 /* FirstTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D540F1C8705FA00555605 /* FirstTableViewController.swift */; };
84368B3F1CFEDDB1007C4278 /* NavigationStack.h in Headers */ = {isa = PBXBuildFile; fileRef = 84368B3E1CFEDDB1007C4278 /* NavigationStack.h */; settings = {ATTRIBUTES = (Public, ); }; };
84368B431CFEDDB1007C4278 /* NavigationStack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 84368B3C1CFEDDB1007C4278 /* NavigationStack.framework */; };
84368B441CFEDDB1007C4278 /* NavigationStack.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 84368B3C1CFEDDB1007C4278 /* NavigationStack.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -21,20 +19,11 @@
8444B0F51C80238500B53B4E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8444B0F31C80238500B53B4E /* Main.storyboard */; };
8444B0F71C80238500B53B4E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8444B0F61C80238500B53B4E /* Assets.xcassets */; };
8444B0FA1C80238500B53B4E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8444B0F81C80238500B53B4E /* LaunchScreen.storyboard */; };
8444B1051C80238500B53B4E /* NavigationStackDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1041C80238500B53B4E /* NavigationStackDemoTests.swift */; };
8444B1271C80250A00B53B4E /* CollectionViewStackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1201C80250A00B53B4E /* CollectionViewStackCell.swift */; };
8444B1281C80250A00B53B4E /* CollectionViewStackFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1221C80250A00B53B4E /* CollectionViewStackFlowLayout.swift */; };
8444B1291C80250A00B53B4E /* CollectionStackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1231C80250A00B53B4E /* CollectionStackViewController.swift */; };
8444B12B1C80250A00B53B4E /* NavigationStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1261C80250A00B53B4E /* NavigationStack.swift */; };
84500F201C87044100B0550E /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847B0FB01C846C6100E2C54D /* SecondViewController.swift */; };
84500F221C87044500B0550E /* ThirdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847B0FAC1C846B9200E2C54D /* ThirdViewController.swift */; };
84500F261C87044B00B0550E /* FifthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847B0FA81C846B8100E2C54D /* FifthViewController.swift */; };
84500F281C87045000B0550E /* CollectionViewStackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1201C80250A00B53B4E /* CollectionViewStackCell.swift */; };
84500F2A1C87045400B0550E /* CollectionViewStackFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1221C80250A00B53B4E /* CollectionViewStackFlowLayout.swift */; };
84500F2C1C87045700B0550E /* CollectionStackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1231C80250A00B53B4E /* CollectionStackViewController.swift */; };
84500F2E1C87045B00B0550E /* NavigationStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8444B1261C80250A00B53B4E /* NavigationStack.swift */; };
846302891C8ABC340015CD81 /* OpenSans-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 846302881C8ABC340015CD81 /* OpenSans-Regular.ttf */; };
8479994C1C870EB50050D164 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8444B0F31C80238500B53B4E /* Main.storyboard */; };
847B0FA91C846B8100E2C54D /* FifthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847B0FA81C846B8100E2C54D /* FifthViewController.swift */; };
847B0FAD1C846B9200E2C54D /* ThirdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847B0FAC1C846B9200E2C54D /* ThirdViewController.swift */; };
847B0FB11C846C6100E2C54D /* SecondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847B0FB01C846C6100E2C54D /* SecondViewController.swift */; };
@@ -50,13 +39,6 @@
remoteGlobalIDString = 84368B3B1CFEDDB1007C4278;
remoteInfo = NavigationStack;
};
8444B1011C80238500B53B4E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 8444B0E41C80238500B53B4E /* Project object */;
proxyType = 1;
remoteGlobalIDString = 8444B0EB1C80238500B53B4E;
remoteInfo = NavigationStackDemo;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -78,15 +60,12 @@
84368B3C1CFEDDB1007C4278 /* NavigationStack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NavigationStack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
84368B3E1CFEDDB1007C4278 /* NavigationStack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NavigationStack.h; sourceTree = "<group>"; };
84368B401CFEDDB1007C4278 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8444B0EC1C80238500B53B4E /* NavigationStackDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NavigationStackDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
8444B0EC1C80238500B53B4E /* Navigation Stack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Navigation Stack.app"; sourceTree = BUILT_PRODUCTS_DIR; };
8444B0EF1C80238500B53B4E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
8444B0F41C80238500B53B4E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
8444B0F61C80238500B53B4E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
8444B0F91C80238500B53B4E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
8444B0FB1C80238500B53B4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8444B1001C80238500B53B4E /* NavigationStackDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NavigationStackDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
8444B1041C80238500B53B4E /* NavigationStackDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationStackDemoTests.swift; sourceTree = "<group>"; };
8444B1061C80238500B53B4E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8444B1201C80250A00B53B4E /* CollectionViewStackCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewStackCell.swift; sourceTree = "<group>"; };
8444B1221C80250A00B53B4E /* CollectionViewStackFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewStackFlowLayout.swift; sourceTree = "<group>"; };
8444B1231C80250A00B53B4E /* CollectionStackViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionStackViewController.swift; sourceTree = "<group>"; };
@@ -115,13 +94,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8444B0FD1C80238500B53B4E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
@@ -138,7 +110,6 @@
isa = PBXGroup;
children = (
8444B0EE1C80238500B53B4E /* NavigationStackDemo */,
8444B1031C80238500B53B4E /* NavigationStackDemoTests */,
84368B3D1CFEDDB1007C4278 /* NavigationStack */,
8444B0ED1C80238500B53B4E /* Products */,
);
@@ -147,8 +118,7 @@
8444B0ED1C80238500B53B4E /* Products */ = {
isa = PBXGroup;
children = (
8444B0EC1C80238500B53B4E /* NavigationStackDemo.app */,
8444B1001C80238500B53B4E /* NavigationStackDemoTests.xctest */,
8444B0EC1C80238500B53B4E /* Navigation Stack.app */,
84368B3C1CFEDDB1007C4278 /* NavigationStack.framework */,
);
name = Products;
@@ -168,15 +138,6 @@
path = NavigationStackDemo;
sourceTree = "<group>";
};
8444B1031C80238500B53B4E /* NavigationStackDemoTests */ = {
isa = PBXGroup;
children = (
8444B1041C80238500B53B4E /* NavigationStackDemoTests.swift */,
8444B1061C80238500B53B4E /* Info.plist */,
);
path = NavigationStackDemoTests;
sourceTree = "<group>";
};
8444B11D1C80247500B53B4E /* Source */ = {
isa = PBXGroup;
children = (
@@ -315,27 +276,9 @@
);
name = NavigationStackDemo;
productName = NavigationStackDemo;
productReference = 8444B0EC1C80238500B53B4E /* NavigationStackDemo.app */;
productReference = 8444B0EC1C80238500B53B4E /* Navigation Stack.app */;
productType = "com.apple.product-type.application";
};
8444B0FF1C80238500B53B4E /* NavigationStackDemoTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 8444B1171C80238500B53B4E /* Build configuration list for PBXNativeTarget "NavigationStackDemoTests" */;
buildPhases = (
8444B0FC1C80238500B53B4E /* Sources */,
8444B0FD1C80238500B53B4E /* Frameworks */,
8444B0FE1C80238500B53B4E /* Resources */,
);
buildRules = (
);
dependencies = (
8444B1021C80238500B53B4E /* PBXTargetDependency */,
);
name = NavigationStackDemoTests;
productName = NavigationStackDemoTests;
productReference = 8444B1001C80238500B53B4E /* NavigationStackDemoTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -356,11 +299,6 @@
DevelopmentTeam = 34MUF9YXTA;
LastSwiftMigration = 0900;
};
8444B0FF1C80238500B53B4E = {
CreatedOnToolsVersion = 7.2.1;
LastSwiftMigration = 0900;
TestTargetID = 8444B0EB1C80238500B53B4E;
};
};
};
buildConfigurationList = 8444B0E71C80238500B53B4E /* Build configuration list for PBXProject "NavigationStackDemo" */;
@@ -377,7 +315,6 @@
projectRoot = "";
targets = (
8444B0EB1C80238500B53B4E /* NavigationStackDemo */,
8444B0FF1C80238500B53B4E /* NavigationStackDemoTests */,
84368B3B1CFEDDB1007C4278 /* NavigationStack */,
);
};
@@ -404,14 +341,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8444B0FE1C80238500B53B4E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8479994C1C870EB50050D164 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -442,23 +371,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
8444B0FC1C80238500B53B4E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
84500F2E1C87045B00B0550E /* NavigationStack.swift in Sources */,
84500F201C87044100B0550E /* SecondViewController.swift in Sources */,
84500F221C87044500B0550E /* ThirdViewController.swift in Sources */,
8444B1051C80238500B53B4E /* NavigationStackDemoTests.swift in Sources */,
84500F2C1C87045700B0550E /* CollectionStackViewController.swift in Sources */,
84500F281C87045000B0550E /* CollectionViewStackCell.swift in Sources */,
842FF8E51C8707DA0030E758 /* FirstTableViewController.swift in Sources */,
84500F2A1C87045400B0550E /* CollectionViewStackFlowLayout.swift in Sources */,
842FF8E11C8707BD0030E758 /* AppDelegate.swift in Sources */,
84500F261C87044B00B0550E /* FifthViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
@@ -467,11 +379,6 @@
target = 84368B3B1CFEDDB1007C4278 /* NavigationStack */;
targetProxy = 84368B411CFEDDB1007C4278 /* PBXContainerItemProxy */;
};
8444B1021C80238500B53B4E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 8444B0EB1C80238500B53B4E /* NavigationStackDemo */;
targetProxy = 8444B1011C80238500B53B4E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -654,7 +561,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.NavigationStackDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_NAME = "Navigation Stack";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
@@ -670,40 +577,12 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.NavigationStackDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
PRODUCT_NAME = "Navigation Stack";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
};
name = Release;
};
8444B1181C80238500B53B4E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = NavigationStackDemoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.NavigationStackDemoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NavigationStackDemo.app/NavigationStackDemo";
};
name = Debug;
};
8444B1191C80238500B53B4E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = NavigationStackDemoTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.ramotion.NavigationStackDemoTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/NavigationStackDemo.app/NavigationStackDemo";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
@@ -734,15 +613,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
8444B1171C80238500B53B4E /* Build configuration list for PBXNativeTarget "NavigationStackDemoTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
8444B1181C80238500B53B4E /* Debug */,
8444B1191C80238500B53B4E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 8444B0E41C80238500B53B4E /* Project object */;
+10 -36
View File
@@ -27,43 +27,17 @@ import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var window: UIWindow?
func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.statusBarStyle = .lightContent
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.statusBarStyle = .lightContent
UINavigationBar.appearance().titleTextAttributes = [
NSAttributedStringKey.foregroundColor : UIColor.white,
NSAttributedStringKey.font : UIFont(name: "OpenSans-Semibold", size: 16)!
]
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// 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.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// 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.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// 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.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
UINavigationBar.appearance().titleTextAttributes = [
NSAttributedStringKey.foregroundColor: UIColor.white,
NSAttributedStringKey.font: UIFont(name: "OpenSans-Semibold", size: 16)!,
]
return true
}
}
+86 -5
View File
@@ -1,38 +1,119 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon-40.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "icon-60.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-58.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"idiom" : "iphone",
"filename" : "icon-87.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-80.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"idiom" : "iphone",
"filename" : "icon-120.png",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-120.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"idiom" : "iphone",
"filename" : "icon-180.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-20.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-29.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "icon-58.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-40.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "icon-80.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "icon-152.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "icon-167.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Ramotion.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"pre-rendered" : true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9530"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
@@ -14,14 +19,35 @@
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2018 Ramotion. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fcf-sN-ku0">
<rect key="frame" x="16" y="630" width="343" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Navigation Stack" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bCd-3b-lHA">
<rect key="frame" x="118.5" y="323" width="139" height="21"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="fcf-sN-ku0" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leadingMargin" id="811-hI-Egq"/>
<constraint firstItem="bCd-3b-lHA" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="T4x-O3-JqD"/>
<constraint firstItem="bCd-3b-lHA" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="VFr-tp-sPw"/>
<constraint firstItem="fcf-sN-ku0" firstAttribute="trailing" secondItem="Ze5-6b-2t3" secondAttribute="trailingMargin" id="dS9-pv-ebe"/>
<constraint firstItem="xb3-aO-Qok" firstAttribute="top" secondItem="fcf-sN-ku0" secondAttribute="bottom" constant="20" id="kbD-dX-t3N"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
<point key="canvasLocation" x="52" y="374.66266866566718"/>
</scene>
</scenes>
</document>
@@ -9,8 +9,8 @@
import UIKit
class FifthViewController: UITableViewController {
@IBAction func backHandler(_ sender: AnyObject) {
let _ = navigationController?.popViewController(animated: true)
}
@IBAction func backHandler(_: AnyObject) {
_ = navigationController?.popViewController(animated: true)
}
}
@@ -11,43 +11,42 @@ import UIKit
// MARK: FirstTableViewController
class FirstTableViewController: UITableViewController {
@IBOutlet var search: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.interactivePopGestureRecognizer?.delegate = self
navigationItem.titleView = search
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = navigationController {
navigationController.navigationBar.barTintColor = UIColor(red:0.4, green:0.47, blue:0.62, alpha:1)
@IBOutlet var search: UISearchBar!
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.interactivePopGestureRecognizer?.delegate = self
navigationItem.titleView = search
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let navigationController = navigationController {
navigationController.navigationBar.barTintColor = UIColor(red: 0.4, green: 0.47, blue: 0.62, alpha: 1)
}
}
override func tableView(_: UITableView, didSelectRowAt _: IndexPath) {
performSegue(withIdentifier: "push", sender: nil)
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "push", sender: nil)
}
}
// MARK: UIGestureRecognizerDelegate
extension FirstTableViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if navigationController?.viewControllers.count == 2 {
return true
func gestureRecognizerShouldBegin(_: UIGestureRecognizer) -> Bool {
if navigationController?.viewControllers.count == 2 {
return true
}
if let navigationController = self.navigationController as? NavigationStack {
navigationController.showControllers()
}
return false
}
if let navigationController = self.navigationController as? NavigationStack {
navigationController.showControllers()
}
return false
}
}
@@ -9,24 +9,22 @@
import UIKit
class SecondViewController: UITableViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// if let navigationController = navigationController {
//// navigationController.navigationBar.barTintColor = UIColor(red:0.61, green:0.86, blue:0.87, alpha:1)
//// tableView.contentOffset = CGPoint(x: 0, y: -44)
//// navigationController.navigationBar.translucent = true
//// navigationController.navigationBar.barTintColor = UIColor(red:0.61, green:0.86, blue:0.87, alpha:1)
//// tableView.contentOffset = CGPoint(x: 0, y: -44)
//// navigationController.navigationBar.translucent = true
// }
}
}
@IBAction func backHandler(_: AnyObject) {
_ = navigationController?.popViewController(animated: true)
}
@IBAction func backHandler(_ sender: AnyObject) {
let _ = navigationController?.popViewController(animated: true)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "push", sender: nil)
}
override func tableView(_: UITableView, didSelectRowAt _: IndexPath) {
performSegue(withIdentifier: "push", sender: nil)
}
}
@@ -9,20 +9,18 @@
import UIKit
class ThirdViewController: UITableViewController {
@IBInspectable var navbarColor: UIColor = .black
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@IBAction func backHandler(_ sender: AnyObject) {
let _ = navigationController?.popViewController(animated: true)
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
performSegue(withIdentifier: "push", sender: nil)
}
@IBInspectable var navbarColor: UIColor = .black
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@IBAction func backHandler(_: AnyObject) {
_ = navigationController?.popViewController(animated: true)
}
override func tableView(_: UITableView, didSelectRowAt _: IndexPath) {
performSegue(withIdentifier: "push", sender: nil)
}
}
-24
View File
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
@@ -1,36 +0,0 @@
//
// NavigationStackDemoTests.swift
// NavigationStackDemoTests
//
// Created by Alex K. on 26/02/16.
// Copyright © 2016 Alex K. All rights reserved.
//
import XCTest
@testable import NavigationStackDemo
class NavigationStackDemoTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measure {
// Put the code you want to measure the time of here.
}
}
}
+2 -2
View File
@@ -29,7 +29,7 @@ The [iPhone mockup](https://store.ramotion.com?utm_source=gthb&utm_medium=specia
## Requirements
- iOS 9.0+
- Xcode 8
- Xcode 9
## Installation
@@ -37,7 +37,7 @@ Just add the Source folder to your project.
or use [CocoaPods](https://cocoapods.org) with Podfile:
``` ruby
pod 'Navigation-stack'
pod 'Navigation-stack'
```
or [Carthage](https://github.com/Carthage/Carthage) users can simply add to their `Cartfile`:
@@ -22,83 +22,80 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
// MARK: CollectionViewStackCell
class CollectionViewStackCell: UICollectionViewCell {
internal var imageView: UIImageView?
override init(frame: CGRect) {
super.init(frame: frame)
imageView = createImageView()
createShadow()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
internal override func prepareForReuse() {
imageView?.image = nil
}
internal var imageView: UIImageView?
override init(frame: CGRect) {
super.init(frame: frame)
imageView = createImageView()
createShadow()
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
internal override func prepareForReuse() {
imageView?.image = nil
}
}
// MARK: configure
extension CollectionViewStackCell {
fileprivate func createImageView() -> UIImageView {
fileprivate func createImageView() -> UIImageView {
let imageView = UIImageView(frame: CGRect.zero)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.layer.shouldRasterize = true
contentView.addSubview(imageView)
contentView.addConstraints([
createConstraint(imageView, toItem: contentView, attribute: .top),
createConstraint(imageView, toItem: contentView, attribute: .bottom),
createConstraint(imageView, toItem: contentView, attribute: .left),
createConstraint(imageView, toItem: contentView, attribute: .right),
])
return imageView
}
fileprivate func createConstraint(_ item: UIImageView, toItem: UIView, attribute: NSLayoutAttribute) -> NSLayoutConstraint {
return NSLayoutConstraint(item: item,
attribute: attribute,
relatedBy: .equal,
toItem: toItem,
attribute: attribute,
multiplier: 1,
constant: 0)
}
fileprivate func createShadow() {
layer.masksToBounds = false;
layer.shadowOpacity = 0.30;
layer.shadowRadius = 10.0;
layer.shadowOffset = CGSize.zero;
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
layer.shouldRasterize = true;
layer.rasterizationScale = max(UIScreen.main.scale, 2.0)
}
fileprivate func addBlurOnImage(_ image: UIImageView) {
let blurEffect = UIBlurEffect(style: .dark)
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.translatesAutoresizingMaskIntoConstraints = false
imageView!.insertSubview(blurView, at: 3)
let imageView = UIImageView(frame: CGRect.zero)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.layer.shouldRasterize = true
contentView.addSubview(imageView)
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
vibrancyView.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(vibrancyView)
}
contentView.addConstraints([
createConstraint(imageView, toItem: contentView, attribute: .top),
createConstraint(imageView, toItem: contentView, attribute: .bottom),
createConstraint(imageView, toItem: contentView, attribute: .left),
createConstraint(imageView, toItem: contentView, attribute: .right),
])
return imageView
}
fileprivate func createConstraint(_ item: UIImageView, toItem: UIView, attribute: NSLayoutAttribute) -> NSLayoutConstraint {
return NSLayoutConstraint(item: item,
attribute: attribute,
relatedBy: .equal,
toItem: toItem,
attribute: attribute,
multiplier: 1,
constant: 0)
}
fileprivate func createShadow() {
layer.masksToBounds = false
layer.shadowOpacity = 0.30
layer.shadowRadius = 10.0
layer.shadowOffset = CGSize.zero
layer.shadowPath = UIBezierPath(rect: bounds).cgPath
layer.shouldRasterize = true
layer.rasterizationScale = max(UIScreen.main.scale, 2.0)
}
fileprivate func addBlurOnImage(_: UIImageView) {
let blurEffect = UIBlurEffect(style: .dark)
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.translatesAutoresizingMaskIntoConstraints = false
imageView!.insertSubview(blurView, at: 3)
let vibrancyEffect = UIVibrancyEffect(blurEffect: blurEffect)
let vibrancyView = UIVisualEffectView(effect: vibrancyEffect)
vibrancyView.translatesAutoresizingMaskIntoConstraints = false
blurView.contentView.addSubview(vibrancyView)
}
}
@@ -22,174 +22,169 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
fileprivate func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
}
// MARK: CollectionStackViewController
protocol CollectionStackViewControllerDelegate: class {
func controllerDidSelected(index: Int)
func controllerDidSelected(index: Int)
}
class CollectionStackViewController: UICollectionViewController {
fileprivate var screens: [UIImage]
fileprivate let overlay: Float
weak var delegate: CollectionStackViewControllerDelegate?
init(images: [UIImage],
delegate: CollectionStackViewControllerDelegate?,
overlay: Float,
scaleRatio: Float,
scaleValue: Float,
bgColor: UIColor = UIColor.clear,
bgView: UIView? = nil,
decelerationRate:CGFloat) {
self.screens = images
self.delegate = delegate
self.overlay = overlay
let layout = CollectionViewStackFlowLayout(itemsCount: images.count, overlay: overlay, scaleRatio: scaleRatio, scale:scaleValue)
super.init(collectionViewLayout: layout)
if let collectionView = self.collectionView {
collectionView.backgroundColor = bgColor
collectionView.backgroundView = bgView
collectionView.decelerationRate = decelerationRate
}
}
fileprivate var screens: [UIImage]
fileprivate let overlay: Float
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
configureCollectionView()
scrolltoIndex(screens.count - 1, animated: false, position: .left) // move to end
}
override func viewDidAppear(_ animated: Bool) {
guard let collectionViewLayout = self.collectionViewLayout as? CollectionViewStackFlowLayout else {
fatalError("wrong collection layout")
weak var delegate: CollectionStackViewControllerDelegate?
init(images: [UIImage],
delegate: CollectionStackViewControllerDelegate?,
overlay: Float,
scaleRatio: Float,
scaleValue: Float,
bgColor: UIColor = UIColor.clear,
bgView: UIView? = nil,
decelerationRate: CGFloat) {
screens = images
self.delegate = delegate
self.overlay = overlay
let layout = CollectionViewStackFlowLayout(itemsCount: images.count, overlay: overlay, scaleRatio: scaleRatio, scale: scaleValue)
super.init(collectionViewLayout: layout)
if let collectionView = self.collectionView {
collectionView.backgroundColor = bgColor
collectionView.backgroundView = bgView
collectionView.decelerationRate = decelerationRate
}
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
configureCollectionView()
scrolltoIndex(screens.count - 1, animated: false, position: .left) // move to end
}
override func viewDidAppear(_: Bool) {
guard let collectionViewLayout = self.collectionViewLayout as? CollectionViewStackFlowLayout else {
fatalError("wrong collection layout")
}
collectionViewLayout.openAnimating = true
scrolltoIndex(0, animated: true, position: .left) // open animation
}
collectionViewLayout.openAnimating = true
scrolltoIndex(0, animated: true, position: .left) // open animation
}
}
// MARK: configure
extension CollectionStackViewController {
fileprivate func configureCollectionView() {
guard let collectionViewLayout = self.collectionViewLayout as? UICollectionViewFlowLayout else {
fatalError("wrong collection layout")
}
collectionViewLayout.scrollDirection = .horizontal
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.register(CollectionViewStackCell.self, forCellWithReuseIdentifier: String(describing: CollectionViewStackCell.self))
}
fileprivate func configureCollectionView() {
guard let collectionViewLayout = self.collectionViewLayout as? UICollectionViewFlowLayout else {
fatalError("wrong collection layout")
}
collectionViewLayout.scrollDirection = .horizontal
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.register(CollectionViewStackCell.self, forCellWithReuseIdentifier: String(describing: CollectionViewStackCell.self))
}
}
// MARK: CollectionViewDataSource
extension CollectionStackViewController {
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return screens.count
}
override func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
if let cell = cell as? CollectionViewStackCell {
cell.imageView?.image = screens[(indexPath as NSIndexPath).row]
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: CollectionViewStackCell.self),
for: indexPath)
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let currentCell = collectionView.cellForItem(at: indexPath) else {
return
override func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
return screens.count
}
// move cells
UIView.animate(withDuration: 0.3, delay: 0, options:.curveEaseIn,
animations: { () -> Void in
for cell in self.collectionView!.visibleCells where cell != currentCell {
let row = (self.collectionView?.indexPath(for: cell) as NSIndexPath?)?.row
let xPosition = row < (indexPath as NSIndexPath).row ? cell.center.x - self.view.bounds.size.width * 2
: cell.center.x + self.view.bounds.size.width * 2
cell.center = CGPoint(x: xPosition, y: cell.center.y)
}
}, completion: nil)
// move to center current cell
UIView.animate(withDuration: 0.2, delay: 0.2, options:.curveEaseOut,
animations: { () -> Void in
let offset = collectionView.contentOffset.x - (self.view.bounds.size.width - collectionView.bounds.size.width * CGFloat(self.overlay)) * CGFloat((indexPath as NSIndexPath).row)
currentCell.center = CGPoint(x: (currentCell.center.x + offset), y: currentCell.center.y)
}, completion: nil)
// scale current cell
UIView.animate(withDuration: 0.2, delay: 0.6, options:.curveEaseOut, animations: { () -> Void in
let scale = CGAffineTransform(scaleX: 1, y: 1)
currentCell.transform = scale
currentCell.alpha = 1
}) { (success) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
self.delegate?.controllerDidSelected(index: (indexPath as NSIndexPath).row)
self.dismiss(animated: false, completion: nil)
})
override func collectionView(_: UICollectionView,
willDisplay cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
if let cell = cell as? CollectionViewStackCell {
cell.imageView?.image = screens[(indexPath as NSIndexPath).row]
}
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: CollectionViewStackCell.self),
for: indexPath)
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let currentCell = collectionView.cellForItem(at: indexPath) else {
return
}
// move cells
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseIn,
animations: { () -> Void in
for cell in self.collectionView!.visibleCells where cell != currentCell {
let row = (self.collectionView?.indexPath(for: cell) as NSIndexPath?)?.row
let xPosition = row < (indexPath as NSIndexPath).row ? cell.center.x - self.view.bounds.size.width * 2
: cell.center.x + self.view.bounds.size.width * 2
cell.center = CGPoint(x: xPosition, y: cell.center.y)
}
}, completion: nil)
// move to center current cell
UIView.animate(withDuration: 0.2, delay: 0.2, options: .curveEaseOut,
animations: { () -> Void in
let offset = collectionView.contentOffset.x - (self.view.bounds.size.width - collectionView.bounds.size.width * CGFloat(self.overlay)) * CGFloat((indexPath as NSIndexPath).row)
currentCell.center = CGPoint(x: (currentCell.center.x + offset), y: currentCell.center.y)
}, completion: nil)
// scale current cell
UIView.animate(withDuration: 0.2, delay: 0.6, options: .curveEaseOut, animations: { () -> Void in
let scale = CGAffineTransform(scaleX: 1, y: 1)
currentCell.transform = scale
currentCell.alpha = 1
}) { (_) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
self.delegate?.controllerDidSelected(index: (indexPath as NSIndexPath).row)
self.dismiss(animated: false, completion: nil)
})
}
}
}
}
// MARK: UICollectionViewDelegateFlowLayout
extension CollectionStackViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return view.bounds.size
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: NSInteger) -> CGFloat {
return -collectionView.bounds.size.width * CGFloat(overlay)
}
}
func collectionView(_: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt _: IndexPath) -> CGSize {
return view.bounds.size
}
func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, minimumLineSpacingForSectionAt _: NSInteger) -> CGFloat {
return -collectionView.bounds.size.width * CGFloat(overlay)
}
}
// MARK: Additional helpers
extension CollectionStackViewController {
fileprivate func scrolltoIndex(_ index: Int, animated: Bool , position: UICollectionViewScrollPosition) {
let indexPath = IndexPath(item: index, section: 0)
collectionView?.scrollToItem(at: indexPath, at: position, animated: animated)
}
fileprivate func scrolltoIndex(_ index: Int, animated: Bool, position: UICollectionViewScrollPosition) {
let indexPath = IndexPath(item: index, section: 0)
collectionView?.scrollToItem(at: indexPath, at: position, animated: animated)
}
}
@@ -22,125 +22,121 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
// MARK: CollectionViewStackFlowLayout
class CollectionViewStackFlowLayout: UICollectionViewFlowLayout {
let itemsCount: Int
let overlay: Float // from 0 to 1
let maxScale: Float
let scaleRatio: Float
var additionScale = 1.0
var openAnimating = false
var dxOffset: Float = 0
init(itemsCount: Int, overlay: Float, scaleRatio: Float, scale: Float) {
self.itemsCount = itemsCount
self.overlay = overlay
self.scaleRatio = scaleRatio
self.maxScale = scale
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let itemsCount: Int
let overlay: Float // from 0 to 1
let maxScale: Float
let scaleRatio: Float
var additionScale = 1.0
var openAnimating = false
var dxOffset: Float = 0
init(itemsCount: Int, overlay: Float, scaleRatio: Float, scale: Float) {
self.itemsCount = itemsCount
self.overlay = overlay
self.scaleRatio = scaleRatio
maxScale = scale
super.init()
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension CollectionViewStackFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let items = NSArray (array: super.layoutAttributesForElements(in: rect)!, copyItems: true)
var headerAttributes: UICollectionViewLayoutAttributes?
items.enumerateObjects({ (object, idex, stop) -> Void in
let attributes = object as! UICollectionViewLayoutAttributes
if attributes.representedElementKind == UICollectionElementKindSectionHeader {
headerAttributes = attributes
}
else {
self.updateCellAttributes(attributes, headerAttributes: headerAttributes)
}
})
return items as? [UICollectionViewLayoutAttributes]
}
func updateCellAttributes(_ attributes: UICollectionViewLayoutAttributes, headerAttributes: UICollectionViewLayoutAttributes?) {
guard let collectionView = self.collectionView else {
return;
}
let itemWidth = collectionView.bounds.size.width - collectionView.bounds.size.width * CGFloat(overlay)
let allWidth = itemWidth * CGFloat(itemsCount - 1)
// set contentOffset range
let contentOffsetX = min(max(0, collectionView.contentOffset.x), allWidth)
let scale = transformScale(attributes, allWidth: allWidth, offset: contentOffsetX)
let move = transformMove(attributes, itemWidth: itemWidth, offset: contentOffsetX)
attributes.transform = scale.concatenating(move)
attributes.alpha = calculateAlpha(attributes, itemWidth: itemWidth, offset: contentOffsetX)
if additionScale > 0 && openAnimating {
additionScale -= 0.02
additionScale = additionScale < 0 ? 0 : additionScale
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let items = NSArray(array: super.layoutAttributesForElements(in: rect)!, copyItems: true)
var headerAttributes: UICollectionViewLayoutAttributes?
items.enumerateObjects({ (object, _, _) -> Void in
let attributes = object as! UICollectionViewLayoutAttributes
if attributes.representedElementKind == UICollectionElementKindSectionHeader {
headerAttributes = attributes
} else {
self.updateCellAttributes(attributes, headerAttributes: headerAttributes)
}
})
return items as? [UICollectionViewLayoutAttributes]
}
func updateCellAttributes(_ attributes: UICollectionViewLayoutAttributes, headerAttributes _: UICollectionViewLayoutAttributes?) {
guard let collectionView = self.collectionView else {
return
}
let itemWidth = collectionView.bounds.size.width - collectionView.bounds.size.width * CGFloat(overlay)
let allWidth = itemWidth * CGFloat(itemsCount - 1)
// set contentOffset range
let contentOffsetX = min(max(0, collectionView.contentOffset.x), allWidth)
let scale = transformScale(attributes, allWidth: allWidth, offset: contentOffsetX)
let move = transformMove(attributes, itemWidth: itemWidth, offset: contentOffsetX)
attributes.transform = scale.concatenating(move)
attributes.alpha = calculateAlpha(attributes, itemWidth: itemWidth, offset: contentOffsetX)
if additionScale > 0 && openAnimating {
additionScale -= 0.02
additionScale = additionScale < 0 ? 0 : additionScale
}
attributes.zIndex = (attributes.indexPath as NSIndexPath).row
}
override func shouldInvalidateLayout(forBoundsChange _: CGRect) -> Bool {
return true
}
attributes.zIndex = (attributes.indexPath as NSIndexPath).row
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
}
// MARK: helpers
extension CollectionViewStackFlowLayout {
fileprivate func transformScale(_ attributes: UICollectionViewLayoutAttributes,
allWidth: CGFloat,
offset: CGFloat) -> CGAffineTransform {
var maximum = CGFloat(maxScale) - CGFloat(itemsCount - (attributes.indexPath as NSIndexPath).row) / CGFloat(scaleRatio)
maximum += CGFloat(1.0 - maximum) * CGFloat(additionScale)
var minimum = CGFloat(maxScale - 0.1) - CGFloat(itemsCount - (attributes.indexPath as NSIndexPath).row) / CGFloat(scaleRatio)
minimum += CGFloat(1.0 - minimum) * CGFloat(additionScale)
var currentScale = (maximum + minimum) - (minimum + offset / (allWidth / (maximum - minimum)))
currentScale = max(min(maximum, currentScale), minimum)
return CGAffineTransform(scaleX: currentScale, y: currentScale)
}
fileprivate func transformMove(_ attributes: UICollectionViewLayoutAttributes,
itemWidth: CGFloat,
offset: CGFloat) -> CGAffineTransform {
var currentContentOffsetX = offset - itemWidth * CGFloat((attributes.indexPath as NSIndexPath).row)
currentContentOffsetX = min(max(currentContentOffsetX, 0),itemWidth)
var dx = (currentContentOffsetX / itemWidth)
if let collectionView = self.collectionView {
dx *= collectionView.bounds.size.width / 8.0
}
dx = currentContentOffsetX - dx
fileprivate func transformScale(_ attributes: UICollectionViewLayoutAttributes,
allWidth: CGFloat,
offset: CGFloat) -> CGAffineTransform {
var maximum = CGFloat(maxScale) - CGFloat(itemsCount - (attributes.indexPath as NSIndexPath).row) / CGFloat(scaleRatio)
maximum += CGFloat(1.0 - maximum) * CGFloat(additionScale)
return CGAffineTransform(translationX: dx, y: 0)
}
fileprivate func calculateAlpha(_ attributes: UICollectionViewLayoutAttributes, itemWidth: CGFloat, offset: CGFloat) -> CGFloat {
var currentContentOffsetX = offset - itemWidth * CGFloat((attributes.indexPath as NSIndexPath).row)
currentContentOffsetX = min(max(currentContentOffsetX, 0),itemWidth)
let dx = (currentContentOffsetX / itemWidth)
return 1.0 - dx
}
var minimum = CGFloat(maxScale - 0.1) - CGFloat(itemsCount - (attributes.indexPath as NSIndexPath).row) / CGFloat(scaleRatio)
minimum += CGFloat(1.0 - minimum) * CGFloat(additionScale)
var currentScale = (maximum + minimum) - (minimum + offset / (allWidth / (maximum - minimum)))
currentScale = max(min(maximum, currentScale), minimum)
return CGAffineTransform(scaleX: currentScale, y: currentScale)
}
fileprivate func transformMove(_ attributes: UICollectionViewLayoutAttributes,
itemWidth: CGFloat,
offset: CGFloat) -> CGAffineTransform {
var currentContentOffsetX = offset - itemWidth * CGFloat((attributes.indexPath as NSIndexPath).row)
currentContentOffsetX = min(max(currentContentOffsetX, 0), itemWidth)
var dx = (currentContentOffsetX / itemWidth)
if let collectionView = self.collectionView {
dx *= collectionView.bounds.size.width / 8.0
}
dx = currentContentOffsetX - dx
return CGAffineTransform(translationX: dx, y: 0)
}
fileprivate func calculateAlpha(_ attributes: UICollectionViewLayoutAttributes, itemWidth: CGFloat, offset: CGFloat) -> CGFloat {
var currentContentOffsetX = offset - itemWidth * CGFloat((attributes.indexPath as NSIndexPath).row)
currentContentOffsetX = min(max(currentContentOffsetX, 0), itemWidth)
let dx = (currentContentOffsetX / itemWidth)
return 1.0 - dx
}
}
+120 -123
View File
@@ -22,153 +22,150 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
/// UINavigationcontroller with animation show lists of UIViewControllers
open class NavigationStack: UINavigationController {
var overlay: Float = 0.8
var scaleRatio: Float = 14.0
var scaleValue: Float = 0.99
/// A floating-point value that determines the rate of deceleration after the user lifts their finger.
@IBInspectable open var decelerationRate: CGFloat = UIScrollViewDecelerationRateNormal
/// The color to use for the background of the lists of UIViewcontrollers.
@IBInspectable open var bgColor: UIColor = .black
/// The background UIView of the lists of UIViewcontrollers.
open var bgView: UIView? = nil
fileprivate var screens = [UIImage]()
/// The delegate of the navigation controller object. Use this instead delegate.
weak open var stackDelegate: UINavigationControllerDelegate?
/**
The initialized navigation controller object or nil if there was a problem initializing the object.
- parameter aDecoder: aDecoder
- returns: The initialized navigation controller object or nil if there was a problem initializing the object.
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
delegate = self
}
/**
Initializes and returns a newly created navigation controller.
- parameter rootViewController: The view controller that resides at the bottom of the navigation stack.
- returns: The initialized navigation controller object or nil if there was a problem initializing the object.
*/
public override init(rootViewController: UIViewController) {
super.init(rootViewController: rootViewController)
delegate = self
}
/**
Necessary to prevent a crash
*/
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
var overlay: Float = 0.8
var scaleRatio: Float = 14.0
var scaleValue: Float = 0.99
/// A floating-point value that determines the rate of deceleration after the user lifts their finger.
@IBInspectable open var decelerationRate: CGFloat = UIScrollViewDecelerationRateNormal
/// The color to use for the background of the lists of UIViewcontrollers.
@IBInspectable open var bgColor: UIColor = .black
/// The background UIView of the lists of UIViewcontrollers.
open var bgView: UIView?
fileprivate var screens = [UIImage]()
/// The delegate of the navigation controller object. Use this instead delegate.
open weak var stackDelegate: UINavigationControllerDelegate?
/**
The initialized navigation controller object or nil if there was a problem initializing the object.
- parameter aDecoder: aDecoder
- returns: The initialized navigation controller object or nil if there was a problem initializing the object.
*/
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
delegate = self
}
/**
Initializes and returns a newly created navigation controller.
- parameter rootViewController: The view controller that resides at the bottom of the navigation stack.
- returns: The initialized navigation controller object or nil if there was a problem initializing the object.
*/
public override init(rootViewController: UIViewController) {
super.init(rootViewController: rootViewController)
delegate = self
}
/**
Necessary to prevent a crash
*/
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
// MARK: pulbic methods
extension NavigationStack {
/**
Show list of ViewControllers.
*/
public func showControllers() {
if screens.count == 0 {
return
}
var allScreens = screens
allScreens.append(view.takeScreenshot())
let collectioView = CollectionStackViewController(images: allScreens,
delegate: self,
overlay: overlay,
scaleRatio: scaleRatio,
scaleValue: scaleValue,
bgColor: bgColor,
bgView: bgView,
decelerationRate: decelerationRate)
present(collectioView, animated: false, completion: nil)
}
}
/**
Show list of ViewControllers.
*/
public func showControllers() {
if screens.count == 0 {
return
}
var allScreens = screens
allScreens.append(view.takeScreenshot())
let collectioView = CollectionStackViewController(images: allScreens,
delegate: self,
overlay: overlay,
scaleRatio: scaleRatio,
scaleValue: scaleValue,
bgColor: bgColor,
bgView: bgView,
decelerationRate: decelerationRate)
present(collectioView, animated: false, completion: nil)
}
}
// MARK: UINavigationControllerDelegate
extension NavigationStack: UINavigationControllerDelegate {
public func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
stackDelegate?.navigationController?(navigationController, willShow: viewController, animated: animated)
if navigationController.viewControllers.count > screens.count + 1 {
screens.append(view.takeScreenshot())
} else
if navigationController.viewControllers.count == screens.count && screens.count > 0 {
screens.removeLast()
}
}
public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
stackDelegate?.navigationController?(navigationController, didShow: viewController, animated: animated)
}
// ???
// public func navigationControllerSupportedInterfaceOrientations(navigationController: UINavigationController) -> UIInterfaceOrientationMask {
public func navigationController(_ navigationController: UINavigationController,
willShow viewController: UIViewController,
animated: Bool) {
stackDelegate?.navigationController?(navigationController, willShow: viewController, animated: animated)
if navigationController.viewControllers.count > screens.count + 1 {
screens.append(view.takeScreenshot())
} else
if navigationController.viewControllers.count == screens.count && screens.count > 0 {
screens.removeLast()
}
}
public func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
stackDelegate?.navigationController?(navigationController, didShow: viewController, animated: animated)
}
// ???
// public func navigationControllerSupportedInterfaceOrientations(navigationController: UINavigationController) -> UIInterfaceOrientationMask {
// return stackDelegate?.navigationControllerSupportedInterfaceOrientations?(navigationController)
// }
// ???
// optional public func navigationControllerPreferredInterfaceOrientationForPresentation(navigationController: UINavigationController) -> UIInterfaceOrientation
//
// }
public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return stackDelegate?.navigationController?(navigationController, interactionControllerFor: animationController)
}
// ???
// optional public func navigationControllerPreferredInterfaceOrientationForPresentation(navigationController: UINavigationController) -> UIInterfaceOrientation
//
public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return stackDelegate?.navigationController?(navigationController, animationControllerFor: operation, from: fromVC, to: toVC)
}
public func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return stackDelegate?.navigationController?(navigationController, interactionControllerFor: animationController)
}
public func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return stackDelegate?.navigationController?(navigationController, animationControllerFor: operation, from: fromVC, to: toVC)
}
}
extension NavigationStack: CollectionStackViewControllerDelegate {
func controllerDidSelected(index: Int) {
let newViewControllers = Array(viewControllers[0...index])
setViewControllers(newViewControllers, animated: false)
screens.removeSubrange(index..<screens.count)
}
func controllerDidSelected(index: Int) {
let newViewControllers = Array(viewControllers[0 ... index])
setViewControllers(newViewControllers, animated: false)
screens.removeSubrange(index ..< screens.count)
}
}
// MARK: UIView
extension UIView {
func takeScreenshot() -> UIImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale)
layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
func takeScreenshot() -> UIImage {
UIGraphicsBeginImageContextWithOptions(bounds.size, false, UIScreen.main.scale)
layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}