├── .gitignore ├── README.md ├── Tiptoes ├── Tiptoes.xcodeproj │ └── project.pbxproj └── Tiptoes │ ├── AppDelegate.swift │ ├── Base.lproj │ └── LaunchScreen.storyboard │ ├── BelowBackViewController.swift │ ├── Info.plist │ ├── TiptoesNavController.swift │ └── TopMostViewController.swift └── images ├── appstore.png ├── fade-in-and-out.gif └── tiptoes-cover.png /.gitignore: -------------------------------------------------------------------------------- 1 | Pods/ 2 | xcuserdata 3 | *.xcuserstate 4 | *.xcworkspacedata 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Description :leaves: 2 | 3 | A subclass of UINavigationController that will make the navigating process more silent and simple. 4 | 5 | ## Why You'd Want This 6 | 7 | If you are tired of using system's own navigation controller and are seeking something different, Tiptoes may suit your needs. And it doesn't break any of your existing code. Just plug and enjoy. 8 | 9 | ## Customization 10 | 11 | Actually you can customize transition effect yourself. 12 | However,the default transition effect of Tiptoes is fade-in-and-out: 13 | 14 | ![](https://i.loli.net/2017/09/26/59c9ce172882d.gif) 15 | 16 | ## Usage 17 | 18 | In the place of your setting navigationController's rootViewController code(normally in AppDelegate.swift): 19 | ``` 20 | UINavigationController(rootViewController:xxx) 21 | ``` 22 | Replace with: 23 | ``` 24 | TiptoesNavController(rootViewController:xxx) 25 | ``` 26 | And then just enjoy it! 27 | 28 | ## License 29 | 30 | MIT 31 | 32 | 33 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 674123551E279E47007E4393 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674123541E279E47007E4393 /* AppDelegate.swift */; }; 11 | 674123571E279E47007E4393 /* TopMostViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674123561E279E47007E4393 /* TopMostViewController.swift */; }; 12 | 6741235F1E279E47007E4393 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6741235D1E279E47007E4393 /* LaunchScreen.storyboard */; }; 13 | 674123671E279EBC007E4393 /* TiptoesNavController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674123661E279EBC007E4393 /* TiptoesNavController.swift */; }; 14 | 674123691E27A01F007E4393 /* BelowBackViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 674123681E27A01F007E4393 /* BelowBackViewController.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 674123511E279E47007E4393 /* Tiptoes.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Tiptoes.app; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | 674123541E279E47007E4393 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 20 | 674123561E279E47007E4393 /* TopMostViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopMostViewController.swift; sourceTree = ""; }; 21 | 6741235E1E279E47007E4393 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 22 | 674123601E279E47007E4393 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 23 | 674123661E279EBC007E4393 /* TiptoesNavController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TiptoesNavController.swift; sourceTree = ""; }; 24 | 674123681E27A01F007E4393 /* BelowBackViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BelowBackViewController.swift; sourceTree = ""; }; 25 | /* End PBXFileReference section */ 26 | 27 | /* Begin PBXFrameworksBuildPhase section */ 28 | 6741234E1E279E47007E4393 /* Frameworks */ = { 29 | isa = PBXFrameworksBuildPhase; 30 | buildActionMask = 2147483647; 31 | files = ( 32 | ); 33 | runOnlyForDeploymentPostprocessing = 0; 34 | }; 35 | /* End PBXFrameworksBuildPhase section */ 36 | 37 | /* Begin PBXGroup section */ 38 | 674123481E279E47007E4393 = { 39 | isa = PBXGroup; 40 | children = ( 41 | 674123531E279E47007E4393 /* Tiptoes */, 42 | 674123521E279E47007E4393 /* Products */, 43 | ); 44 | sourceTree = ""; 45 | }; 46 | 674123521E279E47007E4393 /* Products */ = { 47 | isa = PBXGroup; 48 | children = ( 49 | 674123511E279E47007E4393 /* Tiptoes.app */, 50 | ); 51 | name = Products; 52 | sourceTree = ""; 53 | }; 54 | 674123531E279E47007E4393 /* Tiptoes */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 674123541E279E47007E4393 /* AppDelegate.swift */, 58 | 674123561E279E47007E4393 /* TopMostViewController.swift */, 59 | 674123681E27A01F007E4393 /* BelowBackViewController.swift */, 60 | 674123661E279EBC007E4393 /* TiptoesNavController.swift */, 61 | 6741235D1E279E47007E4393 /* LaunchScreen.storyboard */, 62 | 674123601E279E47007E4393 /* Info.plist */, 63 | ); 64 | path = Tiptoes; 65 | sourceTree = ""; 66 | }; 67 | /* End PBXGroup section */ 68 | 69 | /* Begin PBXNativeTarget section */ 70 | 674123501E279E47007E4393 /* Tiptoes */ = { 71 | isa = PBXNativeTarget; 72 | buildConfigurationList = 674123631E279E47007E4393 /* Build configuration list for PBXNativeTarget "Tiptoes" */; 73 | buildPhases = ( 74 | 6741234D1E279E47007E4393 /* Sources */, 75 | 6741234E1E279E47007E4393 /* Frameworks */, 76 | 6741234F1E279E47007E4393 /* Resources */, 77 | ); 78 | buildRules = ( 79 | ); 80 | dependencies = ( 81 | ); 82 | name = Tiptoes; 83 | productName = Tiptoes; 84 | productReference = 674123511E279E47007E4393 /* Tiptoes.app */; 85 | productType = "com.apple.product-type.application"; 86 | }; 87 | /* End PBXNativeTarget section */ 88 | 89 | /* Begin PBXProject section */ 90 | 674123491E279E47007E4393 /* Project object */ = { 91 | isa = PBXProject; 92 | attributes = { 93 | LastSwiftUpdateCheck = 0810; 94 | LastUpgradeCheck = 0810; 95 | ORGANIZATIONNAME = "Nanjing University"; 96 | TargetAttributes = { 97 | 674123501E279E47007E4393 = { 98 | CreatedOnToolsVersion = 8.1; 99 | DevelopmentTeam = RCMHACTPLY; 100 | ProvisioningStyle = Automatic; 101 | }; 102 | }; 103 | }; 104 | buildConfigurationList = 6741234C1E279E47007E4393 /* Build configuration list for PBXProject "Tiptoes" */; 105 | compatibilityVersion = "Xcode 3.2"; 106 | developmentRegion = English; 107 | hasScannedForEncodings = 0; 108 | knownRegions = ( 109 | en, 110 | Base, 111 | ); 112 | mainGroup = 674123481E279E47007E4393; 113 | productRefGroup = 674123521E279E47007E4393 /* Products */; 114 | projectDirPath = ""; 115 | projectRoot = ""; 116 | targets = ( 117 | 674123501E279E47007E4393 /* Tiptoes */, 118 | ); 119 | }; 120 | /* End PBXProject section */ 121 | 122 | /* Begin PBXResourcesBuildPhase section */ 123 | 6741234F1E279E47007E4393 /* Resources */ = { 124 | isa = PBXResourcesBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | 6741235F1E279E47007E4393 /* LaunchScreen.storyboard in Resources */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXResourcesBuildPhase section */ 132 | 133 | /* Begin PBXSourcesBuildPhase section */ 134 | 6741234D1E279E47007E4393 /* Sources */ = { 135 | isa = PBXSourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | 674123571E279E47007E4393 /* TopMostViewController.swift in Sources */, 139 | 674123671E279EBC007E4393 /* TiptoesNavController.swift in Sources */, 140 | 674123551E279E47007E4393 /* AppDelegate.swift in Sources */, 141 | 674123691E27A01F007E4393 /* BelowBackViewController.swift in Sources */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | /* End PBXSourcesBuildPhase section */ 146 | 147 | /* Begin PBXVariantGroup section */ 148 | 6741235D1E279E47007E4393 /* LaunchScreen.storyboard */ = { 149 | isa = PBXVariantGroup; 150 | children = ( 151 | 6741235E1E279E47007E4393 /* Base */, 152 | ); 153 | name = LaunchScreen.storyboard; 154 | sourceTree = ""; 155 | }; 156 | /* End PBXVariantGroup section */ 157 | 158 | /* Begin XCBuildConfiguration section */ 159 | 674123611E279E47007E4393 /* Debug */ = { 160 | isa = XCBuildConfiguration; 161 | buildSettings = { 162 | ALWAYS_SEARCH_USER_PATHS = NO; 163 | CLANG_ANALYZER_NONNULL = YES; 164 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 165 | CLANG_CXX_LIBRARY = "libc++"; 166 | CLANG_ENABLE_MODULES = YES; 167 | CLANG_ENABLE_OBJC_ARC = YES; 168 | CLANG_WARN_BOOL_CONVERSION = YES; 169 | CLANG_WARN_CONSTANT_CONVERSION = YES; 170 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 171 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 172 | CLANG_WARN_EMPTY_BODY = YES; 173 | CLANG_WARN_ENUM_CONVERSION = YES; 174 | CLANG_WARN_INFINITE_RECURSION = YES; 175 | CLANG_WARN_INT_CONVERSION = YES; 176 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 177 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 178 | CLANG_WARN_UNREACHABLE_CODE = YES; 179 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 180 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 181 | COPY_PHASE_STRIP = NO; 182 | DEBUG_INFORMATION_FORMAT = dwarf; 183 | ENABLE_STRICT_OBJC_MSGSEND = YES; 184 | ENABLE_TESTABILITY = YES; 185 | GCC_C_LANGUAGE_STANDARD = gnu99; 186 | GCC_DYNAMIC_NO_PIC = NO; 187 | GCC_NO_COMMON_BLOCKS = YES; 188 | GCC_OPTIMIZATION_LEVEL = 0; 189 | GCC_PREPROCESSOR_DEFINITIONS = ( 190 | "DEBUG=1", 191 | "$(inherited)", 192 | ); 193 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 194 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 195 | GCC_WARN_UNDECLARED_SELECTOR = YES; 196 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 197 | GCC_WARN_UNUSED_FUNCTION = YES; 198 | GCC_WARN_UNUSED_VARIABLE = YES; 199 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 200 | MTL_ENABLE_DEBUG_INFO = YES; 201 | ONLY_ACTIVE_ARCH = YES; 202 | SDKROOT = iphoneos; 203 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 204 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 205 | }; 206 | name = Debug; 207 | }; 208 | 674123621E279E47007E4393 /* Release */ = { 209 | isa = XCBuildConfiguration; 210 | buildSettings = { 211 | ALWAYS_SEARCH_USER_PATHS = NO; 212 | CLANG_ANALYZER_NONNULL = YES; 213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 214 | CLANG_CXX_LIBRARY = "libc++"; 215 | CLANG_ENABLE_MODULES = YES; 216 | CLANG_ENABLE_OBJC_ARC = YES; 217 | CLANG_WARN_BOOL_CONVERSION = YES; 218 | CLANG_WARN_CONSTANT_CONVERSION = YES; 219 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 220 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 221 | CLANG_WARN_EMPTY_BODY = YES; 222 | CLANG_WARN_ENUM_CONVERSION = YES; 223 | CLANG_WARN_INFINITE_RECURSION = YES; 224 | CLANG_WARN_INT_CONVERSION = YES; 225 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 226 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 227 | CLANG_WARN_UNREACHABLE_CODE = YES; 228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 229 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 230 | COPY_PHASE_STRIP = NO; 231 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 232 | ENABLE_NS_ASSERTIONS = NO; 233 | ENABLE_STRICT_OBJC_MSGSEND = YES; 234 | GCC_C_LANGUAGE_STANDARD = gnu99; 235 | GCC_NO_COMMON_BLOCKS = YES; 236 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 237 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 238 | GCC_WARN_UNDECLARED_SELECTOR = YES; 239 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 240 | GCC_WARN_UNUSED_FUNCTION = YES; 241 | GCC_WARN_UNUSED_VARIABLE = YES; 242 | IPHONEOS_DEPLOYMENT_TARGET = 10.1; 243 | MTL_ENABLE_DEBUG_INFO = NO; 244 | SDKROOT = iphoneos; 245 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 246 | VALIDATE_PRODUCT = YES; 247 | }; 248 | name = Release; 249 | }; 250 | 674123641E279E47007E4393 /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 254 | DEVELOPMENT_TEAM = RCMHACTPLY; 255 | INFOPLIST_FILE = Tiptoes/Info.plist; 256 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 257 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 258 | PRODUCT_BUNDLE_IDENTIFIER = me.soledad.Tiptoes; 259 | PRODUCT_NAME = "$(TARGET_NAME)"; 260 | SWIFT_VERSION = 3.0; 261 | }; 262 | name = Debug; 263 | }; 264 | 674123651E279E47007E4393 /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 268 | DEVELOPMENT_TEAM = RCMHACTPLY; 269 | INFOPLIST_FILE = Tiptoes/Info.plist; 270 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 271 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 272 | PRODUCT_BUNDLE_IDENTIFIER = me.soledad.Tiptoes; 273 | PRODUCT_NAME = "$(TARGET_NAME)"; 274 | SWIFT_VERSION = 3.0; 275 | }; 276 | name = Release; 277 | }; 278 | /* End XCBuildConfiguration section */ 279 | 280 | /* Begin XCConfigurationList section */ 281 | 6741234C1E279E47007E4393 /* Build configuration list for PBXProject "Tiptoes" */ = { 282 | isa = XCConfigurationList; 283 | buildConfigurations = ( 284 | 674123611E279E47007E4393 /* Debug */, 285 | 674123621E279E47007E4393 /* Release */, 286 | ); 287 | defaultConfigurationIsVisible = 0; 288 | defaultConfigurationName = Release; 289 | }; 290 | 674123631E279E47007E4393 /* Build configuration list for PBXNativeTarget "Tiptoes" */ = { 291 | isa = XCConfigurationList; 292 | buildConfigurations = ( 293 | 674123641E279E47007E4393 /* Debug */, 294 | 674123651E279E47007E4393 /* Release */, 295 | ); 296 | defaultConfigurationIsVisible = 0; 297 | defaultConfigurationName = Release; 298 | }; 299 | /* End XCConfigurationList section */ 300 | }; 301 | rootObject = 674123491E279E47007E4393 /* Project object */; 302 | } 303 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Tiptoes 4 | // 5 | // Created by 蔡越 on 17/1/12. 6 | // Copyright © 2017年 Nanjing University. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | window = UIWindow(frame: UIScreen.main.bounds) 18 | window?.rootViewController = TiptoesNavController(rootViewController: BelowBackViewController()) 19 | window?.makeKeyAndVisible() 20 | return true 21 | } 22 | 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes/BelowBackViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SecondaryViewController.swift 3 | // Tiptoes 4 | // 5 | // Created by 蔡越 on 17/1/12. 6 | // Copyright © 2017年 Nanjing University. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class BelowBackViewController: UIViewController { 12 | 13 | lazy var demoButton: UIButton = { 14 | let b = UIButton() 15 | b.setTitle("JUMP TO NEXT", for: .normal) 16 | b.setTitleColor(UIColor.black, for: .normal) 17 | b.addTarget(self, action: #selector(nav), for: .touchUpInside) 18 | return b 19 | }() 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | 24 | title = "HOME" 25 | view.backgroundColor = .white 26 | view.addSubview(demoButton) 27 | } 28 | 29 | override func viewWillLayoutSubviews() { 30 | super.viewWillLayoutSubviews() 31 | demoButton.center = view.center 32 | demoButton.sizeToFit() 33 | } 34 | 35 | func nav(){ 36 | let vc = TopMostViewController() 37 | navigationController?.pushViewController(vc, animated: true) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIViewControllerBasedStatusBarAppearance 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes/TiptoesNavController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TiptoesNavController.swift 3 | // Tiptoes 4 | // 5 | // Created by 蔡越 on 17/1/12. 6 | // Copyright © 2017年 Nanjing University. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TiptoesNavController: UINavigationController { 12 | 13 | private let tiptoesHeight = UIApplication.shared.statusBarFrame.size.height 14 | 15 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 16 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 17 | } 18 | 19 | override init(rootViewController: UIViewController) { 20 | super.init(navigationBarClass: TiptoesNavBar.self, toolbarClass: nil) 21 | viewControllers = [rootViewController] 22 | } 23 | 24 | required init?(coder aDecoder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | 31 | // Hide the system navigation bar 32 | navigationBar.isHidden = true 33 | interactivePopGestureRecognizer?.addTarget(self, action: #selector(handleTiptoesDisplay(sender:))) 34 | setupBar() 35 | } 36 | 37 | override func viewWillLayoutSubviews() { 38 | super.viewWillLayoutSubviews() 39 | 40 | guard let bar = navigationBar as? TiptoesNavBar else { return } 41 | bar.tiptoes.frame = CGRect(x: 0, y: view.frame.height - tiptoesHeight, width: view.frame.width, height: tiptoesHeight) 42 | bar.currentTitleLabel.sizeToFit() 43 | bar.currentTitleLabel.center = CGPoint(x: view.center.x, y: bar.tiptoes.center.y) 44 | bar.priorTitleLabel.frame = bar.currentTitleLabel.frame 45 | } 46 | 47 | fileprivate func setupBar() { 48 | guard let bar = navigationBar as? TiptoesNavBar else { return } 49 | view.addSubview(bar.tiptoes) 50 | view.addSubview(bar.currentTitleLabel) 51 | view.addSubview(bar.priorTitleLabel) 52 | } 53 | 54 | @objc private func handleTiptoesDisplay(sender: UIGestureRecognizer) { 55 | guard let bar = navigationBar as? TiptoesNavBar else { return } 56 | 57 | let portionValue = sender.location(in: view).x 58 | let currentAlpha = portionValue / view.frame.width 59 | 60 | bar.currentTitleLabel.alpha = (1 - currentAlpha) < 0.5 ? (1 - currentAlpha) * 2 : 1 // 1 -> 0 61 | bar.priorTitleLabel.alpha = currentAlpha > 0.5 ? currentAlpha * 2 - 1 : 0 // 0 -> 1 62 | } 63 | } 64 | 65 | extension TiptoesNavController: UINavigationBarDelegate { 66 | 67 | public func navigationBar(_ navigationBar: UINavigationBar, shouldPush item: UINavigationItem) -> Bool { 68 | guard let bar = navigationBar as? TiptoesNavBar else { return true } 69 | bar.priorTitleLabel.text = "" 70 | bar.priorTitleLabel.isHidden = false 71 | return true 72 | } 73 | 74 | public func navigationBar(_ navigationBar: UINavigationBar, didPush item: UINavigationItem) { 75 | if let pushTitle = item.title { 76 | guard let bar = navigationBar as? TiptoesNavBar else { return } 77 | bar.currentTitleLabel.text = pushTitle 78 | bar.currentTitleLabel.sizeToFit() 79 | bar.currentTitleLabel.center = CGPoint(x: view.center.x, y: bar.tiptoes.center.y) 80 | } 81 | } 82 | 83 | public func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool { 84 | guard let bar = navigationBar as? TiptoesNavBar else { return true } 85 | bar.priorTitleLabel.isHidden = false 86 | 87 | // Get the former viewcontroller 88 | let numberOfViewControllers = viewControllers.count 89 | if numberOfViewControllers > 0 { 90 | if let popTitle = viewControllers[numberOfViewControllers - 1].title { 91 | bar.priorTitleLabel.text = popTitle 92 | bar.priorTitleLabel.sizeToFit() 93 | } 94 | } 95 | return true 96 | } 97 | 98 | // The status of completion of pop 99 | public func navigationBar(_ navigationBar: UINavigationBar, didPop item: UINavigationItem) { 100 | guard let bar = navigationBar as? TiptoesNavBar else { return } 101 | bar.currentTitleLabel.text = bar.priorTitleLabel.text 102 | bar.currentTitleLabel.sizeToFit() 103 | bar.currentTitleLabel.center = CGPoint(x: view.center.x, y: bar.tiptoes.center.y) 104 | bar.currentTitleLabel.alpha = 1.0 105 | bar.priorTitleLabel.isHidden = true 106 | } 107 | } 108 | 109 | class TiptoesNavBar: UINavigationBar { 110 | 111 | /// 用来展示当前 viewController 的 title 112 | var currentTitleLabel: UILabel = { 113 | let label = UILabel() 114 | label.font = UIFont.systemFont(ofSize: 8) 115 | label.textColor = UIColor.black 116 | label.text = "HOME" 117 | label.textAlignment = .center 118 | return label 119 | }() 120 | 121 | /// 用来展示前一页 viewController 的 title 122 | var priorTitleLabel: UILabel = { 123 | let label = UILabel() 124 | label.font = UIFont.systemFont(ofSize: 8) 125 | label.textColor = UIColor.black 126 | label.textAlignment = .center 127 | return label 128 | }() 129 | 130 | var tiptoes: UIView = { 131 | let toes = UIView() 132 | return toes 133 | }() 134 | 135 | override init(frame: CGRect) { 136 | super.init(frame: frame) 137 | } 138 | 139 | required init?(coder aDecoder: NSCoder) { 140 | fatalError("init(coder:) has not been implemented") 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /Tiptoes/Tiptoes/TopMostViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Tiptoes 4 | // 5 | // Created by 蔡越 on 17/1/12. 6 | // Copyright © 2017年 Nanjing University. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TopMostViewController: UIViewController { 12 | 13 | lazy var hintLabel: UILabel = { 14 | let l = UILabel() 15 | l.textColor = .black 16 | l.text = "SWIPE TO RETURN" 17 | l.sizeToFit() 18 | return l 19 | }() 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | title = "NEXT" 24 | view.addSubview(hintLabel) 25 | view.backgroundColor = .white 26 | } 27 | 28 | override func viewWillLayoutSubviews() { 29 | super.viewWillLayoutSubviews() 30 | hintLabel.center = view.center 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /images/appstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caiyue1993/Tiptoes/b6d46539f5f7a45ccff7c970d1860cdb217b77d5/images/appstore.png -------------------------------------------------------------------------------- /images/fade-in-and-out.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caiyue1993/Tiptoes/b6d46539f5f7a45ccff7c970d1860cdb217b77d5/images/fade-in-and-out.gif -------------------------------------------------------------------------------- /images/tiptoes-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/caiyue1993/Tiptoes/b6d46539f5f7a45ccff7c970d1860cdb217b77d5/images/tiptoes-cover.png --------------------------------------------------------------------------------