Build a desktop class iPad app

Description: Discover how you can create iPad apps that take advantage of desktop class features. Join Mohammed from the UIKit team as we explore the latest navigation, collection view, menu, and editing APIs and learn best practices for building powerful iPad apps. Code along with this session in real time or download our sample app to use as a reference for updating your own code.

UINavigationItem style

  • .navigator - (default) behaves exactly as a traditional UINavigationBar
    • title is centered
    • there are leading and trailing bar button items
    • a back button appears when there is more than one item on the stack
  • .browser - rearranges contents to be better optimized for interfaces where history matters as much as location (e.g., Files.app, Safari.app)
    • title is leading aligned
  • .editor - optimized for when the primary function is document editing
    • title is leading aligned
    • editor UIs are often a destination, such as after selecting a document with a document picker, and so present a back button for easy access to that UI

Both .browser and .editor styles allow to add center items to take better advantage of screen real estate via the new centerItemGroups UINavigationItem instance property:

  • include support for UIBarButtonItemGroup

Overflow support is available in all modes (a button that, when tapped, shows more buttons)

  • allows the navigator style to indirectly support center items as well (as they will just be tucked away in this overflow button)

To allow navigation bar customization, set the customizationIdentifier

Example:

navigationItem.customizationIdentifier = "com.jetpack.blueprints.maineditor"
navigationItem.centerItemGroups = [
  // groups in the default customization
  UIBarButtonItem(title: "Insert", image: UIImage(systemName: "photo"), primaryAction: UIAction { _ in }).creatingFixedGroup(),
  UIBarButtonItem(title: "Draw", image: UIImage(systemName: "scribble"), primaryAction: UIAction { _ in }).creatingMovableGroup(customizationIdentifier: "Draw"),
  .optionalGroup(
    customizationIdentifier: "Shapes",
    representativeItem: UIBarButtonItem(title: "Shapes", image: UIImage(systemName: "square.on.circle")),
    items: [
        UIBarButtonItem(title: "Square", image: UIImage(systemName: "square"), primaryAction: UIAction { _ in }),
        UIBarButtonItem(title: "Circle", image: UIImage(systemName: "circle"), primaryAction: UIAction { _ in }),
        UIBarButtonItem(title: "Rectangle", image: UIImage(systemName: "rectangle"), primaryAction: UIAction { _ in }),
        UIBarButtonItem(title: "Diamond", image: UIImage(systemName: "diamond"), primaryAction: UIAction { _ in }),
      ]
  ),
  .optionalGroup(
    customizationIdentifier: "Text",
    items: [
      UIBarButtonItem(title: "Label", image: UIImage(systemName: "character.textbox"), primaryAction: UIAction { _ in }),
      UIBarButtonItem(title: "Text", image: UIImage(systemName: "text.bubble"), primaryAction: UIAction { _ in }),
    ]
  ),
  // additional group not in the default customization
  .optionalGroup(
    customizationIdentifier: "Format",
    isInDefaultCustomization: false,
    representativeItem: UIBarButtonItem(title: "BIU", image: UIImage(systemName: "bold.italic.underline")),
    items:[
      UIBarButtonItem(title: "Bold", image: UIImage(systemName: "bold"), primaryAction: UIAction { _ in }),
      UIBarButtonItem(title: "Italic", image: UIImage(systemName: "italic"), primaryAction: UIAction { _ in }),
      UIBarButtonItem(title: "Underline", image: UIImage(systemName: "underline"), primaryAction: UIAction { _ in }),
    ]
  )
]

Document interaction

UINavigationBar now supports adding a menu to the title view

  • add actions that operate on the content as a whole
  • share sheet support
  • drag & drop support

Default actions (these items are filtered based on specific methods in your responder chain):

  • Duplicate
  • Move
  • Rename
  • Export
  • Print

To enable the title menu, set the titleMenuProvider, which is a closure that returns the final menu to be displayed:

navigationItem.titleMenuProvider = { suggestedActions in
  var children = suggestedActions
  children += [
    UIAction(title: "Comments", image: UIImage(systemName: "text.bubble")) { _ in }
  ]
  return UIMenu(children: children)
}

To enable drag and drop and sharing from the menu:

let url = ...
let documentProperties = UIDocumentProperties(url: url)

if let itemProvider = NSItemProvider(contentsOf: url) {
  documentProperties.dragItemsProvider = { _ in
    [UIDragItem(itemProvider: itemProvider)]
  }

  documentProperties.activityViewControllerProvider = {
    UIActivityViewController(activityItems: [itemProvider], applicationActivities: nil)
  }
}

navigationItem.documentProperties = documentProperties

Inline Rename

Example:

class ViewController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    navigationItem.renameDelegate = self
  }
}

extension ViewController: UINavigationItemRenameDelegate {
  func navigationItem(_ navigationItem: UINavigationItem, didEndRenamingWith title: String) {
    // Try renaming our document, the completion handler will have the updated URL or return an error.
    documentBrowserViewController.renameDocument(at: <#T##URL#>, proposedName: title, completionHandler: <#T##(URL?, Error?) -> Void#>)
  }
}

Missing anything? Corrections? Contributions are welcome 😃

Related

Written by

Federico Zanetello

Federico Zanetello

Software engineer with a strong passion for well-written code, thought-out composable architectures, automation, tests, and more.