How to Create a Custom BottomSheet — Swift

Bruno Faganello
Code With Coffee
Published in
5 min readMay 12, 2020

--

“Standard bottom sheets display content that complements the screen’s primary content. They remain visible while users interact with the primary content.”(material.io)”

Hello everyone, in this tutorial we'e gonna learn how to create a Generic Custom Bottom Sheet in Swift. It means that you will transform any viewController into a BottomSheet.

So let's start creating our BottomShettViewController and remember to check to create XIB together.

Add two views like this:

First View Constraints

Let's see the constraint in the firstView (black color)

  • In the horizontal, we have leading and trailing constraints to Safe Area:
  • In the vertical:
  • All constraints:

Remember to put any color with opacity between 0.5 and 0.7 to create a good effect when Bottom View Appear

Second View Constraints

  • In the horizontal we have a leading and trailing constraint to Safe Area or Super View. You choose whats is better for you:
  • In the vertical, we have some different constraints:
  • We have bottom space to Superview
  • We must have a Height Constraint because if our viewController is contained in a table view we need to set the content size. Auto layout will not give us an error but if we don't do it, our layout will be prone to weird behavior
  • We have Top Space to our view blank view
  • And finally we have an Align Top constraint to top Safe Area is Greater Than or equal 40, that's mean if our viewController has a full size, it will be below Safe Area 40 points
  • All Constraints:

Let's code now

Let's create three outlets one for our view, another to our bottomConstraint (we're gonna create an animation), and the last one to our view height as explained above.

and creating two global variables like this

private let childViewController: UIViewController

private var originBeforeAnimation: CGRect = .zero

The first one will be our embedded view controller and the other is our animation controller.

Let's create our init:

We must call our super.init because when we initialize our BottomSheet we don't need to pass nibName and Bundle all the time. Let's change ourmodalPresentntationStyle = . overFullScreen` because we want to see last view controller information.

Extra Code

I have this Extension that will help you to create the animation, corner radius, and present the BottomSheet.

If you don't want this extension, it's not a problem, just remember to set animated as false when presenting a bottomSheet.

Back to BottomSheet

Let's override three methods of the viewController lifecycle:

  • ViewDidLoad
  • ViewDidAppear
  • ViewDidLayoutSubviews

ViewDidLoad

In viewDidload we configure our contentView alpha to 1, added PanGestureRecognizer to dismiss our BottomSheet and finally in our bottom constraint we set the constants property with negative value of height from childViewController to completely hide our content view. We have the func configureChild() don't worry, I'm gonna show later.

ViewDidAppear

Remember when I explained about height constraint? We verify if our childViewController contains a TableView(I'm gonna show this func later) if childView contains a tableView we update our height constraint with tableView content size. Otherwise we disable this constraint. After we change our bottomConstraint to zero and we animated our view to black color with opacity and the layout.

ViewDidLayoutSubviews

We configure our contentView to have a corner radius the top left and top right. And modify our originAnimation with contentView frame.

After that let's create our dismiss func and we do the inverse in ViewDidLoad. And the dismiss func and should set animated as false to not do a standard effect dismiss.

Let's to our private func

ConfigureChild

We add childViewController as Child of our BottomSheet, and add childViewController view as a subview in contentView and set the constraint to our childViewController view.

IMPORTANT

If your childViewController it`s a ViewController and you want a scroll view… your childViewController must have a scroll view with auto layout.

ContainsTableView

Just check if the subviews in childViewController contain a tableView.

ShouldDismissWithGesture

We verify if Pan Gesture state end

PanGesture

We called our ShouldDismissWithGesture func and it's true we called another func dismissViewController.

After we verify if the user moves the point is smaller and equal to our OriginAnimation and disable and enable the gesture.

Finale We move our contentView Y position with gesture Y position

UIGestureRecognizerDelegate

We use this delegate method to no recognize simultaneous gestures, because if our childViewController contains a table View or scroll View, we want to scroll and not dismiss.

And finally we add a TapGesture in our black view top view in XIB and create a IBAction to dismiss our bottom sheet when tapping in the top.

How to use?

It's very simple, just create your viewController and just need to pass the viewController to our BottomSheetViewContoller and presentBottomSheet.

Cocoapods

Thank you guys for reading this article, I created a pod and you can use the BottomSheet in an easy way https://github.com/brqdigital/BRQBottomSheet

--

--

Bruno Faganello
Code With Coffee

Engenheiro de Software Mobile. Fico constantemente atualizado com relação a tecnologia para que isso possa mudar a vida das pessoas. 💻