iPadOS 15 Tutorial: What’s New for Builders

0
9


Whereas tablets don’t appear excessive precedence for many platform or gadget makers, Apple by no means stops enhancing iPad’s {hardware} and software program. In 2019, Apple renamed the pill’s working system iPadOS, emphasizing its distinctive multitasking and keyboard help. Persevering with Apple’s two-year cycle of appreciable iPadOS updates, iPadOS 15 presents many enhancements.

On this tutorial, you’ll find out about enhancements in iPadOS 15, together with:

  • Multitasking enhancements
  • Keyboard shortcuts enhancements
  • Pointer updates

You’ll do that whereas modernizing the app NotesLite, which you should utilize to write down notes and add photographs.

Getting Began

Obtain the starter challenge by clicking the Obtain Supplies button on the prime or backside of the tutorial.

The starter challenge comprises a completely purposeful app with options launched for iPadOS 14 and under. You’ll enhance the app by including new options launched in iPadOS 15 and making it look extra trendy and purposeful.

A number of Home windows or Scenes

In iPadOS 13, Apple launched the idea of scenes to help a number of home windows in iPad apps.

Home windows are represented by UIScene situations. A UISceneSession manages a scene. All through this tutorial, once you see a scene or UISceneSession, you’ll be able to consider it as a window.

If you happen to constructed an app earlier than iOS 13, AppDelegate is the one place that does every little thing associated to app launch, foregrounding, backgrounding and extra.

In iOS 13, Apple moved a few of AppDelegate‘s duties to SceneDelegate.

These days, software entry factors are inside AppDelegate, and window-related stuff — similar to backgrounding, foregrounding and URL dealing with — are inside an object conforming to UISceneDelegate or UIWindowSceneDelegate.

These additionally apply to iPhone apps. You’ll be able to consider an iPhone app as a single window software.

Every scene wants an occasion of UISceneConfiguration for its configuration. You outline these configurations inside Data.plist.

Now, you’ll see how all these join contained in the starter challenge.

Exploring NotesLite

Open the starter challenge and select an iPad goal. Then, construct and run.

NotesLite first run.

The picture above exhibits how the app works out of the field.

Faucet the plus button so a brand new window seems on the facet. Write your notice, add an image and faucet Save. The creation window closes and the newly added notice seems within the sidebar. Tapping the notice within the sidebar will present the element web page on the precise.

Be aware: Typically including a picture within the simulator doesn’t work as anticipated. If this occurs, strive including a unique picture or connecting your iPad and testing on gadget.

The app already helps a number of home windows. Check out the file construction:

NotesLite file and folder structure in Xcode

Contained in the Scenes folder are the three subclasses for UIWindowSceneDelegate:

  • First, there’s SceneDelegate for the default window of the app.
  • Then, there’s CreateSceneDelegate for the notice creation window.
  • Lastly, there’s DetailSceneDelegate for the notice element window.

If you opened the app, the default window appeared. After tapping the plus button, CreateSceneDelegate took over. You’ll add help for a element window later within the tutorial.

Contained in the Supporting Information folder, open Data.plist.

There’s a key known as Utility Scene Manifest whose worth is already within the starter challenge. You have to outline every scene configuration your app helps inside this key.

Info.plist for NotesLite app, showing the scene manifest key.

As you’ll be able to see within the screenshot above, it’s worthwhile to outline at the very least the Configuration Title and the Delegate Class Title to which this configuration relates.

NSUserActivity

In iOS 8, Apple launched a category known as NSUserActivity. At first, you possibly can use this class to combine the Handoff characteristic between gadgets.

Every year, this class turned extra highly effective. There’s even a operating joke locally that Apple may at some point deprecate all iOS APIs and launch every little thing underneath NSUserActivity‘s tent.

As of iOS 15, you’ll be able to — and will — use NSUserActivity in the event you help any of those options:

  • Handoff
  • In-app Highlight search
  • Siri and Shortcuts Intents
  • A number of home windows on iPad

If you need to open a brand new window inside your app, ask the system to create a scene utilizing requestSceneSessionActivation(_:userActivity:choices:errorHandler:) on UIApplication‘s shared object.

Nonetheless, you’ll be able to’t immediately specify a scene identify right here. You do that utilizing NSUserActivity. The system will provide you with again this occasion, and you’ll resolve which scene to configure and current.

Window Presentation Model

On iPadOS 14 and earlier, the consumer interface for managing an app’s home windows was so hidden and tough to make use of that even some professional customers prevented it. Happily, on iPadOS 15, this UI is significantly better.

On the prime of every app that helps Break up View and Slide Over, there’s a brand new button represented by three dots. With NotesLite open, faucet it.

Possible actions of three dots menu

Three buttons seem. This allows you to put the window in Full Display screen, Break up View or Slide Over with out going by the trouble of dragging and dropping. Hurray!

Nonetheless, these aren’t the one choices obtainable. In iPadOS 15, Apple added a brand new type to the window modes: Outstanding.

It seems a like a Type Sheet at first, however you’ll be able to simply put it in some other mode. Now, it’s time so as to add it to the app.

Open NotesListViewController.swift contained in the UI group. Go to openNewNote(). Right here’s what it seems like:


@objc func openNewNote() {
  // 1
  if UIDevice.present.userInterfaceIdiom == .pad {
    // 2
    let userActivity = ActivityIdentifier.create.userActivity()

    // 3
    let choices = UIWindowScene.ActivationRequestOptions()
    choices.preferredPresentationStyle = .commonplace

    // 4
    UIApplication.shared.requestSceneSessionActivation(
      nil,
      userActivity: userActivity,
      choices: choices,
      errorHandler: nil)
  } else {
    let navigationController = UINavigationController(
      rootViewController: NoteViewController.storyboardInstance)
    current(navigationController, animated: true)
  }
}

Right here’s what this does:

  1. Since iPhone apps don’t help a number of scenes, partition primarily based on the gadget the code is operating on.
  2. Create a userActivity utilizing a helper methodology from SceneConfigurations.swift.
  3. Subsequent, present the system with some activation choices. The system tries to think about these requests when activating a scene. This code asks the system to point out a commonplace presentation type. This type is what made the creation window seem alongside the principle window. On iPadOS 15, this feature defaults to automated, and the system decides what works finest.
  4. Request a scene activation with the consumer exercise and the request choices. This makes the brand new window seem.

Now, change the popular presentation type line to this:


choices.preferredPresentationStyle = .distinguished

Construct and run. Then, faucet the plus button.

Launching note creation window in prominent window style

A brand new window seems on prime of the present view.

There’s a tiny indicator that exhibits this isn’t a kind sheet or a normal modal presentation: the three dots button on the highest.

Faucet it, and also you’ll see a brand new possibility:

All four possible window modes on iPadOS 15 under the three dots button.

The icon speaks for itself. You requested the system to current this window prominently.

The three dots button does one other job, too. This time, as an alternative of tapping it, strive swiping it down. If you happen to look intently, the window goes someplace on the backside of the display. This space is the App Shelf. It’s a spot the place you’ll be able to see all open home windows for an app and change between them.

If an app has a number of energetic home windows, once you open it from Residence Display screen, the shelf seems for a cut up second. It’s also possible to summon the shelf at any time by tapping on the three dots button. Shut the home windows from the shelf by swiping up.

Right here’s a GIF for example these interactions:

App Shelf interactions

Subsequent, you’ll find out about activation actions.

Activation Motion

Per Apple’s tips, you solely have to open new home windows on your app primarily based on the consumer’s specific interplay. As you’ll be able to implement many of those interactions utilizing UIAction, Apple offered a code shortcut.

In NotesListViewController.swift, go to configureBarButtonItems(). Then, create an motion that calls openNewNote(), and fasten it to the bar button merchandise.

Do that by changing the present configureBarButtonItems() with this:


non-public func configureBarButtonItems() {
  // 1
  let addAction = UIAction { _ in
    let navigationController = UINavigationController(
      rootViewController: NoteViewController.storyboardInstance)
    self.current(navigationController, animated: true)
  }

  // 2
  let newSceneAction = UIWindowScene.ActivationAction(
    alternate: addAction
  ) { _ in
    // 3
    let userActivity = ActivityIdentifier.create.userActivity()

    let choices = UIWindowScene.ActivationRequestOptions()
    choices.preferredPresentationStyle = .distinguished

    // 4
    return UIWindowScene.ActivationConfiguration(
      userActivity: userActivity, 
      choices: choices)
  }

  // 5
  navigationItem.rightBarButtonItem = UIBarButtonItem(
    systemItem: .add,
    primaryAction: newSceneAction,
    menu: nil)
}

Right here’s what this does:

  1. First, create a UIAction that presents NoteViewController modally.
  2. Subsequent, create an occasion of UIWindowsScene.ActivationAction. Because the identify implies, you utilize it for activating a scene. Go the addAction you created in step 1 as a parameter to this operate. UIKit mechanically runs the alternate motion when the gadget doesn’t help a number of home windows. How handy is that?
  3. Then, create a consumer exercise for the notice creation scene and configure the request choices. You’re already acquainted with this step.
  4. Right here, you come back an occasion of UIWindowScene.ActivationConfiguration, passing the consumer exercise and choices. It’s like once you handed these things to requestSceneSessionActivation(_:userActivity:choices:errorHandler:).
  5. Since newSceneAction is definitely an occasion of UIAction, you set it as the first motion of the bar button merchandise.

Construct and run. Then, strive tapping the plus icon. If nothing adjustments, it means you had been profitable.

Activation Interplay

Whereas on iPadOS 14 and under, Apple insisted on Drag & Drop as the approach to open a brand new window, on iPadOS 15, it advertises context menus and a brand new pinch open gesture. Apple additionally built-in these in its personal apps. As an example, open the Notes app.

Within the sidebar, you’ll be able to contact and maintain or right-click with a mouse or trackpad to open the context menu. Selecting Open In New Window will open a notice in a brand new window with the distinguished type you noticed earlier.

Open In New Window option in Notes app context menu.

It’s also possible to pinch open with two fingers on any merchandise within the sidebar to open it in a brand new window, prominently.

Subsequent, you’ll add these choices to NotesLite.

Context Menu

In NotesListViewController.swift, scroll to the mark line // MARK: - UICollectionViewDelegate.

Have a look at collectionView(_:contextMenuConfigurationForItemAt:level:). This methodology provides context menu objects for every row. For now, it solely comprises delete. You’ll add a brand new motion for opening the notice in a brand new window.

First, although, it’s worthwhile to create a helper methodology for configuration, which you’ll use within the subsequent step. Add this inside NotesListViewController just under the definition of `deleteItem(at:)`:


non-public func activationConfiguration(
  for indexPath: IndexPath
) -> UIWindowScene.ActivationConfiguration? {
  // 1
  guard let notice = dataSource.itemIdentifier(for: indexPath) else {
    return nil
  }
  // 2  
  var data: [String: Any] = [
    NoteUserInfoKey.id.rawValue: note.id,
    NoteUserInfoKey.content.rawValue: note.content
  ]

  // 3
  if let information = notice.picture?.jpegData(compressionQuality: 1) {
    data[NoteUserInfoKey.image.rawValue] = information
  }

  // 4
  let userActivity = ActivityIdentifier.element.userActivity(userInfo: data)

  let choices = UIWindowScene.ActivationRequestOptions()
  choices.preferredPresentationStyle = .distinguished

  let configuration = UIWindowScene.ActivationConfiguration(
    userActivity: userActivity,
    choices: choices)
  return configuration
}

It seems slightly lengthy; nonetheless, it’s fairly easy:

  1. Get the notice pertaining to the indexPath from the collectionView‘s dataSource. It could return nil, so use guard-let syntax and exit the tactic early if the index is nil.
  2. The way in which to cross information to the system for creating a brand new window is thru consumer actions. Every consumer exercise has userInfo, in which you’ll be able to retailer property checklist information. Since userInfo makes use of a string-based key-value dictionary, lower potential errors through the use of some predefined keys, that are contained in the starter challenge. Right here, you retailer the notice’s id and content material.
  3. Verify if the notice has an related picture. If that’s the case, compress it to JPEG and put it aside to userInfo as Information.
  4. Like earlier than, create a consumer exercise, set the request choices and return a configuration made with them.

Now, return to // MARK: - UICollectionViewDelegate and exchange let actions = [delete] with the next:


// 1
var actions = [delete]

// 2
if let configuration = self.activationConfiguration(for: indexPath) {
  // 3
  let newSceneAction = UIWindowScene.ActivationAction { _ in
    return configuration
  }
  
  // 4
  actions.insert(newSceneAction, at: 0)
}

Within the code above, you:

  1. Change actions from a let to a var, so you’ll be able to add objects later.
  2. Get an occasion of UIWindowScene.ActivationConfiguration utilizing activationConfiguration(for:), which you’ll write later. Since it might be nil in sure instances, you conditionally unwrap it.
  3. Create a brand new activation motion as you probably did earlier, after which return the configuration you bought from step 2.
  4. Insert newSceneAction on the prime of actions.

As within the unique code, this returns a menu utilizing the desired actions.

Construct and run. Invoke the context menu within the notes checklist by touching and holding or right-clicking. You could now open the notice in a brand new window.

Open In New Window option in NotesLite context menu.

Note detail page opened in a new window prominently.

Subsequent, you’ll add pinch help on UICollectionView objects.

Pinching

First, implement a brand new delegate methodology. Add this on the finish of NotesListViewController.swift, simply earlier than the closing brace:


override func collectionView(
  _ collectionView: UICollectionView,
  sceneActivationConfigurationForItemAt
  indexPath: IndexPath,
  level: CGPoint
) -> UIWindowScene.ActivationConfiguration? {
  activationConfiguration(for: indexPath)
}

You come back an activation configuration for every merchandise you’d prefer to help pinching.

Construct and run. Then, strive pinching open on a notice.

Pinch on a note in the sidebar

The complete row will get greater whilst you pinch. You’ll be able to customise the transition in a means that solely the picture scales up. To do that, inform the system on which view the size transition ought to happen.

Open activationConfiguration(for:), and proper earlier than the return configuration line, add:


// 1
if let cell = collectionView.cellForItem(at: indexPath) {
  // 2
  if let imageView = cell.contentView.subviews.first(
    the place: { subview in
      (subview as? UIImageView)?.picture != nil
    }
  ) {
    // 3
    configuration.preview = UITargetedPreview(view: imageView)
  }
}

Right here’s what this does:

  1. First, get the cell the consumer pinched.
  2. Discover the imageView contained in the subviews of the cell’s contentView the place picture isn’t nil.
  3. Set the imageView you present in step 2 because the preview of the activation configuration.

Construct and run. Strive pinching yet one more time. It seems way more polished.

Pinch on the note in the sidebar. Transition begins from the image.

Be aware: To help this pinch gesture on views apart from cells in a UICollectionView, create a UIWindowScene.ActivationInteraction and fasten it to a customized view anyplace within the hierarchy. It’s straightforward to do, however past the scope of this tutorial.

Saving and Restoring State in Scenes

Offering polished, handy methods to open content material in new home windows is vital. Nonetheless, it’s equally vital to avoid wasting and restore the scene’s state to have the ability to return to it seamlessly.

When a scene strikes to the background, the system asks the scene’s delegate for an occasion of NSUserActivity to characterize its state.

For the most effective expertise, the scene state shouldn’t solely save the content material, but in addition the visible and interplay state similar to scroll and cursor place.

You must save and restore state for all of your app’s scenes, however for brevity, you’ll learn to save and restore the state just for the notice creation window.

To make saving and restoring simpler, Apple launched two new strategies in UISceneDelegate and its inherited object, UIWindowSceneDelegate.

Open CreateSceneDelegate.swift and add:


func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? {
  // 1
  guard
    let navigationController = window?.rootViewController 
      as? UINavigationController,
    let noteVC = navigationController.viewControllers.first 
      as? NoteViewController 
  else {
    return nil
  }

  // 2
  let stateActivity = ActivityIdentifier.create.userActivity()

  // 3
  var data: [String: Any] = [
    NoteUserInfoKey.content.rawValue: noteVC.textView.text ?? "",
    NoteUserInfoKey.contentInteractionState.rawValue: 
      noteVC.textView.interactionState
  ]
  if let picture = noteVC.selectedImage?.jpegData(compressionQuality: 1) {
    data[NoteUserInfoKey.image.rawValue] = picture
  }

  // 4
  stateActivity.addUserInfoEntries(from: data)

  return stateActivity
}

