Vincent Tourraine

Notes WWDC 2019 : Modernizing Your UI for iOS 13

#dev #iOS

Référence : Session 224 - Modernizing Your UI for iOS 13

Flexible UI


let appearance = UINavigationBarAppearance()
      appearance.titleTextAttributes = [.foregroundColor: myAppLabelColor]
      appearance.largeTitleTextAttributes = [.foregroundColor: myAppLabelColor]
      navigationBar.standardAppearance = appearance

Different layout appearances:

Same for toolbars and tab bars:

Can be customized with view controller navigation item


Pull down to dismiss automatically. Can be customized (for instance, when the user has entered text in the modal, offer to discard or save new content):

class EmailController: UIViewController, UIAdaptivePresentationControllerDelegate {
        func draftDidChange() {
          isModalInPresentation = draft.hasChanges
        func presentationControllerDidAttemptToDismiss(_: UIPresentationController) {
          // Present action sheet

Appearance callbacks: for page and form sheets with iOS 13 SDK, the presenting view controller is not removed from the view hierarchy, therefore the viewWill/Did/Appear/Disappear methods are not called. Use the new “attempt to dismiss” methods instead.

UISearchController: can now hide elements of the search bar (scope, cancel button), search text field exposed

let searchController = UISearchController(searchResultsController: /*...*/)
      // Don’t automatically show the cancel button or scope bar
      searchController.automaticallyShowsCancelButton = false
      searchController.automaticallyShowsScopeBar = false
      // Customize appearance of the search text field
      let searchField = searchController.searchBar.textField
      searchField.textColor = UIColor(named: "MyPinkColor")
      searchField.font = UIFont(name: "American Typewriter", size: 18)

The search results controller can now be displayed as soon as the search bar becomes active (for instance, to display a list of filters, like system Mail app)

// Show the search results controller as soon as search is activated
      searchController.showsSearchResultsController = true

New UISearchTextField API for tokens (copy, paste, drag and drop)

Creating tokens:

let selectedText = field.textIn(field.selectedTextRange)
      let token = UISearchToken(icon: nil, text: selectedText)
      field.replaceTextualPortion(of: field.selectedTextRange, with: token, at: field.tokens.count)


Selection gestures in custom text views

UITextInteraction: implement system text-related gestures in custom text view

// Create selection interaction with type .editable or nonEditable
      let selectionInteraction = UITextInteraction(for: .editable)
      // Assign `textInput` property to your view that implements the UITextInput protocol
      selectionInteraction.textInput = textView
      // Add the interaction to the view

Multiple selection gestures in tables and collections

optional func tableView(_ tableView: UITableView, shouldBeginMultipleSelectionInteractionAtIndexPath indexPath: IndexPath) -> Bool
      optional func tableView(_ tableView: UITableView, didBeginMultipleSelectionInteractionAtIndexPath indexPath: IndexPath)

Editing gestures (undo/redo)

Can opt-out:

public protocol UIResponder {
        public var editingInteractionConfiguration: UIEditingInteractionConfiguration
      public enum UIEditingInteractionConfiguration {
        case `default` // System behavior, default
        case none // Disable


Consistent gestures, based on device capabilities:

UIMenu and UIAction

// Create a UIContextMenuInteraction with Some Delegate
      let interaction = UIContextMenuInteraction(delegate: self)
      // Attach It to Our View


func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration?
let actionProvider = (suggestedActions: [UIMenuElement]) -> UIMenu? {
        let editMenu = UIMenu(title: "Edit...", children: [
          UIAction(title: "Copy") { ... },
          UIAction(title: "Duplicate") { ... }
        return UIMenu(children: [
          UIAction(title: "Share") { ... },
          UIAction(title: "Delete", style: .destructive) { ... }
      return UIContextMenuConfiguration(identifier: "unique-ID" as NSCopying, previewProvider: nil, actionProvider: actionProvider)

UITableView and UICollectionView

// UITableViewDelegate
      optional func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAtIndexPath indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration?