├── SilentScrolly.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ └── SilentScrolly.xcscheme └── project.pbxproj ├── SilentScrolly ├── SilentScrolly.h ├── Info.plist ├── SilentScrolly.swift └── SilentScrollable.swift ├── Example ├── Sources │ ├── Controllers │ │ ├── TabBar │ │ │ ├── NavigationController.swift │ │ │ ├── TabBarController.swift │ │ │ └── TabBarController.storyboard │ │ ├── Table │ │ │ ├── TableVIewController.swift │ │ │ └── TableViewController.storyboard │ │ ├── ToolBar │ │ │ ├── ToolBarViewController.storyboard │ │ │ └── ToolBarViewController.swift │ │ ├── Web │ │ │ ├── WebViewController.swift │ │ │ └── WebViewController.storyboard │ │ └── Collection │ │ │ ├── CollectionViewController.swift │ │ │ └── CollectionViewController.storyboard │ └── AppDelegate.swift └── Resources │ ├── Info.plist │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchScreen.storyboard ├── SilentScrolly.podspec ├── LICENSE ├── .gitignore └── README.md /SilentScrolly.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SilentScrolly.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SilentScrolly/SilentScrolly.h: -------------------------------------------------------------------------------- 1 | // 2 | // SilentScrolly.h 3 | // SilentScrolly 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/19. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SilentScrolly. 12 | FOUNDATION_EXPORT double SilentScrollyVersionNumber; 13 | 14 | //! Project version string for SilentScrolly. 15 | FOUNDATION_EXPORT const unsigned char SilentScrollyVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/TabBar/NavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationController.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/03/11. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class NavigationController: UINavigationController { 12 | 13 | override var preferredStatusBarStyle: UIStatusBarStyle { 14 | return topViewController?.preferredStatusBarStyle ?? .default 15 | } 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | navigationBar.barTintColor = .darkGray 21 | navigationBar.tintColor = .white 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/TabBar/TabBarController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TabBarController.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/20. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class TabBarController: UITabBarController { 12 | 13 | private enum Const { 14 | static let tabBarItemTitles = ["First"] 15 | } 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | 20 | for (index, title) in Const.tabBarItemTitles.enumerated() { 21 | tabBar.items?[index].title = title 22 | } 23 | 24 | tabBar.barTintColor = .darkGray 25 | tabBar.tintColor = .white 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SilentScrolly/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /SilentScrolly.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "SilentScrolly" 3 | s.version = "1.0.8" 4 | s.summary = "Scroll to hide navigationBar, tabBar and toolBar." 5 | s.description = <<-DESC 6 | Adding too much UIGestureRecognizer to the UIView makes handling difficult, so it was handled by UIScrollViewDelegate. 7 | DESC 8 | s.homepage = "https://github.com/horitaku46/SilentScrolly" 9 | s.license = { :type => "MIT", :file => "./LICENSE" } 10 | s.author = { "Takuma Horiuchi" => "horitaku46@gmail.com" } 11 | s.social_media_url = "https://twitter.com/horitaku46" 12 | s.platform = :ios, "11.0" 13 | s.source = { :git => "https://github.com/horitaku46/SilentScrolly.git", :tag => "#{s.version}" } 14 | s.source_files = "SilentScrolly/**/*.{swift}" 15 | s.swift_version = "4.0" 16 | end 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Takuma Horiuchi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SilentScrolly/SilentScrolly.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SilentScrolly.swift 3 | // SilentScrolly 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/22. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct SilentScrolly { 12 | 13 | public enum Const { 14 | public static let minDoNothingAdjustNavigationBarVelocityY: CGFloat = 0 15 | public static let maxDoNothingAdjustNavigationBarVelocityY: CGFloat = 1400 16 | public static let animateDuration: TimeInterval = 0.3 17 | } 18 | 19 | public var preferredStatusBarStyle: UIStatusBarStyle? = nil 20 | public var showStatusBarStyle: UIStatusBarStyle = .default 21 | public var hideStatusBarStyle: UIStatusBarStyle = .default 22 | 23 | public var scrollView: UIScrollView? = nil 24 | 25 | public var isNavigationBarShow = true 26 | public var isTransitionCompleted = true 27 | public var isAddObserver = true 28 | 29 | public var prevPositiveContentOffsetY: CGFloat = 0 30 | 31 | public var showNavigationBarFrameOriginY: CGFloat = 0 32 | public var hideNavigationBarFrameOriginY: CGFloat = 0 33 | public var showScrollIndicatorInsetsTop: CGFloat = 0 34 | public var hideScrollIndicatorInsetsTop: CGFloat = 0 35 | 36 | public var bottomView: UIView? 37 | public var showBottomViewFrameOriginY: CGFloat = 0 38 | public var hideBottomViewFrameOriginY: CGFloat = 0 39 | public var showContentInsetBottom: CGFloat = 0 40 | public var hideContentInsetBottom: CGFloat = 0 41 | } 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | 54 | Carthage/ 55 | 56 | # fastlane 57 | # 58 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 59 | # screenshots whenever they are needed. 60 | # For more information about the recommended setup visit: 61 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 62 | 63 | fastlane/report.xml 64 | fastlane/Preview.html 65 | fastlane/screenshots 66 | fastlane/test_output 67 | -------------------------------------------------------------------------------- /Example/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | SilentScrolly 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSAppTransportSecurity 24 | 25 | NSAllowsArbitraryLoads 26 | 27 | 28 | UILaunchStoryboardName 29 | LaunchScreen 30 | UIMainStoryboardFile 31 | TabBarController 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Example/Sources/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/20. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? { 15 | didSet { 16 | window?.backgroundColor = .white 17 | } 18 | } 19 | 20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 21 | // Override point for customization after application launch. 22 | return true 23 | } 24 | 25 | func applicationWillResignActive(_ application: UIApplication) { 26 | // 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. 27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 31 | // 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. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | func applicationWillEnterForeground(_ application: UIApplication) { 36 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | func applicationDidBecomeActive(_ application: UIApplication) { 40 | // 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. 41 | } 42 | 43 | func applicationWillTerminate(_ application: UIApplication) { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/Table/TableVIewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableVIewController.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/03/21. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class TableViewController: UIViewController, SilentScrollable { 12 | 13 | override var preferredStatusBarStyle: UIStatusBarStyle { 14 | return statusBarStyle(showStyle: .lightContent, hideStyle: .default) 15 | } 16 | 17 | @IBOutlet weak var tableView: UITableView! { 18 | didSet { 19 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") 20 | tableView.delegate = self 21 | tableView.dataSource = self 22 | } 23 | } 24 | 25 | var silentScrolly: SilentScrolly? 26 | 27 | override func viewDidLoad() { 28 | super.viewDidLoad() 29 | 30 | let label = UILabel() 31 | label.text = "Table" 32 | label.textColor = .white 33 | label.font = UIFont.boldSystemFont(ofSize: 17) 34 | navigationItem.titleView = label 35 | } 36 | 37 | override func viewDidLayoutSubviews() { 38 | super.viewDidLayoutSubviews() 39 | silentDidLayoutSubviews() 40 | } 41 | 42 | override func viewDidAppear(_ animated: Bool) { 43 | super.viewDidAppear(animated) 44 | configureSilentScrolly(tableView, followBottomView: tabBarController?.tabBar) 45 | } 46 | 47 | override func viewWillDisappear(_ animated: Bool) { 48 | super.viewWillDisappear(animated) 49 | silentWillDisappear() 50 | } 51 | 52 | override func viewDidDisappear(_ animated: Bool) { 53 | super.viewDidDisappear(animated) 54 | silentDidDisappear() 55 | } 56 | 57 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 58 | super.viewWillTransition(to: size, with: coordinator) 59 | silentWillTranstion() 60 | } 61 | } 62 | 63 | extension TableViewController: UITableViewDelegate { 64 | 65 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 66 | silentDidScroll() 67 | } 68 | 69 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 70 | tableView.deselectRow(at: indexPath, animated: true) 71 | } 72 | 73 | func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { 74 | showNavigationBar() 75 | return true 76 | } 77 | } 78 | 79 | extension TableViewController: UITableViewDataSource { 80 | 81 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 82 | return 100 83 | } 84 | 85 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 86 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 87 | cell.textLabel?.text = "Row: \(indexPath.row)" 88 | return cell 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/ToolBar/ToolBarViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/Web/WebViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WebViewController.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/20. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import WebKit 11 | 12 | final class WebViewController: UIViewController, SilentScrollable { 13 | 14 | override var preferredStatusBarStyle: UIStatusBarStyle { 15 | return statusBarStyle(showStyle: .lightContent, hideStyle: .default) 16 | } 17 | 18 | @IBOutlet weak var webView: WKWebView! { 19 | didSet { 20 | webView.navigationDelegate = self 21 | webView.scrollView.delegate = self 22 | let url = URL(string: "http://www.keyakizaka46.com/") 23 | let urlRequest = URLRequest(url: url!) 24 | webView.load(urlRequest) 25 | } 26 | } 27 | 28 | var silentScrolly: SilentScrolly? 29 | 30 | override func viewDidLoad() { 31 | super.viewDidLoad() 32 | 33 | let rightShowBarButtonItem = UIBarButtonItem(title: "Show", 34 | style: .plain, 35 | target: self, 36 | action: #selector(tapRightShowBarButtonItem)) 37 | navigationItem.setRightBarButton(rightShowBarButtonItem, animated: true) 38 | 39 | let label = UILabel() 40 | label.text = "Web" 41 | label.textColor = .white 42 | label.font = UIFont.boldSystemFont(ofSize: 17) 43 | navigationItem.titleView = label 44 | } 45 | 46 | override func viewDidLayoutSubviews() { 47 | super.viewDidLayoutSubviews() 48 | silentDidLayoutSubviews() 49 | } 50 | 51 | override func viewDidAppear(_ animated: Bool) { 52 | super.viewDidAppear(animated) 53 | configureSilentScrolly(webView.scrollView, followBottomView: tabBarController?.tabBar) 54 | } 55 | 56 | override func viewWillDisappear(_ animated: Bool) { 57 | super.viewWillDisappear(animated) 58 | silentWillDisappear() 59 | } 60 | 61 | override func viewDidDisappear(_ animated: Bool) { 62 | super.viewDidDisappear(animated) 63 | silentDidDisappear() 64 | } 65 | 66 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 67 | super.viewWillTransition(to: size, with: coordinator) 68 | silentWillTranstion() 69 | } 70 | 71 | @objc private func tapRightShowBarButtonItem() { 72 | let viewController = ToolBarViewController.make() 73 | navigationController?.show(viewController, sender: nil) 74 | } 75 | } 76 | 77 | extension WebViewController: UIScrollViewDelegate { 78 | 79 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 80 | silentDidScroll() 81 | } 82 | 83 | func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { 84 | showNavigationBar() 85 | return true 86 | } 87 | } 88 | 89 | extension WebViewController: WKNavigationDelegate { 90 | 91 | func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { 92 | showNavigationBar() 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /SilentScrolly.xcodeproj/xcshareddata/xcschemes/SilentScrolly.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/Table/TableViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/Web/WebViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/Collection/CollectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewController.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/03/21. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class CollectionViewController: UIViewController, SilentScrollable { 12 | 13 | override var preferredStatusBarStyle: UIStatusBarStyle { 14 | return .lightContent 15 | } 16 | 17 | @IBOutlet weak var collectionView: UICollectionView! { 18 | didSet { 19 | collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell") 20 | collectionView.delegate = self 21 | collectionView.dataSource = self 22 | } 23 | } 24 | 25 | @IBOutlet weak var flowLayout: UICollectionViewFlowLayout! { 26 | didSet { 27 | flowLayout.scrollDirection = .vertical 28 | flowLayout.minimumInteritemSpacing = 1 29 | flowLayout.minimumLineSpacing = 1 30 | } 31 | } 32 | 33 | var silentScrolly: SilentScrolly? 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | 38 | let label = UILabel() 39 | label.text = "Collection" 40 | label.textColor = .white 41 | label.font = UIFont.boldSystemFont(ofSize: 17) 42 | navigationItem.titleView = label 43 | } 44 | 45 | override func viewDidLayoutSubviews() { 46 | super.viewDidLayoutSubviews() 47 | silentDidLayoutSubviews() 48 | } 49 | 50 | override func viewDidAppear(_ animated: Bool) { 51 | super.viewDidAppear(animated) 52 | configureSilentScrolly(collectionView, followBottomView: tabBarController?.tabBar) 53 | } 54 | 55 | override func viewWillDisappear(_ animated: Bool) { 56 | super.viewWillDisappear(animated) 57 | silentWillDisappear() 58 | } 59 | 60 | override func viewDidDisappear(_ animated: Bool) { 61 | super.viewDidDisappear(animated) 62 | silentDidDisappear() 63 | } 64 | 65 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 66 | super.viewWillTransition(to: size, with: coordinator) 67 | silentWillTranstion() 68 | } 69 | } 70 | 71 | extension CollectionViewController: UICollectionViewDelegate { 72 | 73 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 74 | silentDidScroll() 75 | } 76 | 77 | func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { 78 | showNavigationBar() 79 | return true 80 | } 81 | } 82 | 83 | extension CollectionViewController: UICollectionViewDataSource { 84 | 85 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 86 | return 100 87 | } 88 | 89 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 90 | let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) 91 | cell.contentView.backgroundColor = .lightGray 92 | return cell 93 | } 94 | } 95 | 96 | extension CollectionViewController: UICollectionViewDelegateFlowLayout { 97 | 98 | func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 99 | let isPortraint = UIInterfaceOrientationIsPortrait(UIApplication.shared.statusBarOrientation) 100 | let itemSide: CGFloat = isPortraint ? (collectionView.frame.width - 2) / 3 : (collectionView.frame.width - 3) / 4 101 | return CGSize(width: floor(itemSide), height: floor(itemSide)) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/ToolBar/ToolBarViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ToolBarViewController.swift 3 | // Example 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/20. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import WebKit 11 | 12 | final class ToolBarViewController: UIViewController, SilentScrollable { 13 | 14 | override var preferredStatusBarStyle: UIStatusBarStyle { 15 | return statusBarStyle(showStyle: .lightContent, hideStyle: .default) 16 | } 17 | 18 | class func make() -> ToolBarViewController { 19 | let viewController = UIStoryboard(name: "ToolBarViewController", bundle: nil) 20 | .instantiateViewController(withIdentifier: "ToolBarViewController") as! ToolBarViewController 21 | viewController.hidesBottomBarWhenPushed = true 22 | return viewController 23 | } 24 | 25 | private var webView: WKWebView = { 26 | let webConfiguration = WKWebViewConfiguration() 27 | webConfiguration.ignoresViewportScaleLimits = true 28 | let webView = WKWebView(frame: .zero, configuration: webConfiguration) 29 | webView.translatesAutoresizingMaskIntoConstraints = false 30 | webView.load(URLRequest(url: URL(string: "http://www.keyakizaka46.com/")!)) 31 | return webView 32 | }() 33 | 34 | @IBOutlet weak var toolBar: UIToolbar! { 35 | didSet { 36 | toolBar.barTintColor = .darkGray 37 | toolBar.tintColor = .white 38 | } 39 | } 40 | 41 | var silentScrolly: SilentScrolly? 42 | 43 | override func viewDidLoad() { 44 | super.viewDidLoad() 45 | 46 | webView.navigationDelegate = self 47 | webView.scrollView.delegate = self 48 | view.addSubview(webView) 49 | NSLayoutConstraint.activate([ 50 | webView.topAnchor.constraint(equalTo: view.topAnchor), 51 | webView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), 52 | webView.bottomAnchor.constraint(equalTo: view.bottomAnchor), 53 | webView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor) 54 | ]) 55 | 56 | view.bringSubview(toFront: toolBar) 57 | 58 | let label = UILabel() 59 | label.text = "ToolBar" 60 | label.textColor = .white 61 | label.font = UIFont.boldSystemFont(ofSize: 17) 62 | navigationItem.titleView = label 63 | } 64 | 65 | override func viewDidLayoutSubviews() { 66 | super.viewDidLayoutSubviews() 67 | silentDidLayoutSubviews() 68 | } 69 | 70 | override func viewDidAppear(_ animated: Bool) { 71 | super.viewDidAppear(animated) 72 | configureSilentScrolly(webView.scrollView, followBottomView: toolBar) 73 | } 74 | 75 | override func viewWillDisappear(_ animated: Bool) { 76 | super.viewWillDisappear(animated) 77 | silentWillDisappear() 78 | } 79 | 80 | override func viewDidDisappear(_ animated: Bool) { 81 | super.viewDidDisappear(animated) 82 | silentDidDisappear() 83 | } 84 | 85 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 86 | super.viewWillTransition(to: size, with: coordinator) 87 | silentWillTranstion() 88 | } 89 | } 90 | 91 | extension ToolBarViewController: UIScrollViewDelegate { 92 | 93 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 94 | silentDidScroll() 95 | } 96 | 97 | func scrollViewDidZoom(_ scrollView: UIScrollView) { 98 | silentDidZoom() 99 | } 100 | 101 | func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { 102 | showNavigationBar() 103 | return true 104 | } 105 | } 106 | 107 | extension ToolBarViewController: WKNavigationDelegate { 108 | 109 | func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { 110 | showNavigationBar() 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/Collection/CollectionViewController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Example/Resources/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | [![Platform](http://img.shields.io/badge/platform-iOS-blue.svg?style=flat)](https://developer.apple.com/iphone/index.action) 6 | ![Swift](https://img.shields.io/badge/Swift-4.0-orange.svg) 7 | [![Cocoapods](https://img.shields.io/badge/Cocoapods-compatible-brightgreen.svg)](https://img.shields.io/badge/Cocoapods-compatible-brightgreen.svg) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-Compatible-brightgreen.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | [![License](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](http://mit-license.org) 10 | 11 | ## Overview 12 | Scroll to hide navigationBar, tabBar and toolBar. 13 | 14 |