The system calls this methodology to avoid wasting the state for a scene. It returns a consumer exercise, which the system provides again to you once you need to restore the state.

Right here, you:

  1. Attempt to discover the occasion of NoteViewController, which is within the view hierarchy. If there isn’t any, you don’t have something to avoid wasting, so return nil.
  2. Create an empty consumer exercise for the notice creation web page, as you probably did once you wished to request a brand new window.
  3. Retailer the values of the textual content and interactionState properties of textView into the userInfo dictionary. interactionState is a brand new property of UITextField and UITextView on iPadOS 15 that permits you to save and restore cursor and scroll place. You additionally save the picture as Information if it’s obtainable.
  4. Add the contents of the data dictionary to the consumer exercise and return it.

To revive the state, implement the tactic under, extracting the information you saved into the consumer exercise and restoring it within the respective views. Add this methodology under the tactic you simply added in CreateSceneDelegate.swift:


func scene(
  _ scene: UIScene, 
  restoreInteractionStateWith stateRestorationActivity: NSUserActivity
) {
  // 1
  guard
    let navigationController = window?.rootViewController 
      as? UINavigationController,
    let noteVC = navigationController.viewControllers.first 
      as? NoteViewController,
    let userInfo = stateRestorationActivity.userInfo 
  else {
    return
  }

  // 2
  noteVC.viewType = .create

  // 3
  let picture: UIImage?
  if let information = userInfo[NoteUserInfoKey.image.rawValue] as? Information {
    picture = UIImage(information: information)
  } else {
    picture = nil
  }

  // 4
  let textual content = userInfo[NoteUserInfoKey.content.rawValue] as? String
  noteVC.textView.textual content = textual content ?? ""
  noteVC.selectedImage = picture

  // 5
  if let interactionState = 
    userInfo[NoteUserInfoKey.contentInteractionState.rawValue] {
      noteVC.textView.interactionState = interactionState
  }
}

Within the code above:

  1. First, you examine if the system has completed organising the view controllers. You additionally examine if there’s any userInfo obtainable to revive.
  2. Subsequent, you set the viewType of NoteViewController to .create. As you might have seen, NoteViewController is used for each creating and viewing a notice.
  3. Then, you examine if picture information is on the market inside userInfo. If it’s there and you’ll create a UIImage from it, you retailer its picture variable.
  4. Subsequent, you set the contents of textView and selectedImage.
  5. Lastly, after setting textual content on UITextView, you set interactionState if it’s obtainable. At all times set the interplay state after setting the content material.

That’s it. Construct and run.

Steps to trigger save and restore in a scene.

Now, comply with these directions to see the save and restore mechanism in motion:

  1. Run the app from Xcode.
  2. Faucet the plus button.
  3. Add some textual content and maybe a picture.
  4. Transfer the cursor to someplace aside from the top of the textual content.
  5. Swipe down on the three dots button of the note-creating window to attenuate it to the shelf.
  6. Kill the app from Xcode utilizing the Cease button. This can simulate the scenario the place the system kills the app course of.
  7. Run the app once more from Xcode.
  8. Faucet the New Be aware window from the shelf.
  9. Every part is there, even the cursor place.

Within the subsequent part, you’ll find out about keyboard enhancements.

Keyboard Shortcuts Enhancements

One attribute of a Mac app is its Menu Bar, a single place containing each potential motion for the app. After Apple began embracing the {hardware} keyboard for iPad, many individuals wished for a menu bar on iPad. On iPadOS 15, Apple fulfilled this want — type of!

Apps on iPad gained’t get a persistent menu bar like Mac apps. Moderately, once you maintain Command on the {hardware} keyboard related to the iPad, you’ll get a brand new menu system that appears much like the Mac implementation.

Listed below are among the options of this new system:

  1. Apps can categorize actions into teams.
  2. Customers can seek for obtainable actions, similar to on macOS.
  3. The system mechanically hides inactive actions as an alternative of disabling them.
  4. The API is much like the one used to create menu objects for a Catalyst app. Consequently, you don’t have to duplicate issues when including keyboard shortcuts for iPad and Mac Catalyst.

In NotesLite, there are a few keyboard shortcuts obtainable.

Particularly, NoteViewController comprises Save and Shut actions triggered by Command-S and Command-W. In NotesListViewController, you’ll be able to create a brand new notice by urgent Command-N.

See the shortcut motion teams obtainable proper now in NotesLite by holding the Command key:

Uncategorized keyboard shortcuts

The class for the motion is the identify of the app. When the builders of an app use the previous mechanism for offering keyboard shortcuts, that is the way it seems. Subsequent, you’ll replace to the fashionable strategy.

Updating to the Menu Builder API

One of many previous methods of including keyboard shortcuts help was overriding the keyCommands property of UIResponder. Since UIViewController is a UIResponder, you are able to do this in view controllers.

There are two occurrences of keyCommands in NotesLite. In NoteViewController.swift, you’ll see:


override var keyCommands: [UIKeyCommand]? {
  [
    UIKeyCommand(title: "Save", action: #selector(saveNote), 
      input: "s", modifierFlags: .command),
    UIKeyCommand(title: "Close", action: #selector(dismiss), 
      input: "w", modifierFlags: .command)
  ]
}

Take away keyCommands from NotesListViewController.swift and NoteViewController.swift. You need to use Xcode’s Discover characteristic.

Apple recommends defining all menu objects on your app at launch. To take action, open AppDelegate.swift.

Override buildMenu(with:), which is a technique on UIResponder:


override func buildMenu(with builder: UIMenuBuilder) {
  tremendous.buildMenu(with: builder)

  // 1
  guard builder.system == .essential else { return }

  // 2
  let newNoteMenu = UIMenu(
    choices: .displayInline,
    youngsters: [
      UIKeyCommand(
        title: "New Note",
        action: #selector(NotesListViewController.openNewNote),
        input: "n",
        modifierFlags: .command)
    ])

  // 3
  let saveMenu = UIMenu(
    choices: .displayInline,
    youngsters: [
      UIKeyCommand(
        title: "Save",
        action: #selector(NoteViewController.saveNote),
        input: "s",
        modifierFlags: .command)
    ])

  // 4
  let closeMenu = UIMenu(
    choices: .displayInline,
    youngsters: [
      UIKeyCommand(
        title: "Close",
        action: #selector(NoteViewController.dismiss),
        input: "w",
        modifierFlags: .command)
    ])

  // 5
  builder.insertChild(newNoteMenu, atStartOfMenu: .file)
  builder.insertChild(closeMenu, atEndOfMenu: .file)
  builder.insertChild(saveMenu, atEndOfMenu: .file)
}

Within the code above, you:

  1. Verify if the system is asking the menu builder API for the essential menu bar.
  2. Create UIMenu situations for all objects you need within the menu bar. Right here, you’re making a menu merchandise known as New Be aware with the keyboard shortcut Command-N. The selector for this motion is openNewNote() inside NotesListViewController.
  3. Make a menu merchandise for saving a notice. This time, the set off is inside NoteViewController.
  4. Create a menu merchandise for closing the notice window.
  5. Put menu objects in numerous system-defined teams, similar to File and Edit. You’ll be able to create a brand new class in the event you want.

Construct and run. Faucet the plus button or press Command-N, after which maintain the Command key.

Categorized keyboard shortcuts for note creation window

The system even added textual content enhancing shortcuts underneath the Edit menu without spending a dime. Who doesn’t like free stuff?

Be aware: If the shortcuts don’t seem, be sure you’re returning true in software(_:didFinishLaunchingWithOptions:) in AppDelegate.

Conditionally Disabling Sure Actions

There’s a small concern, although. What if you wish to conditionally disable sure actions? As an example, the Save motion doesn’t make sense when the NoteViewController isn’t in create mode.

To resolve this, override one other UIResponder methodology known as canPerformAction(_:withSender:). If you return true right here, the motion works; in any other case, it’ll get ignored. Add this methodology inside NoteViewController proper after viewDidLoad():


override func canPerformAction(
  _ motion: Selector, 
  withSender sender: Any?
) -> Bool {
  if motion == #selector(dismiss) { // 1
    return splitViewController == nil
  } else if motion == #selector(saveNote) { // 2
    return viewType == .create
  } else { // 3
    return tremendous.canPerformAction(motion, withSender: sender)
  }
}

