Context: To allow us to create APIs for our users to set different appearances based on the different states the drawer can be in, we need to create an initial state system. The Problem: Without defining a state for our drawer, we won't be able to differentiate between different presentations the drawer may be in, and then alter the drawer's appearance effectively. The Fix: Provide a state enum as part of MDCBottomDrawerController, that is read only, and is set using a delegate that is initially set by the internal implementation. Testing: Unit Tests + Tested on an iPhone X and iPhone 7 with smaller and bigger preferredContentSize to imitate different states. Related Bugs: Closes #5524
Navigation Drawer
Navigation drawers provide access to destinations and app functionality, such as switching accounts. They can either be permanently on-screen or controlled by a navigation menu icon.
Navigation drawers are recommended for:
Design & API documentation
- Material Design guidelines: Navigation Drawer
- Class: MDCBottomDrawerPresentationController
- Class: MDCBottomDrawerTransitionController
- Class: MDCBottomDrawerViewController
- Protocol: MDCBottomDrawerHeader
Table of contents
Overview
Navigation Drawer is currently an alpha component. Therefore, clients that wish to use Navigation Drawer in their app will need to manually clone the repo and add the code to their project.
Navigation Drawer currently provides the Bottom Drawer presentation style.
The Navigation Drawer is architected by implementing a custom UIPresentationController and a UIViewControllerTransitioningDelegate named MDCBottomDrawerPresentationController and MDCBottomDrawerTransitionController respectively.
This allows us to use the default API Apple provides for UIViewController presentation (more on usage below).
Through the MDCBottomDrawerViewController class, the Navigation Drawer allows you to pass a contentViewController to act as the content of the drawer, and also a headerViewController which will stick to the top once the drawer is in full screen.
MDCBottomDrawerViewController also provides a settable trackingScrollView property that should be set to the UITableView or UICollectionView inside your content, if and only if that view fills the entire bounds, and if you are seeking for a more performant solution of having the algorithm only load your view as you scroll and not all at once.
Lastly, your headerViewController conforms to the MDCBottomDrawerHeader protocol, which implements the method updateDrawerHeaderTransitionRatio:(CGFloat)transitionToTopRatio. This method provides transitionToTopRatio, which moves between 0 to 1 as the transition of the header view
transforms from being above the content to becoming sticky on the top. It is 0 when the drawer is above the content and starts changing as the header view expands to cover the status bar and safe area based on the completion rate. It is 1 once the header finishes its transition to become sticky on the top and it's height is at the size of its preferredContentSize + the safe area.
Navigation Drawer Classes
MDCBottomDrawerViewController
MDCBottomDrawerViewController is a UIViewController that allows you to provide your drawer content via the contentViewController and your desired header (optional) through the headerViewController property.
Installation
This component is an alpha component and therefore doesn't support installation via CocoaPods. To install this component you will need to manually clone the repo and add the code to your project. This is intended.
Importing
To import the component:
Swift
import MaterialComponentsAlpha.MaterialNavigationDrawer
Objective-C
#import "MaterialNavigationDrawer.h"
Usage
Typical use: using the MDCBottomDrawerViewController with/without a header.
Swift
let bottomDrawerViewController = MDCBottomDrawerViewController()
bottomDrawerViewController.contentViewController = UIViewController()
bottomDrawerViewController.headerViewController = UIViewController() # this is optional
present(bottomDrawerViewController, animated: true, completion: nil)
Objective-C
MDCBottomDrawerViewController *bottomDrawerViewController = [[MDCBottomDrawerViewController alloc] init];
bottomDrawerViewController.contentViewController = [UIViewController new];
bottomDrawerViewController.headerViewController = [UIViewController new];
[self presentViewController:bottomDrawerViewController animated:YES completion:nil];
Typical use: presenting in a drawer without a header.
Swift
let contentViewController = UIViewController()
contentViewController.transitioningDelegate = MDCBottomDrawerTransitionController()
contentViewController.modalPresentationStyle = .custom
present(contentViewController, animated: true, completion: nil)
Objective-C
UIViewController *contentViewController = [UIViewController new];
contentViewController.transitioningDelegate = [MDCBottomDrawerTransitionController new];
contentViewController.modalPresentationStyle = UIModalPresentationCustom;
[self presentViewController:contentViewController animated:YES completion:nil];
Typical use: using the MDCBottomDrawerViewController with a need for performant scrolling.
Swift
let contentViewController = UITableViewController()
let bottomDrawerViewController = MDCBottomDrawerViewController()
bottomDrawerViewController.contentViewController = contentViewController
bottomDrawerViewController.headerViewController = UIViewController() # this is optional
bottomDrawerViewController.trackingScrollView = contentViewController.view
present(bottomDrawerViewController, animated: true, completion: nil)
Objective-C
UITableViewController *contentViewController = [UITableViewController new];
MDCBottomDrawerViewController *bottomDrawerViewController = [[MDCBottomDrawerViewController alloc] init];
bottomDrawerViewController.contentViewController = contentViewController;
bottomDrawerViewController.headerViewController = [UIViewController new];
bottomDrawerViewController.trackingScrollView = contentViewController.view;
[self presentViewController:bottomDrawerViewController animated:YES completion:nil];