UI Component. This is a copy swipe-panel from app: Apple Maps, Stocks. Swift version

Overview

image(Landscape)

ContainerController

Version License Platform Swift 5.0 Swift 5.1 Swift 5.2

UI Component. This is a copy swipe-panel from app: https://www.apple.com/ios/maps/

Preview

image image image(Landscape)

Requirements

✏️ ContainerController is written in Swift 5.0+. It can be built by Xcode 11 or later. Compatible with iOS 13.0+.

Installation

CocoaPods

ContainerControllerSwift is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'ContainerControllerSwift'

Swift Package Manager with Xcode 11

Follow this doc.

Getting Started

import UIKit
import ContainerControllerSwift

class ViewController: UIViewController, ContainerControllerDelegate {
    
    var container: ContainerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Create ContainerController Layout object
        let layout = ContainerLayout()
        layout.startPosition = .hide
        layout.backgroundShadowShow = true
        layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)
        
        // Create ContainerController object, along with the container.view
        // Pass the current UIViewController 
        let container = ContainerController(addTo: self, layout: layout)
        container.view.cornerRadius = 15
        container.view.addShadow()
        
        // Create subclass scrollView
        let tableView = UITableView()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.delegate = self
        tableView.dataSource = self
        
        // Add scrollView to container
        container.add(scrollView: tableView)
        
        // Finishing settings ContainerController,
        // Animated move position Top
        container.move(type: .top)
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        // Remove the subviews ContainerController
        container.remove()
        container = nil
    }
}

Action

Move position with an animation

container.move(type: .top)
container.move(type: .middle)
container.move(type: .bottom)

Adding possible custom subviews in ContainerController view

Add ScrollView

let tableView = UITableView()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.backgroundColor = .clear
tableView.tableFooterView = UIView()
tableView.delegate = self
tableView.dataSource = self

// Add scrollView to container
container.add(scrollView: tableView)

Delegate to self πŸ‘†

If you implement delegate ScrollView (TableView, CollectionView, TextView) to self, then you need to call 4 functions in ContainerController

extension ViewController: UIScrollViewDelegate {
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        container.scrollViewDidScroll(scrollView)
    }
    
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        container.scrollViewWillBeginDragging(scrollView)
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        container.scrollViewDidEndDecelerating(scrollView)
    }
    
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        container.scrollViewDidEndDragging(scrollView, willDecelerate: decelerate)
    }
}

extension ViewController: UITableViewDelegate {
    ...
}

extension ViewController: UITableViewDataSource {
    ...
}

Add HeaderView

let headerView = ExampleHeaderGripView()
headerView.height = 20

container.add(headerView: headerView)

Add FooterView

let tabBarView = HeaderTabBarView()
tabBarView.height = 49.0

container.add(footerView: tabBarView)

Add Custom View

// Add custom shadow
let layer = container.view.layer
layer.shadowOpacity = 0.5
layer.shadowColor = UIColor.red.cgColor
layer.shadowOffset = CGSize(width: 1, height: 4)
layer.shadowRadius = 5

// Add view in container.view
let viewRed = UIView(frame: CGRect(x: 50, y: 50, width: 50, height: 50))
viewRed.backgroundColor = .systemRed
container.view.addSubview(viewRed)

// Add view under scrollView container.view
let viewGreen = UIView(frame: CGRect(x: 25, y: 25, width: 50, height: 50))
viewGreen.backgroundColor = .systemGreen
container.view.insertSubview(viewGreen, at: 0)

Settings βš™οΈ

Layout

Customize the layout with create subclass ContainerLayout on initialization

class NewContainerLayout: ContainerLayout {
    
    override init() {
        super.init()
        
        // Initialization start position.
        startPosition = .hide
        
        // Disables any moving with gestures.
        movingEnabled = true
        
        // Sets the new value for positions of animated movement (top, middle, bottom).
        positions = ContainerPosition(top: 70, middle: 250, bottom: 70)
        
        // Sets insets container.view  (left, right).
        insets = ContainerInsets(right: 20, left: 20)
    }
}

class ViewController: UIViewController {

    var container: ContainerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        container = ContainerController(addTo: self, layout: NewContainerLayout())
        container.move(type: .top)
    }
}

Or create object ContainerLayout

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Create ContainerController Layout object
    let layout = ContainerLayout()
    layout.startPosition = .hide
    layout.backgroundShadowShow = true
    layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)
    
    container = ContainerController(addTo: self, layout: layout)
}

Change settings right away

// Properties
container.set(movingEnabled: true)
container.set(trackingPosition: false)
container.set(footerPadding: 100)

// Add ScrollInsets Top/Bottom
container.set(scrollIndicatorTop: 5) // ↓
container.set(scrollIndicatorBottom: 5) // ↑