Within the code above:

  1. The system calls this any time a selector reaches this view controller within the responder chain. Consequently, it’s worthwhile to examine for motion to behave primarily based on the enter. If it’s the dismiss selector, return true provided that splitViewController is nil. If you happen to offered this web page inside a brand new window, there could be no UISplitViewController concerned. Urgent Command-W will kill the app in the event you don’t do that examine.
  2. If the motion is saveNote, examine whether or not this view controller is in create mode.
  3. In any other case, let the system resolve.

Construct and run.

Hiding unrelated keyboard shortcuts in note detail page

Open a notice in a brand new window, and maintain the Command key. This time, the Save motion isn’t there anymore.

Pointer Enhancements

Apple launched pointer help in iPadOS 13.4. This 12 months, it bought its first set of enhancements.

Band Choice

The primary addition is band choice, a brand new pointer-specific multi-selection expertise acquainted to Mac customers.

In iPadOS 15, once you click on and drag in a non-list UICollectionView, the pointer stretches right into a rectangle, and the gathering view selects the objects the rectangle encompasses.

Any UICollectionView that helps the present one and two-finger multi-selection gestures by way of the shouldBeginMultiple Choice Interplay API will get this habits mechanically in iPadOS 15.

For something aside from a UICollectionView, the brand new UIBandSelectionInteraction API permits you to simply undertake this expertise.

Right here’s a GIF from the Information app:

Band selection in Files app on iPadOS 15

Pointer Equipment

The second addition to the system pointer is the power to connect equipment.

In iPadOS 14 and earlier, you possibly can present a customized form for the pointer in the event you desired. Nonetheless, for many use instances, you solely want so as to add sure equipment across the system pointer.

If you happen to look intently on the notice element web page, there’s a deal with on the backside of the picture. If you happen to contact and drag it, you’ll be able to resize the picture. You’ll add equipment to the pointer, so it’s clearer that you would be able to resize the picture vertically.

Resizing the image without pointer interactions

In NoteViewController.swift, discover dragHandler. On the finish of the didSet block, add:


let interplay = UIPointerInteraction(delegate: self)
dragHandler.addInteraction(interplay)

This creates a brand new pointer interplay, units the NoteViewController as its delegate and provides it to the interactions checklist of dragHandler.

To silence the compiler’s nagging, on the finish of the present file, add this:


extension NoteViewController: UIPointerInteractionDelegate {
  // 1
  func pointerInteraction(
    _ interplay: UIPointerInteraction, 
    styleFor area: UIPointerRegion
  ) -> UIPointerStyle? {
    // 2
    let preview = UITargetedPreview(view: dragHandler)

    // 3
    let type = UIPointerStyle(impact: .raise(preview))

    // 4
    type.equipment = [
      .arrow(.top),
      .arrow(.bottom)
    ]

    // 5
    area.latchingAxes = .vertical

    return type
  }
}

Within the code above, you:

  1. Override pointerInteraction(_:styleFor:). The system consults this methodology for a pointer’s type on a sure view.
  2. Create a focused preview with dragHandler. You recognize this API because you used it to customise the pinch transition.
  3. Create a pointer-style object with the raise impact. Different choices are spotlight and hover. Carry seems finest for this interplay.
  4. Add equipment across the pointer. Right here, you added two arrows to the highest and backside of the pointer. You’re not restricted to this, although. One can use a customized form with a customized place.
  5. Being able to set latchingAxes is new this 12 months. When set, the type related to this area will lock in and permit free-form motion alongside the desired axes.

Lastly, construct and run. If you happen to’re testing within the simulator, choose EnterShip Pointer to System from the I/O menu.

Resizing the image with pointer interactions and accessories.

Look how cool the pointer interplay is!

The place to Go From Right here?

You’ll be able to obtain the finished challenge information by clicking Obtain Supplies on the prime or backside of this tutorial.

When you’ve achieved loads at this time, iPadOS 15 is a stable launch and there’s extra to study.

Listed below are some locations to seek the advice of:

We hope you loved this tutorial. In case you have any questions or feedback, please be part of the discussion board dialogue under!

LEAVE A REPLY

Please enter your comment!
Please enter your name here