├── .gitignore ├── .swift-version ├── Example ├── LICENSE ├── NotchToolkit-Example.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── NotchToolkit-Example.xcscheme │ │ └── NotchToolkit.xcscheme ├── NotchToolkit-Example.xcworkspace │ └── contents.xcworkspacedata ├── NotchToolkit-Example │ ├── AppDelegate.swift │ ├── Assets │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── pikachusquare.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── pikachusquare.png │ │ │ └── spongebob.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── spongebob.png │ │ └── tst_img.JPG │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── CornerOvalViewController.swift │ ├── Info.plist │ ├── NotchImageViewController.swift │ └── ViewController.swift ├── NotchToolkit-ExampleTests │ ├── Info.plist │ └── NotchToolkit_ExampleTests.swift ├── NotchToolkit │ ├── Cells │ │ ├── NotchToolCell.swift │ │ └── NotchToolNameIconCell.swift │ ├── Classes │ │ ├── NotchBar.swift │ │ ├── NotchImageView.swift │ │ └── NotchToolbar.swift │ ├── Enumerations │ │ ├── CurveSettings.swift │ │ ├── DeviceOrientation.swift │ │ ├── NotchMode.swift │ │ ├── NotchScroll.swift │ │ └── ToolIconTypes.swift │ ├── Extenstions │ │ ├── UIScreen+NotchFrame.swift │ │ ├── UIScreen+NotchPositionMultiplier.swift │ │ ├── UIScreen+iPhone10.swift │ │ └── UIView+DrawNotch.swift │ ├── Info.plist │ ├── NotchToolkit.h │ └── Protocols │ │ └── NotchToolbarDelegate.swift ├── Podfile ├── Podfile.lock └── Pods │ ├── Local Podspecs │ └── NotchToolkit.podspec.json │ ├── Manifest.lock │ ├── NotchToolkit │ ├── LICENSE │ ├── NotchToolkit │ │ ├── Cells │ │ │ └── NotchToolCell.swift │ │ ├── Enumerators │ │ │ ├── CurveSettings.swift │ │ │ ├── DeviceOrientation.swift │ │ │ ├── NotchMode.swift │ │ │ └── NotchScroll.swift │ │ ├── Extensions │ │ │ ├── UIScreen+NotchFrame.swift │ │ │ ├── UIScreen+NotchPositionMultiplier.swift │ │ │ ├── UIScreen+iPhone10.swift │ │ │ └── UIView+OvalOrCorners.swift │ │ ├── NotchBar.swift │ │ ├── NotchToolbar.swift │ │ ├── NotchToolkit.h │ │ └── Protocols │ │ │ └── NotchToolbarDelegate.swift │ └── README.md │ ├── Pods.xcodeproj │ └── project.pbxproj │ └── Target Support Files │ ├── NotchToolkit │ ├── Info.plist │ ├── NotchToolkit-dummy.m │ ├── NotchToolkit-prefix.pch │ ├── NotchToolkit-umbrella.h │ ├── NotchToolkit.modulemap │ └── NotchToolkit.xcconfig │ ├── Pods-NotchToolkit-Example │ ├── Info.plist │ ├── Pods-NotchToolkit-Example-acknowledgements.markdown │ ├── Pods-NotchToolkit-Example-acknowledgements.plist │ ├── Pods-NotchToolkit-Example-dummy.m │ ├── Pods-NotchToolkit-Example-frameworks.sh │ ├── Pods-NotchToolkit-Example-resources.sh │ ├── Pods-NotchToolkit-Example-umbrella.h │ ├── Pods-NotchToolkit-Example.debug.xcconfig │ ├── Pods-NotchToolkit-Example.modulemap │ └── Pods-NotchToolkit-Example.release.xcconfig │ └── Pods-NotchToolkit-ExampleTests │ ├── Info.plist │ ├── Pods-NotchToolkit-ExampleTests-acknowledgements.markdown │ ├── Pods-NotchToolkit-ExampleTests-acknowledgements.plist │ ├── Pods-NotchToolkit-ExampleTests-dummy.m │ ├── Pods-NotchToolkit-ExampleTests-frameworks.sh │ ├── Pods-NotchToolkit-ExampleTests-resources.sh │ ├── Pods-NotchToolkit-ExampleTests-umbrella.h │ ├── Pods-NotchToolkit-ExampleTests.debug.xcconfig │ ├── Pods-NotchToolkit-ExampleTests.modulemap │ └── Pods-NotchToolkit-ExampleTests.release.xcconfig ├── LICENSE ├── NotchToolkit.podspec ├── NotchToolkit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── NotchToolkit.xcscheme ├── NotchToolkit ├── Cells │ ├── NotchToolCell.swift │ └── NotchToolNameIconCell.swift ├── Classes │ ├── NotchBar.swift │ ├── NotchImageView.swift │ └── NotchToolbar.swift ├── Enumerations │ ├── CurveSettings.swift │ ├── DeviceOrientation.swift │ ├── NotchMode.swift │ ├── NotchScroll.swift │ └── ToolIconTypes.swift ├── Extensions │ ├── UIScreen+NotchFrame.swift │ ├── UIScreen+NotchPositionMultiplier.swift │ ├── UIScreen+iPhone10.swift │ └── UIView+DrawNotch.swift ├── Info.plist ├── NotchToolkit.h └── Protocols │ └── NotchToolbarDelegate.swift ├── NotchToolkitTests ├── Info.plist └── NotchToolkitTests.swift ├── README.md └── drawNotch.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.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 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | echo "4.0" > .swift-version -------------------------------------------------------------------------------- /Example/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ahmed Fathi Bekhit[me@ahmedbekhit.com] 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 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example.xcodeproj/xcshareddata/xcschemes/NotchToolkit-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 87 | 93 | 94 | 95 | 96 | 98 | 99 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example.xcodeproj/xcshareddata/xcschemes/NotchToolkit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // NotchToolkit-Example 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/Assets/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/NotchToolkit-Example/Assets/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/Assets/Assets.xcassets/pikachusquare.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "pikachusquare.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/Assets/Assets.xcassets/pikachusquare.imageset/pikachusquare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AFathi/NotchToolkit/d8c0e69c440df88eb7f66103a6e01ebc24506f74/Example/NotchToolkit-Example/Assets/Assets.xcassets/pikachusquare.imageset/pikachusquare.png -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/Assets/Assets.xcassets/spongebob.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "spongebob.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/Assets/Assets.xcassets/spongebob.imageset/spongebob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AFathi/NotchToolkit/d8c0e69c440df88eb7f66103a6e01ebc24506f74/Example/NotchToolkit-Example/Assets/Assets.xcassets/spongebob.imageset/spongebob.png -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/Assets/tst_img.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AFathi/NotchToolkit/d8c0e69c440df88eb7f66103a6e01ebc24506f74/Example/NotchToolkit-Example/Assets/tst_img.JPG -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/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 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/CornerOvalViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CornerOvalViewController.swift 3 | // NotchToolkit-Example 4 | // 5 | // Created by Ahmed Bekhit on 9/26/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CornerOvalViewController: UIViewController { 12 | @IBOutlet var aView: UIView! 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | override func didReceiveMemoryWarning() { 21 | super.didReceiveMemoryWarning() 22 | // Dispose of any resources that can be recreated. 23 | } 24 | 25 | @IBAction func drawOval(_ sender: UISegmentedControl) { 26 | if sender.selectedSegmentIndex == 0 { 27 | aView.draw(.oval, position: .right, curve: 1.5) 28 | }else if sender.selectedSegmentIndex == 1 { 29 | aView.draw(.oval, position: .left, curve: 1.5) 30 | }else if sender.selectedSegmentIndex == 2 { 31 | aView.draw(.oval, position: .top, curve: 1.5) 32 | }else if sender.selectedSegmentIndex == 3 { 33 | aView.draw(.oval, position: .bottom, curve: 1.5) 34 | }else if sender.selectedSegmentIndex == 4 { 35 | aView.draw(.oval, position: .horizontalSides, curve: 1.5) 36 | }else if sender.selectedSegmentIndex == 5 { 37 | aView.draw(.oval, position: .verticalSides, curve: 1.5) 38 | }else if sender.selectedSegmentIndex == 6 { 39 | aView.draw(.oval, position: .all, curve: 1.5) 40 | } 41 | } 42 | @IBAction func drawCorner(_ sender: UISegmentedControl) { 43 | if sender.selectedSegmentIndex == 0 { 44 | aView.draw(.corner, position: .right, curve: 35) 45 | }else if sender.selectedSegmentIndex == 1 { 46 | aView.draw(.corner, position: .left, curve: 35) 47 | }else if sender.selectedSegmentIndex == 2 { 48 | aView.draw(.corner, position: .top, curve: 35) 49 | }else if sender.selectedSegmentIndex == 3 { 50 | aView.draw(.corner, position: .bottom, curve: 35) 51 | }else if sender.selectedSegmentIndex == 4 { 52 | aView.draw(.corner, position: .diagonalAC, curve: 35) 53 | }else if sender.selectedSegmentIndex == 5 { 54 | aView.draw(.corner, position: .diagonalBD, curve: 35) 55 | }else if sender.selectedSegmentIndex == 6 { 56 | aView.draw(.corner, position: .all, curve: 35) 57 | } 58 | } 59 | 60 | @IBAction func dismissView(_ sender: UIButton) { 61 | self.dismiss(animated: true, completion:nil) 62 | } 63 | /* 64 | // MARK: - Navigation 65 | 66 | // In a storyboard-based application, you will often want to do a little preparation before navigation 67 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 68 | // Get the new view controller using segue.destinationViewController. 69 | // Pass the selected object to the new view controller. 70 | } 71 | */ 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/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 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/NotchImageViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchImageViewController.swift 3 | // NotchToolkit-Example 4 | // 5 | // Created by Ahmed Bekhit on 11/8/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NotchToolkit 11 | 12 | // MARK: - Implement NotchToolkit 13 | 14 | //Step 1. add `NotchToolbarDelegate` 15 | //Step 2. implement delegate functions, check NotchToolkit Delegates 16 | 17 | class NotchImageViewController: UIViewController { 18 | //Step 3. initialize `NotchImageView` 19 | var imageView: NotchImageView? 20 | 21 | override func viewDidLoad() { 22 | super.viewDidLoad() 23 | imageView = NotchImageView(image: UIImage(named:"tst_img.JPG")) 24 | } 25 | 26 | override func didReceiveMemoryWarning() { 27 | super.didReceiveMemoryWarning() 28 | } 29 | 30 | } 31 | 32 | // MARK: - NotchToolkit Delegate Methods 33 | extension NotchImageViewController: NotchToolbarDelegate { 34 | func deviceDidRotate() { 35 | //Step 5. call `autoResize` in the `deviceDidRotate` function 36 | imageView?.autoResize() 37 | } 38 | 39 | // This delegate function allows you to detect which toolbar icon was selected. 40 | func didTapToolIcon(_ tools: UICollectionView, toolIndex: IndexPath, section: Int, row: Int) { 41 | } 42 | } 43 | 44 | // MARK: - ViewController Buttons IBAction 45 | extension NotchImageViewController { 46 | @IBAction func loadNotchImage(_ sender: UIButton) { 47 | if !(imageView?.isVisible)! { 48 | sender.setTitle("Delete Image Object", for: .normal) 49 | imageView?.durationIntervals = 2.8 50 | imageView?.printBarColor = .red 51 | imageView?.printBarHeight = 5 52 | imageView?.delegate = self 53 | imageView?.prepare(in: self) 54 | imageView?.load() 55 | self.view.insertSubview(sender, aboveSubview: imageView!) 56 | }else{ 57 | sender.setTitle("Load Image from Notch", for: .normal) 58 | imageView?.remove() 59 | imageView = NotchImageView(image: UIImage(named:"tst_img.JPG")) 60 | } 61 | } 62 | 63 | @IBAction func goBack(_ sender: UIButton) { 64 | self.dismiss(animated: true, completion: nil) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Example/NotchToolkit-Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // NotchToolkit-Example 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NotchToolkit 11 | 12 | // MARK: - Tool Icons Arrays 13 | extension ViewController { 14 | /** 15 | This is a custom array used to show more info when an icon is tapped 16 | */ 17 | var iconListInfo:[String] { 18 | return ["Pika-Pikachu CHAAAAA", "AYYEE AYYEE CAPTAIN!","Just thinking, brb.", "Oh nerdy, my fav emoji.", "An iPhone compiling apps wirelessly.", "hacker", "hacker", "checklist", "sooooo liitttt"] 19 | } 20 | 21 | /** 22 | This array contains all the tool icons info. 23 | **NOTE**: an array of [UIImage, String] is displayed as one icon with the string content as a title. 24 | */ 25 | var toolListIcons:[Any] { 26 | return [ 27 | [UIImage(named:"pikachusquare")!, "Pikachu"], 28 | [UIImage(named:"spongebob")!, "Spongebob"], 29 | "🤔", "🤓", 30 | "📱", "👩‍💻", 31 | "👨‍💻", "✅", 32 | "🔥"] 33 | } 34 | } 35 | 36 | // MARK: - Implement NotchToolkit 37 | 38 | //Step 1. add `NotchToolbarDelegate` 39 | //Step 2. implement delegate functions, check NotchToolkit Delegates 40 | 41 | class ViewController: UIViewController { 42 | 43 | //Step 3. initialize `NotchToolbar` 44 | let toolbar = NotchToolbar() 45 | 46 | override func viewDidLoad() { 47 | super.viewDidLoad() 48 | //Step 4. setup `NotchToolbar` options 49 | 50 | //Set to true to make the toolbar visible initially--default is false. 51 | toolbar.notch.isVisible = false 52 | 53 | //Set the height of the NotchBar--default is 250. 54 | toolbar.notch.height = 250 55 | 56 | //`toolList` array accepts Strings, UIImage or an array of both types 57 | toolbar.iconWithNameFont = UIFont(name: "Avenir-Medium", size: 10.0)! 58 | toolbar.toolList = toolListIcons 59 | 60 | toolbar.delegate = self 61 | toolbar.prepare(in: self) 62 | } 63 | 64 | override func didReceiveMemoryWarning() { 65 | super.didReceiveMemoryWarning() 66 | // Dispose of any resources that can be recreated. 67 | } 68 | } 69 | 70 | // MARK: - NotchToolkit Delegate Methods 71 | extension ViewController: NotchToolbarDelegate { 72 | func deviceDidRotate() { 73 | //Step 5. call `autoResize` in the `deviceDidRotate` function 74 | toolbar.autoResize() 75 | } 76 | 77 | // This delegate function allows you to detect which toolbar icon was selected. 78 | func didTapToolIcon(_ tools: UICollectionView, toolIndex: IndexPath, section: Int, row: Int) { 79 | let alert = UIAlertController(title: "NotchToolkit Alert", message: iconListInfo[row], preferredStyle: UIAlertControllerStyle.alert) 80 | alert.addAction(UIAlertAction(title: "👍", style: UIAlertActionStyle.cancel, handler: { 81 | (UIAlertAction)in 82 | })) 83 | self.present(alert, animated: true, completion: nil) 84 | } 85 | } 86 | 87 | // MARK: - ViewController Buttons IBAction 88 | extension ViewController { 89 | @IBAction func showAction(_ sender: UIButton) { 90 | if toolbar.notch.isVisible { 91 | sender.setTitle("Show Notch Toolbar", for: .normal) 92 | }else{ 93 | sender.setTitle("Hide Notch Toolbar", for: .normal) 94 | } 95 | toolbar.showOrHide() 96 | 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Example/NotchToolkit-ExampleTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/NotchToolkit-ExampleTests/NotchToolkit_ExampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolkit_ExampleTests.swift 3 | // NotchToolkit-ExampleTests 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import NotchToolkit_Example 11 | 12 | class NotchToolkit_ExampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Cells/NotchToolCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolCell.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class NotchToolCell: UICollectionViewCell { 12 | private var toolIcon : UIImageView? 13 | private var toolTitle : UILabel? 14 | 15 | func setIcon(_ image:UIImage?) { 16 | if toolIcon == nil { 17 | toolIcon = UIImageView() 18 | toolIcon?.frame = CGRect(x: 0, y:0, width: contentView.frame.width, height: contentView.frame.height) 19 | toolIcon?.contentMode = .scaleAspectFit 20 | contentView.addSubview(toolIcon!) 21 | } 22 | 23 | if let icon = toolIcon { 24 | if let img = image { 25 | icon.image = img 26 | } 27 | icon.isHidden = false 28 | } 29 | if let title = toolTitle { 30 | title.isHidden = true 31 | } 32 | } 33 | 34 | func setTitle(_ text:String, font:UIFont, color:UIColor) { 35 | if toolTitle == nil { 36 | toolTitle = UILabel() 37 | toolTitle?.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 38 | toolTitle?.font = font 39 | toolTitle?.textColor = color 40 | toolTitle?.textAlignment = .center 41 | contentView.addSubview(toolTitle!) 42 | } 43 | 44 | if let title = toolTitle { 45 | title.text = text 46 | title.isHidden = false 47 | } 48 | 49 | if let icon = toolIcon { 50 | icon.isHidden = true 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Cells/NotchToolNameIconCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolNameIconCell.swift 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 9/28/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NotchToolNameIconCell: UICollectionViewCell { 12 | private var toolIcon : UIImageView? 13 | private var toolTitle : UILabel? 14 | 15 | func set(_ image:UIImage? = nil, text:String? = nil, font:UIFont? = nil, color:UIColor? = nil, type: toolIconTypes) { 16 | var titleFrame:CGRect! 17 | var iconFrame:CGRect! 18 | 19 | var isTitleHidden:Bool! 20 | var isIconHidden:Bool! 21 | 22 | switch type { 23 | case .image: 24 | titleFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 25 | iconFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 26 | isTitleHidden = true 27 | isIconHidden = false 28 | case .text: 29 | titleFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 30 | iconFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 31 | isTitleHidden = false 32 | isIconHidden = true 33 | case .both: 34 | titleFrame = CGRect(x: 0, y: contentView.frame.height*0.75, width: contentView.frame.width, height: contentView.frame.height*0.25) 35 | iconFrame = CGRect(x: 0, y:0, width: contentView.frame.width, height: contentView.frame.height*0.75) 36 | isTitleHidden = false 37 | isIconHidden = false 38 | } 39 | 40 | if toolTitle == nil { 41 | toolTitle = UILabel() 42 | toolTitle?.frame = titleFrame 43 | if let font = font { 44 | toolTitle?.font = font 45 | } 46 | if let color = color { 47 | toolTitle?.textColor = color 48 | } 49 | toolTitle?.textAlignment = .center 50 | contentView.addSubview(toolTitle!) 51 | } 52 | 53 | if toolIcon == nil { 54 | toolIcon = UIImageView() 55 | toolIcon?.frame = iconFrame 56 | toolIcon?.contentMode = .scaleAspectFit 57 | contentView.addSubview(toolIcon!) 58 | } 59 | if let title = toolTitle { 60 | if let txt = text { 61 | title.text = txt 62 | } 63 | title.isHidden = isTitleHidden 64 | } 65 | if let icon = toolIcon { 66 | if let img = image { 67 | icon.image = img 68 | } 69 | icon.isHidden = isIconHidden 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Classes/NotchBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchBar.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | public class NotchBar: UIView { 11 | /** 12 | This allows you to choose between statusBar & noStatusBar modes. 13 | */ 14 | public var mode:notchMode = .statusBar 15 | /** 16 | This allows you to set the height of the NotchBar. 17 | */ 18 | public var height:CGFloat = 250 19 | /** 20 | This allows you to set the background color of the NotchBar. 21 | */ 22 | public var bgColor:UIColor = .black 23 | /** 24 | This allows you to set the corner radii of the NotchBar. 25 | */ 26 | public var curve:CGFloat = 35 27 | /** 28 | This allows you to initially set the NotchBar visibility. 29 | */ 30 | public var isVisible:Bool = false 31 | /** 32 | This allows you to set the animation show/hide & rotation animation time interval of the NotchBar. 33 | */ 34 | public var animationInterval:TimeInterval = 0.3 35 | 36 | override init(frame: CGRect) { 37 | super.init(frame: frame) 38 | create() 39 | } 40 | 41 | required public init?(coder aDecoder: NSCoder) { 42 | super.init(coder: aDecoder) 43 | create() 44 | } 45 | 46 | var scale:CGFloat! 47 | var multiplier:CGFloat! 48 | func create() { 49 | switch mode { 50 | case .statusBar: 51 | scale = UIScreen.main.portraitNotch.width 52 | multiplier = UIScreen.main.multiplier 53 | case .noStatusBar: 54 | scale = UIScreen.main.widePortraitNotch.width 55 | multiplier = UIScreen.main.multiplierWide 56 | } 57 | self.bounds = CGRect(x: 0, y: 0, width: scale, height: height) 58 | self.center = CGPoint(x: UIScreen.main.portraitNotch.origin.x, y: (self.bounds.height/2)) 59 | self.backgroundColor = bgColor 60 | self.draw(.corner, position: .bottom, curve: curve) 61 | self.layer.masksToBounds = true 62 | self.alpha = isVisible ? 1 : 0 63 | } 64 | 65 | /** 66 | This function is used to resize the NotchBar when device orientation is changed. 67 | */ 68 | public func refresh(orientation:deviceOrientation) { 69 | let subtrehend = isVisible ? 0 : self.bounds.height 70 | 71 | switch mode { 72 | case .statusBar: 73 | scale = UIScreen.main.portraitNotch.width 74 | multiplier = UIScreen.main.multiplier 75 | case .noStatusBar: 76 | scale = UIScreen.main.widePortraitNotch.width 77 | multiplier = UIScreen.main.multiplierWide 78 | } 79 | 80 | switch orientation { 81 | case .portrait: 82 | UIView.animate(withDuration: animationInterval, animations: { 83 | self.bounds = CGRect(x: 0, y: 0, width: self.scale, height: self.height) 84 | self.center = CGPoint(x: UIScreen.main.portraitNotch.origin.x, y: (self.bounds.height/2) - subtrehend) 85 | self.backgroundColor = self.bgColor 86 | self.draw(.corner, position: .bottom, curve: self.curve) 87 | self.alpha = self.isVisible ? 1 : 0 88 | }) 89 | case .landscapeLeft: 90 | UIView.animate(withDuration: animationInterval, animations: { 91 | self.bounds = CGRect(x: 0, y: 0, width: self.height, height: self.scale) 92 | self.center = CGPoint(x: (self.bounds.height*(self.multiplier*self.height)) - subtrehend, y: UIScreen.main.landscapeLeftNotch.origin.y) 93 | self.backgroundColor = self.bgColor 94 | self.draw(.corner, position: .right, curve: self.curve) 95 | self.alpha = self.isVisible ? 1 : 0 96 | }) 97 | case .landscapeRight: 98 | UIView.animate(withDuration: animationInterval, animations: { 99 | self.bounds = CGRect(x: 0, y: 0, width: self.height, height: self.scale) 100 | self.center = CGPoint(x: (UIScreen.main.bounds.width-self.bounds.height*(self.multiplier*self.height)) + subtrehend, y: UIScreen.main.landscapeRightNotch.origin.y) 101 | self.backgroundColor = self.bgColor 102 | self.draw(.corner, position: .left, curve: self.curve) 103 | self.alpha = self.isVisible ? 1 : 0 104 | }) 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Classes/NotchImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchImageView.swift 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 11/1/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | *NotchToolkit* is a framework for iOS that allow developers use the iPhones X notch space in creative ways. 13 | 14 | - Author: Ahmed Fathi Bekhit 15 | * [Github](http://github.com/AFathi) 16 | * [Website](http://ahmedbekhit.com) 17 | * [Twitter](http://twitter.com/iAFapps) 18 | * [Email](mailto:me@ahmedbekhit.com) 19 | */ 20 | public class NotchImageView: NotchBar { 21 | // MARK: - Public objects 22 | 23 | /// This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 24 | public var delegate:NotchToolbarDelegate? 25 | 26 | /// This allows you to enable NotchToolbar only for iPhone X. Default is false. 27 | public var onlyFor10:Bool = false 28 | /// Configure printing bar height 29 | public var printBarHeight:CGFloat = 3 30 | /// Configure printing color 31 | public var printBarColor:UIColor = .cyan 32 | /// Configure image loading duration intervals 33 | public var durationIntervals:TimeInterval = 0.8 34 | 35 | // MARK: - Private Objects 36 | private var recentOrientation: deviceOrientation! 37 | private var imageView:UIImageView = UIImageView() 38 | private var notchImage:UIImage? 39 | private var printerBar:UIView = UIView() 40 | private var isShown:Bool = false 41 | private var isLoaded:Bool = false 42 | 43 | /// Initialize 44 | public init() { 45 | super.init(frame: CGRect.zero) 46 | } 47 | /// Initialize with a UIImage 48 | public init(image: UIImage?) { 49 | super.init(frame: CGRect.zero) 50 | notchImage = image 51 | self.bgColor = .clear 52 | self.animationInterval = 0.1 53 | } 54 | 55 | required public init?(coder aDecoder: NSCoder) { 56 | fatalError("init(coder:) has not been implemented") 57 | } 58 | } 59 | 60 | //MARK:- Methods 61 | extension NotchImageView { 62 | /// This method is required to prepare the NotchImageView in your view controller. 63 | public func prepare(in vc:UIViewController) { 64 | NotificationCenter.default.addObserver(vc, selector: #selector(delegate?.deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 65 | if onlyFor10 && !UIScreen.main.isiPhone10 { 66 | print("NotchToolbar: If you want to enable NotchToolBar on this device please add this line to your code\nNotchToolBar().onlyFor10 = false") 67 | }else{ 68 | recentOrientation = .portrait 69 | imageView = UIImageView(frame: CGRect(x:0, y:0, width:self.bounds.width, height:self.bounds.height)) 70 | imageView.center = CGPoint(x:(self.bounds.width)*0.5, y:-(self.bounds.height*0.5)) 71 | imageView.backgroundColor = .clear 72 | imageView.contentMode = .scaleAspectFill 73 | imageView.clipsToBounds = true 74 | imageView.draw(.corner, position: .bottom, curve: self.curve) 75 | if let img = notchImage { 76 | imageView.image = img 77 | } 78 | self.addSubview(imageView) 79 | 80 | printerBar = UIView(frame: CGRect(x:0, y:0, width:self.bounds.width, height:printBarHeight)) 81 | printerBar.center = CGPoint(x:self.bounds.width*0.5, y:-(self.bounds.height*0.5)) 82 | printerBar.backgroundColor = printBarColor.withAlphaComponent(0.4) 83 | printerBar.layer.shadowColor = printBarColor.cgColor 84 | printerBar.layer.shadowOffset = CGSize(width: 0.0, height: 2.5) 85 | printerBar.layer.shadowOpacity = 1.0 86 | self.addSubview(printerBar) 87 | 88 | vc.view.addSubview(self) 89 | } 90 | } 91 | /// Loads image view from notch with animation 92 | public func load() { 93 | self.isVisible = true 94 | 95 | UIView.animate(withDuration: 0.3, delay: 0.1, usingSpringWithDamping: 1.2, initialSpringVelocity: 0.4, options: [.autoreverse, .repeat], animations: { 96 | self.printerBar.center = CGPoint(x:self.self.bounds.width*0.5, y:(self.self.bounds.height)) 97 | }) 98 | 99 | autoResize() 100 | isShown = true 101 | updateBounds(orientation: recentOrientation) 102 | } 103 | /// Removes image view from superview 104 | public func remove() { 105 | self.self.removeFromSuperview() 106 | self.removeFromSuperview() 107 | } 108 | /// This function is required to be called from the `deviceDidRotate` delegate function. 109 | public func autoResize() { 110 | switch UIDevice.current.orientation { 111 | case .portrait: 112 | recentOrientation = .portrait 113 | self.refresh(orientation: .portrait) 114 | self.updateBounds(orientation: .portrait) 115 | case .portraitUpsideDown: 116 | self.refresh(orientation: recentOrientation) 117 | self.updateBounds(orientation: recentOrientation) 118 | case .landscapeLeft: 119 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 120 | recentOrientation = .landscapeLeft 121 | self.refresh(orientation: .landscapeLeft) 122 | self.updateBounds(orientation: .landscapeLeft) 123 | } 124 | case .landscapeRight: 125 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 126 | recentOrientation = .landscapeRight 127 | self.refresh(orientation: .landscapeRight) 128 | self.updateBounds(orientation: .landscapeRight) 129 | } 130 | case .faceDown: 131 | self.refresh(orientation: recentOrientation) 132 | self.updateBounds(orientation: recentOrientation) 133 | case .faceUp: 134 | self.refresh(orientation: recentOrientation) 135 | self.updateBounds(orientation: recentOrientation) 136 | case .unknown: 137 | self.refresh(orientation: recentOrientation) 138 | self.updateBounds(orientation: recentOrientation) 139 | } 140 | } 141 | 142 | private func updateBounds(orientation: deviceOrientation) { 143 | var xPos = (self.bounds.width*0.5) 144 | var yPos = (self.bounds.height*0.5) 145 | switch orientation { 146 | case .landscapeLeft : 147 | xPos = (!isShown) ? -(self.bounds.width*0.5) : (self.bounds.width*0.5) 148 | case .landscapeRight: 149 | xPos = (!isShown) ? (self.bounds.width*1.5) : (self.bounds.width*0.5) 150 | case .portrait: 151 | yPos = (!isShown) ? -(self.bounds.height*0.5) : (self.bounds.height*0.5) 152 | } 153 | 154 | imageView.bounds = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height) 155 | if self.isLoaded{ 156 | self.self.frame = UIScreen.main.bounds 157 | self.imageView.frame = self.self.frame 158 | self.self.draw(.corner, position: .bottom, curve: 0) 159 | self.imageView.draw(.corner, position: .bottom, curve: 0) 160 | return 161 | } 162 | 163 | UIView.animate(withDuration: self.durationIntervals, animations: { 164 | self.imageView.center = CGPoint(x:xPos, y:yPos) 165 | }) 166 | if self.isShown { 167 | UIView.animate(withDuration: 0.4, delay: self.durationIntervals, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.4, options: .curveLinear, animations: { 168 | self.self.frame = UIScreen.main.bounds 169 | self.imageView.frame = self.self.frame 170 | self.draw(.corner, position: .bottom, curve: 0) 171 | self.imageView.draw(.corner, position: .bottom, curve: 0) 172 | self.printerBar.alpha = 0 173 | }){ done in 174 | self.isLoaded = true 175 | self.printerBar.layer.removeAllAnimations() 176 | } 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Enumerations/CurveSettings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurveSettings.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of bezier paths drawn in a view. 11 | 12 | `oval` Is an oval-based bezier path. 13 | 14 | `corner` Is a rounded-rectangle-based bezier path. 15 | */ 16 | public enum curveType { 17 | /** 18 | `oval` Is an oval-based bezier path. 19 | */ 20 | case oval 21 | /** 22 | `corner` Is a rounded-rectangle-based bezier path. 23 | */ 24 | case corner 25 | } 26 | 27 | /** 28 | Position options to draw the bezier paths. 29 | 30 | `right` Draws a bezier path vertically on the right side of a view. 31 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topRight and bottomRight of a view. 32 | - If **curveType** is `oval`, it draws an oval-based bezier path vertically on the right side of a view. 33 | 34 | `left` Draws a bezier path vertically on the left side of a view. 35 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topLeft and bottomLeft of a view. 36 | - If **curveType** is `oval`, it draws an oval-based bezier path vertically on the left side of a view. 37 | 38 | `top` Draws a bezier path horizontally on the top side of a view. 39 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topRight and topLeft of a view. 40 | - If **curveType** is `oval`, it draws an oval-based bezier path horizontally on the top side of a view. 41 | 42 | `bottom` Draws a bezier path vertically on the bottom side of a view. 43 | - If **curveType** is `corner`, it draws a rounded rectangle corner on bottomRight and bottomLeft of a view. 44 | - If **curveType** is `oval`, it draws an oval-based bezier path horizontally on the bottom side of a view. 45 | 46 | `horizontalSides` Draws an oval-based bezier path vertically on the right & left sides of a view. 47 | - Can only be applied when **curveType** is `oval`. 48 | 49 | `verticalSides` Draws an oval-based bezier path horizontally on the top & bottom sides of a view. 50 | - Can only be applied when **curveType** is `oval`. 51 | 52 | `all` Draws a bezier path on all sides of a view. 53 | - If **curveType** is `corner`, it draws rounded rectangle corners in topLeft, topRight, bottomLeft and bottomRight. 54 | - If **curveType** is `oval`, it draws a full oval shape out of the view. 55 | */ 56 | public enum curvePosition { 57 | /** 58 | `right` Draws a bezier path vertically on the right side of a view. 59 | */ 60 | case right 61 | /** 62 | `left` Draws a bezier path vertically on the left side of a view. 63 | */ 64 | case left 65 | /** 66 | `top` Draws a bezier path horizontally on the top side of a view. 67 | */ 68 | case top 69 | /** 70 | `bottom` Draws a bezier path vertically on the bottom side of a view. 71 | */ 72 | case bottom 73 | /** 74 | `horizontalSides` Draws an oval-based bezier path vertically on the right & left sides of a view. 75 | */ 76 | case horizontalSides 77 | /** 78 | `verticalSides` Draws an oval-based bezier path horizontally on the top & bottom sides of a view. 79 | */ 80 | case verticalSides 81 | /** 82 | `diagonalAC` Draws rounded rectangle corners diagonally from topLeft to bottomRight of a view. 83 | */ 84 | case diagonalAC 85 | /** 86 | `diagonalBD` Draws rounded rectangle corners diagonally from topRight to bottomLeft of a view. 87 | */ 88 | case diagonalBD 89 | /** 90 | `all` Draws a bezier path on all sides of a view. 91 | */ 92 | case all 93 | } 94 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Enumerations/DeviceOrientation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceOrientation.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of the device orientation used to resize the NotchBar. 11 | 12 | `portrait` When the device's notch is on the top. 13 | 14 | `landscapeLeft` When the device's notch is on the left. 15 | 16 | `landscapeRight` When the device's notch is on the right. 17 | 18 | */ 19 | public enum deviceOrientation { 20 | /** 21 | `portrait` When the device's notch is on the top. 22 | */ 23 | case portrait 24 | /** 25 | `landscapeLeft` When the device's notch is on the left. 26 | */ 27 | case landscapeLeft 28 | /** 29 | `landscapeRight` When the device's notch is on the right. 30 | */ 31 | case landscapeRight 32 | } 33 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Enumerations/NotchMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchMode.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Modes of the NotchBar based on status bar visibility. 11 | */ 12 | public enum notchMode { 13 | /** 14 | This mode sets the width of the NotchBar as the iPhone's X notch width. 15 | */ 16 | case statusBar 17 | /** 18 | This mode sets a wider width to display more content. Recommended for full landscape apps and when status bar is hidden. 19 | */ 20 | case noStatusBar 21 | } 22 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Enumerations/NotchScroll.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchScroll.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of NotchToolbar scrolling directions. 11 | 12 | `alwaysHorizontal` sets scrolling direction to horizontal with all **deviceOriention** types. 13 | 14 | `alwaysVertical` sets scrolling direction to vertical with all **deviceOriention** types. 15 | 16 | `auto` sets scrolling direction to vertical when **deviceOriention** is `portrait` and horizontal when **deviceOriention** is `landscape`. 17 | */ 18 | 19 | public enum notchScroll { 20 | /** 21 | `alwaysHorizontal` sets scrolling direction to horizontal with all **deviceOriention** types. 22 | */ 23 | case alwaysHorizontal 24 | /** 25 | `alwaysVertical` sets scrolling direction to vertical with all **deviceOriention** types. 26 | */ 27 | case alwaysVertical 28 | /** 29 | `auto` sets scrolling direction to vertical when **deviceOriention** is `portrait` and horizontal when **deviceOriention** is `landscape`. 30 | */ 31 | case auto 32 | } 33 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Enumerations/ToolIconTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ToolIconTypes.swift 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 9/28/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | public enum toolIconTypes { 10 | case image 11 | case text 12 | case both 13 | } 14 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Extenstions/UIScreen+NotchFrame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+NotchFrame.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIScreen { 12 | private func setNotchFrame(orientation:deviceOrientation, mode:notchMode) -> CGRect { 13 | var notchScale: CGFloat { 14 | switch mode { 15 | case .statusBar: 16 | if self.bounds.size.width > self.bounds.size.height { 17 | return self.bounds.size.height/1.8 18 | }else{ 19 | return self.bounds.size.width/1.8 20 | } 21 | case .noStatusBar: 22 | if self.bounds.size.width > self.bounds.size.height { 23 | return self.bounds.size.height/1.5 24 | }else{ 25 | return self.bounds.size.width/1.5 26 | } 27 | } 28 | } 29 | 30 | switch orientation { 31 | case .portrait: 32 | return CGRect(x: self.bounds.width/2, y: 0, width: notchScale, height: 0) 33 | case .landscapeLeft: 34 | return CGRect(x: 0, y: self.bounds.height/2, width: 0, height: notchScale) 35 | case .landscapeRight: 36 | return CGRect(x: 0, y: self.bounds.height/2, width: 0, height: notchScale) 37 | } 38 | } 39 | 40 | /** 41 | `portraitNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `portrait`. 42 | */ 43 | public var portraitNotch: CGRect { 44 | return setNotchFrame(orientation: .portrait, mode: .statusBar) 45 | } 46 | /** 47 | `landscapeLeftNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `landscapeLeft`. 48 | */ 49 | public var landscapeLeftNotch: CGRect { 50 | return setNotchFrame(orientation: .landscapeLeft, mode: .statusBar) 51 | } 52 | /** 53 | `landscapeRightNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `landscapeRight`. 54 | */ 55 | public var landscapeRightNotch: CGRect { 56 | return setNotchFrame(orientation: .landscapeRight, mode: .statusBar) 57 | } 58 | 59 | //Wider frame for .noStatusBar mode 60 | /** 61 | `widePortraitNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `portrait`. 62 | */ 63 | public var widePortraitNotch: CGRect { 64 | return setNotchFrame(orientation: .portrait, mode: .noStatusBar) 65 | } 66 | /** 67 | `wideLandscapeLeftNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `landscapeLeft`. 68 | */ 69 | public var wideLandscapeLeftNotch: CGRect { 70 | return setNotchFrame(orientation: .landscapeLeft, mode: .noStatusBar) 71 | } 72 | /** 73 | `wideLandscapeRightNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `landscapeRight`. 74 | */ 75 | public var wideLandscapeRightNotch: CGRect { 76 | return setNotchFrame(orientation: .landscapeRight, mode: .noStatusBar) 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Extenstions/UIScreen+NotchPositionMultiplier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+NotchPositionMultiplier.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIScreen { 12 | private func setMultiplier(mode:notchMode) -> CGFloat { 13 | switch mode { 14 | case .statusBar: 15 | return 0.0021 16 | case .noStatusBar: 17 | return 0.0017 18 | } 19 | } 20 | /** 21 | `multiplier` is a float number that's used to postion the NotchBar when **deviceOrientation** is landscape. 22 | */ 23 | public var multiplier: CGFloat { 24 | return setMultiplier(mode: .statusBar) 25 | } 26 | /** 27 | `multiplierWide` is a float number that's used to postion the wide NotchBar when **deviceOrientation** is landscape. 28 | */ 29 | public var multiplierWide: CGFloat { 30 | return setMultiplier(mode: .noStatusBar) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Extenstions/UIScreen+iPhone10.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+iPhone10.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | public extension UIScreen { 11 | /** 12 | `isiPhone10` is a boolean that returns if the device is iPhone X or not. 13 | */ 14 | public var isiPhone10: Bool { 15 | return self.nativeBounds.size == CGSize(width: 1125, height: 2436) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Extenstions/UIView+DrawNotch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+OvalOrCorners.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIView { 12 | /** 13 | **UIView.draw(notch type,position,curve,customBounds)** is a UIView extension that allows you add ovals and rounded corners to a UIView. 14 | - For type `oval`, set `curve` from 1.0 - 10.0. 15 | - For type `corner`, `curve` is the radius size. 16 | - Check `curveType` & `curvePosition` for more info. 17 | */ 18 | public func draw(_ notch:curveType, position:curvePosition, curve:CGFloat?, customBounds:CGRect? = nil) { 19 | let offset:CGFloat = self.frame.size.width/curve! 20 | var bounds:CGRect! 21 | var viewBounds:CGRect! 22 | var viewPath:UIBezierPath! 23 | 24 | if let finalBounds = customBounds { 25 | bounds = finalBounds 26 | }else{ 27 | bounds = self.bounds 28 | } 29 | 30 | switch notch { 31 | case .oval: 32 | var ovalBounds:CGRect! 33 | switch position { 34 | case .right: 35 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 36 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width/2, height: bounds.size.height) 37 | 38 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 39 | viewPath = UIBezierPath(rect: viewBounds) 40 | viewPath.append(ovalPath) 41 | break 42 | case .left: 43 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 44 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width/2, y: bounds.origin.y, width: bounds.size.width/2, height: bounds.size.height) 45 | 46 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 47 | viewPath = UIBezierPath(rect: viewBounds) 48 | viewPath.append(ovalPath) 49 | break 50 | case .top: 51 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 52 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height / 2, width: bounds.size.width, height: bounds.size.height / 2) 53 | 54 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 55 | viewPath = UIBezierPath(rect: viewBounds) 56 | viewPath.append(ovalPath) 57 | break 58 | case .bottom: 59 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 60 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height / 2) 61 | 62 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 63 | viewPath = UIBezierPath(rect: viewBounds) 64 | viewPath.append(ovalPath) 65 | break 66 | case .horizontalSides: 67 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 68 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width, y: bounds.origin.y+bounds.size.height, width: bounds.size.width, height: bounds.size.height) 69 | 70 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 71 | viewPath = UIBezierPath(rect: viewBounds) 72 | viewPath.append(ovalPath) 73 | break 74 | case .verticalSides: 75 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 76 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width, y: bounds.origin.y+bounds.size.height, width: bounds.size.width, height: bounds.size.height) 77 | 78 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 79 | viewPath = UIBezierPath(rect: viewBounds) 80 | viewPath.append(ovalPath) 81 | break 82 | case .all: 83 | viewPath = UIBezierPath(ovalIn: self.bounds) 84 | break 85 | default: 86 | break 87 | } 88 | break 89 | case .corner: 90 | switch position { 91 | case .right: 92 | 93 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 94 | break 95 | case .left: 96 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .bottomLeft], cornerRadii: CGSize(width:curve!, height:curve!)) 97 | break 98 | case .top: 99 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width:curve!, height:curve!)) 100 | break 101 | case .bottom: 102 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 103 | break 104 | case .diagonalAC: 105 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 106 | break 107 | case .diagonalBD: 108 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topRight, .bottomLeft], cornerRadii: CGSize(width:curve!, height:curve!)) 109 | break 110 | case .all: 111 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.allCorners], cornerRadii: CGSize(width:curve!, height:curve!)) 112 | break 113 | default: 114 | break 115 | } 116 | break 117 | } 118 | if let path = viewPath { 119 | let shapeLayer: CAShapeLayer = CAShapeLayer() 120 | shapeLayer.frame = bounds 121 | shapeLayer.path = path.cgPath 122 | self.layer.mask = shapeLayer 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Example/NotchToolkit/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.4 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/NotchToolkit/NotchToolkit.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolkit.h 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 11/6/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for NotchToolkit. 12 | FOUNDATION_EXPORT double NotchToolkitVersionNumber; 13 | 14 | //! Project version string for NotchToolkit. 15 | FOUNDATION_EXPORT const unsigned char NotchToolkitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Example/NotchToolkit/Protocols/NotchToolbarDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolbarDelegate.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | /** 11 | This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 12 | */ 13 | @objc public protocol NotchToolbarDelegate { 14 | /** 15 | This delegate function detects when the device orientation changes. Calling **autoResize()** function inside this delegate is **required**. 16 | */ 17 | func deviceDidRotate() 18 | /** 19 | This delegate function allows you to detect which toolbar icon was selected. 20 | */ 21 | func didTapToolIcon(_ tools: UICollectionView, toolIndex:IndexPath, section: Int, row: Int) 22 | } 23 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'NotchToolkit-Example' do 5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 6 | use_frameworks! 7 | 8 | # Pods for NotchToolkit-Example 9 | pod 'NotchToolkit', :git => 'https://github.com/AFathi/NotchToolkit.git', :tag => '1.2' 10 | 11 | target 'NotchToolkit-ExampleTests' do 12 | inherit! :search_paths 13 | # Pods for testing 14 | end 15 | 16 | end 17 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - NotchToolkit (1.0) 3 | 4 | DEPENDENCIES: 5 | - NotchToolkit (from `https://github.com/AFathi/NotchToolkit.git`, tag `1.0`) 6 | 7 | EXTERNAL SOURCES: 8 | NotchToolkit: 9 | :git: https://github.com/AFathi/NotchToolkit.git 10 | :tag: 1.0 11 | 12 | CHECKOUT OPTIONS: 13 | NotchToolkit: 14 | :git: https://github.com/AFathi/NotchToolkit.git 15 | :tag: 1.0 16 | 17 | SPEC CHECKSUMS: 18 | NotchToolkit: 5aa78dd66d354aad3be2f5e61e8615d2af6b61f6 19 | 20 | PODFILE CHECKSUM: d1eca35aae7b4c7fb911fb7b5985cb76b079dc2a 21 | 22 | COCOAPODS: 1.3.1 23 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/NotchToolkit.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NotchToolkit", 3 | "version": "1.0", 4 | "summary": "A light-weight iOS framework for iPhone's X notch.", 5 | "description": "A light-weight framework for iOS that allow developers use the iPhone's X notch space in creative ways.", 6 | "homepage": "http://github.com/AFathi", 7 | "screenshots": "https://im3.ezgif.com/tmp/ezgif-3-bd73dd3458.gif", 8 | "license": { 9 | "type": "MIT", 10 | "file": "LICENSE" 11 | }, 12 | "authors": { 13 | "AFathi": "me@ahmedbekhit.com" 14 | }, 15 | "social_media_url": "http://twitter.com/AFathi", 16 | "platforms": { 17 | "ios": "11.0" 18 | }, 19 | "source": { 20 | "git": "https://github.com/AFathi/NotchToolkit.git", 21 | "tag": "1.0" 22 | }, 23 | "source_files": [ 24 | "NotchToolkit", 25 | "NotchToolkit/**/*.{h,m,swift}" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - NotchToolkit (1.0) 3 | 4 | DEPENDENCIES: 5 | - NotchToolkit (from `https://github.com/AFathi/NotchToolkit.git`, tag `1.0`) 6 | 7 | EXTERNAL SOURCES: 8 | NotchToolkit: 9 | :git: https://github.com/AFathi/NotchToolkit.git 10 | :tag: 1.0 11 | 12 | CHECKOUT OPTIONS: 13 | NotchToolkit: 14 | :git: https://github.com/AFathi/NotchToolkit.git 15 | :tag: 1.0 16 | 17 | SPEC CHECKSUMS: 18 | NotchToolkit: 5aa78dd66d354aad3be2f5e61e8615d2af6b61f6 19 | 20 | PODFILE CHECKSUM: d1eca35aae7b4c7fb911fb7b5985cb76b079dc2a 21 | 22 | COCOAPODS: 1.3.1 23 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ahmed Fathi Bekhit[me@ahmedbekhit.com] 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 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Cells/NotchToolCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolCell.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class NotchToolCell: UICollectionViewCell { 12 | private var toolIcon : UIImageView? 13 | private var toolTitle : UILabel? 14 | 15 | func setIcon(_ image:UIImage?) { 16 | if toolIcon == nil { 17 | toolIcon = UIImageView() 18 | toolIcon?.frame = CGRect(x: 0, y:0, width: contentView.frame.width, height: contentView.frame.height) 19 | toolIcon?.contentMode = .scaleAspectFit 20 | contentView.addSubview(toolIcon!) 21 | } 22 | 23 | if let icon = toolIcon { 24 | if let img = image { 25 | icon.image = img 26 | } 27 | icon.isHidden = false 28 | } 29 | if let title = toolTitle { 30 | title.isHidden = true 31 | } 32 | } 33 | 34 | func setTitle(_ text:String, font:UIFont, color:UIColor) { 35 | if toolTitle == nil { 36 | toolTitle = UILabel() 37 | toolTitle?.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 38 | toolTitle?.font = font 39 | toolTitle?.textColor = color 40 | toolTitle?.textAlignment = .center 41 | contentView.addSubview(toolTitle!) 42 | } 43 | 44 | if let title = toolTitle { 45 | title.text = text 46 | title.isHidden = false 47 | } 48 | 49 | if let icon = toolIcon { 50 | icon.isHidden = true 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Enumerators/CurveSettings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurveSettings.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of bezier paths drawn in a view. 11 | 12 | `oval` Is an oval-based bezier path. 13 | 14 | `corner` Is a rounded-rectangle-based bezier path. 15 | */ 16 | public enum curveType { 17 | /** 18 | `oval` Is an oval-based bezier path. 19 | */ 20 | case oval 21 | /** 22 | `corner` Is a rounded-rectangle-based bezier path. 23 | */ 24 | case corner 25 | } 26 | 27 | /** 28 | Position options to draw the bezier paths. 29 | 30 | `right` Draws a bezier path vertically on the right side of a view. 31 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topRight and bottomRight of a view. 32 | - If **curveType** is `oval`, it draws an oval-based bezier path vertically on the right side of a view. 33 | 34 | `left` Draws a bezier path vertically on the left side of a view. 35 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topLeft and bottomLeft of a view. 36 | - If **curveType** is `oval`, it draws an oval-based bezier path vertically on the left side of a view. 37 | 38 | `top` Draws a bezier path horizontally on the top side of a view. 39 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topRight and topLeft of a view. 40 | - If **curveType** is `oval`, it draws an oval-based bezier path horizontally on the top side of a view. 41 | 42 | `bottom` Draws a bezier path vertically on the bottom side of a view. 43 | - If **curveType** is `corner`, it draws a rounded rectangle corner on bottomRight and bottomLeft of a view. 44 | - If **curveType** is `oval`, it draws an oval-based bezier path horizontally on the bottom side of a view. 45 | 46 | `horizontalSides` Draws an oval-based bezier path vertically on the right & left sides of a view. 47 | - Can only be applied when **curveType** is `oval`. 48 | 49 | `verticalSides` Draws an oval-based bezier path horizontally on the top & bottom sides of a view. 50 | - Can only be applied when **curveType** is `oval`. 51 | 52 | `all` Draws a bezier path on all sides of a view. 53 | - If **curveType** is `corner`, it draws rounded rectangle corners in topLeft, topRight, bottomLeft and bottomRight. 54 | - If **curveType** is `oval`, it draws a full oval shape out of the view. 55 | */ 56 | public enum curvePosition { 57 | /** 58 | `right` Draws a bezier path vertically on the right side of a view. 59 | */ 60 | case right 61 | /** 62 | `left` Draws a bezier path vertically on the left side of a view. 63 | */ 64 | case left 65 | /** 66 | `top` Draws a bezier path horizontally on the top side of a view. 67 | */ 68 | case top 69 | /** 70 | `bottom` Draws a bezier path vertically on the bottom side of a view. 71 | */ 72 | case bottom 73 | /** 74 | `horizontalSides` Draws an oval-based bezier path vertically on the right & left sides of a view. 75 | */ 76 | case horizontalSides 77 | /** 78 | `verticalSides` Draws an oval-based bezier path horizontally on the top & bottom sides of a view. 79 | */ 80 | case verticalSides 81 | /** 82 | `all` Draws a bezier path on all sides of a view. 83 | */ 84 | case all 85 | } 86 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Enumerators/DeviceOrientation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceOrientation.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of the device orientation used to resize the NotchBar. 11 | 12 | `portrait` When the device's notch is on the top. 13 | 14 | `landscapeLeft` When the device's notch is on the left. 15 | 16 | `landscapeRight` When the device's notch is on the right. 17 | 18 | */ 19 | public enum deviceOrientation { 20 | /** 21 | `portrait` When the device's notch is on the top. 22 | */ 23 | case portrait 24 | /** 25 | `landscapeLeft` When the device's notch is on the left. 26 | */ 27 | case landscapeLeft 28 | /** 29 | `landscapeRight` When the device's notch is on the right. 30 | */ 31 | case landscapeRight 32 | } 33 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Enumerators/NotchMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchMode.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Modes of the NotchBar based on status bar visibility. 11 | */ 12 | public enum notchMode { 13 | /** 14 | This mode sets the width of the NotchBar as the iPhone's X notch width. 15 | */ 16 | case statusBar 17 | /** 18 | This mode sets a wider width to display more content. Recommended for full landscape apps and when status bar is hidden. 19 | */ 20 | case noStatusBar 21 | } 22 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Enumerators/NotchScroll.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchScroll.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of NotchToolbar scrolling directions. 11 | 12 | `alwaysHorizontal` sets scrolling direction to horizontal with all **deviceOriention** types. 13 | 14 | `alwaysVertical` sets scrolling direction to vertical with all **deviceOriention** types. 15 | 16 | `auto` sets scrolling direction to vertical when **deviceOriention** is `portrait` and horizontal when **deviceOriention** is `landscape`. 17 | */ 18 | 19 | public enum notchScroll { 20 | /** 21 | `alwaysHorizontal` sets scrolling direction to horizontal with all **deviceOriention** types. 22 | */ 23 | case alwaysHorizontal 24 | /** 25 | `alwaysVertical` sets scrolling direction to vertical with all **deviceOriention** types. 26 | */ 27 | case alwaysVertical 28 | /** 29 | `auto` sets scrolling direction to vertical when **deviceOriention** is `portrait` and horizontal when **deviceOriention** is `landscape`. 30 | */ 31 | case auto 32 | } 33 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Extensions/UIScreen+NotchFrame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+NotchFrame.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIScreen { 12 | private func setNotchFrame(orientation:deviceOrientation, mode:notchMode) -> CGRect { 13 | var notchScale: CGFloat { 14 | switch mode { 15 | case .statusBar: 16 | if self.bounds.size.width > self.bounds.size.height { 17 | return self.bounds.size.height/1.8 18 | }else{ 19 | return self.bounds.size.width/1.8 20 | } 21 | case .noStatusBar: 22 | if self.bounds.size.width > self.bounds.size.height { 23 | return self.bounds.size.height/1.5 24 | }else{ 25 | return self.bounds.size.width/1.5 26 | } 27 | } 28 | } 29 | 30 | switch orientation { 31 | case .portrait: 32 | return CGRect(x: self.bounds.width/2, y: 0, width: notchScale, height: 0) 33 | case .landscapeLeft: 34 | return CGRect(x: 0, y: self.bounds.height/2, width: 0, height: notchScale) 35 | case .landscapeRight: 36 | return CGRect(x: 0, y: self.bounds.height/2, width: 0, height: notchScale) 37 | } 38 | } 39 | 40 | /** 41 | `portraitNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `portrait`. 42 | */ 43 | public var portraitNotch: CGRect { 44 | return setNotchFrame(orientation: .portrait, mode: .statusBar) 45 | } 46 | /** 47 | `landscapeLeftNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `landscapeLeft`. 48 | */ 49 | public var landscapeLeftNotch: CGRect { 50 | return setNotchFrame(orientation: .landscapeLeft, mode: .statusBar) 51 | } 52 | /** 53 | `landscapeRightNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `landscapeRight`. 54 | */ 55 | public var landscapeRightNotch: CGRect { 56 | return setNotchFrame(orientation: .landscapeRight, mode: .statusBar) 57 | } 58 | 59 | //Wider frame for .noStatusBar mode 60 | /** 61 | `widePortraitNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `portrait`. 62 | */ 63 | public var widePortraitNotch: CGRect { 64 | return setNotchFrame(orientation: .portrait, mode: .noStatusBar) 65 | } 66 | /** 67 | `wideLandscapeLeftNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `landscapeLeft`. 68 | */ 69 | public var wideLandscapeLeftNotch: CGRect { 70 | return setNotchFrame(orientation: .landscapeLeft, mode: .noStatusBar) 71 | } 72 | /** 73 | `wideLandscapeRightNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `landscapeRight`. 74 | */ 75 | public var wideLandscapeRightNotch: CGRect { 76 | return setNotchFrame(orientation: .landscapeRight, mode: .noStatusBar) 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Extensions/UIScreen+NotchPositionMultiplier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+NotchPositionMultiplier.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIScreen { 12 | private func setMultiplier(mode:notchMode) -> CGFloat { 13 | switch mode { 14 | case .statusBar: 15 | return 0.0021 16 | case .noStatusBar: 17 | return 0.0017 18 | } 19 | } 20 | /** 21 | `multiplier` is a float number that's used to postion the NotchBar when **deviceOrientation** is landscape. 22 | */ 23 | public var multiplier: CGFloat { 24 | return setMultiplier(mode: .statusBar) 25 | } 26 | /** 27 | `multiplierWide` is a float number that's used to postion the wide NotchBar when **deviceOrientation** is landscape. 28 | */ 29 | public var multiplierWide: CGFloat { 30 | return setMultiplier(mode: .noStatusBar) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Extensions/UIScreen+iPhone10.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+iPhone10.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | public extension UIScreen { 11 | /** 12 | `isiPhone10` is a boolean that returns if the device is iPhone X or not. 13 | */ 14 | public var isiPhone10: Bool { 15 | return self.nativeBounds.size == CGSize(width: 1125, height: 2436) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Extensions/UIView+OvalOrCorners.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+OvalOrCorners.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIView { 12 | /** 13 | **UIView.addOvalOrCorner(type,position,curve,customBounds)** is a UIView extension that allows you add ovals and rounded corners to a UIView. 14 | - For type `oval`, set `curve` from 1.0 - 10.0. 15 | - For type `corner`, `curve` is the radius size. 16 | - Check `curveType` & `curvePosition` for more info. 17 | */ 18 | public func addOvalOrCorner(type:curveType, position:curvePosition, curve:CGFloat?, customBounds:CGRect? = nil) { 19 | let offset:CGFloat = self.frame.size.width/curve! 20 | var bounds:CGRect! 21 | var viewBounds:CGRect! 22 | var viewPath:UIBezierPath! 23 | 24 | if let finalBounds = customBounds { 25 | bounds = finalBounds 26 | }else{ 27 | bounds = self.bounds 28 | } 29 | 30 | switch type { 31 | case .oval: 32 | var ovalBounds:CGRect! 33 | switch position { 34 | case .right: 35 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 36 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width/2, height: bounds.size.height) 37 | 38 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 39 | viewPath = UIBezierPath(rect: viewBounds) 40 | viewPath.append(ovalPath) 41 | break 42 | case .left: 43 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 44 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width/2, y: bounds.origin.y, width: bounds.size.width/2, height: bounds.size.height) 45 | 46 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 47 | viewPath = UIBezierPath(rect: viewBounds) 48 | viewPath.append(ovalPath) 49 | break 50 | case .top: 51 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 52 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height / 2, width: bounds.size.width, height: bounds.size.height / 2) 53 | 54 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 55 | viewPath = UIBezierPath(rect: viewBounds) 56 | viewPath.append(ovalPath) 57 | break 58 | case .bottom: 59 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 60 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height / 2) 61 | 62 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 63 | viewPath = UIBezierPath(rect: viewBounds) 64 | viewPath.append(ovalPath) 65 | break 66 | case .horizontalSides: 67 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 68 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width, y: bounds.origin.y+bounds.size.height, width: bounds.size.width, height: bounds.size.height) 69 | 70 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 71 | viewPath = UIBezierPath(rect: viewBounds) 72 | viewPath.append(ovalPath) 73 | break 74 | case .verticalSides: 75 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 76 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width, y: bounds.origin.y+bounds.size.height, width: bounds.size.width, height: bounds.size.height) 77 | 78 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 79 | viewPath = UIBezierPath(rect: viewBounds) 80 | viewPath.append(ovalPath) 81 | break 82 | case .all: 83 | viewPath = UIBezierPath(ovalIn: self.bounds) 84 | break 85 | } 86 | break 87 | case .corner: 88 | switch position { 89 | case .right: 90 | 91 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 92 | break 93 | case .left: 94 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .bottomLeft], cornerRadii: CGSize(width:curve!, height:curve!)) 95 | break 96 | case .top: 97 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width:curve!, height:curve!)) 98 | break 99 | case .bottom: 100 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 101 | break 102 | case .all: 103 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.allCorners], cornerRadii: CGSize(width:curve!, height:curve!)) 104 | break 105 | default: 106 | break 107 | } 108 | break 109 | } 110 | if let path = viewPath { 111 | let shapeLayer: CAShapeLayer = CAShapeLayer() 112 | shapeLayer.frame = bounds 113 | shapeLayer.path = path.cgPath 114 | self.layer.mask = shapeLayer 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/NotchBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchBar.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | public class NotchBar: UIView { 11 | /** 12 | This allows you to choose between statusBar & noStatusBar modes. 13 | */ 14 | public var mode:notchMode = .statusBar 15 | /** 16 | This allows you to set the height of the NotchBar. 17 | */ 18 | public var height:CGFloat = 250 19 | /** 20 | This allows you to set the background color of the NotchBar. 21 | */ 22 | public var bgColor:UIColor = .black 23 | /** 24 | This allows you to set the corner radii of the NotchBar. 25 | */ 26 | public var curve:CGFloat = 35 27 | /** 28 | This allows you to initially set the NotchBar visibility. 29 | */ 30 | public var isVisible:Bool = false 31 | /** 32 | This allows you to set the animation show/hide & rotation animation time interval of the NotchBar. 33 | */ 34 | public var animationInterval:TimeInterval = 0.3 35 | 36 | override init(frame: CGRect) { 37 | super.init(frame: frame) 38 | create() 39 | } 40 | 41 | required public init?(coder aDecoder: NSCoder) { 42 | super.init(coder: aDecoder) 43 | create() 44 | } 45 | 46 | var scale:CGFloat! 47 | var multiplier:CGFloat! 48 | func create() { 49 | switch mode { 50 | case .statusBar: 51 | scale = UIScreen.main.portraitNotch.width 52 | multiplier = UIScreen.main.multiplier 53 | case .noStatusBar: 54 | scale = UIScreen.main.widePortraitNotch.width 55 | multiplier = UIScreen.main.multiplierWide 56 | } 57 | self.bounds = CGRect(x: 0, y: 0, width: scale, height: height) 58 | self.center = CGPoint(x: UIScreen.main.portraitNotch.origin.x, y: (self.bounds.height/2)) 59 | self.backgroundColor = bgColor 60 | self.addOvalOrCorner(type: .corner, position: .bottom, curve: curve) 61 | self.layer.masksToBounds = true 62 | self.alpha = isVisible ? 1 : 0 63 | } 64 | 65 | /** 66 | This function is used to resize the NotchBar when device orientation is changed. 67 | */ 68 | public func refresh(orientation:deviceOrientation) { 69 | let subtrehend = isVisible ? 0 : self.bounds.height 70 | 71 | switch mode { 72 | case .statusBar: 73 | scale = UIScreen.main.portraitNotch.width 74 | multiplier = UIScreen.main.multiplier 75 | case .noStatusBar: 76 | scale = UIScreen.main.widePortraitNotch.width 77 | multiplier = UIScreen.main.multiplierWide 78 | } 79 | 80 | switch orientation { 81 | case .portrait: 82 | UIView.animate(withDuration: animationInterval, animations: { 83 | self.bounds = CGRect(x: 0, y: 0, width: self.scale, height: self.height) 84 | self.center = CGPoint(x: UIScreen.main.portraitNotch.origin.x, y: (self.bounds.height/2) - subtrehend) 85 | self.backgroundColor = self.bgColor 86 | self.addOvalOrCorner(type: .corner, position: .bottom, curve: self.curve) 87 | self.alpha = self.isVisible ? 1 : 0 88 | }) 89 | case .landscapeLeft: 90 | UIView.animate(withDuration: animationInterval, animations: { 91 | self.bounds = CGRect(x: 0, y: 0, width: self.height, height: self.scale) 92 | self.center = CGPoint(x: (self.bounds.height*(self.multiplier*self.height)) - subtrehend, y: UIScreen.main.landscapeLeftNotch.origin.y) 93 | self.backgroundColor = self.bgColor 94 | self.addOvalOrCorner(type: .corner, position: .right, curve: self.curve) 95 | self.alpha = self.isVisible ? 1 : 0 96 | }) 97 | case .landscapeRight: 98 | UIView.animate(withDuration: animationInterval, animations: { 99 | self.bounds = CGRect(x: 0, y: 0, width: self.height, height: self.scale) 100 | self.center = CGPoint(x: (UIScreen.main.bounds.width-self.bounds.height*(self.multiplier*self.height)) + subtrehend, y: UIScreen.main.landscapeRightNotch.origin.y) 101 | self.backgroundColor = self.bgColor 102 | self.addOvalOrCorner(type: .corner, position: .left, curve: self.curve) 103 | self.alpha = self.isVisible ? 1 : 0 104 | }) 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/NotchToolbar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolbar.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | *NotchToolkit* is a light-weight framework for iOS that allow developers use the iPhone's X notch space in creative ways. 13 | 14 | - Author: Ahmed Fathi Bekhit 15 | * [Github](http://github.com/AFathi) 16 | * [Website](http://ahmedbekhit.com) 17 | * [Twitter](http://twitter.com/iAFapps) 18 | * [Email](mailto:me@ahmedbekhit.com) 19 | */ 20 | public class NotchToolbar: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate { 21 | /** 22 | This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 23 | */ 24 | public var delegate:NotchToolbarDelegate? 25 | /** 26 | This provides you options to customize NotchBar. 27 | */ 28 | public var notch:NotchBar = NotchBar() 29 | /** 30 | This gives you options to change the NotchToolbar scrolling directions. Default is auto. 31 | */ 32 | public var scrollMode:notchScroll = .auto 33 | 34 | /** 35 | This allows you to enable NotchToolbar only for iPhone X. Default is false. 36 | */ 37 | public var onlyFor10:Bool = false 38 | /** 39 | This is the collection view that loads the toolList. 40 | */ 41 | public var tools:UICollectionView? 42 | /** 43 | This allows you to set the tool icon size. Default is 60x60 44 | */ 45 | public var toolIconSize:CGSize = CGSize(width: 60, height: 60) 46 | /** 47 | This allows you to customize the collection view edge insets. 48 | */ 49 | public var toolIconsInsets:UIEdgeInsets = UIEdgeInsetsMake(5, 35, 5, 35) 50 | /** 51 | This is the array of the tool icons in the NotchToolbar. You may only use String & UIImage types. 52 | */ 53 | public var toolList:[Any?] = ["🤓", "😊", "🙄", "👩‍🔬", "👨‍💻"] 54 | /** 55 | This allows you to customize the tools title font. 56 | */ 57 | public var toolsTitleFont:UIFont = UIFont(name:"Avenir-Medium", size: 45)! 58 | /** 59 | This allows you to customize the tools title color. 60 | */ 61 | public var toolsTitleColor:UIColor = .white 62 | 63 | public var toolsFlow = UICollectionViewFlowLayout() 64 | 65 | /** 66 | This function is required to initialize the NotchToolbar. 67 | */ 68 | public func prepare(in vc:UIViewController) { 69 | NotificationCenter.default.addObserver(vc, selector: #selector(delegate?.deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 70 | if onlyFor10 && !UIScreen.main.isiPhone10 { 71 | print("NotchToolbar: If you want to enable NotchToolBar on this device please add this line to your code\nNotchToolBar().onlyFor10 = false") 72 | }else{ 73 | switch scrollMode { 74 | case .alwaysHorizontal: 75 | toolsFlow.scrollDirection = .horizontal 76 | case .alwaysVertical: 77 | toolsFlow.scrollDirection = .vertical 78 | default: 79 | break 80 | } 81 | tools = UICollectionView(frame: CGRect(x:0, y:0, width:notch.bounds.width, height:notch.bounds.height), collectionViewLayout: toolsFlow) 82 | tools?.register(NotchToolCell.self, forCellWithReuseIdentifier: "toolCell") 83 | tools?.delegate = self 84 | tools?.dataSource = self 85 | tools?.contentOffset = CGPoint(x: 0, y: 0) 86 | tools?.backgroundColor = .clear 87 | tools?.setContentOffset(CGPoint.zero, animated: false) 88 | notch.addSubview(tools!) 89 | vc.view.addSubview(notch) 90 | } 91 | } 92 | 93 | /** 94 | This function allows you to show and hide the NotchToolbar. 95 | */ 96 | public func showOrHide() { 97 | notch.isVisible = notch.isVisible ? false : true 98 | autoResize() 99 | } 100 | } 101 | 102 | //MARK:- NotchToolbarDelegates 103 | extension NotchToolbar { 104 | /** 105 | This function is required to be called from the `deviceDidRotate` delegate function. 106 | */ 107 | public func autoResize() { 108 | var offsetPoint:CGPoint! = CGPoint.zero 109 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 110 | switch scrollMode { 111 | case .auto: 112 | offsetPoint = CGPoint(x:-(pow(toolIconsInsets.top, 2.4)),y:0) 113 | toolsFlow.scrollDirection = .horizontal 114 | case .alwaysVertical: 115 | offsetPoint = CGPoint(x:-(pow(toolIconsInsets.top, 2.4)),y:0) 116 | default: 117 | break 118 | } 119 | }else{ 120 | switch scrollMode { 121 | case .auto: 122 | offsetPoint = CGPoint(x:0,y:-(pow(toolIconsInsets.top, 2.4))) 123 | toolsFlow.scrollDirection = .vertical 124 | case .alwaysVertical: 125 | offsetPoint = CGPoint(x:0,y:-(pow(toolIconsInsets.top, 2.4))) 126 | default: 127 | break 128 | } 129 | } 130 | 131 | switch UIDevice.current.orientation { 132 | case .portrait: 133 | notch.refresh(orientation: .portrait) 134 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 135 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 136 | tools?.reloadData() 137 | tools?.setContentOffset(offsetPoint, animated: false) 138 | case .portraitUpsideDown: 139 | //no changes 140 | break 141 | case .landscapeLeft: 142 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 143 | notch.refresh(orientation: .landscapeLeft) 144 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 145 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 146 | tools?.reloadData() 147 | tools?.setContentOffset(offsetPoint, animated: false) 148 | } 149 | case .landscapeRight: 150 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 151 | notch.refresh(orientation: .landscapeRight) 152 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 153 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 154 | tools?.reloadData() 155 | tools?.setContentOffset(offsetPoint, animated: false) 156 | } 157 | default: 158 | break 159 | } 160 | } 161 | 162 | public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 163 | return toolList.count 164 | } 165 | 166 | public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 167 | let cell:NotchToolCell = collectionView.dequeueReusableCell(withReuseIdentifier: "toolCell", for: indexPath as IndexPath) as! NotchToolCell 168 | if let text = toolList[indexPath.row] as? String { 169 | cell.setTitle(text, font: toolsTitleFont, color: toolsTitleColor) 170 | }else if let image = toolList[indexPath.row] as? UIImage { 171 | cell.setIcon(image) 172 | } 173 | 174 | return cell 175 | } 176 | 177 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 178 | return toolIconSize 179 | } 180 | 181 | public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 182 | delegate?.didTapToolIcon(collectionView, toolIndex: indexPath, section: indexPath.section, row: indexPath.row) 183 | } 184 | 185 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 186 | return toolIconsInsets 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/NotchToolkit.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolkit.h 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for NotchToolkit. 12 | FOUNDATION_EXPORT double NotchToolkitVersionNumber; 13 | 14 | //! Project version string for NotchToolkit. 15 | FOUNDATION_EXPORT const unsigned char NotchToolkitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/NotchToolkit/Protocols/NotchToolbarDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolbarDelegate.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | /** 11 | This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 12 | */ 13 | @objc public protocol NotchToolbarDelegate { 14 | /** 15 | This delegate function detects when the device orientation changes. Calling **autoResize()** function inside this delegate is **required**. 16 | */ 17 | func deviceDidRotate() 18 | /** 19 | This delegate function allows you to detect which toolbar icon was selected. 20 | */ 21 | func didTapToolIcon(_ tools: UICollectionView, toolIndex:IndexPath, section: Int, row: Int) 22 | } 23 | -------------------------------------------------------------------------------- /Example/Pods/NotchToolkit/README.md: -------------------------------------------------------------------------------- 1 | # NotchToolkit 2 | NotchToolkit is a light-weight framework for iOS that allow developers use the iPhone's X notch space in creative ways 3 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/NotchToolkit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/NotchToolkit/NotchToolkit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_NotchToolkit : NSObject 3 | @end 4 | @implementation PodsDummy_NotchToolkit 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/NotchToolkit/NotchToolkit-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/NotchToolkit/NotchToolkit-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "NotchToolkit.h" 14 | 15 | FOUNDATION_EXPORT double NotchToolkitVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char NotchToolkitVersionString[]; 17 | 18 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/NotchToolkit/NotchToolkit.modulemap: -------------------------------------------------------------------------------- 1 | framework module NotchToolkit { 2 | umbrella header "NotchToolkit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/NotchToolkit/NotchToolkit.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/NotchToolkit 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/NotchToolkit 9 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 10 | SKIP_INSTALL = YES 11 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## NotchToolkit 5 | 6 | MIT License 7 | 8 | Copyright (c) 2017 Ahmed Fathi Bekhit[me@ahmedbekhit.com] 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | 28 | Generated by CocoaPods - https://cocoapods.org 29 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | MIT License 18 | 19 | Copyright (c) 2017 Ahmed Fathi Bekhit[me@ahmedbekhit.com] 20 | 21 | Permission is hereby granted, free of charge, to any person obtaining a copy 22 | of this software and associated documentation files (the "Software"), to deal 23 | in the Software without restriction, including without limitation the rights 24 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 25 | copies of the Software, and to permit persons to whom the Software is 26 | furnished to do so, subject to the following conditions: 27 | 28 | The above copyright notice and this permission notice shall be included in all 29 | copies or substantial portions of the Software. 30 | 31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 37 | SOFTWARE. 38 | 39 | License 40 | MIT 41 | Title 42 | NotchToolkit 43 | Type 44 | PSGroupSpecifier 45 | 46 | 47 | FooterText 48 | Generated by CocoaPods - https://cocoapods.org 49 | Title 50 | 51 | Type 52 | PSGroupSpecifier 53 | 54 | 55 | StringsTable 56 | Acknowledgements 57 | Title 58 | Acknowledgements 59 | 60 | 61 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_NotchToolkit_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_NotchToolkit_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | 104 | if [[ "$CONFIGURATION" == "Debug" ]]; then 105 | install_framework "${BUILT_PRODUCTS_DIR}/NotchToolkit/NotchToolkit.framework" 106 | fi 107 | if [[ "$CONFIGURATION" == "Release" ]]; then 108 | install_framework "${BUILT_PRODUCTS_DIR}/NotchToolkit/NotchToolkit.framework" 109 | fi 110 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 111 | wait 112 | fi 113 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_NotchToolkit_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_NotchToolkit_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit/NotchToolkit.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "NotchToolkit" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_NotchToolkit_Example { 2 | umbrella header "Pods-NotchToolkit-Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-Example/Pods-NotchToolkit-Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit/NotchToolkit.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "NotchToolkit" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_BUILD_DIR = $BUILD_DIR 9 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_NotchToolkit_ExampleTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_NotchToolkit_ExampleTests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 10 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 11 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 12 | 13 | install_framework() 14 | { 15 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 16 | local source="${BUILT_PRODUCTS_DIR}/$1" 17 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 18 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 19 | elif [ -r "$1" ]; then 20 | local source="$1" 21 | fi 22 | 23 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 24 | 25 | if [ -L "${source}" ]; then 26 | echo "Symlinked..." 27 | source="$(readlink "${source}")" 28 | fi 29 | 30 | # Use filter instead of exclude so missing patterns don't throw errors. 31 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 32 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 33 | 34 | local basename 35 | basename="$(basename -s .framework "$1")" 36 | binary="${destination}/${basename}.framework/${basename}" 37 | if ! [ -r "$binary" ]; then 38 | binary="${destination}/${basename}" 39 | fi 40 | 41 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 42 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 43 | strip_invalid_archs "$binary" 44 | fi 45 | 46 | # Resign the code if required by the build settings to avoid unstable apps 47 | code_sign_if_enabled "${destination}/$(basename "$1")" 48 | 49 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 50 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 51 | local swift_runtime_libs 52 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 53 | for lib in $swift_runtime_libs; do 54 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 55 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 56 | code_sign_if_enabled "${destination}/${lib}" 57 | done 58 | fi 59 | } 60 | 61 | # Copies the dSYM of a vendored framework 62 | install_dsym() { 63 | local source="$1" 64 | if [ -r "$source" ]; then 65 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\"" 66 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}" 67 | fi 68 | } 69 | 70 | # Signs a framework with the provided identity 71 | code_sign_if_enabled() { 72 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 73 | # Use the current code_sign_identitiy 74 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 75 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'" 76 | 77 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 78 | code_sign_cmd="$code_sign_cmd &" 79 | fi 80 | echo "$code_sign_cmd" 81 | eval "$code_sign_cmd" 82 | fi 83 | } 84 | 85 | # Strip invalid architectures 86 | strip_invalid_archs() { 87 | binary="$1" 88 | # Get architectures for current file 89 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 90 | stripped="" 91 | for arch in $archs; do 92 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then 93 | # Strip non-valid architectures in-place 94 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 95 | stripped="$stripped $arch" 96 | fi 97 | done 98 | if [[ "$stripped" ]]; then 99 | echo "Stripped $binary of architectures:$stripped" 100 | fi 101 | } 102 | 103 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then 104 | wait 105 | fi 106 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | # This protects against multiple targets copying the same framework dependency at the same time. The solution 12 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html 13 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") 14 | 15 | case "${TARGETED_DEVICE_FAMILY}" in 16 | 1,2) 17 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 18 | ;; 19 | 1) 20 | TARGET_DEVICE_ARGS="--target-device iphone" 21 | ;; 22 | 2) 23 | TARGET_DEVICE_ARGS="--target-device ipad" 24 | ;; 25 | 3) 26 | TARGET_DEVICE_ARGS="--target-device tv" 27 | ;; 28 | 4) 29 | TARGET_DEVICE_ARGS="--target-device watch" 30 | ;; 31 | *) 32 | TARGET_DEVICE_ARGS="--target-device mac" 33 | ;; 34 | esac 35 | 36 | install_resource() 37 | { 38 | if [[ "$1" = /* ]] ; then 39 | RESOURCE_PATH="$1" 40 | else 41 | RESOURCE_PATH="${PODS_ROOT}/$1" 42 | fi 43 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 44 | cat << EOM 45 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 46 | EOM 47 | exit 1 48 | fi 49 | case $RESOURCE_PATH in 50 | *.storyboard) 51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 53 | ;; 54 | *.xib) 55 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true 56 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 57 | ;; 58 | *.framework) 59 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 60 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 61 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true 62 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 63 | ;; 64 | *.xcdatamodel) 65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true 66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 67 | ;; 68 | *.xcdatamodeld) 69 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true 70 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 71 | ;; 72 | *.xcmappingmodel) 73 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true 74 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 75 | ;; 76 | *.xcassets) 77 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 78 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 79 | ;; 80 | *) 81 | echo "$RESOURCE_PATH" || true 82 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 83 | ;; 84 | esac 85 | } 86 | 87 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 88 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 89 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 90 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 91 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 92 | fi 93 | rm -f "$RESOURCES_TO_COPY" 94 | 95 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 96 | then 97 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 98 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 99 | while read line; do 100 | if [[ $line != "${PODS_ROOT}*" ]]; then 101 | XCASSET_FILES+=("$line") 102 | fi 103 | done <<<"$OTHER_XCASSETS" 104 | 105 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 106 | fi 107 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_NotchToolkit_ExampleTestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_NotchToolkit_ExampleTestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit/NotchToolkit.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_NotchToolkit_ExampleTests { 2 | umbrella header "Pods-NotchToolkit-ExampleTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-NotchToolkit-ExampleTests/Pods-NotchToolkit-ExampleTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/NotchToolkit/NotchToolkit.framework/Headers" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ahmed Fathi Bekhit[me@ahmedbekhit.com] 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 | -------------------------------------------------------------------------------- /NotchToolkit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "NotchToolkit" 4 | s.version = "1.3" 5 | s.summary = "An iOS framework for iPhone X notch." 6 | 7 | s.description = "A framework for iOS that allow developers use the iPhone X notch space in creative ways." 8 | 9 | s.homepage = "https://github.com/AFathi/NotchToolkit" 10 | s.screenshots = "http://ahmedbekhit.com/toolbar_preview.gif" 11 | s.license = { :type => "MIT", :file => "LICENSE" } 12 | 13 | s.author = { "Ahmed Bekhit" => "me@ahmedbekhit.com" } 14 | s.social_media_url = "http://twitter.com/iAFapps" 15 | 16 | s.platform = :ios, "11.0" 17 | 18 | s.source = { :git => "https://github.com/AFathi/NotchToolkit.git", :tag => "1.3" } 19 | 20 | s.source_files = "NotchToolkit", "NotchToolkit/**/*.{swift}" 21 | 22 | end -------------------------------------------------------------------------------- /NotchToolkit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /NotchToolkit.xcodeproj/xcshareddata/xcschemes/NotchToolkit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /NotchToolkit/Cells/NotchToolCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolCell.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class NotchToolCell: UICollectionViewCell { 12 | private var toolIcon : UIImageView? 13 | private var toolTitle : UILabel? 14 | 15 | func setIcon(_ image:UIImage?) { 16 | if toolIcon == nil { 17 | toolIcon = UIImageView() 18 | toolIcon?.frame = CGRect(x: 0, y:0, width: contentView.frame.width, height: contentView.frame.height) 19 | toolIcon?.contentMode = .scaleAspectFit 20 | contentView.addSubview(toolIcon!) 21 | } 22 | 23 | if let icon = toolIcon { 24 | if let img = image { 25 | icon.image = img 26 | } 27 | icon.isHidden = false 28 | } 29 | if let title = toolTitle { 30 | title.isHidden = true 31 | } 32 | } 33 | 34 | func setTitle(_ text:String, font:UIFont, color:UIColor) { 35 | if toolTitle == nil { 36 | toolTitle = UILabel() 37 | toolTitle?.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 38 | toolTitle?.font = font 39 | toolTitle?.textColor = color 40 | toolTitle?.textAlignment = .center 41 | contentView.addSubview(toolTitle!) 42 | } 43 | 44 | if let title = toolTitle { 45 | title.text = text 46 | title.isHidden = false 47 | } 48 | 49 | if let icon = toolIcon { 50 | icon.isHidden = true 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /NotchToolkit/Cells/NotchToolNameIconCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolNameIconCell.swift 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 9/28/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NotchToolNameIconCell: UICollectionViewCell { 12 | private var toolIcon : UIImageView? 13 | private var toolTitle : UILabel? 14 | 15 | func set(_ image:UIImage? = nil, text:String? = nil, font:UIFont? = nil, color:UIColor? = nil, type: toolIconTypes) { 16 | var titleFrame:CGRect! 17 | var iconFrame:CGRect! 18 | 19 | var isTitleHidden:Bool! 20 | var isIconHidden:Bool! 21 | 22 | switch type { 23 | case .image: 24 | titleFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 25 | iconFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 26 | isTitleHidden = true 27 | isIconHidden = false 28 | case .text: 29 | titleFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 30 | iconFrame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height) 31 | isTitleHidden = false 32 | isIconHidden = true 33 | case .both: 34 | titleFrame = CGRect(x: 0, y: contentView.frame.height*0.75, width: contentView.frame.width, height: contentView.frame.height*0.25) 35 | iconFrame = CGRect(x: 0, y:0, width: contentView.frame.width, height: contentView.frame.height*0.75) 36 | isTitleHidden = false 37 | isIconHidden = false 38 | } 39 | 40 | if toolTitle == nil { 41 | toolTitle = UILabel() 42 | toolTitle?.frame = titleFrame 43 | if let font = font { 44 | toolTitle?.font = font 45 | } 46 | if let color = color { 47 | toolTitle?.textColor = color 48 | } 49 | toolTitle?.textAlignment = .center 50 | contentView.addSubview(toolTitle!) 51 | } 52 | 53 | if toolIcon == nil { 54 | toolIcon = UIImageView() 55 | toolIcon?.frame = iconFrame 56 | toolIcon?.contentMode = .scaleAspectFit 57 | contentView.addSubview(toolIcon!) 58 | } 59 | if let title = toolTitle { 60 | if let txt = text { 61 | title.text = txt 62 | } 63 | title.isHidden = isTitleHidden 64 | } 65 | if let icon = toolIcon { 66 | if let img = image { 67 | icon.image = img 68 | } 69 | icon.isHidden = isIconHidden 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /NotchToolkit/Classes/NotchBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchBar.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | public class NotchBar: UIView { 11 | /** 12 | This allows you to choose between statusBar & noStatusBar modes. 13 | */ 14 | public var mode:notchMode = .statusBar 15 | /** 16 | This allows you to set the height of the NotchBar. 17 | */ 18 | public var height:CGFloat = 250 19 | /** 20 | This allows you to set the background color of the NotchBar. 21 | */ 22 | public var bgColor:UIColor = .black 23 | /** 24 | This allows you to set the corner radii of the NotchBar. 25 | */ 26 | public var curve:CGFloat = 35 27 | /** 28 | This allows you to initially set the NotchBar visibility. 29 | */ 30 | public var isVisible:Bool = false 31 | /** 32 | This allows you to set the animation show/hide & rotation animation time interval of the NotchBar. 33 | */ 34 | public var animationInterval:TimeInterval = 0.3 35 | 36 | override init(frame: CGRect) { 37 | super.init(frame: frame) 38 | create() 39 | } 40 | 41 | required public init?(coder aDecoder: NSCoder) { 42 | super.init(coder: aDecoder) 43 | create() 44 | } 45 | 46 | var scale:CGFloat! 47 | var multiplier:CGFloat! 48 | func create() { 49 | switch mode { 50 | case .statusBar: 51 | scale = UIScreen.main.portraitNotch.width 52 | multiplier = UIScreen.main.multiplier 53 | case .noStatusBar: 54 | scale = UIScreen.main.widePortraitNotch.width 55 | multiplier = UIScreen.main.multiplierWide 56 | } 57 | self.bounds = CGRect(x: 0, y: 0, width: scale, height: height) 58 | self.center = CGPoint(x: UIScreen.main.portraitNotch.origin.x, y: (self.bounds.height/2)) 59 | self.backgroundColor = bgColor 60 | self.draw(.corner, position: .bottom, curve: curve) 61 | self.layer.masksToBounds = true 62 | self.alpha = isVisible ? 1 : 0 63 | } 64 | 65 | /** 66 | This function is used to resize the NotchBar when device orientation is changed. 67 | */ 68 | public func refresh(orientation:deviceOrientation) { 69 | let subtrehend = isVisible ? 0 : self.bounds.height 70 | 71 | switch mode { 72 | case .statusBar: 73 | scale = UIScreen.main.portraitNotch.width 74 | multiplier = UIScreen.main.multiplier 75 | case .noStatusBar: 76 | scale = UIScreen.main.widePortraitNotch.width 77 | multiplier = UIScreen.main.multiplierWide 78 | } 79 | 80 | switch orientation { 81 | case .portrait: 82 | UIView.animate(withDuration: animationInterval, animations: { 83 | self.bounds = CGRect(x: 0, y: 0, width: self.scale, height: self.height) 84 | self.center = CGPoint(x: UIScreen.main.portraitNotch.origin.x, y: (self.bounds.height/2) - subtrehend) 85 | self.backgroundColor = self.bgColor 86 | self.draw(.corner, position: .bottom, curve: self.curve) 87 | self.alpha = self.isVisible ? 1 : 0 88 | }) 89 | case .landscapeLeft: 90 | UIView.animate(withDuration: animationInterval, animations: { 91 | self.bounds = CGRect(x: 0, y: 0, width: self.height, height: self.scale) 92 | self.center = CGPoint(x: (self.bounds.height*(self.multiplier*self.height)) - subtrehend, y: UIScreen.main.landscapeLeftNotch.origin.y) 93 | self.backgroundColor = self.bgColor 94 | self.draw(.corner, position: .right, curve: self.curve) 95 | self.alpha = self.isVisible ? 1 : 0 96 | }) 97 | case .landscapeRight: 98 | UIView.animate(withDuration: animationInterval, animations: { 99 | self.bounds = CGRect(x: 0, y: 0, width: self.height, height: self.scale) 100 | self.center = CGPoint(x: (UIScreen.main.bounds.width-self.bounds.height*(self.multiplier*self.height)) + subtrehend, y: UIScreen.main.landscapeRightNotch.origin.y) 101 | self.backgroundColor = self.bgColor 102 | self.draw(.corner, position: .left, curve: self.curve) 103 | self.alpha = self.isVisible ? 1 : 0 104 | }) 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /NotchToolkit/Classes/NotchImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchImageView.swift 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 11/1/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | *NotchToolkit* is a framework for iOS that allow developers use the iPhones X notch space in creative ways. 13 | 14 | - Author: Ahmed Fathi Bekhit 15 | * [Github](http://github.com/AFathi) 16 | * [Website](http://ahmedbekhit.com) 17 | * [Twitter](http://twitter.com/iAFapps) 18 | * [Email](mailto:me@ahmedbekhit.com) 19 | */ 20 | public class NotchImageView: NotchBar { 21 | // MARK: - Public objects 22 | 23 | /// This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 24 | public var delegate:NotchToolbarDelegate? 25 | 26 | /// This allows you to enable NotchToolbar only for iPhone X. Default is false. 27 | public var onlyFor10:Bool = false 28 | /// Configure printing bar height 29 | public var printBarHeight:CGFloat = 3 30 | /// Configure printing color 31 | public var printBarColor:UIColor = .cyan 32 | /// Configure image loading duration intervals 33 | public var durationIntervals:TimeInterval = 0.8 34 | 35 | // MARK: - Private Objects 36 | private var recentOrientation: deviceOrientation! 37 | private var imageView:UIImageView = UIImageView() 38 | private var notchImage:UIImage? 39 | private var printerBar:UIView = UIView() 40 | private var isShown:Bool = false 41 | private var isLoaded:Bool = false 42 | 43 | /// Initialize 44 | public init() { 45 | super.init(frame: CGRect.zero) 46 | } 47 | /// Initialize with a UIImage 48 | public init(image: UIImage?) { 49 | super.init(frame: CGRect.zero) 50 | notchImage = image 51 | self.bgColor = .clear 52 | self.animationInterval = 0.1 53 | } 54 | 55 | required public init?(coder aDecoder: NSCoder) { 56 | fatalError("init(coder:) has not been implemented") 57 | } 58 | } 59 | 60 | //MARK:- Methods 61 | extension NotchImageView { 62 | /// This method is required to prepare the NotchImageView in your view controller. 63 | public func prepare(in vc:UIViewController) { 64 | NotificationCenter.default.addObserver(vc, selector: #selector(delegate?.deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 65 | if onlyFor10 && !UIScreen.main.isiPhone10 { 66 | print("NotchToolbar: If you want to enable NotchToolBar on this device please add this line to your code\nNotchToolBar().onlyFor10 = false") 67 | }else{ 68 | recentOrientation = .portrait 69 | imageView = UIImageView(frame: CGRect(x:0, y:0, width:self.bounds.width, height:self.bounds.height)) 70 | imageView.center = CGPoint(x:(self.bounds.width)*0.5, y:-(self.bounds.height*0.5)) 71 | imageView.backgroundColor = .clear 72 | imageView.contentMode = .scaleAspectFill 73 | imageView.clipsToBounds = true 74 | imageView.draw(.corner, position: .bottom, curve: self.curve) 75 | if let img = notchImage { 76 | imageView.image = img 77 | } 78 | self.addSubview(imageView) 79 | 80 | printerBar = UIView(frame: CGRect(x:0, y:0, width:self.bounds.width, height:printBarHeight)) 81 | printerBar.center = CGPoint(x:self.bounds.width*0.5, y:-(self.bounds.height*0.5)) 82 | printerBar.backgroundColor = printBarColor.withAlphaComponent(0.4) 83 | printerBar.layer.shadowColor = printBarColor.cgColor 84 | printerBar.layer.shadowOffset = CGSize(width: 0.0, height: 2.5) 85 | printerBar.layer.shadowOpacity = 1.0 86 | self.addSubview(printerBar) 87 | 88 | vc.view.addSubview(self) 89 | } 90 | } 91 | /// Loads image view from notch with animation 92 | public func load() { 93 | self.isVisible = true 94 | 95 | UIView.animate(withDuration: 0.3, delay: 0.1, usingSpringWithDamping: 1.2, initialSpringVelocity: 0.4, options: [.autoreverse, .repeat], animations: { 96 | self.printerBar.center = CGPoint(x:self.self.bounds.width*0.5, y:(self.self.bounds.height)) 97 | }) 98 | 99 | autoResize() 100 | isShown = true 101 | updateBounds(orientation: recentOrientation) 102 | } 103 | /// Removes image view from superview 104 | public func remove() { 105 | self.self.removeFromSuperview() 106 | self.removeFromSuperview() 107 | } 108 | /// This function is required to be called from the `deviceDidRotate` delegate function. 109 | public func autoResize() { 110 | switch UIDevice.current.orientation { 111 | case .portrait: 112 | recentOrientation = .portrait 113 | self.refresh(orientation: .portrait) 114 | self.updateBounds(orientation: .portrait) 115 | case .portraitUpsideDown: 116 | self.refresh(orientation: recentOrientation) 117 | self.updateBounds(orientation: recentOrientation) 118 | case .landscapeLeft: 119 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 120 | recentOrientation = .landscapeLeft 121 | self.refresh(orientation: .landscapeLeft) 122 | self.updateBounds(orientation: .landscapeLeft) 123 | } 124 | case .landscapeRight: 125 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 126 | recentOrientation = .landscapeRight 127 | self.refresh(orientation: .landscapeRight) 128 | self.updateBounds(orientation: .landscapeRight) 129 | } 130 | case .faceDown: 131 | self.refresh(orientation: recentOrientation) 132 | self.updateBounds(orientation: recentOrientation) 133 | case .faceUp: 134 | self.refresh(orientation: recentOrientation) 135 | self.updateBounds(orientation: recentOrientation) 136 | case .unknown: 137 | self.refresh(orientation: recentOrientation) 138 | self.updateBounds(orientation: recentOrientation) 139 | } 140 | } 141 | 142 | private func updateBounds(orientation: deviceOrientation) { 143 | var xPos = (self.bounds.width*0.5) 144 | var yPos = (self.bounds.height*0.5) 145 | switch orientation { 146 | case .landscapeLeft : 147 | xPos = (!isShown) ? -(self.bounds.width*0.5) : (self.bounds.width*0.5) 148 | case .landscapeRight: 149 | xPos = (!isShown) ? (self.bounds.width*1.5) : (self.bounds.width*0.5) 150 | case .portrait: 151 | yPos = (!isShown) ? -(self.bounds.height*0.5) : (self.bounds.height*0.5) 152 | } 153 | 154 | imageView.bounds = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height) 155 | if self.isLoaded{ 156 | self.self.frame = UIScreen.main.bounds 157 | self.imageView.frame = self.self.frame 158 | self.self.draw(.corner, position: .bottom, curve: 0) 159 | self.imageView.draw(.corner, position: .bottom, curve: 0) 160 | return 161 | } 162 | 163 | UIView.animate(withDuration: self.durationIntervals, animations: { 164 | self.imageView.center = CGPoint(x:xPos, y:yPos) 165 | }) 166 | if self.isShown { 167 | UIView.animate(withDuration: 0.4, delay: self.durationIntervals, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.4, options: .curveLinear, animations: { 168 | self.self.frame = UIScreen.main.bounds 169 | self.imageView.frame = self.self.frame 170 | self.draw(.corner, position: .bottom, curve: 0) 171 | self.imageView.draw(.corner, position: .bottom, curve: 0) 172 | self.printerBar.alpha = 0 173 | }){ done in 174 | self.isLoaded = true 175 | self.printerBar.layer.removeAllAnimations() 176 | } 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /NotchToolkit/Classes/NotchToolbar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolbar.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | /** 12 | *NotchToolkit* is a framework for iOS that allow developers use the iPhones X notch space in creative ways. 13 | 14 | - Author: Ahmed Fathi Bekhit 15 | * [Github](http://github.com/AFathi) 16 | * [Website](http://ahmedbekhit.com) 17 | * [Twitter](http://twitter.com/iAFapps) 18 | * [Email](mailto:me@ahmedbekhit.com) 19 | */ 20 | public class NotchToolbar: NSObject, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate { 21 | /** 22 | This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 23 | */ 24 | public var delegate:NotchToolbarDelegate? 25 | /** 26 | This provides you options to customize NotchBar. 27 | */ 28 | public var notch:NotchBar = NotchBar() 29 | /** 30 | This gives you options to change the NotchToolbar scrolling directions. Default is auto. 31 | */ 32 | public var scrollMode:notchScroll = .auto 33 | 34 | /** 35 | This allows you to enable NotchToolbar only for iPhone X. Default is false. 36 | */ 37 | public var onlyFor10:Bool = false 38 | /** 39 | This is the collection view that loads the toolList. 40 | */ 41 | public var tools:UICollectionView? 42 | /** 43 | This allows you to set the tool icon size. Default is 60x60 44 | */ 45 | public var toolIconSize:CGSize = CGSize(width: 60, height: 60) 46 | /** 47 | This allows you to customize the collection view edge insets. 48 | */ 49 | public var toolIconsInsets:UIEdgeInsets = UIEdgeInsetsMake(5, 35, 5, 35) 50 | /** 51 | This is the array of the tool icons in the NotchToolbar. You may use String, UIImage, or an array of both types. 52 | */ 53 | public var toolList:[Any?] = ["🤓", "😊", "🙄", "👩‍🔬", "👨‍💻"] 54 | /** 55 | This allows you to customize the tools title font. 56 | */ 57 | public var toolsTitleFont:UIFont = UIFont(name:"Avenir-Medium", size: 45)! 58 | 59 | /** 60 | This allows you to customize the tools image icon with title font. 61 | */ 62 | public var iconWithNameFont:UIFont = UIFont(name:"Avenir-Medium", size: 12)! 63 | 64 | /** 65 | This allows you to customize the tools title color. 66 | */ 67 | public var toolsTitleColor:UIColor = .white 68 | 69 | /** 70 | This allows you to customize the tools image icon with title color. 71 | */ 72 | public var iconWithNameColor:UIColor = .white 73 | 74 | public var toolsFlow = UICollectionViewFlowLayout() 75 | 76 | private var recentOrientation: deviceOrientation! 77 | 78 | /** 79 | This function is required to initialize the NotchToolbar. 80 | */ 81 | public func prepare(in vc:UIViewController) { 82 | NotificationCenter.default.addObserver(vc, selector: #selector(delegate?.deviceDidRotate), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil) 83 | if onlyFor10 && !UIScreen.main.isiPhone10 { 84 | print("NotchToolbar: If you want to enable NotchToolBar on this device please add this line to your code\nNotchToolBar().onlyFor10 = false") 85 | }else{ 86 | switch scrollMode { 87 | case .alwaysHorizontal: 88 | toolsFlow.scrollDirection = .horizontal 89 | case .alwaysVertical: 90 | toolsFlow.scrollDirection = .vertical 91 | default: 92 | break 93 | } 94 | recentOrientation = .portrait 95 | tools = UICollectionView(frame: CGRect(x:0, y:0, width:notch.bounds.width, height:notch.bounds.height), collectionViewLayout: toolsFlow) 96 | tools?.register(NotchToolCell.self, forCellWithReuseIdentifier: "toolCell") 97 | tools?.register(NotchToolNameIconCell.self, forCellWithReuseIdentifier: "toolIconNameCell") 98 | tools?.delegate = self 99 | tools?.dataSource = self 100 | tools?.contentOffset = CGPoint(x: 0, y: 0) 101 | tools?.backgroundColor = .clear 102 | tools?.setContentOffset(CGPoint.zero, animated: false) 103 | notch.addSubview(tools!) 104 | vc.view.addSubview(notch) 105 | } 106 | } 107 | 108 | /** 109 | This function allows you to show and hide the NotchToolbar. 110 | */ 111 | public func showOrHide() { 112 | notch.isVisible = notch.isVisible ? false : true 113 | autoResize() 114 | } 115 | } 116 | 117 | //MARK:- Methods and Delegates 118 | extension NotchToolbar { 119 | /** 120 | This function is required to be called from the `deviceDidRotate` delegate function. 121 | */ 122 | public func autoResize() { 123 | var offsetPoint:CGPoint! = CGPoint.zero 124 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 125 | switch scrollMode { 126 | case .auto: 127 | offsetPoint = CGPoint(x:-(pow(toolIconsInsets.top, 2.4)),y:0) 128 | toolsFlow.scrollDirection = .horizontal 129 | case .alwaysVertical: 130 | offsetPoint = CGPoint(x:-(pow(toolIconsInsets.top, 2.4)),y:0) 131 | default: 132 | break 133 | } 134 | }else{ 135 | switch scrollMode { 136 | case .auto: 137 | offsetPoint = CGPoint(x:0,y:-(pow(toolIconsInsets.top, 2.4))) 138 | toolsFlow.scrollDirection = .vertical 139 | case .alwaysVertical: 140 | offsetPoint = CGPoint(x:0,y:-(pow(toolIconsInsets.top, 2.4))) 141 | default: 142 | break 143 | } 144 | } 145 | 146 | switch UIDevice.current.orientation { 147 | case .portrait: 148 | recentOrientation = .portrait 149 | notch.refresh(orientation: .portrait) 150 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 151 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 152 | tools?.reloadData() 153 | tools?.setContentOffset(offsetPoint, animated: false) 154 | case .portraitUpsideDown: 155 | notch.refresh(orientation: recentOrientation) 156 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 157 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 158 | tools?.reloadData() 159 | tools?.setContentOffset(offsetPoint, animated: false) 160 | case .landscapeLeft: 161 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 162 | recentOrientation = .landscapeLeft 163 | notch.refresh(orientation: .landscapeLeft) 164 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 165 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 166 | tools?.reloadData() 167 | tools?.setContentOffset(offsetPoint, animated: false) 168 | } 169 | case .landscapeRight: 170 | if UIScreen.main.bounds.size.width > UIScreen.main.bounds.height { 171 | recentOrientation = .landscapeRight 172 | notch.refresh(orientation: .landscapeRight) 173 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 174 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 175 | tools?.reloadData() 176 | tools?.setContentOffset(offsetPoint, animated: false) 177 | } 178 | case .faceDown: 179 | notch.refresh(orientation: recentOrientation) 180 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 181 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 182 | tools?.reloadData() 183 | tools?.setContentOffset(offsetPoint, animated: false) 184 | case .faceUp: 185 | notch.refresh(orientation: recentOrientation) 186 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 187 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 188 | tools?.reloadData() 189 | tools?.setContentOffset(offsetPoint, animated: false) 190 | case .unknown: 191 | notch.refresh(orientation: recentOrientation) 192 | tools?.bounds = CGRect(x: 0, y: 0, width: notch.bounds.size.width, height: notch.bounds.size.height) 193 | tools?.center = CGPoint(x: notch.bounds.size.width/2, y: notch.bounds.size.height/2) 194 | tools?.reloadData() 195 | tools?.setContentOffset(offsetPoint, animated: false) 196 | } 197 | } 198 | 199 | public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 200 | return toolList.count 201 | } 202 | 203 | public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 204 | if let iconMultiple = toolList[indexPath.row] as? [Any] { 205 | let cell:NotchToolNameIconCell = collectionView.dequeueReusableCell(withReuseIdentifier: "toolIconNameCell", for: indexPath as IndexPath) as! NotchToolNameIconCell 206 | 207 | let extractedStrings = iconMultiple.filter{if let _ = $0 as? String{return true} else {return false}} 208 | let extractedImages = iconMultiple.filter{if let _ = $0 as? UIImage{return true} else {return false}} 209 | 210 | if let text = extractedStrings[0] as? String { 211 | if let image = extractedImages[0] as? UIImage { 212 | cell.set(image, text: text, font: iconWithNameFont, color: toolsTitleColor, type: .both) 213 | } 214 | } 215 | return cell 216 | }else{ 217 | let cell:NotchToolCell = collectionView.dequeueReusableCell(withReuseIdentifier: "toolCell", for: indexPath as IndexPath) as! NotchToolCell 218 | 219 | if let text = toolList[indexPath.row] as? String { 220 | cell.setTitle(text, font: toolsTitleFont, color: toolsTitleColor) 221 | }else if let image = toolList[indexPath.row] as? UIImage { 222 | cell.setIcon(image) 223 | } 224 | return cell 225 | } 226 | } 227 | 228 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 229 | return toolIconSize 230 | } 231 | 232 | public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 233 | delegate?.didTapToolIcon(collectionView, toolIndex: indexPath, section: indexPath.section, row: indexPath.row) 234 | } 235 | 236 | public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 237 | return toolIconsInsets 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /NotchToolkit/Enumerations/CurveSettings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurveSettings.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of bezier paths drawn in a view. 11 | 12 | `oval` Is an oval-based bezier path. 13 | 14 | `corner` Is a rounded-rectangle-based bezier path. 15 | */ 16 | public enum curveType { 17 | /** 18 | `oval` Is an oval-based bezier path. 19 | */ 20 | case oval 21 | /** 22 | `corner` Is a rounded-rectangle-based bezier path. 23 | */ 24 | case corner 25 | } 26 | 27 | /** 28 | Position options to draw the bezier paths. 29 | 30 | `right` Draws a bezier path vertically on the right side of a view. 31 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topRight and bottomRight of a view. 32 | - If **curveType** is `oval`, it draws an oval-based bezier path vertically on the right side of a view. 33 | 34 | `left` Draws a bezier path vertically on the left side of a view. 35 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topLeft and bottomLeft of a view. 36 | - If **curveType** is `oval`, it draws an oval-based bezier path vertically on the left side of a view. 37 | 38 | `top` Draws a bezier path horizontally on the top side of a view. 39 | - If **curveType** is `corner`, it draws a rounded rectangle corner on topRight and topLeft of a view. 40 | - If **curveType** is `oval`, it draws an oval-based bezier path horizontally on the top side of a view. 41 | 42 | `bottom` Draws a bezier path vertically on the bottom side of a view. 43 | - If **curveType** is `corner`, it draws a rounded rectangle corner on bottomRight and bottomLeft of a view. 44 | - If **curveType** is `oval`, it draws an oval-based bezier path horizontally on the bottom side of a view. 45 | 46 | `horizontalSides` Draws an oval-based bezier path vertically on the right & left sides of a view. 47 | - Can only be applied when **curveType** is `oval`. 48 | 49 | `verticalSides` Draws an oval-based bezier path horizontally on the top & bottom sides of a view. 50 | - Can only be applied when **curveType** is `oval`. 51 | 52 | `all` Draws a bezier path on all sides of a view. 53 | - If **curveType** is `corner`, it draws rounded rectangle corners in topLeft, topRight, bottomLeft and bottomRight. 54 | - If **curveType** is `oval`, it draws a full oval shape out of the view. 55 | */ 56 | public enum curvePosition { 57 | /** 58 | `right` Draws a bezier path vertically on the right side of a view. 59 | */ 60 | case right 61 | /** 62 | `left` Draws a bezier path vertically on the left side of a view. 63 | */ 64 | case left 65 | /** 66 | `top` Draws a bezier path horizontally on the top side of a view. 67 | */ 68 | case top 69 | /** 70 | `bottom` Draws a bezier path vertically on the bottom side of a view. 71 | */ 72 | case bottom 73 | /** 74 | `horizontalSides` Draws an oval-based bezier path vertically on the right & left sides of a view. 75 | */ 76 | case horizontalSides 77 | /** 78 | `verticalSides` Draws an oval-based bezier path horizontally on the top & bottom sides of a view. 79 | */ 80 | case verticalSides 81 | /** 82 | `diagonalAC` Draws rounded rectangle corners diagonally from topLeft to bottomRight of a view. 83 | */ 84 | case diagonalAC 85 | /** 86 | `diagonalBD` Draws rounded rectangle corners diagonally from topRight to bottomLeft of a view. 87 | */ 88 | case diagonalBD 89 | /** 90 | `all` Draws a bezier path on all sides of a view. 91 | */ 92 | case all 93 | } 94 | -------------------------------------------------------------------------------- /NotchToolkit/Enumerations/DeviceOrientation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DeviceOrientation.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of the device orientation used to resize the NotchBar. 11 | 12 | `portrait` When the device's notch is on the top. 13 | 14 | `landscapeLeft` When the device's notch is on the left. 15 | 16 | `landscapeRight` When the device's notch is on the right. 17 | 18 | */ 19 | public enum deviceOrientation { 20 | /** 21 | `portrait` When the device's notch is on the top. 22 | */ 23 | case portrait 24 | /** 25 | `landscapeLeft` When the device's notch is on the left. 26 | */ 27 | case landscapeLeft 28 | /** 29 | `landscapeRight` When the device's notch is on the right. 30 | */ 31 | case landscapeRight 32 | } 33 | -------------------------------------------------------------------------------- /NotchToolkit/Enumerations/NotchMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchMode.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Modes of the NotchBar based on status bar visibility. 11 | */ 12 | public enum notchMode { 13 | /** 14 | This mode sets the width of the NotchBar as the iPhone's X notch width. 15 | */ 16 | case statusBar 17 | /** 18 | This mode sets a wider width to display more content. Recommended for full landscape apps and when status bar is hidden. 19 | */ 20 | case noStatusBar 21 | } 22 | -------------------------------------------------------------------------------- /NotchToolkit/Enumerations/NotchScroll.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchScroll.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | /** 10 | Types of NotchToolbar scrolling directions. 11 | 12 | `alwaysHorizontal` sets scrolling direction to horizontal with all **deviceOriention** types. 13 | 14 | `alwaysVertical` sets scrolling direction to vertical with all **deviceOriention** types. 15 | 16 | `auto` sets scrolling direction to vertical when **deviceOriention** is `portrait` and horizontal when **deviceOriention** is `landscape`. 17 | */ 18 | 19 | public enum notchScroll { 20 | /** 21 | `alwaysHorizontal` sets scrolling direction to horizontal with all **deviceOriention** types. 22 | */ 23 | case alwaysHorizontal 24 | /** 25 | `alwaysVertical` sets scrolling direction to vertical with all **deviceOriention** types. 26 | */ 27 | case alwaysVertical 28 | /** 29 | `auto` sets scrolling direction to vertical when **deviceOriention** is `portrait` and horizontal when **deviceOriention** is `landscape`. 30 | */ 31 | case auto 32 | } 33 | -------------------------------------------------------------------------------- /NotchToolkit/Enumerations/ToolIconTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ToolIconTypes.swift 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 9/28/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | public enum toolIconTypes { 10 | case image 11 | case text 12 | case both 13 | } 14 | -------------------------------------------------------------------------------- /NotchToolkit/Extensions/UIScreen+NotchFrame.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+NotchFrame.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIScreen { 12 | private func setNotchFrame(orientation:deviceOrientation, mode:notchMode) -> CGRect { 13 | var notchScale: CGFloat { 14 | switch mode { 15 | case .statusBar: 16 | if self.bounds.size.width > self.bounds.size.height { 17 | return self.bounds.size.height/1.8 18 | }else{ 19 | return self.bounds.size.width/1.8 20 | } 21 | case .noStatusBar: 22 | if self.bounds.size.width > self.bounds.size.height { 23 | return self.bounds.size.height/1.5 24 | }else{ 25 | return self.bounds.size.width/1.5 26 | } 27 | } 28 | } 29 | 30 | switch orientation { 31 | case .portrait: 32 | return CGRect(x: self.bounds.width/2, y: 0, width: notchScale, height: 0) 33 | case .landscapeLeft: 34 | return CGRect(x: 0, y: self.bounds.height/2, width: 0, height: notchScale) 35 | case .landscapeRight: 36 | return CGRect(x: 0, y: self.bounds.height/2, width: 0, height: notchScale) 37 | } 38 | } 39 | 40 | /** 41 | `portraitNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `portrait`. 42 | */ 43 | public var portraitNotch: CGRect { 44 | return setNotchFrame(orientation: .portrait, mode: .statusBar) 45 | } 46 | /** 47 | `landscapeLeftNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `landscapeLeft`. 48 | */ 49 | public var landscapeLeftNotch: CGRect { 50 | return setNotchFrame(orientation: .landscapeLeft, mode: .statusBar) 51 | } 52 | /** 53 | `landscapeRightNotch` is a rectangle that returns the notch frame when **deviceOrientation** is `landscapeRight`. 54 | */ 55 | public var landscapeRightNotch: CGRect { 56 | return setNotchFrame(orientation: .landscapeRight, mode: .statusBar) 57 | } 58 | 59 | //Wider frame for .noStatusBar mode 60 | /** 61 | `widePortraitNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `portrait`. 62 | */ 63 | public var widePortraitNotch: CGRect { 64 | return setNotchFrame(orientation: .portrait, mode: .noStatusBar) 65 | } 66 | /** 67 | `wideLandscapeLeftNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `landscapeLeft`. 68 | */ 69 | public var wideLandscapeLeftNotch: CGRect { 70 | return setNotchFrame(orientation: .landscapeLeft, mode: .noStatusBar) 71 | } 72 | /** 73 | `wideLandscapeRightNotch` is a rectangle that returns a wider notch frame when **deviceOrientation** is `landscapeRight`. 74 | */ 75 | public var wideLandscapeRightNotch: CGRect { 76 | return setNotchFrame(orientation: .landscapeRight, mode: .noStatusBar) 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /NotchToolkit/Extensions/UIScreen+NotchPositionMultiplier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+NotchPositionMultiplier.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIScreen { 12 | private func setMultiplier(mode:notchMode) -> CGFloat { 13 | switch mode { 14 | case .statusBar: 15 | return 0.0021 16 | case .noStatusBar: 17 | return 0.0017 18 | } 19 | } 20 | /** 21 | `multiplier` is a float number that's used to postion the NotchBar when **deviceOrientation** is landscape. 22 | */ 23 | public var multiplier: CGFloat { 24 | return setMultiplier(mode: .statusBar) 25 | } 26 | /** 27 | `multiplierWide` is a float number that's used to postion the wide NotchBar when **deviceOrientation** is landscape. 28 | */ 29 | public var multiplierWide: CGFloat { 30 | return setMultiplier(mode: .noStatusBar) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /NotchToolkit/Extensions/UIScreen+iPhone10.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIScreen+iPhone10.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | public extension UIScreen { 11 | /** 12 | `isiPhone10` is a boolean that returns if the device is iPhone X or not. 13 | */ 14 | public var isiPhone10: Bool { 15 | return self.nativeBounds.size == CGSize(width: 1125, height: 2436) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /NotchToolkit/Extensions/UIView+DrawNotch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+OvalOrCorners.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/23/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public extension UIView { 12 | /** 13 | **UIView.draw(notch type,position,curve,customBounds)** is a UIView extension that allows you add ovals and rounded corners to a UIView. 14 | - For type `oval`, set `curve` from 1.0 - 10.0. 15 | - For type `corner`, `curve` is the radius size. 16 | - Check `curveType` & `curvePosition` for more info. 17 | */ 18 | public func draw(_ notch:curveType, position:curvePosition, curve:CGFloat?, customBounds:CGRect? = nil) { 19 | let offset:CGFloat = self.frame.size.width/curve! 20 | var bounds:CGRect! 21 | var viewBounds:CGRect! 22 | var viewPath:UIBezierPath! 23 | 24 | if let finalBounds = customBounds { 25 | bounds = finalBounds 26 | }else{ 27 | bounds = self.bounds 28 | } 29 | 30 | switch notch { 31 | case .oval: 32 | var ovalBounds:CGRect! 33 | switch position { 34 | case .right: 35 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 36 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width/2, height: bounds.size.height) 37 | 38 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 39 | viewPath = UIBezierPath(rect: viewBounds) 40 | viewPath.append(ovalPath) 41 | break 42 | case .left: 43 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 44 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width/2, y: bounds.origin.y, width: bounds.size.width/2, height: bounds.size.height) 45 | 46 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 47 | viewPath = UIBezierPath(rect: viewBounds) 48 | viewPath.append(ovalPath) 49 | break 50 | case .top: 51 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 52 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y + bounds.size.height / 2, width: bounds.size.width, height: bounds.size.height / 2) 53 | 54 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 55 | viewPath = UIBezierPath(rect: viewBounds) 56 | viewPath.append(ovalPath) 57 | break 58 | case .bottom: 59 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 60 | viewBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height / 2) 61 | 62 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 63 | viewPath = UIBezierPath(rect: viewBounds) 64 | viewPath.append(ovalPath) 65 | break 66 | case .horizontalSides: 67 | ovalBounds = CGRect(x: bounds.origin.x, y: bounds.origin.y - offset / 2, width:bounds.size.width , height:bounds.size.height + offset) 68 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width, y: bounds.origin.y+bounds.size.height, width: bounds.size.width, height: bounds.size.height) 69 | 70 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 71 | viewPath = UIBezierPath(rect: viewBounds) 72 | viewPath.append(ovalPath) 73 | break 74 | case .verticalSides: 75 | ovalBounds = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width:bounds.size.width + offset, height:bounds.size.height) 76 | viewBounds = CGRect(x: bounds.origin.x+bounds.size.width, y: bounds.origin.y+bounds.size.height, width: bounds.size.width, height: bounds.size.height) 77 | 78 | let ovalPath = UIBezierPath(ovalIn: ovalBounds) 79 | viewPath = UIBezierPath(rect: viewBounds) 80 | viewPath.append(ovalPath) 81 | break 82 | case .all: 83 | viewPath = UIBezierPath(ovalIn: self.bounds) 84 | break 85 | default: 86 | break 87 | } 88 | break 89 | case .corner: 90 | switch position { 91 | case .right: 92 | 93 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topRight, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 94 | break 95 | case .left: 96 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .bottomLeft], cornerRadii: CGSize(width:curve!, height:curve!)) 97 | break 98 | case .top: 99 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width:curve!, height:curve!)) 100 | break 101 | case .bottom: 102 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 103 | break 104 | case .diagonalAC: 105 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .bottomRight], cornerRadii: CGSize(width:curve!, height:curve!)) 106 | break 107 | case .diagonalBD: 108 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topRight, .bottomLeft], cornerRadii: CGSize(width:curve!, height:curve!)) 109 | break 110 | case .all: 111 | viewPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.allCorners], cornerRadii: CGSize(width:curve!, height:curve!)) 112 | break 113 | default: 114 | break 115 | } 116 | break 117 | } 118 | if let path = viewPath { 119 | let shapeLayer: CAShapeLayer = CAShapeLayer() 120 | shapeLayer.frame = bounds 121 | shapeLayer.path = path.cgPath 122 | self.layer.mask = shapeLayer 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /NotchToolkit/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.3 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /NotchToolkit/NotchToolkit.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolkit.h 3 | // NotchToolkit 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for NotchToolkit. 12 | FOUNDATION_EXPORT double NotchToolkitVersionNumber; 13 | 14 | //! Project version string for NotchToolkit. 15 | FOUNDATION_EXPORT const unsigned char NotchToolkitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /NotchToolkit/Protocols/NotchToolbarDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolbarDelegate.swift 3 | // NotchToolbar 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | /** 11 | This delegate is required to detect toolbar actions & automatically resize the NotchBar when device orientation is changed. 12 | */ 13 | @objc public protocol NotchToolbarDelegate { 14 | /** 15 | This delegate function detects when the device orientation changes. Calling **autoResize()** function inside this delegate is **required**. 16 | */ 17 | func deviceDidRotate() 18 | /** 19 | This delegate function allows you to detect which toolbar icon was selected. 20 | */ 21 | func didTapToolIcon(_ tools: UICollectionView, toolIndex:IndexPath, section: Int, row: Int) 22 | } 23 | -------------------------------------------------------------------------------- /NotchToolkitTests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /NotchToolkitTests/NotchToolkitTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotchToolkitTests.swift 3 | // NotchToolkitTests 4 | // 5 | // Created by Ahmed Bekhit on 9/25/17. 6 | // Copyright © 2017 Ahmed Fathi Bekhit. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import NotchToolkit 11 | 12 | class NotchToolkitTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NotchToolkit 2 | NotchToolkit is a framework for iOS that allow developers use the iPhone X notch space in creative ways. 3 | Inspired by 4 | 5 | | Table of Contents | Description | 6 | | ------------------ |:------------------:| 7 | | [Documentation](https://github.com/AFathi/NotchToolkit/wiki) | Describes the configuration options `NotchToolkit` offers | 8 | | [Preview](#preview) | Displays preview images of `NotchToolkit` features | 9 | | [Compatibility](#compatibility) | Describes the `NotchToolkit` device and iOS compatibality | 10 | | [Example Project](#example-project) | Explains how to run the example project provided in this repository | 11 | | [Installation](#installation) | Describes the [CocoaPods](#cocoapods), [Carthage](#carthage), and [Manual](#manual) options to install `NotchToolkit` | 12 | | [Implementation](#implement-in-your-project) | Lists the steps needed to implement `NotchToolkit` into your project | 13 | | [More Options](#more-options) | Describes an extra feature `NotchToolkit` supports | 14 | | [License](#license) | Describes `NotchToolkit` license | 15 | 16 | ## Preview 17 | [**NotchImageView**](https://github.com/AFathi/NotchToolkit/wiki/NotchImageView) 18 | 19 | ![imageViewPreview](http://ahmedbekhit.com/magic_notch_img.gif) 20 | 21 | 22 | [**NotchToolbar**](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbar) 23 | 24 | ![toolbarPreview](http://ahmedbekhit.com/toolbar_preview.gif) 25 | 26 | 27 | [**Draw Notch**](#more-options) 28 | 29 | ![drawPreview](drawNotch.gif) 30 | 31 | ## Compatibility 32 | Although `NotchToolkit` is made for iPhone X, it can be implemented in older iPhone devices. This framework was tested on: 33 | 34 | 1. iPhone X 35 | 2. iPhone 8 plus, 7 plus, 6s plus and 6 plus 36 | 3. iPhone 8, 7, 6s and 6 37 | 4. iPhone SE and 5s 38 | 39 | `NotchToolkit` requires 40 | 41 | - iOS 11 42 | - Swift 3.2 or higher 43 | 44 | `NotchToolkit` has options to customize your Toolbar and UIView, 45 | 46 | check [**Documentation**](https://github.com/AFathi/NotchToolkit/wiki) and [**More Options**](#more-options) for more details. 47 | 48 | ## Example Project 49 | To try the example project, simply download this repo then open `NotchToolkit-Example.xcworkspace` project file, found in the `Example` folder. 50 | 51 | ## Installation 52 | ### CocoaPods 53 | 1. Download [CocoaPods](http://cocoapods.org) using this command in `Terminal` 54 | ``` 55 | $ sudo gem install cocoapods 56 | ``` 57 | 2. Redirect to your project folder in `Terminal` 58 | ``` 59 | $ cd YOUR_PROJECT_FILE_PATH 60 | ``` 61 | 3. Initialize a pod in `Terminal` 62 | ``` 63 | $ pod init 64 | ``` 65 | 4. Open Podfile in a text editor and add this line 66 | ``` 67 | pod 'NotchToolkit' 68 | ``` 69 | 5. Go back to `Terminal` and install the pod 70 | ``` 71 | $ pod install 72 | ``` 73 | ### Carthage 74 | 1. Add this line to the `Cartfile` in your project directory 75 | ``` 76 | github "AFathi/NotchToolkit" 77 | ``` 78 | 2. Update your Carthage directory 79 | ``` 80 | $ carthage update 81 | ``` 82 | ### Manual 83 | Drag the `NotchToolkit.xcodeproj` file into your project then add `NotchToolkit` as an embedded binary of your targets. 84 | 85 | ## Implement in your project 86 | 1. `import NotchToolkit` in a `UIViewController` class 87 | 2. Add [`NotchToolbarDelegate`](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbarDelegate) in the delegate section 88 | ``` 89 | class ViewController: UIViewController, NotchToolbarDelegate 90 | ``` 91 | 3. Add delegate methods 92 | ``` 93 | //A protocol method that's triggered when the device rotates. 94 | func deviceDidRotate() { 95 | } 96 | 97 | //A protocol method that's triggered when an icon is selected. 98 | func didTapToolIcon(_ tools: UICollectionView, toolIndex: IndexPath, section: Int, row: Int) { 99 | } 100 | ``` 101 | 4. Create a [`NotchToolbar`](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbar) global variable 102 | ``` 103 | let toolbar = NotchToolbar() 104 | ``` 105 | 5. Configure and initialize `toolbar` in `viewDidLoad` 106 | ``` 107 | toolbar.notch.isVisible = true 108 | 109 | toolbar.notch.height = 250 110 | 111 | toolbar.toolList = [ 112 | //[icon image, title] 113 | [UIImage(named:"pikachusquare")!, "Pikachu"], 114 | //only image icons 115 | UIImage(named:"spongebob")!, 116 | //only string icons (mainly for emojis 😉) 117 | "🤔", "🤓", 118 | "📱", "👩‍💻", 119 | "👨‍💻", "✅", "🔥"] 120 | 121 | toolbar.delegate = self 122 | toolbar.initializeToolbar(self) 123 | ``` 124 | 6. Call [`autoResize()`](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbar#func-autoresize) method in the [`deviceDidRotate`](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbarDelegate#func-devicedidrotate) delegate method 125 | ``` 126 | func deviceDidRotate() { 127 | toolbar.autoResize() 128 | } 129 | ``` 130 | **You're all set! 🤓** 131 | ## Show and Hide `toolbar` 132 | ### [showOrHide()](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbar#func-showorhide) 133 | This method allows you to show and hide the `NotchToolbar`. You can call this method in an `IBAction` that handles showing/hiding the toolbar. 134 | ``` 135 | @IBAction func buttonClicked(_ sender: UIButton) { 136 | toolbar.showOrHide() 137 | } 138 | ``` 139 | ## Handle Icon Selection 140 | 1. Make sure you set the [`NotchToolbar`](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbar) delegate to `self`. 141 | 2. Handle the icon selection in the [`didTapToolIcon`](https://github.com/AFathi/NotchToolkit/wiki/NotchToolbarDelegate#func-didtaptoolicon_-tools-uicollectionview-toolindexindexpath-section-int-row-int) delegate method: 142 | ``` 143 | func didTapToolIcon(_ tools: UICollectionView, toolIndex: IndexPath, section: Int, row: Int) { 144 | if row == 0 { 145 | print("first icon") 146 | }else if row == 1 { 147 | print("second icon") 148 | } 149 | } 150 | ``` 151 | ## More Options 152 | This framework include a `UIView` extension that allow you draw a notch bezier path to any `UIView` class or subclass. 153 | ### draw(_ notch:curveType, position:curvePosition, curve:CGFloat?, customBounds:CGRect? = nil) 154 | This is a UIView extension that allows you add ovals and rounded corners to any UIView. 155 | 156 | - For type `oval`, set `curve` scale from 1.0 - 10.0. 157 | - For type `corner`, `curve` is the radius size. 158 | - Check `curveType` & `curvePosition` for more info. 159 | ### Example 160 | ``` 161 | //horizontalSides draws an oval-based bezier path vertically on the right & left sides of a view. 162 | myView.draw(.oval, position: .horizontalSides, curve: 1.5) 163 | 164 | //diagonalAC draws rounded rectangle corners diagonally from topLeft to bottomRight of a view. 165 | myView.draw(.corner, position: .diagonalAC, curve: 35) 166 | 167 | ``` 168 | ### Preview 169 | ![Demo](drawNotch.gif) 170 | 171 | ## LICENSE 172 | `NotchToolkit` is under MIT license. Check the [LICENSE](LICENSE) file for more details. 173 | 174 | -------------------------------------------------------------------------------- /drawNotch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AFathi/NotchToolkit/d8c0e69c440df88eb7f66103a6e01ebc24506f74/drawNotch.gif --------------------------------------------------------------------------------