A framework that provides CurtainController. CurtainController is a container view controller that implements a content-curtain interface. You can find a similar implementation in applications like Apple Maps, Find My, Stocks, etc. Someone calls it "Pull Up" or "Bottom Sheet".

Overview

A framework that provides Curtain Controller. Curtain Controller is a container view controller that implements a content-curtain interface.

Platform Swift 5.3 MIT

Contents

Overview

A SweetCurtain framework provides a Curtain Controller. A Curtain Controller is a container view controller that manages two child view controllers in a content-curtain interface. In this type of interface, the primary view controller (the content) is covered with the secondary view controller (the curtain).

When building your app’s user interface, the Curtain Controller is typically the root view controller of your app’s window, but it may be embedded in another view controller. The Curtain Controller has no significant appearance of its own. Most of its appearance is defined by the child view controllers you install. You can configure the child view controllers using Interface Builder or programmatically using the init(content: curtain:) initializer. The child view controllers can be custom view controllers or other container view controller, such as navigation controllers.

Note: You can push a Curtain Controller onto a navigation stack. Also, its children can be contained in the navigation controller or tab bar controller. But remember that curtain always covers the content. For example, if the content embed in the navigation controller, the curtain will cover the navigation bar too.

When displayed onscreen, the Curtain Controller uses its Delegation object to messaging of its curtain changes. Also, the Curtain Controller provides the curtain object to manage the curtain's properties.

Features

  • Coefficient oriented metrics.
  • Friendly content changes mechanism.
  • Works with storyboard and code.
  • So easy to setup and use.
  • Compatible with safe area.
  • Compatible with scroll view.
  • Compatible with horizontal scroll or swipe.
  • Designed by the principle of iOS UI components.

Installation

CocoaPods

CocoaPods is a dependency manager for Cocoa projects. You can install it with the following command:

$ gem install cocoapods

To integrate SweetCurtain into your Xcode project using CocoaPods, specify it in your Podfile:

platform :ios, '9.0'
use_frameworks!

target '<Your Target Name>' do
  pod 'SweetCurtain'
end

Then, run the following command:

$ pod install

Carthage

Carthage is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.

You can install Carthage with Homebrew using the following command:

$ brew update
$ brew install carthage

To integrate SweetCurtain into your Xcode project using Carthage, specify it in your Cartfile:

git "https://github.com/multimediasuite/SweetCurtain"

Run carthage update to build the framework and drag the built SweetCurtain.framework into your Xcode project.

Manually

If you prefer not to use either of the aforementioned dependency managers, you can integrate SweetCurtain into your project manually.

Usage and explanation

Setup using storyboard

  1. Create a view controller and set the Class to be CurtainController in the Identity Inspector.

  1. Create two other view controllers you want. The one will be a Content and another one will be a Curtain.

  1. Connect your CurtainController to your new view controllers with the Curtain Connection Segue.

  1. Choose the Curtain Connection Segue of your Content view controller and type ContentID as it's identifier in the Identity Inspector.

  1. Choose the Curtain Connection Segue of your Curtain view controller and type CurtainID as it's identifier in the Identity Inspector.

You all set!

Note: Double-check your segues and segue IDs. This is important for the right setup of the flow.

Setup using code

  1. Create a two view controllers you want for using them as Content and Curtain.
//Also, you can instantiate your controllers from storyboard if you want it.
let contentViewController = IceCreamDetailViewController()
let curtainViewController = IceCreamListViewController()
  1. Create a Curtain Controller using two controllers that you created in the previous step.
let curtainController = CurtainController(content: contentViewController, curtain: curtainViewController)
  1. Show the curtainController where and when you want.
show(curtainController, sender: nil)

You all set!

CurtainController

Curtain Controller is a container view controller that implements a content-curtain interface. You can create the Curtain Controller using Storyboard or from the code. All of your view controllers have access to the curtainController property. It's computed property that provides access to the nearest ancestor in the view controller hierarchy that is a Curtain Controller.

The Curtain Controller object has a couple of properties and functions.

Property Type Description
curtainDelegate CurtainDelegate? The delegate you want to receive curtain controller messages that concern its curtain.
curtain Curtain! The object that provides all curtain's behaviour properties.

The initializer for creating a new Curtain Controller:

init(content: UIViewController, curtain: UIViewController)

Function for moving curtain to the position you want:

func moveCurtain(to position: CurtainHeightState, animated: Bool)

Curtain

The Curtain is the object of Curtain Controller that provides a couple of properties for behavior and view customization. But Curtain is not the view. The Сurtain is the abstract object represented by protocol with properties that Curtain Controller uses for its purposes. Simply put, the Curtain designed to reduce confusion and delimit settings duty in the controller.

Property Type Description
minHeightCoefficient CGFloat The minimum value that describes the ratio of the curtain minimum permissible height to the height of the content.
midHeightCoefficient CGFloat? The intermediate value that describes the ratio of the curtain intermediate permissible height to the height of the content.
maxHeightCoefficient CGFloat The maximum value that describes the ratio of the curtain maximum permissible height to the height of the content.
swipeResistance CurtainSwipeResistance The swipe resistance of the curtain.
movingDuration TimeInterval The time in seconds for reaching curtain to the nearest point.
topBounce Bool The boolean value that controls whether the curtain bounces past the top.
bottomBounce Bool The boolean value that controls whether the curtain bounces past the bottom.
showsHandleIndicator Bool The boolean that controls whether the curtain shows top handle indicator.
handleIndicatorColor UIColor The color of the curtain's handle indicator.
heightCoefficient CGFloat The current readonly value that describes the ratio of the curtain actual height to the height of the content.
actualHeight CGFloat The current readonly value that describes the curtain actual height.

Note: heightCoefficient is the property that describes the absolute value of the curtain position. Value 0 means that actualHeight might 0 too if the constraints do not interfere. Value 1 means that actualHeight is the same as the sum of safeAreaInsets.bottom and safe area height. See the image below for better understanding.

CurtainDelegate

Curtain Delegate is the protocol that allows receiving messages from Curtain Controller. Curtain Delegate provides a couple of functions.

Tells the delegate when thecCurtain did change ir's height state:

func curtain(_ curtain: Curtain, didChange heightState: CurtainHeightState)

Tells the delegate when the curtain is about to start dragging:

func curtainWillBeginDragging(_ curtain: Curtain)

Tells the delegate when dragging ended in the curtain:

func curtainDidEndDragging(_ curtain: Curtain)

Tells the delegate when the user draggs the curtain:

func curtainDidDrag(_ curtain: Curtain)

CurtainHeightState

Curtain height state is an enumerator of height states of the curtain.

Case Description
min Minimum defined height state.
mid Intermediate defined height state.
max Maximum defined height state.
hide Hidden state.

CurtainSwipeResistance

Curtain Swipe Resistance is an enumerator of predefined (or custom) velocity swipe resistances available for the curtain.

Case Description
any No resistance. Velocity value is 0.
low Low resistance. Velocity value is 300.
normal Normal resistance. Velocity value is 600.
high High resistance. Velocity value is 900.
custom(velocity: CGFloat) Custom resistance. Velocity value is what you set.

UIViewController extension

There is the public UIViewController extension in the SweetCurtain framework.

The extension provides curtainController property that is the nearest ancestor in the view controller hierarchy that is a curtain controller.

Note: You can find the CurtainController from any Curtain or Content view controllers. For example, this can be useful if your curtain is a UINavigationController and you need to find CurtainController for its top view controller.

The extension also provides the function func allowScrollViewInCurtain() that allows topmost scroll view in the hierarchy to use its scroll simultaneously with the curtain.

Note: Your Curtain view controller may contain UIScrollView or any of its subclasses. But by default, it does not affect the scrolling of the curtain. If you want to enable simultaneous scroll for top most scroll view in hierarchy, call func allowScrollViewInCurtain() in your view controller.

ATTENTION: The function func allowScrollViewInCurtain() resets your previous scroll view scroll observation from the Curtain befor applies new one. Be careful using this function. For example, if you need to use a navigation controller as Curtain there is a good idea to call this function in 'func viewDidAppear(animated: Bool)' function of its view controllers.

TODO

  • Test gestures in the controller.
  • Write unit tests.
  • Update for iPad and big-phones horizontal screen.
  • Write log messages for the wrong usage.
  • Update animation parameters for grow smoothness.
  • Fix horizontal scroll view work.
  • Add videos that describe how to use SweetCurtain well.
  • Add Swift Dependency way to install.

Credits

License

SweetCurtain is released under the MIT license. See LICENSE for details.

You might also like...
A flexible container view featuring a solid background with rounded corners.
A flexible container view featuring a solid background with rounded corners.

A flexible container view featuring a solid background with rounded corners.

List tree data souce to display hierachical data structures in lists-like way. It's UI agnostic, just like view-model and doesn't depend on UI framework
List tree data souce to display hierachical data structures in lists-like way. It's UI agnostic, just like view-model and doesn't depend on UI framework

SwiftListTreeDataSource List tree data souce to display hierachical data structures in lists-like way. It's UI agnostic, just like view-model, so can

A library to imitate the iOS 10 Maps UI.
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

🍞 Toast for Swift - Toaster Android-like toast with very simple interface
🍞 Toast for Swift - Toaster Android-like toast with very simple interface

Toaster Android-like toast with very simple interface. (formerly JLToast) Screenshots Features Queueing: Centralized toast center manages the toast qu

A child view controller framework that makes setting up your parent controllers as easy as pie.
A child view controller framework that makes setting up your parent controllers as easy as pie.

Description Family is a child view controller framework that makes setting up your parent controllers as easy as pie. With a simple yet powerful publi

