{"id":13466241,"url":"https://github.com/mrustaa/ContainerController","last_synced_at":"2025-03-25T21:31:47.021Z","repository":{"id":43917019,"uuid":"271083960","full_name":"mrustaa/ContainerController","owner":"mrustaa","description":"👉↕️📱ContainerController 🧩✨⚙️  is a UI Component Swipe-Panel (Customizable). 💡 The idea is copied from the app: Apple Maps, Stocks. Swift version","archived":false,"fork":false,"pushed_at":"2024-01-24T15:46:34.000Z","size":1292,"stargazers_count":461,"open_issues_count":4,"forks_count":44,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-04-28T21:36:02.120Z","etag":null,"topics":["animation","cocoapods","collectionview","containercontroller","containerview","ios","landscape","layout","maps","move","pan-gesture","scrollview","swift","swift-package-manager","swipe-panel","tableview","ui-components","xcode"],"latest_commit_sha":null,"homepage":"","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/mrustaa.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-09T18:48:00.000Z","updated_at":"2024-06-19T11:14:08.034Z","dependencies_parsed_at":"2023-12-23T16:16:04.475Z","dependency_job_id":"bec4ad3f-4506-43f5-affe-8c31965cf95a","html_url":"https://github.com/mrustaa/ContainerController","commit_stats":{"total_commits":68,"total_committers":3,"mean_commits":"22.666666666666668","dds":0.1029411764705882,"last_synced_commit":"4f1ca8157ab331fcb0a11febbc75386c60e4df9c"},"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrustaa%2FContainerController","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrustaa%2FContainerController/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrustaa%2FContainerController/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrustaa%2FContainerController/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrustaa","download_url":"https://codeload.github.com/mrustaa/ContainerController/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222091991,"owners_count":16929761,"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":["animation","cocoapods","collectionview","containercontroller","containerview","ios","landscape","layout","maps","move","pan-gesture","scrollview","swift","swift-package-manager","swipe-panel","tableview","ui-components","xcode"],"created_at":"2024-07-31T15:00:41.412Z","updated_at":"2024-10-29T18:31:27.644Z","avatar_url":"https://github.com/mrustaa.png","language":"Swift","readme":"![image(Landscape)](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screenLandscape9.png)\n\n# ContainerController \n\n[![Version](https://img.shields.io/cocoapods/v/ContainerControllerSwift.svg?style=flat)](https://cocoapods.org/pods/ContainerControllerSwift)\n[![License](https://img.shields.io/cocoapods/l/ContainerControllerSwift.svg?style=flat)](https://cocoapods.org/pods/ContainerControllerSwift)\n[![Platform](https://img.shields.io/cocoapods/p/ContainerControllerSwift.svg?style=flat)](https://cocoapods.org/pods/ContainerControllerSwift)\n[![Swift 5.0](https://img.shields.io/badge/Swift-5.0-orange.svg?style=flat)](https://swift.org/)\n[![Swift 5.1](https://img.shields.io/badge/Swift-5.1-orange.svg?style=flat)](https://swift.org/)\n[![Swift 5.2](https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat)](https://swift.org/)\n\nUI Component. This is a copy swipe-panel from app: https://www.apple.com/ios/maps/\n\nIt can:\n- Animately move top / middle / bottom\n- Add multiple ContainerControlleron top of each other in self.view \n- Add any type of ScrollView: Table / Collection / Text\n- Control Gesture or Scroll\n- Pin HeaderView to top / pin FooterView to bottom,\n- Add Background Color / background blur transparency\n- Adjust cornerRadius edges\n- Adjust container shadow\n- When raised to top = Add background shadow -\n- Has the ability to adjust Left / Right margins\n- And adjust Left / Right margins for landscape state.\n\n\n## Preview\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/maps.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/examples.gif)\n![image(Landscape)](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/mapsLandscape.gif)\n\n \n## About the project\n\nExamples of use (ui swipe component ContainerController) in popular design applications.\n\nIt is used in different categories apps:\n- Maps / Menu / Player Music / Market / Sports News / Taxi / Finance Banks Stock / Wallets / Analytics / Notes\n- Alerts / Popups / Notifications\n\n\n\n## Features\n\n\u003c!-- TOC --\u003e\n\n\n- [Requirements](#requirements)\n- [Installation](#installation)\n  - [CocoaPods](#cocoapods)\n  - [Swift Package Manager with Xcode 11](#swift-package-manager-with-xcode-11)\n- [Design examples](#design-examples)\n- [Getting Started](#getting-started)\n- [Action](#action)\n  - [Move position with an animation](#move-position-with-an-animation)\n- [Adding possible custom subviews in ContainerController view](#adding-possible-custom-subviews-in-containercontroller-view)\n  - [Add `ScrollView`📃](#add-scrollview)\n    - [`Delegate` to self 👆](#delegate-to-self-)\n  - [Add `HeaderView`](#add-headerview)\n  - [Add `FooterView`](#add-footerview)\n  - [Add Custom `View`](#add-custom-view)\n- [Settings ⚙️](#settings-)\n  - [Layout](#layout)\n    - [Customize the layout with create subclass `ContainerLayout` on initialization](#customize-the-layout-with-create-subclass-containerlayout-on-initialization)\n    - [Or create object `ContainerLayout`](#or-create-object-containerlayout)\n  - [Change settings right away](#change-settings-right-away)\n  - [ContainerController `View`](#containercontroller-view)\n    - [Use a ready-made solution](#use-a-ready-made-solution)\n    - [Change `CornerRadius`](#change-cornerradius)\n    - [Add Layer `Shadow`](#add-layer-shadow)\n    - [Add Background `Blur`](#add-background-blur)\n  - [More details](#more-details)\n    - [Change positions on screen Top Middle Bottom](#change-positions-on-screen-top-middle-bottom)\n    - [Customize indentations for View](#customize-indentations-for-view)\n    - [Customize for landscape orientation](#customize-for-landscape-orientation)\n    - [Parameters for control footerView](#parameters-for-control-footerview)\n- [ContainerController `Delegate`](#containercontroller-delegate)\n- [Author](#author)\n- [License](#license)\n\n\u003c!-- /TOC --\u003e\n\n## Requirements \n\n✏️ ContainerController is written in Swift 5.0+. It can be built by Xcode 11 or later. Compatible with iOS 13.0+.\n\n## Installation \n\n### [CocoaPods](https://cocoapods.org)\n\nContainerControllerSwift is available through [CocoaPods](https://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'ContainerControllerSwift'\n```\n\n### [Swift Package Manager with Xcode 11](https://swift.org/package-manager/)\n\n```ruby\ndependencies: [\n    .package(url: \"https://github.com/mrustaa/ContainerController.git\")\n]\n```\n\nFollow [this doc](https://developer.apple.com/documentation/swift_packages/adding_package_dependencies_to_your_app).\n\n\n## Design examples\n### Designs are borrowed from [Dribbble](https://dribbble.com)\n\nTo get the design, you need to add a branch\n[ui_examples](https://github.com/mrustaa/ContainerController/tree/ui_examples)\n\n```swift \ngit clone https://github.com/mrustaa/ContainerController.git\ncd ContainerController/\ngit checkout ui_examples\n```\n\nURLs Author:\n\n - [Play Music](https://dribbble.com/shots/15381326-Move-Multipurpose-HTML-Template-I), [Sallets](https://dribbble.com/shots/18054638-Sowallet-Mobile-Appp), [Crypto](https://dribbble.com/shots/24353177-Crypto-Loan-Mobile-App), [Buy Stock](https://dribbble.com/shots/14364583-Online-Banking-Mobile-App), [Sport](https://dribbble.com/shots/15544535-Sneakers-Shopping-App), [Taxi](https://dribbble.com/shots/23691282-Taxi-Booking-App-Design), [Map Parking](https://dribbble.com/shots/15034854-AirGarage-Mobile-App-Redesign), [Custom Card](https://dribbble.com/shots/20629590-Business-Card-Mobile-IOS-App), [Apple.Maps App](https://apps.apple.com/us/app/apple-maps/id915056765)\n\nGIF Previews:\n\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_play_music_mini_2.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_wallets_mini_2.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_sport_mini_2.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_buy_stock_mini_2.gif)\n\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_crypto_mini_2.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_taxi_mini_2.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_map_parking_mini_2.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/screen_custom_card_mini_2.gif)\n\n\n\n\n\n## Getting Started\n\n```swift\n\nimport UIKit\nimport ContainerControllerSwift\n\nclass ViewController: UIViewController, ContainerControllerDelegate {\n    \n    var container: ContainerController!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        // Create ContainerController Layout object\n        let layout = ContainerLayout()\n        layout.startPosition = .hide\n        layout.backgroundShadowShow = true\n        layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)\n        \n        // Create ContainerController object, along with the container.view\n        // Pass the current UIViewController \n        let container = ContainerController(addTo: self, layout: layout)\n        container.view.cornerRadius = 15\n        container.view.addShadow()\n        \n        // Create subclass scrollView\n        let tableView = UITableView()\n        tableView.register(UITableViewCell.self, forCellReuseIdentifier: \"cell\")\n        tableView.delegate = self\n        tableView.dataSource = self\n        \n        // Add scrollView to container\n        container.add(scrollView: tableView)\n        \n        // Finishing settings ContainerController,\n        // Animated move position Top\n        container.move(type: .top)\n    }\n    \n    override func viewDidDisappear(_ animated: Bool) {\n        super.viewDidDisappear(animated)\n        \n        // Remove the subviews ContainerController\n        container.remove()\n        container = nil\n    }\n}\n```\n\n## Action\n\n### Move position with an animation\n\n```swift\n\ncontainer.move(type: .top)\ncontainer.move(type: .middle)\ncontainer.move(type: .bottom)\n\n```\n\n## Adding possible custom subviews in ContainerController view\n\n### Add `ScrollView`\n\n```swift \n\nlet tableView = UITableView()\ntableView.register(UITableViewCell.self, forCellReuseIdentifier: \"cell\")\ntableView.backgroundColor = .clear\ntableView.tableFooterView = UIView()\ntableView.delegate = self\ntableView.dataSource = self\n\n// Add scrollView to container\ncontainer.add(scrollView: tableView)\n\n```\n\n\n#### `Delegate` to self 👆\n#### If you implement delegate ScrollView (TableView, CollectionView, TextView) to `self`, then you need to call 4 functions in ContainerController\n\n```swift\nextension ViewController: UIScrollViewDelegate {\n    \n    func scrollViewDidScroll(_ scrollView: UIScrollView) {\n        container.scrollViewDidScroll(scrollView)\n    }\n    \n    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {\n        container.scrollViewWillBeginDragging(scrollView)\n    }\n    \n    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {\n        container.scrollViewDidEndDecelerating(scrollView)\n    }\n    \n    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {\n        container.scrollViewDidEndDragging(scrollView, willDecelerate: decelerate)\n    }\n}\n\nextension ViewController: UITableViewDelegate {\n    ...\n}\n\nextension ViewController: UITableViewDataSource {\n    ...\n}\n\n```\n\n### Add `HeaderView`\n\n```swift\n\nlet headerView = ExampleHeaderGripView()\nheaderView.height = 20\n\ncontainer.add(headerView: headerView)\n\n```\n\n### Add `FooterView`\n\n```swift\n\nlet tabBarView = HeaderTabBarView()\ntabBarView.height = 49.0\n\ncontainer.add(footerView: tabBarView)\n\n```\n### Add Custom `View`\n\n```swift\n\n// Add custom shadow\nlet layer = container.view.layer\nlayer.shadowOpacity = 0.5\nlayer.shadowColor = UIColor.red.cgColor\nlayer.shadowOffset = CGSize(width: 1, height: 4)\nlayer.shadowRadius = 5\n\n// Add view in container.view\nlet viewRed = UIView(frame: CGRect(x: 50, y: 50, width: 50, height: 50))\nviewRed.backgroundColor = .systemRed\ncontainer.view.addSubview(viewRed)\n\n// Add view under scrollView container.view\nlet viewGreen = UIView(frame: CGRect(x: 25, y: 25, width: 50, height: 50))\nviewGreen.backgroundColor = .systemGreen\ncontainer.view.insertSubview(viewGreen, at: 0)\n\n```\n\n## Settings ⚙️\n\n### Layout \n\n#### Customize the layout with create subclass `ContainerLayout` on initialization \n\n```swift\n\nclass NewContainerLayout: ContainerLayout {\n    \n    override init() {\n        super.init()\n        \n        // Initialization start position.\n        startPosition = .hide\n        \n        // Disables any moving with gestures.\n        movingEnabled = true\n        \n        // Sets the new value for positions of animated movement (top, middle, bottom).\n        positions = ContainerPosition(top: 70, middle: 250, bottom: 70)\n        \n        // Sets insets container.view  (left, right).\n        insets = ContainerInsets(right: 20, left: 20)\n    }\n}\n\nclass ViewController: UIViewController {\n\n    var container: ContainerController!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        container = ContainerController(addTo: self, layout: NewContainerLayout())\n        container.move(type: .top)\n    }\n}\n\n```\n\n#### Or create object `ContainerLayout` \n\n```swift\n\noverride func viewDidLoad() {\n    super.viewDidLoad()\n    \n    // Create ContainerController Layout object\n    let layout = ContainerLayout()\n    layout.startPosition = .hide\n    layout.backgroundShadowShow = true\n    layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)\n    \n    container = ContainerController(addTo: self, layout: layout)\n}\n\n```\n\n### Change settings right away\n\n\n```swift\n\n// Properties\ncontainer.set(movingEnabled: true)\ncontainer.set(trackingPosition: false)\ncontainer.set(footerPadding: 100)\n\n// Add ScrollInsets Top/Bottom\ncontainer.set(scrollIndicatorTop: 5) // ↓\ncontainer.set(scrollIndicatorBottom: 5) // ↑\n\n// Positions\ncontainer.set(top: 70) // ↓\ncontainer.set(middle: 250) // ↑\ncontainer.set(bottom: 80) // ↑\n\n// Middle Enable/Disable\ncontainer.set(middle: 250)\ncontainer.set(middle: nil)\n\n// Background Shadow\ncontainer.set(backgroundShadowShow: true)\n\n// Insets View\ncontainer.set(left: 5) // →\ncontainer.set(right: 5) // ←\n\n// Landscape params\ncontainer.setLandscape(top: 30)\ncontainer.setLandscape(middle: 150)\ncontainer.setLandscape(bottom: 70)\ncontainer.setLandscape(middle: nil)\n\ncontainer.setLandscape(backgroundShadowShow: false)\n\ncontainer.setLandscape(left: 10)\ncontainer.setLandscape(right: 100)\n\n```\n\n## ContainerController `View`\n\n#### Use a ready-made solution\n\n`ContainerView` is generated automatically when you create ContainerController\nUse a ready-made solution to change the radius, add shadow, and blur.\n\n#### Change `CornerRadius`\n\n```swift\n// Change cornerRadius global for all subviews\ncontainer.view.cornerRadius = 15 \n```\n#### Add Layer `Shadow`\n\n```swift\ncontainer.view.addShadow(opacity: 0.1) \n```\n#### Add Background `Blur`\n\n```swift\n// add blur UIVisualEffectView\ncontainer.view.addBlur(style: .dark) \n\n```\n\n### More details\n\n#### Change positions on screen Top Middle Bottom\n\n```swift\n\n// These parameters set the new position value.\ncontainer.layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)\n\n// Change settings right away\ncontainer.set(top: 70) // ↓\ncontainer.set(middle: 250) // ↑\ncontainer.set(bottom: 80) // ↑\n\n```\n\n#### Customize indentations for View\n\n```swift\n\n// Sets insets container.view  (left, right).\ncontainer.layout.insets = ContainerInsets(right: 20, left: 20)\n\ncontainer.layout.landscapeInsets = ContainerInsets(right: 20, left: 100)\n\n\n// Change settings right away\ncontainer.set(left: 5) // →\ncontainer.set(right: 5) // ←\n\ncontainer.setLandscape(left: 10)\ncontainer.setLandscape(right: 100)\n\n```\n\n#### Customize for landscape orientation\n\n```swift\n\n// Sets the background shadow under container. (Default: backgroundShadowShow).\ncontainer.layout.landscapeBackgroundShadowShow = false\n\n// Sets the new value for positions of animated movement (top, middle, bottom). (Default: positions).\ncontainer.layout.landscapePositions = ContainerPosition(top: 20, middle: 150, bottom: 70)\n\n// Sets insets container.view (left, right). (Default: insets).\ncontainer.layout.landscapeInsets = ContainerInsets(right: 20, left: 100)\n\n\n// Change settings right away\n\ncontainer.setLandscape(top: 30)\ncontainer.setLandscape(middle: 150)\ncontainer.setLandscape(bottom: 70)\ncontainer.setLandscape(middle: nil)\n\ncontainer.setLandscape(backgroundShadowShow: false)\n\ncontainer.setLandscape(left: 10)\ncontainer.setLandscape(right: 100)\n\n```\n\n#### Parameters for control footerView\n\n```swift\n\n// Padding-top from container.view, if headerView is added, then its + height is summed.\ncontainer.layout.footerPadding = 100\n\n// Tracking position container.view during animated movement.\ncontainer.layout.trackingPosition = false\n\n// Change settings right away\n\ncontainer.set(footerPadding: 100)\ncontainer.set(trackingPosition: false)\n\n```\n\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/footerPadding.gif)\n![image](https://github.com/mrustaa/gif_presentation/blob/master/ContainerControllerSwift/trackingPosition.gif)\n\n## ContainerController `Delegate`\n\n```swift\n\nclass ViewController: UIViewController, ContainerControllerDelegate {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        \n        let container = ContainerController(addTo: self, layout: layout)\n        container.delegate = self\n    }\n}\n\n/// Reports rotation and orientation changes\nfunc containerControllerRotation(_ containerController: ContainerController) {\n    ...\n}\n\n/// Reports a click on the background shadow\nfunc containerControllerShadowClick(_ containerController: ContainerController) {\n    ...\n}\n\n/// Reports the changes current position of the container, after its use\nfunc containerControllerMove(_ containerController: ContainerController, position: CGFloat, type: ContainerMoveType, animation: Bool) {\n    ...\n}\n\n```\n\n## Author\n\n\u003cmotionrustam@gmail.com\u003e 📩| [mrustaa](https://github.com/mrustaa/) JUNE 2020\n\n## License\n\nContainerController is available under the MIT license. See the LICENSE file for more info.\n\n","funding_links":[],"categories":["Libs","UI [🔝](#readme)"],"sub_categories":["UI"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrustaa%2FContainerController","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrustaa%2FContainerController","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrustaa%2FContainerController/lists"}