Skip to content

A reusable bottom sheet with customizable stops. Compatible with both UIKit and SwiftUI.

License

Notifications You must be signed in to change notification settings

colinfwalsh/CoverSheet

Repository files navigation

Cover Sheet

Swift Version Platform SPM IOS MIT Pod Version

Cover sheet is a dynamic, customizable, sheet that supports both UIKit and SwiftUI. You'll also be able to mix and match SwiftUI and UIKit views as needed to create any view you can imagine. In addition, CoverSheet also supports dynamic fullscreen animations similar to what you'd see in the Messages app on iPhone.

example-gif


Requirements

Platform Minimum Swift Version
iOS 13+ 5.0

Installation

SPM

If you're using Swift package manager, simply add CoverSheet as a dependency in your Package.swift file.

dependencies: [
    .package(url: "https://github.com/colinfwalsh/CoverSheet.git", branch(“main”))
]

Cocoapods

pod 'CoverSheet', '~> 0.1.2'

Setup project

Out of the box, you're provided with a DefaultSheetManager and DefaultSheetState which should serve most of your needs. DefaultSheetState provides you with 5 states:

// Sheet is offscreen
// 0% of view height
DefaultSheetState.hidden

// Sheet is in a collapsed state, similar to what you'd see in Google maps on initial load 
// 35% of view height
DefaultSheetState.collapsed

// Sheet is in an expanded state, but you can still see content in the inner view
// 70% of view height
DefaultSheetState.normal

// Sheet is the primary focus but you're still able to see the inner view
// 90% of view height
DefaultSheetState.full

// Sheet takes up the full screen and animates away the corner radius and handle bar
// 100% of view height
DefaultSheetState.cover

SwiftUI

  // Define your State array
  var states: [DefaultSheetState] = [.hidden, .collapsed, .normal]
  // sheetManager conforms to Manager
  CoverSheetView(sheetManager, states: states) {
    // Background View is here
  } sheet: { 
    // Sheet View goes here
  }

UIKit

If you're initializing CoverSheet programatically, simply use the built in initializer.

  // If you're initializing programatically, use the built in initializer
  var states: [DefaultSheetState] = [.hidden, .collapsed, .normal]
  let vc = CoverSheetController(states: states)
  
  // viewDidLoad
  vc.configure(inner: innerVC, sheet: sheetVC)

For storyboards, you'll need to set your ViewController class to CoverSheetController in your storyboard and then define your ViewController like so.

// Defining your ViewController

class MyViewController: CoverSheetController<DefaultSheetManager, DefaultSheetState> {
  override func viewDidLoad() {
    super.viewDidLoad()

    // Configuration goes here
  }
}

Alternatively, if you've declared a custom Manager with a custom SheetState you can define the ViewController as follows.

class MyCustomManager: Manager { ... }
enum MySheetState: CGFloat, RawRepresentable { ... }

class MyViewController: CoverSheetController<MyCustomManager, MySheetState> { ... }

Configuring

There are many public methods for you to update / override values for CoverSheet including setting custom managers, states, animations, and more. Below are brief summaries of the methods available:

    // Sets the Inner and Sheet ViewControllers - used in UIKit
    public func configure(inner: UIViewController, sheet: UIViewController) {}
    
    // Sets the Inner and Sheet Views - only use this if you're creating a custom implementation of CoverSheetView
    public func configure(inner: some View, sheet: some View) {}
    
    // Called on a SwiftUI redraw
    public func updateViews(inner: some View, sheet: some View) {}
    
    // Updates the current value in the manager.  If the value is not present in the state array, it's added and the states are sorted again
    public func updateCurrentState(_ newState: EnumValue) {}

    // Overrides the manager.  Only used if initializing via Storyboard.
    public func overrideManager(_ manager: ViewManager) {}
    
    // Overrides the states.  Only used if initializing via Storyboard.
    public func overrideStates(_ states: [EnumValue]) {}
    
    // Overrides the animation config, which in turn, updates the animations the sheet uses
    public func overrideAnimationConfig(_ config: AnimationConfig) {}
    
    // Overrides the animation values directly which will kick off the creation of a new AnimationConfig
    public func overrideAnimationValues(timing: CGFloat = 0.1,
                                        options: UIView.AnimationOptions = [.curveLinear],
                                        springDamping: CGFloat = 2.0,
                                        springVelocity: CGFloat = 7.0) {}
    
    // Updates the blur effect and background color of the sheet
    public func updateSheet(shouldBlur: Bool, backgroundColor: UIColor) {}

Protocols

To configure CoverSheet you have a few options depending on which UI framework you're using

  • CoverSheetDelegate - conform to the cover sheet delegate, helpful if you're using UIKit or if you're making a custom manager
  • Manager - protocol for defining your own sheet manager in SwiftUI. CoverSheetView requires an object that conforms to this protocol. Use DefaultSheetManager if you do not need any custom functionality.
  • Containable - a protocol for defining your own ContainerViewControllers. You likely shouldn't need this, but it's exposed in case you need a completely custom solution.

Project example

SwiftUI Example - example of using CoverSheet in SwiftUI

UIKit Example - example of using CoverSheet in UIKit

About

A reusable bottom sheet with customizable stops. Compatible with both UIKit and SwiftUI.

Resources

License

Stars

Watchers

Forks

Packages

No packages published