Simple and elegant dropdown transition for iOS
I needed to perform the dropdown transition in the app I was building and I've found many great libraries out there that provide desired functionality. But all of them had one flaw in them: they were NOT implemented as custom transitions, but rather as some view animations.
This library solves this problem by providing you custom modal transition that is implemented using UIPresentationController
and UITransitionCoordinator
. It provides you with greater flexibility and is more suitable for the use in projects that follow some standard architecture & navigation patterns (e.g. Router
, Navigator
& Coordinator
patterns)
There are multiple options for installing DropdownTransition:
Using Carthage dependency manager, add following line to Cartfile
:
github "nugmanoff/DropdownTransition" ~> 1.0.0
Using CocoaPods add following line to your project Podfile
:
pod 'DropdownTransition', '~> 1.0.0'
Using Swift Package Manager, add the following line to your Package.swift
:
dependencies: [
.package(url: "https://github.com/nugmanoff/DropdownTransition.git", .exact("1.0.0")),
]
Or just simply drag *.swift
files from DropdownTransition
folder to your project (my favorite option).
- You need to conform to
DropdownPresentable
protocol in theUIViewController
subclass you wish to present.
class SomeViewController: UIViewController, DropdownPresentable {
// ...
}
- You need to store instance variable of
DropdownTransitioningDelegate
somewhere accessible form your call topresent
method (e.g. inCoordinator
pattern that'd be insideRouter
implementation)
let dropdownTransitioningDelegate = DropdownTransitioningDelegate()`
- As the final step, you need to perform the actual transition by assigning the tweaking the options of view controller that is going to be presented, and calling the
present
function with it.
let someViewController = SomeViewController()
someViewController.transitioningDelegate = dropdownTransitioningDelegate
someViewController.modalPresentationStyle = .custom
navigationController?.present(someViewController, animated: true, completion: nil)
If you are using Auto Layout and wondering how to present controller with the proper height, take a look at the Pro tip
In order to customize various presentation parameters, you need to override implement needed variables from DropdownPresentable
protocol, otherwise their values will be set to some sensible defaults.
var isDraggingEnabled: Bool { get } // option that indicates whether you can drag (pan gesture) the dropdown controller or not
var dismissAfterRelease: Bool { get } // when enabled automatically dismisses controller when it surpasses threshold value
var dismissDraggingTranslationThreshold: CGFloat { get } // threshold value for dismissals
var stretchableBackgroundColor: UIColor { get } // background color of the view that stretches at the top of the controller (if dragging is enabled)
var dismissAfterTappingDimmingView: Bool { get } // when enabled automatically dismisses controller upon tap on the dimmed (black) area
var isFeedbackEnabled: Bool { get } // whether or not haptic feedback is generated on reaching threshold value
var feedbackStyle: UIImpactFeedbackGenerator.FeedbackStyle { get } // haptic feedback style
Demo above shows the presented controller with dismissAfterRelease
set to false
, as you see controller is not dismissed automatically as opposed to the default state shown in the first demo.
Intrinsic height of the presented UIViewController
needs to be set correctly in order to attain the desired height and behavior of the transition.
Luckily you can do that easily by calling this function in viewDidLayoutSubviews
and viewDidLoad
methods of the UIViewController
private func updatePreferredContentSize() {
view.updateConstraintsIfNeeded()
let viewSize = CGSize(width: UIScreen.main.bounds.width, height: .leastNonzeroMagnitude)
preferredContentSize = view.systemLayoutSizeFitting(viewSize,
withHorizontalFittingPriority: .required,
verticalFittingPriority: .defaultLow)
If you are still experiencing issues with the height of the controller not being set correctly, make sure that you got your constraints right and they are feasibly satisfiable.
In case if you are looking for into more details I've added demonstrated Example to the repo.
If you have any questions regarding the library, found a bug or want to contribute, please open an issue on GitHub.
Author of the project is @nugmanoff
This project is licensed under MIT License