// Positions
container.set(top: 70) // ↓
container.set(middle: 250) // ↑
container.set(bottom: 80) // ↑

// Middle Enable/Disable
container.set(middle: 250)
container.set(middle: nil)

// Background Shadow
container.set(backgroundShadowShow: true)

// Insets View
container.set(left: 5) // β†’
container.set(right: 5) // ←

// Landscape params
container.setLandscape(top: 30)
container.setLandscape(middle: 150)
container.setLandscape(bottom: 70)
container.setLandscape(middle: nil)

container.setLandscape(backgroundShadowShow: false)

container.setLandscape(left: 10)
container.setLandscape(right: 100)

ContainerController View

Use a ready-made solution

ContainerView is generated automatically when you create ContainerController Use a ready-made solution to change the radius, add shadow, and blur.

Change CornerRadius

// Change cornerRadius global for all subviews
container.view.cornerRadius = 15 

Add Layer Shadow

container.view.addShadow(opacity: 0.1) 

Add Background Blur

// add blur UIVisualEffectView
container.view.addBlur(style: .dark) 

More details

Change positions on screen Top Middle Bottom

// These parameters set the new position value.
container.layout.positions = ContainerPosition(top: 70, middle: 250, bottom: 70)

// Change settings right away
container.set(top: 70) // ↓
container.set(middle: 250) // ↑
container.set(bottom: 80) // ↑

Customize indentations for View

// Sets insets container.view  (left, right).
container.layout.insets = ContainerInsets(right: 20, left: 20)

container.layout.landscapeInsets = ContainerInsets(right: 20, left: 100)


// Change settings right away
container.set(left: 5) // β†’
container.set(right: 5) // ←

container.setLandscape(left: 10)
container.setLandscape(right: 100)

Customize for landscape orientation

// Sets the background shadow under container. (Default: backgroundShadowShow).
container.layout.landscapeBackgroundShadowShow = false

// Sets the new value for positions of animated movement (top, middle, bottom). (Default: positions).
container.layout.landscapePositions = ContainerPosition(top: 20, middle: 150, bottom: 70)

// Sets insets container.view (left, right). (Default: insets).
container.layout.landscapeInsets = ContainerInsets(right: 20, left: 100)


// Change settings right away

container.setLandscape(top: 30)
container.setLandscape(middle: 150)
container.setLandscape(bottom: 70)
container.setLandscape(middle: nil)

container.setLandscape(backgroundShadowShow: false)

container.setLandscape(left: 10)
container.setLandscape(right: 100)

Parameters for control footerView

// Padding-top from container.view, if headerView is added, then its + height is summed.
container.layout.footerPadding = 100

// Tracking position container.view during animated movement.
container.layout.trackingPosition = false

// Change settings right away

container.set(footerPadding: 100)
container.set(trackingPosition: false)

image image

ContainerController Delegate

class ViewController: UIViewController, ContainerControllerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let container = ContainerController(addTo: self, layout: layout)
        container.delegate = self
    }
}

/// Reports rotation and orientation changes
func containerControllerRotation(_ containerController: ContainerController) {
    ...
}

/// Reports a click on the background shadow
func containerControllerShadowClick(_ containerController: ContainerController) {
    ...
}

/// Reports the changes current position of the container, after its use
func containerControllerMove(_ containerController: ContainerController, position: CGFloat, type: ContainerMoveType, animation: Bool) {
    ...
}

Author

[email protected] πŸ“© | mrustaa

License

ContainerController is available under the MIT license. See the LICENSE file for more info.

You might also like...
A modern HUD inspired by Apple Music and Apple Podcasts
A modern HUD inspired by Apple Music and Apple Podcasts

HUD A modern HUD inspired by Apple Music and Apple Podcasts. Appearance Light Dark HUD Activity Indicator HUD Requirements iOS 13+ Installation You ca

AGCircularPicker is helpful component for creating a controller aimed to manage any calculated parameter
AGCircularPicker is helpful component for creating a controller aimed to manage any calculated parameter

We are pleased to offer you our new free lightweight plugin named AGCircularPicker. AGCircularPicker is helpful for creating a controller aimed to man

An easy to use UI component to help display a signal bar with an added customizable fill animation
An easy to use UI component to help display a signal bar with an added customizable fill animation

TZSignalStrengthView for iOS Introduction TZSignalStrengthView is an easy to use UI component to help display a signal bar with an added customizable

UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS
UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

UIPheonix is a super easy, flexible, dynamic and highly scalable UI framework + concept for building reusable component/control-driven apps for macOS, iOS and tvOS

Zeplin component preview for your SwiftUI views
Zeplin component preview for your SwiftUI views