You can dismiss modal viewcontroller like Facebook Messenger by pulling scrollview or navigationbar in Swift.
You can dismiss modal viewcontroller like Facebook Messenger by pulling scrollview or navigationbar in Swift.

PullToDismiss PullToDismiss provides dismiss modal viewcontroller function like Facebook Messenger by pulling scrollview or navigationbar with smooth

A custom UIControl which functions like UISlider where you can set multiple intervals with different step values for each interval.
A custom UIControl which functions like UISlider where you can set multiple intervals with different step values for each interval.

MultiStepSlider A custom UIControl which functions like UISlider where you can set multiple intervals with different step values for each interval. Th

RangeSeedSlider provides a customizable range slider like a UISlider.
RangeSeedSlider provides a customizable range slider like a UISlider.

RangeSeekSlider Overview RangeSeekSlider provides a customizable range slider like a UISlider. This library is based on TomThorpe/TTRangeSlider (Objec

A custom stretchable header view for UIScrollView or any its subclasses with UIActivityIndicatorView and iPhone X safe area support for content reloading. Built for iOS 10 and later.

Arale A custom stretchable header view for UIScrollView or any its subclasses with UIActivityIndicatorView support for reloading your content. Built f

Comments
  • Question - How would one update the curtain view controller?

    Question - How would one update the curtain view controller?

    I am programmatically creating the CurtainController:

    AppDelegate.swift

        curtainViewController = TestSheetViewController()
        curtainController = CurtainController(content: contentViewController!, curtain: curtainViewController!)
        curtainController?.curtain.minHeightCoefficient = 0.0
        curtainController?.curtain.midHeightCoefficient = 0.57
        curtainController?.curtain.maxHeightCoefficient = 0.98
        curtainController?.curtain.swipeResistance = .normal
        curtainController?.curtain.movingDuration = 0.5
        curtainController?.curtain.topBounce = true
        curtainController?.curtain.bottomBounce = true
        curtainController?.curtain.showsHandleIndicator = false
        curtainController?.curtainDelegate = self
        window.rootViewController = curtainController!
    

    AnotherViewController.swift

    // TODO: How do we push updated content to the curtain view?
    //let testVC = UIViewController()
    //testVC.view.backgroundColor = UIColor.red
    //self.appDelegate.curtainViewController = testVC
    self.curtainController?.moveCurtain(to: .mid, animated: true)
    

    And in another ViewController I am able to show the view, however what is good way to updating the curtainViewController? e.g. if I want to use a different VC.

    opened by naturalui 5
  • Support for Dimming/Dismissing (to match Apple Sheets)

    Support for Dimming/Dismissing (to match Apple Sheets)

    I will be working on this on a fork, will keep you posted but wanted to check if you had on plans on doing similar?

    e.g. Apple zooms and fades the Content area and allows to dismiss by tapping area above Sheet.

    image

    opened by naturalui 0
Owner
Ihor Malovanyi
iOS developer with 6 years of experience in programming for the iOS platform. WWDC18/WWDC19 attendee
Ihor Malovanyi
UI Component. This is a copy swipe-panel from app: Apple Maps, Stocks. Swift version

ContainerController UI Component. This is a copy swipe-panel from app: https://www.apple.com/ios/maps/ Preview Requirements Installation CocoaPods Swi

Rustam 419 Dec 12, 2022
Full configurable spreadsheet view user interfaces for iOS applications. With this framework, you can easily create complex layouts like schedule, gantt chart or timetable as if you are using Excel.

kishikawakatsumi/SpreadsheetView has moved! It is being actively maintained at bannzai/SpreadsheetView. This fork was created when the project was mov

Kishikawa Katsumi 34 Sep 26, 2022
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
A controller that uses a UIStackView and view controller composition to display content in a list

StackViewController Overview StackViewController is a Swift framework that simplifies the process of building forms and other static content using UIS

Seed 867 Dec 27, 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
UI framework that allows developers to integrate an amazing selection interface into their applications

UI framework that allows developers to integrate an amazing selection interface into their applications! Each bubble has a set of parameters, which could be configured individually.

AJIJIi 5 Jul 12, 2022
Provides an iOS view controller allowing a user to draw their signature with their finger in a realistic style.

Swift version now available! Mimicking pen-on-paper signatures with a touch screen presents a difficult set of challenges. The rate touch events are e

Uber Open Source 1.3k Jan 6, 2023
A nice iOS View Capture Swift Library which can capture all content.

SwViewCapture A nice iOS View Capture Library which can capture all content. SwViewCapture could convert all content of UIWebView to a UIImage. 一个用起来还

Xing Chen 597 Nov 22, 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 container view that responds to scrolling of UIScrollView

FlexibleHeader A container view that responds to scrolling of UIScrollView. normal threshold FlexibleHeaderExecutantType Getting Started Progressive I

DongHee Kang 69 May 2, 2022