{"id":13355490,"url":"https://github.com/ivanvorobei/SPStorkController","last_synced_at":"2025-03-12T11:30:57.303Z","repository":{"id":33537123,"uuid":"159327622","full_name":"ivanvorobei/SPStorkController","owner":"ivanvorobei","description":"Now playing controller from Apple Music, Mail \u0026 Podcasts Apple's apps.","archived":false,"fork":false,"pushed_at":"2023-01-31T11:38:32.000Z","size":18363,"stargazers_count":2739,"open_issues_count":17,"forks_count":204,"subscribers_count":38,"default_branch":"master","last_synced_at":"2024-10-29T15:34:12.656Z","etag":null,"topics":["alert","animation","app","apple","controller","gester","ios11","mail","mimicrate","music","native","pop","popover","popup","similar","swift","swipe","transition","ui","up"],"latest_commit_sha":null,"homepage":"https://opensource.ivanvorobei.io","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivanvorobei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-27T11:51:50.000Z","updated_at":"2024-10-22T11:21:21.000Z","dependencies_parsed_at":"2023-02-16T18:46:24.984Z","dependency_job_id":null,"html_url":"https://github.com/ivanvorobei/SPStorkController","commit_stats":null,"previous_names":[],"tags_count":54,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanvorobei%2FSPStorkController","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanvorobei%2FSPStorkController/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanvorobei%2FSPStorkController/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivanvorobei%2FSPStorkController/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivanvorobei","download_url":"https://codeload.github.com/ivanvorobei/SPStorkController/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243208792,"owners_count":20254107,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alert","animation","app","apple","controller","gester","ios11","mail","mimicrate","music","native","pop","popover","popup","similar","swift","swipe","transition","ui","up"],"created_at":"2024-07-29T21:02:19.697Z","updated_at":"2025-03-12T11:30:54.934Z","avatar_url":"https://github.com/ivanvorobei.png","language":"Swift","readme":"# SPStorkController\n\n\u003ca href=\"https://itunes.apple.com/app/id1446635818\" target=\"_blank\"\u003e\u003cimg align=\"left\" src=\"https://github.com/ivanvorobei/SPStorkController/blob/master/Resources/Preview.gif\" width=\"400\"/\u003e\u003c/a\u003e\n\n### About\nController **as in Apple Music, Podcasts and Mail** apps. Help if you need customize height or suppport modal style in iOS 12.\n\nSimple adding close button and centering arrow indicator. Customizable height. Using custom `TransitionDelegate`.\n\nAlert you can find in [SPAlert](https://github.com/ivanvorobei/SPAlert) project. It support diffrents presets, some animatable.\n\nIf you like the project, don't forget to `put star ★` and follow me on GitHub:\n\n\u003cp float=\"left\"\u003e\n    \u003ca href=\"https://github.com/ivanvorobei\"\u003e\n        \u003cimg src=\"https://github.com/ivanvorobei/Readme/blob/main/Buttons/follow-me-ivanvorobei.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://opensource.ivanvorobei.by\"\u003e\n        \u003cimg src=\"https://github.com/ivanvorobei/Readme/blob/main/Buttons/more-libraries.svg\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## Navigate\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n    - [CocoaPods](#cocoapods)\n    - [Carthage](#carthage)\n    - [Swift Package Manager](#swift-package-manager)\n    - [Manually](#manually)\n- [Quick Start](#quick-start)\n- [Usage](#usage)\n    - [Light StatusBar](#light-statusbar)\n    - [Custom Height](#custom-height)\n    - [Close Button](#close-button)\n    - [Arrow Indicator](#arrow-indicator)\n    - [Dismissing](#dismissing)\n    - [Corner Radius](#corner-radius)\n    - [Haptic](#haptic)\n    - [Snapshots](#snapshots)\n    - [Navigation Bar](#navigation-bar)\n    - [Working with UIScrollView](#working-with-uiscrollview)\n    - [UITableView \u0026 UICollectionView](#working-with-uitableview--uicollectionview)\n    - [Confirm before dismiss](#confirm-before-dismiss)\n    - [Delegate](#delegate)\n    - [Storyboard](#storyboard)\n- [Sheets in iOS 13](#sheets-in-ios-13)\n- [Other Projects](#other-projects)\n- [Russian Community](#russian-community)\n\n## Requirements\n\nSwift `4.2` \u0026 `5.0`. Ready for use on iOS 10+\n\n## Installation\n\n### CocoaPods:\n\n[CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. For usage and installation instructions, visit their website. To integrate `SPStorkController` into your Xcode project using CocoaPods, specify it in your `Podfile`:\n\n```ruby\npod 'SPStorkController'\n```\n\n### Carthage\n\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. To integrate `SPStorkController` into your Xcode project using Carthage, specify it in your `Cartfile`:\n\n```ogdl\ngithub \"ivanvorobei/SPStorkController\"\n```\n\n### Swift Package Manager\n\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.\n\nTo integrate `SPStorkController` into your Xcode project using Xcode 11, specify it in `Project \u003e Swift Packages`:\n\n```ogdl\nhttps://github.com/ivanvorobei/SPStorkController\n```\n\n### Manually\n\nIf you prefer not to use any of the aforementioned dependency managers, you can integrate `SPStorkController` into your project manually. Put `Source/SPStorkController` folder in your Xcode project. Make sure to enable `Copy items if needed` and `Create groups`.\n\n## Quick Start\n\nCreate controller and call func `presentAsStork`:\n\n```swift\nimport UIKit\nimport SPStorkController\n\nclass ViewController: UIViewController {\n    \n    override func viewDidAppear(_ animated: Bool) {\n        super.viewDidAppear(animated)\n\n        let controller = UIViewController()\n        self.presentAsStork(controller)\n    }\n}\n```\n\nIf you want customize controller (remove indicator, set custom height and other), create controller and set `transitioningDelegate` to `SPStorkTransitioningDelegate` object. Use `present` or `dismiss` functions:\n\n```swift\nlet controller = UIViewController()\nlet transitionDelegate = SPStorkTransitioningDelegate()\ncontroller.transitioningDelegate = transitionDelegate\ncontroller.modalPresentationStyle = .custom\ncontroller.modalPresentationCapturesStatusBarAppearance = true\nself.present(controller, animated: true, completion: nil)\n```\n\nPlease, do not init `SPStorkTransitioningDelegate` like this:\n\n```swift\ncontroller.transitioningDelegate = SPStorkTransitioningDelegate()\n```\n\nYou will get an error about weak property.\n\n## Usage\n\n### Light StatusBar\n\nTo set light status bar for presented controller, use `preferredStatusBarStyle` property. Also set `modalPresentationCapturesStatusBarAppearance`. See example:\n\n```swift\nimport UIKit\n\nclass ModalViewController: UIViewController {\n    \n    override var preferredStatusBarStyle: UIStatusBarStyle {\n        return .lightContent\n    }\n}\n```\n\n### Custom Height\n\nProperty `customHeight` sets custom height for controller. Default is `nil`:\n\n```swift\ntransitionDelegate.customHeight = 350\n```\n\n### Close Button\n\nProperty `showCloseButton` added circle button with dismiss action. Default is `false`:\n```swift\ntransitionDelegate.showCloseButton = false\n```\n\n### Arrow Indicator\n\nOn the top of controller you can add arrow indicator with animatable states. It simple configure.\nProperty `showIndicator` shows or hides top arrow indicator. Default is `true`:\n\n```swift\ntransitionDelegate.showIndicator = true\n```\n\nProperty Parameter `indicatorColor` for customize color of arrow. Default is `gray`:\n\n```swift\ntransitionDelegate.indicatorColor = UIColor.white\n```\n\nProperty `hideIndicatorWhenScroll` shows or hides indicator when scrolling. Default is `false`:\n\n```swift\ntransitionDelegate.hideIndicatorWhenScroll = true\n```\n\nYou can set always line or arrow indicator. Set `indicatorMode`:\n\n```swift\ntransitionDelegate.indicatorMode = .alwaysLine\n```\n\n### Dismissing\n\nYou can also configure events that will dimiss the controller.\nProperty `swipeToDismissEnabled` enables dismissal by swipe gesture. Default is `true`:\n\n```swift\ntransitionDelegate.swipeToDismissEnabled = true\n```\n\nProperty `translateForDismiss` sets how much need to swipe down to close the controller. Work only if `swipeToDismissEnabled` is true. Default is `240`:\n\n```swift\ntransitionDelegate.translateForDismiss = 100\n```\n\nProperty `tapAroundToDismissEnabled` enables dismissal by tapping parent controller. Default is `true`:\n\n```swift\ntransitionDelegate.tapAroundToDismissEnabled = true\n```\n\n### Corner Radius\n\nProperty `cornerRadius` for customize corner radius of controller's view. Default is `10`:\n\n```swift\ntransitionDelegate.cornerRadius = 10\n```\n\n### Haptic\n\nProperty `hapticMoments` allow add taptic feedback for some moments. Default is `.willDismissIfRelease`:\n\n```swift\ntransitionDelegate.hapticMoments = [.willPresent, .willDismiss]\n```\n\n### Snapshots\n\nThe project uses a snapshot of the screen in order to avoid compatibility and customisation issues. Before controller presentation, a snapshot of the parent view is made, and size and position are changed for the snapshot. Sometimes you will need to update the screenshot of the parent view, for that use static func:\n\n```swift\nSPStorkController.updatePresentingController(modal: controller)\n```\n\nand pass the controller, which is modal and uses `SPStorkTransitioningDelegate`.\n\nIf the parent controller scrollings and you try to show `SPStorkController`, you will see how it froze, and in a second its final position is updated. I recommend before present `SPStorkController`  stop scrolling force:\n\n```swift \nscrollView.setContentOffset(self.contentOffset, animated: false)\n```\n\n### Navigation Bar\n\nYou may want to add a navigation bar to your modal controller. Since it became impossible to change or customize the native controller in swift 4 (I couldn’t even find a way to change the height of the bar), I had to recreate navigation bar from the ground up. Visually it looks real, but it doesn’t execute the necessary functions:\n\n```swift\nimport UIKit\nimport SPFakeBar\n\nclass ModalController: UIViewController {\n    \n    let navBar = SPFakeBarView(style: .stork)\n        \n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        self.view.backgroundColor = UIColor.white\n\n        self.navBar.titleLabel.text = \"Title\"\n        self.navBar.leftButton.setTitle(\"Cancel\", for: .normal)\n        self.navBar.leftButton.addTarget(self, action: #selector(self.dismissAction), for: .touchUpInside)\n\n        self.view.addSubview(self.navBar)\n    }\n}\n```\n\nYou only need to add a navigation bar to the main view, it will automatically layout. Use style `.stork` in init of `SPFakeBarView`. Here is visual preview with Navigation Bar and without it:\n\n\u003cimg src=\"https://github.com/ivanvorobei/SPStorkController/blob/master/Resources/Navigation%20Bar.jpg\"/\u003e\n\nTo use it, you need to install [SPFakeBar](https://github.com/ivanvorobei/SPFakeBar) pod: \n\n```ruby\npod 'SPFakeBar'\n```\n\n### Working with UIScrollView\n\nIf you use `UIScrollView` (or UITableView \u0026 UICollectionView) on controller, I recommend making it more interactive. When scrolling reaches the top position, the controller will interactively drag down, simulating a closing animation. Also available close controller by drag down on `UIScrollView`. To do this, set the delegate and in the function `scrollViewDidScroll` call:\n\n```swift\nfunc scrollViewDidScroll(_ scrollView: UIScrollView) {\n    SPStorkController.scrollViewDidScroll(scrollView)\n}\n```\n\n### Working with UITableView \u0026 UICollectionView\n\nWorking with a collections classes is not difficult. In the `Example` folder you can find an implementation. However, I will give a couple of tips for making the table look better.\n\nFirstly, if you use `SPFakeBarView`, don't forget to set top insets for content \u0026 scroll indicator. Also, I recommend setting bottom insets (it optional):\n\n```swift\ntableView.contentInset.top = self.navBar.height\ntableView.scrollIndicatorInsets.top = self.navBar.height\n```\n\nPlease, also use `SPStorkController.scrollViewDidScroll` function in scroll delegate for more interactiveness with your collection or table view.\n\n### Confirm before dismiss\n\nFor confirm closing by swipe, tap around, close button and indicator use `SPStorkControllerConfirmDelegate`. Implenet protocol:\n\n```swift\n@objc public protocol SPStorkControllerConfirmDelegate: class {\n    \n    var needConfirm: Bool { get }\n    \n    func confirm(_ completion: @escaping (_ isConfirmed: Bool)-\u003e())\n}\n```\n\nand set `confirmDelegate` property to object, which protocol impleneted. Function `confirm` call if `needConfirm` return true. Pass `isConfirmed` with result. Best options use `UIAlertController` with `.actionSheet` style for confirmation.\n\nIf you use custom buttons, in the target use this code:\n\n```swift\nSPStorkController.dismissWithConfirmation(controller: self, completion: nil)\n```\n\nIt call `confirm` func and check result of confirmation. See example project for more details.\n\n### Delegate\n\nYou can check events by implement `SPStorkControllerDelegate` and set delegate for `transitionDelegate`:\n\n```swift\ntransitionDelegate.storkDelegate = self\n```\n\nDelagate has this functions: \n\n```swift\nprotocol SPStorkControllerDelegate: class {\n    \n    optional func didDismissStorkBySwipe()\n    \n    optional func didDismissStorkByTap()\n}\n```\n\n### Storyboard\n\nIf need using `SPStorkController` with storyboard, set class `SPStorkSegue` for transition setting in storyboard file. I will give the class code so that you understand what it does:\n\n```swift\nimport UIKit\n\nclass SPStorkSegue: UIStoryboardSegue {\n    \n    public var transitioningDelegate: SPStorkTransitioningDelegate?\n    \n    override func perform() {\n        transitioningDelegate = transitioningDelegate ?? SPStorkTransitioningDelegate()\n        destination.transitioningDelegate = transitioningDelegate\n        destination.modalPresentationStyle = .custom\n        super.perform()\n    }\n}\n```\n\nOpen your storyboard, choose transition and open right menu. Open `Attributes Inspector` and in Class section insert `SPStorkSegue`.\n\n### Modal presentation of other controller\n\nIf you want to present modal controller on `SPStorkController`, please set:\n\n```swift\ncontroller.modalPresentationStyle = .custom\n```\n\nIt’s needed for correct presentation and dismissal of all modal controllers.\n\n## Sheets in iOS 13\n\nApple present in `WWDC 2019` new modal presentation style - `Sheets`. It ready use Support interactive dismiss and work with navigations bars. Available since iOS 13. I will add more information when I study this in more detail. You can see presentation [here](https://developer.apple.com/videos/play/wwdc2019/224/).\n\n\u003ca href=\"https://developer.apple.com/videos/play/wwdc2019/224/\" target=\"_blank\"\u003e\u003cimg align=\"center\" src=\"https://github.com/ivanvorobei/SPStorkController/blob/master/Resources/Sheets.png\"/\u003e\u003c/a\u003e\n\n## Other Projects\n\nI love being helpful. Here I have provided a list of libraries that I keep up to date. For see `video previews` of libraries without install open [opensource.ivanvorobei.by](https://opensource.ivanvorobei.by) website.\u003cbr\u003e\nI have libraries with native interface and managing permissions. Also available pack of useful extensions for boost your development process.\n\n\u003cp float=\"left\"\u003e\n    \u003ca href=\"https://opensource.ivanvorobei.by\"\u003e\n        \u003cimg src=\"https://github.com/ivanvorobei/Readme/blob/main/Buttons/more-libraries.svg\"\u003e\n    \u003c/a\u003e\n        \u003ca href=\"https://xcodeshop.ivanvorobei.by\"\u003e\n        \u003cimg src=\"https://github.com/ivanvorobei/Readme/blob/main/Buttons/xcode-shop.svg\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n## Russian Community\n\nПодписывайся в телеграмм-канал, если хочешь получать уведомления о новых туториалах.\u003cbr\u003e\nСо сложными и непонятными задачами помогут в чате.\n\n\u003cp float=\"left\"\u003e\n    \u003ca href=\"https://tutorials.ivanvorobei.by/telegram/channel\"\u003e\n        \u003cimg src=\"https://github.com/ivanvorobei/Readme/blob/main/Buttons/open-telegram-channel.svg\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://tutorials.ivanvorobei.by/telegram/chat\"\u003e\n        \u003cimg src=\"https://github.com/ivanvorobei/Readme/blob/main/Buttons/russian-community-chat.svg\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nВидео-туториалы выклыдываю на [YouTube](https://tutorials.ivanvorobei.by/youtube):\n\n[![Tutorials on YouTube](https://cdn.ivanvorobei.by/github/readme/youtube-preview.jpg)](https://tutorials.ivanvorobei.by/youtube)\n","funding_links":[],"categories":["Libs","Swift","UI [🔝](#readme)","Content"],"sub_categories":["UI","Controller"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanvorobei%2FSPStorkController","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivanvorobei%2FSPStorkController","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivanvorobei%2FSPStorkController/lists"}