15 | 16 |

17 | 18 | ## Features 19 | Adding too much `UIGestureRecognizer` to the `UIView` makes handling difficult, so it was handled by `UIScrollViewDelegate`. 20 | 21 | ## Translation 22 | Mr. [Gargo](https://github.com/Gargo) translated [this README into Russian](http://gargo.of.by/silentscrolly/)!🙇‍♂️ 23 | 24 | ## Requirements 25 | - Xcode 9.0+ 26 | - iOS 10+ 27 | - Swift 4.0+ 28 | 29 | ## Installation 30 | ### CocoaPods 31 | ```ruby 32 | pod 'SilentScrolly' 33 | ``` 34 | ### Carthage 35 | ```ruby 36 | github "horitaku46/SilentScrolly" 37 | ``` 38 | ## Usage 39 | **See [Example](https://github.com/horitaku46/SilentScrolly/tree/master/Example), for more details.** 40 | 41 | **《1》** If you want to change the color of the statusBar, add `func statusBarStyle(showStyle: UIStatusBarStyle, hideStyle: UIStatusBarStyle)` to the `UINavigationController`. 42 | 43 | ```swift 44 | import UIKit 45 | 46 | final class NavigationController: UINavigationController { 47 | 48 | override var preferredStatusBarStyle: UIStatusBarStyle { 49 | return topViewController?.preferredStatusBarStyle ?? .default 50 | } 51 | } 52 | ``` 53 | 54 | **《2》** Please describe accordingly as below. 55 | 56 | 57 | ```swift 58 | import UIKit 59 | 60 | final class TableViewController: UIViewController, SilentScrollable { 61 | 62 | override var preferredStatusBarStyle: UIStatusBarStyle { 63 | return statusBarStyle(showStyle: .lightContent, hideStyle: .default) // Optional 64 | } 65 | 66 | @IBOutlet weak var tableView: UITableView! { 67 | didSet { 68 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") 69 | tableView.delegate = self 70 | tableView.dataSource = self 71 | } 72 | } 73 | 74 | var silentScrolly: SilentScrolly? 75 | 76 | override func viewDidLayoutSubviews() { 77 | super.viewDidLayoutSubviews() 78 | silentDidLayoutSubviews() 79 | } 80 | 81 | override func viewDidAppear(_ animated: Bool) { 82 | super.viewDidAppear(animated) 83 | configureSilentScrolly(tableView, followBottomView: tabBarController?.tabBar) 84 | } 85 | 86 | override func viewWillDisappear(_ animated: Bool) { 87 | super.viewWillDisappear(animated) 88 | silentWillDisappear() 89 | } 90 | 91 | override func viewDidDisappear(_ animated: Bool) { 92 | super.viewDidDisappear(animated) 93 | silentDidDisappear() 94 | } 95 | 96 | override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 97 | super.viewWillTransition(to: size, with: coordinator) 98 | silentWillTranstion() 99 | } 100 | } 101 | 102 | extension TableViewController: UITableViewDelegate { 103 | 104 | func scrollViewDidScroll(_ scrollView: UIScrollView) { 105 | silentDidScroll() 106 | } 107 | 108 | func scrollViewDidZoom(_ scrollView: UIScrollView) { 109 | silentDidZoom() // Optional 110 | } 111 | 112 | func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { 113 | showNavigationBar() // Optional 114 | return true 115 | } 116 | } 117 | 118 | extension TableViewController: UITableViewDataSource { 119 | 120 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 121 | return 100 122 | } 123 | 124 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 125 | let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) 126 | cell.textLabel?.text = "Row: \(indexPath.row)" 127 | return cell 128 | } 129 | } 130 | ``` 131 | 132 | ## Author 133 | ### Takuma Horiuchi 134 | - [Facebook](https://www.facebook.com/profile.php?id=100008388074028) 135 | - [Twitter](https://twitter.com/horitaku_) 136 | - [GitHub](https://github.com/horitaku46) 137 | 138 | ## License 139 | `SilentScrolly` is available under the MIT license. See the [LICENSE](./LICENSE) file for more info. 140 | -------------------------------------------------------------------------------- /Example/Sources/Controllers/TabBar/TabBarController.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /SilentScrolly/SilentScrollable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SilentScrollable.swift 3 | // SilentScrolly 4 | // 5 | // Created by Takuma Horiuchi on 2018/02/22. 6 | // Copyright © 2018年 Takuma Horiuchi. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol SilentScrollable: class { 12 | var silentScrolly: SilentScrolly? { get set } 13 | func statusBarStyle(showStyle: UIStatusBarStyle, hideStyle: UIStatusBarStyle) -> UIStatusBarStyle 14 | func configureSilentScrolly(_ scrollView: UIScrollView, followBottomView: UIView?, completion: (() -> Void)?) 15 | func showNavigationBar() 16 | func hideNavigationBar() 17 | func silentWillDisappear() 18 | func silentDidDisappear() 19 | func silentDidLayoutSubviews() 20 | func silentWillTranstion() 21 | func silentDidScroll() 22 | func silentDidZoom() 23 | } 24 | 25 | public extension SilentScrollable where Self: UIViewController { 26 | 27 | public func statusBarStyle(showStyle: UIStatusBarStyle, hideStyle: UIStatusBarStyle) -> UIStatusBarStyle { 28 | guard let preferredStatusBarStyle = silentScrolly?.preferredStatusBarStyle else { 29 | /// To consider whether statusBarStyle and configureSilentScrolly precede. 30 | if silentScrolly == nil { 31 | silentScrolly = SilentScrolly() 32 | } 33 | silentScrolly?.preferredStatusBarStyle = showStyle 34 | silentScrolly?.showStatusBarStyle = showStyle 35 | silentScrolly?.hideStatusBarStyle = hideStyle 36 | return showStyle 37 | } 38 | return preferredStatusBarStyle 39 | } 40 | 41 | private func setStatusBarAppearanceShow() { 42 | guard let showStyle = silentScrolly?.showStatusBarStyle else { 43 | return 44 | } 45 | silentScrolly?.preferredStatusBarStyle = showStyle 46 | setNeedsStatusBarAppearanceUpdate() 47 | } 48 | 49 | private func setStatusBarAppearanceHide() { 50 | guard let hideStyle = silentScrolly?.hideStatusBarStyle else { 51 | return 52 | } 53 | silentScrolly?.preferredStatusBarStyle = hideStyle 54 | setNeedsStatusBarAppearanceUpdate() 55 | } 56 | 57 | public func configureSilentScrolly(_ scrollView: UIScrollView, followBottomView: UIView?, completion: (() -> Void)? = nil) { 58 | guard let navigationBarHeight = navigationController?.navigationBar.bounds.height, 59 | let safeAreaInsetsBottom = UIApplication.shared.keyWindow?.safeAreaInsets.bottom else { 60 | return 61 | } 62 | let statusBarHeight = UIApplication.shared.statusBarFrame.height 63 | let totalHeight = statusBarHeight + navigationBarHeight 64 | 65 | /// To consider whether statusBarStyle and configureSilentScrolly precede. 66 | if silentScrolly == nil { 67 | silentScrolly = SilentScrolly() 68 | } 69 | 70 | silentScrolly?.scrollView = scrollView 71 | 72 | silentScrolly?.isNavigationBarShow = true 73 | silentScrolly?.isTransitionCompleted = true 74 | 75 | silentScrolly?.showNavigationBarFrameOriginY = statusBarHeight 76 | silentScrolly?.hideNavigationBarFrameOriginY = -navigationBarHeight 77 | silentScrolly?.showScrollIndicatorInsetsTop = scrollView.scrollIndicatorInsets.top 78 | silentScrolly?.hideScrollIndicatorInsetsTop = scrollView.scrollIndicatorInsets.top - totalHeight 79 | 80 | // FIXME: Because the following adjusts it to the setting that I showed with a example. 81 | if let bottomView = followBottomView { 82 | let screenHeight = UIScreen.main.bounds.height 83 | let eitherSafeAreaInsetsBottom = bottomView is UITabBar ? 0 : safeAreaInsetsBottom 84 | let bottomViewHeight = bottomView.bounds.height + eitherSafeAreaInsetsBottom 85 | silentScrolly?.bottomView = bottomView 86 | silentScrolly?.showBottomViewFrameOriginY = screenHeight - bottomViewHeight 87 | silentScrolly?.hideBottomViewFrameOriginY = screenHeight 88 | silentScrolly?.showContentInsetBottom = bottomView is UITabBar ? 0 : bottomViewHeight 89 | silentScrolly?.hideContentInsetBottom = bottomView is UITabBar ? -bottomViewHeight : -eitherSafeAreaInsetsBottom 90 | } 91 | 92 | if let isAddObserver = silentScrolly?.isAddObserver { 93 | if isAddObserver { 94 | NotificationCenter.default.addObserver(forName: .UIDeviceOrientationDidChange, object: nil, queue: nil) { [weak self] in 95 | self?.orientationDidChange($0) 96 | } 97 | NotificationCenter.default.addObserver(forName: .UIApplicationDidEnterBackground, object: nil, queue: nil) { [weak self] in 98 | self?.didEnterBackground($0) 99 | } 100 | } 101 | silentScrolly?.isAddObserver = false 102 | } 103 | 104 | completion?() 105 | } 106 | 107 | private func orientationDidChange(_ notification: Notification) { 108 | guard isViewLoaded, 109 | let _ = view.window, 110 | let scrollView = silentScrolly?.scrollView, 111 | let isShow = silentScrolly?.isNavigationBarShow else { 112 | return 113 | } 114 | adjustEitherView(scrollView, isShow: isShow, animated: false) 115 | } 116 | 117 | private func didEnterBackground(_ notification: Notification) { 118 | guard isViewLoaded, 119 | let _ = view.window, 120 | let scrollView = silentScrolly?.scrollView else { 121 | return 122 | } 123 | adjustEitherView(scrollView, isShow: true, animated: false) 124 | } 125 | 126 | public func showNavigationBar() { 127 | guard let scrollView = silentScrolly?.scrollView else { 128 | return 129 | } 130 | adjustEitherView(scrollView, isShow: true) 131 | } 132 | 133 | public func hideNavigationBar() { 134 | guard let scrollView = silentScrolly?.scrollView else { 135 | return 136 | } 137 | adjustEitherView(scrollView, isShow: false) 138 | } 139 | 140 | public func silentWillDisappear() { 141 | showNavigationBar() 142 | silentScrolly?.isTransitionCompleted = false 143 | } 144 | 145 | public func silentDidDisappear() { 146 | silentScrolly?.isTransitionCompleted = true 147 | } 148 | 149 | public func silentDidLayoutSubviews() { 150 | guard let scrollView = silentScrolly?.scrollView else { 151 | return 152 | } 153 | // animation completed because the calculation is crazy 154 | adjustEitherView(scrollView, isShow: true, animated: false) { [weak self] in 155 | guard let me = self else { return } 156 | me.configureSilentScrolly(scrollView, followBottomView: me.silentScrolly?.bottomView) { [weak self] in 157 | self?.adjustEitherView(scrollView, isShow: true, animated: false) 158 | scrollView.setZoomScale(1, animated: false) 159 | } 160 | } 161 | } 162 | 163 | public func silentWillTranstion() { 164 | guard let scrollView = silentScrolly?.scrollView else { 165 | return 166 | } 167 | adjustEitherView(scrollView, isShow: true, animated: false) 168 | } 169 | 170 | public func silentDidScroll() { 171 | guard let scrollView = silentScrolly?.scrollView, 172 | let prevPositiveContentOffsetY = silentScrolly?.prevPositiveContentOffsetY else { 173 | return 174 | } 175 | 176 | if scrollView.contentSize.height < scrollView.bounds.height || scrollView.isZooming { 177 | return 178 | } 179 | 180 | if scrollView.contentOffset.y <= 0 { 181 | adjustEitherView(scrollView, isShow: true) 182 | return 183 | } 184 | 185 | let positiveContentOffsetY = calcPositiveContentOffsetY(scrollView) 186 | let velocityY = scrollView.panGestureRecognizer.velocity(in: view).y 187 | 188 | if positiveContentOffsetY != prevPositiveContentOffsetY && scrollView.isTracking { 189 | if velocityY < SilentScrolly.Const.minDoNothingAdjustNavigationBarVelocityY { 190 | adjustEitherView(scrollView, isShow: false) 191 | } else if velocityY > SilentScrolly.Const.maxDoNothingAdjustNavigationBarVelocityY { 192 | adjustEitherView(scrollView, isShow: true) 193 | } 194 | } 195 | 196 | silentScrolly?.prevPositiveContentOffsetY = positiveContentOffsetY 197 | } 198 | 199 | public func silentDidZoom() { 200 | guard let scrollView = silentScrolly?.scrollView else { 201 | return 202 | } 203 | func setNavigationBar() { 204 | scrollView.zoomScale <= 1 ? showNavigationBar() : hideNavigationBar() 205 | } 206 | scrollView.isZooming ? setNavigationBar() : scrollView.setZoomScale(1, animated: true) 207 | } 208 | 209 | private func calcPositiveContentOffsetY(_ scrollView: UIScrollView) -> CGFloat { 210 | var contentOffsetY = scrollView.contentOffset.y + scrollView.contentInset.top 211 | contentOffsetY = contentOffsetY > 0 ? contentOffsetY : 0 212 | return contentOffsetY 213 | } 214 | 215 | private func adjustEitherView(_ scrollView: UIScrollView, isShow: Bool, animated: Bool = true, completion: (() -> Void)? = nil) { 216 | guard let isTransitionCompleted = silentScrolly?.isTransitionCompleted, 217 | let showNavigationBarFrameOriginY = silentScrolly?.showNavigationBarFrameOriginY, 218 | let hideNavigationBarFrameOriginY = silentScrolly?.hideNavigationBarFrameOriginY, 219 | let showScrollIndicatorInsetsTop = silentScrolly?.showScrollIndicatorInsetsTop, 220 | let hideScrollIndicatorInsetsTop = silentScrolly?.hideScrollIndicatorInsetsTop, 221 | let currentNavigationBarOriginY = navigationController?.navigationBar.frame.origin.y else { 222 | return 223 | } 224 | 225 | if scrollView.contentSize.height < scrollView.bounds.height || !isTransitionCompleted { 226 | return 227 | } 228 | 229 | let eitherNavigationBarFrameOriginY = isShow ? showNavigationBarFrameOriginY : hideNavigationBarFrameOriginY 230 | let eitherScrollIndicatorInsetsTop = isShow ? showScrollIndicatorInsetsTop : hideScrollIndicatorInsetsTop 231 | let navigationBarContentsAlpha: CGFloat = isShow ? 1 : 0 232 | 233 | func setPosition() { 234 | if silentScrolly?.preferredStatusBarStyle != nil { 235 | isShow ? setStatusBarAppearanceShow() : setStatusBarAppearanceHide() 236 | } 237 | navigationController?.navigationBar.frame.origin.y = eitherNavigationBarFrameOriginY 238 | scrollView.scrollIndicatorInsets.top = eitherScrollIndicatorInsetsTop 239 | setNavigationBarContentsAlpha(navigationBarContentsAlpha) 240 | silentScrolly?.isNavigationBarShow = isShow 241 | } 242 | 243 | if !animated { 244 | setPosition() 245 | animateBottomView(scrollView, isShow: isShow, animated: animated) 246 | completion?() 247 | return 248 | } 249 | 250 | if currentNavigationBarOriginY != eitherNavigationBarFrameOriginY && scrollView.scrollIndicatorInsets.top != eitherScrollIndicatorInsetsTop { 251 | UIView.animate(withDuration: SilentScrolly.Const.animateDuration, animations: { 252 | setPosition() 253 | }, completion: { _ in 254 | completion?() 255 | }) 256 | 257 | animateBottomView(scrollView, isShow: isShow, animated: animated) 258 | } 259 | } 260 | 261 | private func animateBottomView(_ scrollView: UIScrollView, isShow: Bool, animated: Bool = true) { 262 | guard let bottomView = silentScrolly?.bottomView, 263 | let showBottomViewFrameOriginY = silentScrolly?.showBottomViewFrameOriginY, 264 | let hideBottomViewFrameOriginY = silentScrolly?.hideBottomViewFrameOriginY, 265 | let showContentInsetBottom = silentScrolly?.showContentInsetBottom, 266 | let hideContentInsetBottom = silentScrolly?.hideContentInsetBottom else { 267 | return 268 | } 269 | 270 | let eitherBottomViewFrameOriginY = isShow ? showBottomViewFrameOriginY : hideBottomViewFrameOriginY 271 | let eitherContentInsetBottom = isShow ? showContentInsetBottom : hideContentInsetBottom 272 | 273 | func setPosition() { 274 | bottomView.frame.origin.y = eitherBottomViewFrameOriginY 275 | scrollView.contentInset.bottom = eitherContentInsetBottom 276 | scrollView.scrollIndicatorInsets.bottom = eitherContentInsetBottom 277 | } 278 | 279 | if !animated { 280 | setPosition() 281 | return 282 | } 283 | 284 | UIView.animate(withDuration: SilentScrolly.Const.animateDuration) { 285 | setPosition() 286 | } 287 | } 288 | 289 | private func setNavigationBarContentsAlpha(_ alpha: CGFloat) { 290 | guard let navigationBar = navigationController?.navigationBar else { 291 | return 292 | } 293 | navigationItem.titleView?.alpha = alpha 294 | navigationBar.tintColor = navigationBar.tintColor.withAlphaComponent(alpha) 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /SilentScrolly.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 6154F5ED203B1CC600040F47 /* SilentScrolly.h in Headers */ = {isa = PBXBuildFile; fileRef = 6154F5EB203B1CC600040F47 /* SilentScrolly.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 615EC445205574EC00F2A392 /* SilentScrolly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615EC443205574EC00F2A392 /* SilentScrolly.swift */; }; 12 | 615EC446205574EC00F2A392 /* SilentScrollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615EC444205574EC00F2A392 /* SilentScrollable.swift */; }; 13 | 615EC4472055750800F2A392 /* SilentScrollable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615EC444205574EC00F2A392 /* SilentScrollable.swift */; }; 14 | 615EC4482055750800F2A392 /* SilentScrolly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 615EC443205574EC00F2A392 /* SilentScrolly.swift */; }; 15 | 6176604D203BDD330049B35E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6176603D203BDC2F0049B35E /* AppDelegate.swift */; }; 16 | 6176604E203BDD3F0049B35E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 61766037203BDC2F0049B35E /* Assets.xcassets */; }; 17 | 61F540C8206238BF006E11FB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61F540C7206238BF006E11FB /* LaunchScreen.storyboard */; }; 18 | 61F540DE20625D61006E11FB /* TabBarController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61F540D520625D61006E11FB /* TabBarController.storyboard */; }; 19 | 61F540DF20625D61006E11FB /* NavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F540D620625D61006E11FB /* NavigationController.swift */; }; 20 | 61F540E020625D61006E11FB /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F540D720625D61006E11FB /* TabBarController.swift */; }; 21 | 61F540E120625D61006E11FB /* ToolBarViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61F540D920625D61006E11FB /* ToolBarViewController.storyboard */; }; 22 | 61F540E220625D61006E11FB /* ToolBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F540DA20625D61006E11FB /* ToolBarViewController.swift */; }; 23 | 61F540E320625D61006E11FB /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F540DC20625D61006E11FB /* WebViewController.swift */; }; 24 | 61F540E420625D61006E11FB /* WebViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61F540DD20625D61006E11FB /* WebViewController.storyboard */; }; 25 | 61F540E820625DDC006E11FB /* TableVIewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F540E720625DDC006E11FB /* TableVIewController.swift */; }; 26 | 61F540EA20625DEA006E11FB /* TableViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61F540E920625DEA006E11FB /* TableViewController.storyboard */; }; 27 | 61F540EC20625DFE006E11FB /* CollectionViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 61F540EB20625DFE006E11FB /* CollectionViewController.storyboard */; }; 28 | 61F540EE20625E05006E11FB /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61F540ED20625E05006E11FB /* CollectionViewController.swift */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 6154F5E8203B1CC600040F47 /* SilentScrolly.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SilentScrolly.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 6154F5EB203B1CC600040F47 /* SilentScrolly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SilentScrolly.h; sourceTree = ""; }; 34 | 6154F5EC203B1CC600040F47 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 615EC443205574EC00F2A392 /* SilentScrolly.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilentScrolly.swift; sourceTree = ""; }; 36 | 615EC444205574EC00F2A392 /* SilentScrollable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SilentScrollable.swift; sourceTree = ""; }; 37 | 61766023203BCD6D0049B35E /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 61766037203BDC2F0049B35E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 39 | 61766038203BDC2F0049B35E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 40 | 6176603D203BDC2F0049B35E /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | 61F540C7206238BF006E11FB /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; 42 | 61F540D520625D61006E11FB /* TabBarController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = TabBarController.storyboard; sourceTree = ""; }; 43 | 61F540D620625D61006E11FB /* NavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationController.swift; sourceTree = ""; }; 44 | 61F540D720625D61006E11FB /* TabBarController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; 45 | 61F540D920625D61006E11FB /* ToolBarViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ToolBarViewController.storyboard; sourceTree = ""; }; 46 | 61F540DA20625D61006E11FB /* ToolBarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolBarViewController.swift; sourceTree = ""; }; 47 | 61F540DC20625D61006E11FB /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; }; 48 | 61F540DD20625D61006E11FB /* WebViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = WebViewController.storyboard; sourceTree = ""; }; 49 | 61F540E720625DDC006E11FB /* TableVIewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableVIewController.swift; sourceTree = ""; }; 50 | 61F540E920625DEA006E11FB /* TableViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TableViewController.storyboard; sourceTree = ""; }; 51 | 61F540EB20625DFE006E11FB /* CollectionViewController.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = CollectionViewController.storyboard; sourceTree = ""; }; 52 | 61F540ED20625E05006E11FB /* CollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 6154F5E4203B1CC600040F47 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | ); 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | 61766020203BCD6D0049B35E /* Frameworks */ = { 64 | isa = PBXFrameworksBuildPhase; 65 | buildActionMask = 2147483647; 66 | files = ( 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | 6154F5DE203B1CC600040F47 = { 74 | isa = PBXGroup; 75 | children = ( 76 | 61766035203BDC2F0049B35E /* Example */, 77 | 6154F5EA203B1CC600040F47 /* SilentScrolly */, 78 | 6154F5E9203B1CC600040F47 /* Products */, 79 | ); 80 | sourceTree = ""; 81 | }; 82 | 6154F5E9203B1CC600040F47 /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 6154F5E8203B1CC600040F47 /* SilentScrolly.framework */, 86 | 61766023203BCD6D0049B35E /* Example.app */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | 6154F5EA203B1CC600040F47 /* SilentScrolly */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 615EC444205574EC00F2A392 /* SilentScrollable.swift */, 95 | 615EC443205574EC00F2A392 /* SilentScrolly.swift */, 96 | 6154F5EB203B1CC600040F47 /* SilentScrolly.h */, 97 | 6154F5EC203B1CC600040F47 /* Info.plist */, 98 | ); 99 | path = SilentScrolly; 100 | sourceTree = ""; 101 | }; 102 | 61766035203BDC2F0049B35E /* Example */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 61766036203BDC2F0049B35E /* Resources */, 106 | 61766039203BDC2F0049B35E /* Sources */, 107 | ); 108 | path = Example; 109 | sourceTree = ""; 110 | }; 111 | 61766036203BDC2F0049B35E /* Resources */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 61F540C7206238BF006E11FB /* LaunchScreen.storyboard */, 115 | 61766037203BDC2F0049B35E /* Assets.xcassets */, 116 | 61766038203BDC2F0049B35E /* Info.plist */, 117 | ); 118 | path = Resources; 119 | sourceTree = ""; 120 | }; 121 | 61766039203BDC2F0049B35E /* Sources */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 61F540C920625CD3006E11FB /* Controllers */, 125 | 6176603D203BDC2F0049B35E /* AppDelegate.swift */, 126 | ); 127 | path = Sources; 128 | sourceTree = ""; 129 | }; 130 | 61F540C920625CD3006E11FB /* Controllers */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 61F540E520625DBF006E11FB /* Table */, 134 | 61F540E620625DBF006E11FB /* Collection */, 135 | 61F540DB20625D61006E11FB /* Web */, 136 | 61F540D820625D61006E11FB /* ToolBar */, 137 | 61F540D420625D61006E11FB /* TabBar */, 138 | ); 139 | path = Controllers; 140 | sourceTree = ""; 141 | }; 142 | 61F540D420625D61006E11FB /* TabBar */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 61F540D520625D61006E11FB /* TabBarController.storyboard */, 146 | 61F540D720625D61006E11FB /* TabBarController.swift */, 147 | 61F540D620625D61006E11FB /* NavigationController.swift */, 148 | ); 149 | path = TabBar; 150 | sourceTree = ""; 151 | }; 152 | 61F540D820625D61006E11FB /* ToolBar */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | 61F540D920625D61006E11FB /* ToolBarViewController.storyboard */, 156 | 61F540DA20625D61006E11FB /* ToolBarViewController.swift */, 157 | ); 158 | path = ToolBar; 159 | sourceTree = ""; 160 | }; 161 | 61F540DB20625D61006E11FB /* Web */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 61F540DD20625D61006E11FB /* WebViewController.storyboard */, 165 | 61F540DC20625D61006E11FB /* WebViewController.swift */, 166 | ); 167 | path = Web; 168 | sourceTree = ""; 169 | }; 170 | 61F540E520625DBF006E11FB /* Table */ = { 171 | isa = PBXGroup; 172 | children = ( 173 | 61F540E920625DEA006E11FB /* TableViewController.storyboard */, 174 | 61F540E720625DDC006E11FB /* TableVIewController.swift */, 175 | ); 176 | path = Table; 177 | sourceTree = ""; 178 | }; 179 | 61F540E620625DBF006E11FB /* Collection */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 61F540EB20625DFE006E11FB /* CollectionViewController.storyboard */, 183 | 61F540ED20625E05006E11FB /* CollectionViewController.swift */, 184 | ); 185 | path = Collection; 186 | sourceTree = ""; 187 | }; 188 | /* End PBXGroup section */ 189 | 190 | /* Begin PBXHeadersBuildPhase section */ 191 | 6154F5E5203B1CC600040F47 /* Headers */ = { 192 | isa = PBXHeadersBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | 6154F5ED203B1CC600040F47 /* SilentScrolly.h in Headers */, 196 | ); 197 | runOnlyForDeploymentPostprocessing = 0; 198 | }; 199 | /* End PBXHeadersBuildPhase section */ 200 | 201 | /* Begin PBXNativeTarget section */ 202 | 6154F5E7203B1CC600040F47 /* SilentScrolly */ = { 203 | isa = PBXNativeTarget; 204 | buildConfigurationList = 6154F5F0203B1CC600040F47 /* Build configuration list for PBXNativeTarget "SilentScrolly" */; 205 | buildPhases = ( 206 | 6154F5E3203B1CC600040F47 /* Sources */, 207 | 6154F5E4203B1CC600040F47 /* Frameworks */, 208 | 6154F5E5203B1CC600040F47 /* Headers */, 209 | 6154F5E6203B1CC600040F47 /* Resources */, 210 | ); 211 | buildRules = ( 212 | ); 213 | dependencies = ( 214 | ); 215 | name = SilentScrolly; 216 | productName = SilentScrolly; 217 | productReference = 6154F5E8203B1CC600040F47 /* SilentScrolly.framework */; 218 | productType = "com.apple.product-type.framework"; 219 | }; 220 | 61766022203BCD6D0049B35E /* Example */ = { 221 | isa = PBXNativeTarget; 222 | buildConfigurationList = 61766034203BCD6D0049B35E /* Build configuration list for PBXNativeTarget "Example" */; 223 | buildPhases = ( 224 | 6176601F203BCD6D0049B35E /* Sources */, 225 | 61766020203BCD6D0049B35E /* Frameworks */, 226 | 61766021203BCD6D0049B35E /* Resources */, 227 | ); 228 | buildRules = ( 229 | ); 230 | dependencies = ( 231 | ); 232 | name = Example; 233 | productName = Example; 234 | productReference = 61766023203BCD6D0049B35E /* Example.app */; 235 | productType = "com.apple.product-type.application"; 236 | }; 237 | /* End PBXNativeTarget section */ 238 | 239 | /* Begin PBXProject section */ 240 | 6154F5DF203B1CC600040F47 /* Project object */ = { 241 | isa = PBXProject; 242 | attributes = { 243 | LastSwiftUpdateCheck = 0920; 244 | LastUpgradeCheck = 0930; 245 | ORGANIZATIONNAME = "Takuma Horiuchi"; 246 | TargetAttributes = { 247 | 6154F5E7203B1CC600040F47 = { 248 | CreatedOnToolsVersion = 9.2; 249 | LastSwiftMigration = 0920; 250 | ProvisioningStyle = Automatic; 251 | }; 252 | 61766022203BCD6D0049B35E = { 253 | CreatedOnToolsVersion = 9.2; 254 | LastSwiftMigration = 0920; 255 | ProvisioningStyle = Automatic; 256 | }; 257 | }; 258 | }; 259 | buildConfigurationList = 6154F5E2203B1CC600040F47 /* Build configuration list for PBXProject "SilentScrolly" */; 260 | compatibilityVersion = "Xcode 8.0"; 261 | developmentRegion = en; 262 | hasScannedForEncodings = 0; 263 | knownRegions = ( 264 | en, 265 | Base, 266 | ); 267 | mainGroup = 6154F5DE203B1CC600040F47; 268 | productRefGroup = 6154F5E9203B1CC600040F47 /* Products */; 269 | projectDirPath = ""; 270 | projectRoot = ""; 271 | targets = ( 272 | 6154F5E7203B1CC600040F47 /* SilentScrolly */, 273 | 61766022203BCD6D0049B35E /* Example */, 274 | ); 275 | }; 276 | /* End PBXProject section */ 277 | 278 | /* Begin PBXResourcesBuildPhase section */ 279 | 6154F5E6203B1CC600040F47 /* Resources */ = { 280 | isa = PBXResourcesBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | ); 284 | runOnlyForDeploymentPostprocessing = 0; 285 | }; 286 | 61766021203BCD6D0049B35E /* Resources */ = { 287 | isa = PBXResourcesBuildPhase; 288 | buildActionMask = 2147483647; 289 | files = ( 290 | 61F540E120625D61006E11FB /* ToolBarViewController.storyboard in Resources */, 291 | 6176604E203BDD3F0049B35E /* Assets.xcassets in Resources */, 292 | 61F540EA20625DEA006E11FB /* TableViewController.storyboard in Resources */, 293 | 61F540DE20625D61006E11FB /* TabBarController.storyboard in Resources */, 294 | 61F540E420625D61006E11FB /* WebViewController.storyboard in Resources */, 295 | 61F540C8206238BF006E11FB /* LaunchScreen.storyboard in Resources */, 296 | 61F540EC20625DFE006E11FB /* CollectionViewController.storyboard in Resources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | /* End PBXResourcesBuildPhase section */ 301 | 302 | /* Begin PBXSourcesBuildPhase section */ 303 | 6154F5E3203B1CC600040F47 /* Sources */ = { 304 | isa = PBXSourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | 615EC445205574EC00F2A392 /* SilentScrolly.swift in Sources */, 308 | 615EC446205574EC00F2A392 /* SilentScrollable.swift in Sources */, 309 | ); 310 | runOnlyForDeploymentPostprocessing = 0; 311 | }; 312 | 6176601F203BCD6D0049B35E /* Sources */ = { 313 | isa = PBXSourcesBuildPhase; 314 | buildActionMask = 2147483647; 315 | files = ( 316 | 61F540EE20625E05006E11FB /* CollectionViewController.swift in Sources */, 317 | 61F540E320625D61006E11FB /* WebViewController.swift in Sources */, 318 | 61F540E220625D61006E11FB /* ToolBarViewController.swift in Sources */, 319 | 615EC4472055750800F2A392 /* SilentScrollable.swift in Sources */, 320 | 61F540E820625DDC006E11FB /* TableVIewController.swift in Sources */, 321 | 61F540DF20625D61006E11FB /* NavigationController.swift in Sources */, 322 | 615EC4482055750800F2A392 /* SilentScrolly.swift in Sources */, 323 | 6176604D203BDD330049B35E /* AppDelegate.swift in Sources */, 324 | 61F540E020625D61006E11FB /* TabBarController.swift in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | /* End PBXSourcesBuildPhase section */ 329 | 330 | /* Begin XCBuildConfiguration section */ 331 | 6154F5EE203B1CC600040F47 /* Debug */ = { 332 | isa = XCBuildConfiguration; 333 | buildSettings = { 334 | ALWAYS_SEARCH_USER_PATHS = NO; 335 | CLANG_ANALYZER_NONNULL = YES; 336 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 337 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 338 | CLANG_CXX_LIBRARY = "libc++"; 339 | CLANG_ENABLE_MODULES = YES; 340 | CLANG_ENABLE_OBJC_ARC = YES; 341 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 342 | CLANG_WARN_BOOL_CONVERSION = YES; 343 | CLANG_WARN_COMMA = YES; 344 | CLANG_WARN_CONSTANT_CONVERSION = YES; 345 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 346 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 347 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 348 | CLANG_WARN_EMPTY_BODY = YES; 349 | CLANG_WARN_ENUM_CONVERSION = YES; 350 | CLANG_WARN_INFINITE_RECURSION = YES; 351 | CLANG_WARN_INT_CONVERSION = YES; 352 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 353 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 354 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 355 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 356 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 357 | CLANG_WARN_STRICT_PROTOTYPES = YES; 358 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 359 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 360 | CLANG_WARN_UNREACHABLE_CODE = YES; 361 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 362 | CODE_SIGN_IDENTITY = "iPhone Developer"; 363 | COPY_PHASE_STRIP = NO; 364 | CURRENT_PROJECT_VERSION = 1; 365 | DEBUG_INFORMATION_FORMAT = dwarf; 366 | ENABLE_STRICT_OBJC_MSGSEND = YES; 367 | ENABLE_TESTABILITY = YES; 368 | GCC_C_LANGUAGE_STANDARD = gnu11; 369 | GCC_DYNAMIC_NO_PIC = NO; 370 | GCC_NO_COMMON_BLOCKS = YES; 371 | GCC_OPTIMIZATION_LEVEL = 0; 372 | GCC_PREPROCESSOR_DEFINITIONS = ( 373 | "DEBUG=1", 374 | "$(inherited)", 375 | ); 376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 378 | GCC_WARN_UNDECLARED_SELECTOR = YES; 379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 380 | GCC_WARN_UNUSED_FUNCTION = YES; 381 | GCC_WARN_UNUSED_VARIABLE = YES; 382 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 383 | MTL_ENABLE_DEBUG_INFO = YES; 384 | ONLY_ACTIVE_ARCH = YES; 385 | SDKROOT = iphoneos; 386 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 387 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 388 | VERSIONING_SYSTEM = "apple-generic"; 389 | VERSION_INFO_PREFIX = ""; 390 | }; 391 | name = Debug; 392 | }; 393 | 6154F5EF203B1CC600040F47 /* Release */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | ALWAYS_SEARCH_USER_PATHS = NO; 397 | CLANG_ANALYZER_NONNULL = YES; 398 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 399 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 400 | CLANG_CXX_LIBRARY = "libc++"; 401 | CLANG_ENABLE_MODULES = YES; 402 | CLANG_ENABLE_OBJC_ARC = YES; 403 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 404 | CLANG_WARN_BOOL_CONVERSION = YES; 405 | CLANG_WARN_COMMA = YES; 406 | CLANG_WARN_CONSTANT_CONVERSION = YES; 407 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 408 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 409 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 410 | CLANG_WARN_EMPTY_BODY = YES; 411 | CLANG_WARN_ENUM_CONVERSION = YES; 412 | CLANG_WARN_INFINITE_RECURSION = YES; 413 | CLANG_WARN_INT_CONVERSION = YES; 414 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 415 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 416 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 419 | CLANG_WARN_STRICT_PROTOTYPES = YES; 420 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 421 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 422 | CLANG_WARN_UNREACHABLE_CODE = YES; 423 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 424 | CODE_SIGN_IDENTITY = "iPhone Developer"; 425 | COPY_PHASE_STRIP = NO; 426 | CURRENT_PROJECT_VERSION = 1; 427 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 428 | ENABLE_NS_ASSERTIONS = NO; 429 | ENABLE_STRICT_OBJC_MSGSEND = YES; 430 | GCC_C_LANGUAGE_STANDARD = gnu11; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 433 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 434 | GCC_WARN_UNDECLARED_SELECTOR = YES; 435 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 436 | GCC_WARN_UNUSED_FUNCTION = YES; 437 | GCC_WARN_UNUSED_VARIABLE = YES; 438 | IPHONEOS_DEPLOYMENT_TARGET = 11.2; 439 | MTL_ENABLE_DEBUG_INFO = NO; 440 | SDKROOT = iphoneos; 441 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 442 | VALIDATE_PRODUCT = YES; 443 | VERSIONING_SYSTEM = "apple-generic"; 444 | VERSION_INFO_PREFIX = ""; 445 | }; 446 | name = Release; 447 | }; 448 | 6154F5F1203B1CC600040F47 /* Debug */ = { 449 | isa = XCBuildConfiguration; 450 | buildSettings = { 451 | CLANG_ENABLE_MODULES = YES; 452 | CODE_SIGN_IDENTITY = ""; 453 | CODE_SIGN_STYLE = Automatic; 454 | DEFINES_MODULE = YES; 455 | DEVELOPMENT_TEAM = 4ZJ5LV82G2; 456 | DYLIB_COMPATIBILITY_VERSION = 1; 457 | DYLIB_CURRENT_VERSION = 1; 458 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 459 | INFOPLIST_FILE = SilentScrolly/Info.plist; 460 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 461 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 462 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 463 | PRODUCT_BUNDLE_IDENTIFIER = TakumaHoriuchi.SilentScrolly; 464 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 465 | SKIP_INSTALL = YES; 466 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 467 | SWIFT_VERSION = 4.0; 468 | TARGETED_DEVICE_FAMILY = "1,2"; 469 | }; 470 | name = Debug; 471 | }; 472 | 6154F5F2203B1CC600040F47 /* Release */ = { 473 | isa = XCBuildConfiguration; 474 | buildSettings = { 475 | CLANG_ENABLE_MODULES = YES; 476 | CODE_SIGN_IDENTITY = ""; 477 | CODE_SIGN_STYLE = Automatic; 478 | DEFINES_MODULE = YES; 479 | DEVELOPMENT_TEAM = 4ZJ5LV82G2; 480 | DYLIB_COMPATIBILITY_VERSION = 1; 481 | DYLIB_CURRENT_VERSION = 1; 482 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 483 | INFOPLIST_FILE = SilentScrolly/Info.plist; 484 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 485 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 486 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 487 | PRODUCT_BUNDLE_IDENTIFIER = TakumaHoriuchi.SilentScrolly; 488 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 489 | SKIP_INSTALL = YES; 490 | SWIFT_VERSION = 4.0; 491 | TARGETED_DEVICE_FAMILY = "1,2"; 492 | }; 493 | name = Release; 494 | }; 495 | 61766032203BCD6D0049B35E /* Debug */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 499 | CLANG_ENABLE_MODULES = YES; 500 | CODE_SIGN_STYLE = Automatic; 501 | DEVELOPMENT_TEAM = 4ZJ5LV82G2; 502 | INFOPLIST_FILE = "$(SRCROOT)/Example/Resources/Info.plist"; 503 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 504 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 505 | PRODUCT_BUNDLE_IDENTIFIER = TakumaHoriuchi.SilentScrolly.Example; 506 | PRODUCT_NAME = "$(TARGET_NAME)"; 507 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 508 | SWIFT_VERSION = 4.0; 509 | TARGETED_DEVICE_FAMILY = "1,2"; 510 | }; 511 | name = Debug; 512 | }; 513 | 61766033203BCD6D0049B35E /* Release */ = { 514 | isa = XCBuildConfiguration; 515 | buildSettings = { 516 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 517 | CLANG_ENABLE_MODULES = YES; 518 | CODE_SIGN_STYLE = Automatic; 519 | DEVELOPMENT_TEAM = 4ZJ5LV82G2; 520 | INFOPLIST_FILE = "$(SRCROOT)/Example/Resources/Info.plist"; 521 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 522 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 523 | PRODUCT_BUNDLE_IDENTIFIER = TakumaHoriuchi.SilentScrolly.Example; 524 | PRODUCT_NAME = "$(TARGET_NAME)"; 525 | SWIFT_VERSION = 4.0; 526 | TARGETED_DEVICE_FAMILY = "1,2"; 527 | }; 528 | name = Release; 529 | }; 530 | /* End XCBuildConfiguration section */ 531 | 532 | /* Begin XCConfigurationList section */ 533 | 6154F5E2203B1CC600040F47 /* Build configuration list for PBXProject "SilentScrolly" */ = { 534 | isa = XCConfigurationList; 535 | buildConfigurations = ( 536 | 6154F5EE203B1CC600040F47 /* Debug */, 537 | 6154F5EF203B1CC600040F47 /* Release */, 538 | ); 539 | defaultConfigurationIsVisible = 0; 540 | defaultConfigurationName = Release; 541 | }; 542 | 6154F5F0203B1CC600040F47 /* Build configuration list for PBXNativeTarget "SilentScrolly" */ = { 543 | isa = XCConfigurationList; 544 | buildConfigurations = ( 545 | 6154F5F1203B1CC600040F47 /* Debug */, 546 | 6154F5F2203B1CC600040F47 /* Release */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | 61766034203BCD6D0049B35E /* Build configuration list for PBXNativeTarget "Example" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 61766032203BCD6D0049B35E /* Debug */, 555 | 61766033203BCD6D0049B35E /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | /* End XCConfigurationList section */ 561 | }; 562 | rootObject = 6154F5DF203B1CC600040F47 /* Project object */; 563 | } 564 | --------------------------------------------------------------------------------