Chapters

Hide chapters

Auto Layout by Tutorials

First Edition · iOS 13 · Swift 5.1 · Xcode 11

Section II: Intermediate Auto Layout

Section 2: 10 chapters
Show chapters Hide chapters

Section III: Advanced Auto Layout

Section 3: 6 chapters
Show chapters Hide chapters

17. Auto Layout for External Displays
Written by Jayven Nhan

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Nowadays, using an external display goes well beyond merely connecting a monitor to a stationary computer. In recent years, more and more people are looking to connect their mobile devices to some type of external display — and as an app developer, it’s your responsibility to know how to handle this demand.

For iOS, there are currently three popular external display solutions:

  • AirPlay
  • Physical connections (cables)
  • Chromecast

Generally speaking, an iPhone user will often look for this type of functionality for:

  • Video playback: The iOS device becomes the video playback controller, and the external display becomes the core content provider.
  • Powerpoint presentations: The iOS device shows the slide notes to the presenter while the external display shows the slide content to the audience.
  • Gaming: The iOS device becomes the game controller, and the external display becomes the core content provider.

While this type of symbiotic relationship is common — where the device is the controller and the display shows the content — it’s not the only reason users rely on external displays. Some like to use external displays simply because they offer more screen real estate than their mobile counterparts. Whatever the reason may be, by adding support for external displays, you can provide a better overall experience for your users.

In this chapter, you’ll learn how to:

  • Build a layout for an external display.
  • Configure an external display window.
  • Handle new external display connections.
  • Handle existing external display connections.
  • Handle external display disconnections.
  • Accommodate different external display resolutions.

You’ll accomplish all of this by building a music playback app that supports external displays. By the end of this chapter, you’ll know how to support external displays in your iOS project, and in the process, you’ll gain greater clarity of using windows within your apps.

Getting started

Open ExternalDisplay.xcodeproj in the starter folder. Build and run the app on the simulator.

From within the Simulator app, select Hardware ▸ External Displays ▸ 1920×1080 (1080p). For now, you won’t see anything but a blank screen. Close the simulator, and return to Xcode.

The good news is that you can use the Auto Layout fundamentals you already know to build layouts for external displays — provided you understand the key differences.

Building a layout for an external display

Open Main.storyboard and look at MusicPlayerViewController. This will be the view controller for the external display.

Configuring an external display window

For every display that you plan to show to your users, you contain it inside of a view. A window is the parent of all views for a display, whether it’s an iPhone, iPad or external display. For supporting an additional external display, it’s paramount that you correctly create and manage the external display’s window to show separate content and present a smooth user experience to your users.

private func makeWindow(from screen: UIScreen) -> UIWindow {
  // 1
  let bounds = screen.bounds
  let window = UIWindow(frame: bounds)
  // 2
  window.screen = screen
  // 3
  window.rootViewController = musicPlayerViewController
  // 4
  window.isHidden = false
  return window
}
let storyboard = UIStoryboard(name: "Name", bundle: nil)
let viewController =
  storyboard.instantiateInitialViewController()
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = viewController
window?.makeKeyAndVisible()

Handling an existing external display connection

Your app can launch with or without an external display connection established. In this section, you’ll learn how to handle cases in which an external display is already connected.

// 1
let screens = UIScreen.screens
// 2
guard 
  screens.count > 1,
  let screen = screens.last 
  else { return }
// 3
let window = makeWindow(from: screen)
externalWindows.append(window)

Connecting a new external display

Although most people find at-most two external displays on their desk, Apple’s documentation doesn’t state the upper bound of simultaneously connected external displays. Whether you set up your app to support one or ten external displays, you need to implement business logic to deal with the connectivity of the displays. One way to do that is to observe external display event notifications.

// 1
notificationCenter.addObserver(
  forName: UIScreen.didConnectNotification,
  object: nil, 
  queue: nil) { [weak self] notification in
    // 2
    guard 
      let self = self,
      let screen = notification.object as? UIScreen
      else { return }
    // 3
    let window = self.makeWindow(from: screen)
    self.externalWindows.append(window)
}

Disconnecting an external display

Similar to the previous implementation, you’ll use NotificationCenter to handle disconnecting an external display connection.

// 1
notificationCenter.addObserver(
  forName: UIScreen.didDisconnectNotification,
  object: nil, 
  queue: nil) { [weak self] notification in
    // 2
    guard 
      let self = self,
      let screen = notification.object as? UIScreen
      else { return }
      
    // 3
    for (index, window) in self.externalWindows.enumerated() {
      guard window.screen == screen else { continue }
      self.externalWindows.remove(at: index)
    }
}

Accommodating external display resolutions

Depending on the external display size, you may want to display the UI differently. In this section, you’ll set the music genre label’s visibility based on the display resolution.

// 1
private func setMusicGenreLabelVisibility(screen: UIScreen) {
  // 2
  guard let currentMode = screen.currentMode else { return }
  // 3
  screen.availableModes.forEach {
    print("Available mode:", $0)
  }
  // 4
  let lowerBoundSize = CGSize(width: 1024, height: 768)
  // 5
  self.musicPlayerViewController.musicGenreLabel.isHidden =
    currentMode.size.width <= lowerBoundSize.width
}
self.setMusicGenreLabelVisibility(screen: screen)
// 1
notificationCenter.addObserver(
  forName: UIScreen.modeDidChangeNotification,
  object: nil, 
  queue: nil) { [weak self] notification in
    // 2
    guard 
      let self = self,
      let screen = notification.object as? UIScreen 
      else { return }
      
    // 3
    self.setMusicGenreLabelVisibility(screen: screen)
}

Key points

  • The two native external display solutions in iOS are AirPlay and a physical cable.
  • Use NotificationCenter to observe existing, new and disconnected external display connections.
  • Extract and adapt the app’s UI to the screen resolution using the external display screen mode attribute.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now