A Zeplin component preview for your SwiftUI views. You can use Zeplin components instead of real views within your app until you implement them.

⬆️ A SwiftUI view component sliding in from bottom
⬆️ A SwiftUI view component sliding in from bottom

⬆️ A SwiftUI view component sliding in from bottom

Customizable CheckBox / RadioButton component for iOS
Customizable CheckBox / RadioButton component for iOS

GDCheckbox An easy to use CheckBox/Radio button component for iOS, with Attributes inspector support. Requirements Xcode 10+ Swift 5 iOS 9+ Installati

A multi-platform SwiftUI component for tabular data
A multi-platform SwiftUI component for tabular data

SwiftTabler A multi-platform SwiftUI component for tabular data. NOTE this component is BRAND NEW and under active development. If you need stability,

 Flutter Apple Product Store App UI Home Page With Getx
Flutter Apple Product Store App UI Home Page With Getx

Flutter Apple Product Store App UI Home Page With Getx A new Flutter UI Project on my Youtube Channel . About The Project Create a beautiful Flutter U

Comments
  • ContainerController issues during rotation

    ContainerController issues during rotation

    Hey

    I am having an issue where the my Apps orientation settings are all off and the app is only supposed to work in Portrait but one of my view controllers uses your ContainerController. The problem is, when you rotate the device upside down just for fun -> Your ContainerController goes bezerk and jumps all over the place.

    Are you aware of this issue?

    opened by adamdahan 6
  • Confusing.

    Confusing.

    Why would everything you add to the container need to be a scrollView? This library is cool but the implementation is not very usable. Same with the example code. It's all over the place.

    opened by adamdahan 1
  • Weak reference

    Weak reference

    Is there a reason not to make the controller and delegate weakly in the ContainerController?

    Since they are all strong references so I have to call remove() every time I dismiss the root view controller so it won't produce a memory leak, I have tried to make them weak and it works fine, and I don't have to call remove() anymore to prevent memory leak.

    opened by Barry0327 0
  • Preliminary SwiftUI support

    Preliminary SwiftUI support

    For now it will simply add a UIHostingController view to the contentView.

    I commented out calls needed for proper view controller containment because it doesn’t play well with my UINavigationController.

    opened by rivera-ernesto 2
Releases(1.1.3)
Owner
Rustam
iOS developer
Rustam
DrawerKit lets an UIViewController modally present another UIViewController in a manner similar to the way Apple's Maps app works.

DrawerKit What is DrawerKit? DrawerKit is a custom view controller presentation mimicking the kind of behaviour in the Apple Maps app. It lets any vie

Babylon Health 773 Dec 27, 2022
Basic iOS app to track stocks (data from Finnhub, Tiingo, or IEX Cloud)

Basic iOS app to track stocks (data from Finnhub, Tiingo, or IEX Cloud)

null 33 Dec 21, 2022
A SwiftUI bottom-up controller, like in the Maps app. Drag to expand or minimize.

SwiftUI Drawer A SwiftUI bottom-up controller, like in the Maps app. Drag to expand or minimize. Contents Add the Package Basic Usage Examples Credits

Michael Verges 695 Jan 3, 2023
Swipe Left2Right & Right2Left, pure SwiftUI implementation

SwipeCell Preview Features Swipe cell from Left2Right & Right2Left. Destructive swipe Usage Simply add onSwipe(leading, trailing) method to your list

Enes Karaosman 266 Jan 6, 2023
A library to imitate the iOS 10 Maps UI.

Pulley A library to imitate the drawer in Maps for iOS 10/11. The master branch follows the latest currently released version of Swift. If you need an

52inc 2k Dec 29, 2022
Pull up controller with multiple sticky points like in iOS Maps

PullUpController Create your own pull up controller with multiple sticky points like in iOS Maps Features Multiple sticky points Landscape support Scr

Mario Iannotta 1.2k Dec 22, 2022
TSnackBarView is a simple and flexible UI component fully written in Swift

TSnackBarView is a simple and flexible UI component fully written in Swift. TSnackBarView helps you to show snackbar easily with 3 styles: normal, successful and error

Nguyen Duc Thinh 3 Aug 22, 2022
TDetailBoxView is a simple and flexible UI component fully written in Swift

TDetailBoxView is a simple and flexible UI component fully written in Swift. TDetailBoxView is developed to help users quickly display the detail screen without having to develop from scratch.

Nguyen Duc Thinh 2 Aug 18, 2022
TSwitchLabel is a simple and flexible UI component fully written in Swift.

TSwitchLabel is a simple and flexible UI component fully written in Swift. TSwitchLabel is developed for you to easily use when you need to design a UI with Label and Switch in the fastest way without having to spend time on develop from scratch.

Nguyen Duc Thinh 2 Aug 18, 2022