Whereas tablets donāt appear excessive precedence for many platform or system makers, Apple by no means stops bettering 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 use to put in writing notes and add photographs.
Getting Began
Obtain the starter undertaking by clicking the Obtain Supplies button on the prime or backside of the tutorial.
The starter undertaking incorporates a completely practical app with options launched for iPadOS 14 and beneath. Youāll enhance the app by including new options launched in iPadOS 15 and making it look extra fashionable and practical.
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 cases. A UISceneSession manages a scene. All through this tutorial, if you see a scene or UISceneSession, you possibly can consider it as a window.
Should you constructed an app earlier than iOS 13, you recognize AppDelegate is the one place that does all the things associated to app launch, foregrounding, backgrounding and extra.
In iOS 13, Apple moved a few of AppDelegateās tasks to SceneDelegate.
These days, utility 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 utility.
Every scene wants an occasion of UISceneConfiguration for its configuration. You outline these configurations inside Information.plist.
Now, youāll see how all these join contained in the starter undertaking.
Exploring NotesLite
Open the starter undertaking and select an iPad goal. Then, construct and 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 aspect. Write your be aware, add an image and faucet Save. The creation window closes and the newly added be aware seems within the sidebar. Tapping the be aware within the sidebar will present the element web page on the precise.
Be aware: Generally 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 system.
The app already helps a number of home windows. Check out the file construction:
Contained in the Scenes folder are the three subclasses for UIWindowSceneDelegate:
- First, thereās
SceneDelegatefor the default window of the app. - Then, thereās
CreateSceneDelegatefor the be aware creation window. - Lastly, thereās
DetailSceneDelegatefor the be aware element window.
Whenever 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 Recordsdata folder, open Information.plist.
Thereās a key known as Software Scene Manifest whose worth is already within the starter undertaking. It is advisable outline every scene configuration your app helps inside this key.
As you possibly can see within the screenshot above, you should outline no less than the Configuration Identify and the Delegate Class Identify to which this configuration relates.
NSUserActivity
In iOS 8, Apple launched a category known as NSUserActivity. At first, you would use this class to combine the Handoff characteristic between units.
Annually, this class turned extra highly effective. Thereās even a operating joke in the neighborhood that Apple would possibly sooner or later deprecate all iOS APIs and launch all the things below NSUserActivityās tent.
As of iOS 15, you possibly can ā 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
Whenever you wish 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 possibly canāt straight specify a scene identify right here. You do that utilizing NSUserActivity. The system offers you again this occasion, and you may resolve which scene to configure and current.
Window Presentation Type
On iPadOS 14 and earlier, the person interface for managing an appās home windows was so hidden and tough to make use of that even some professional customers prevented it. Fortuitously, on iPadOS 15, this UI is significantly better.
On the prime of every app that helps Cut up View and Slide Over, thereās a brand new button represented by three dots. With NotesLite open, faucet it.
Three buttons seem. This allows you to put the window in Full Display screen, Cut up View or Slide Over with out going by way of the trouble of dragging and dropping. Hurray!
Nonetheless, these arenāt the one choices accessible. In iPadOS 15, Apple added a brand new fashion to the window modes: Distinguished.
It seems a like a Kind Sheet at first, however you possibly can simply put it in another 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 = .customary
// 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:
- Since iPhone apps donāt help a number of scenes, partition primarily based on the system the code is operating on.
- Create a
userActivityutilizing a helper technique from SceneConfigurations.swift. - Subsequent, present the system with some activation choices. The system tries to contemplate these requests when activating a scene. This code asks the system to indicate a
customarypresentation fashion. This fashion is what made the creation window seem alongside the principle window. On iPadOS 15, this feature defaults toautomated, and the system decides what works greatest. - Request a scene activation with the person exercise and the request choices. This makes the brand new window seem.
Now, change the popular presentation fashion line to this:
choices.preferredPresentationStyle = .distinguished
Construct and run. Then, faucet the plus button.
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 standard modal presentation: the three dots button on the highest.
Faucet it, and also youāll see a brand new choice:
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. Should you look carefully, the window goes someplace on the backside of the display. This space is the App Shelf. Itās a spot the place you possibly can see all open home windows for an app and change between them.
If an app has a number of lively home windows, if you open it from House Display screen, the shelf seems for a break 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 instance these interactions:
Subsequent, youāll find out about activation actions.
Activation Motion
Per Appleās pointers, you solely have to open new home windows in your app primarily based on the personās specific interplay. As you possibly can implement many of those interactions utilizing UIAction, Apple supplied 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:
- First, create a
UIActionthat presentsNoteViewControllermodally. - Subsequent, create an occasion of
UIWindowsScene.ActivationAction. Because the identify implies, you utilize it for activating a scene. Go theaddActionyou created in step 1 as a parameter to this operate.UIKitrobotically runs thealternatemotion when the system doesnāt help a number of home windows. How handy is that? - Then, create a person exercise for the be aware creation scene and configure the request choices. Youāre already acquainted with this step.
- Right here, you come back an occasion of
UIWindowScene.ActivationConfiguration, passing the person exercise and choices. Itās like if you handed this stuff torequestSceneSessionActivation(_:userActivity:choices:errorHandler:). - Since
newSceneActionis definitely an occasion ofUIAction, 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 have been profitable.
Activation Interplay
Whereas on iPadOS 14 and beneath, Apple insisted on Drag & Drop as the method 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 illustration, open the Notes app.
Within the sidebar, you possibly can contact and maintain or right-click with a mouse or trackpad to open the context menu. Selecting Open In New Window will open a be aware in a brand new window with the distinguished fashion you noticed earlier.
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.
Take a look at collectionView(_:contextMenuConfigurationForItemAt:level:). This technique provides context menu objects for every row. For now, it solely incorporates delete. Youāll add a brand new motion for opening the be aware in a brand new window.
First, although, you should create a helper technique for configuration, which youāll use within the subsequent step. Add this inside NotesListViewController slightly below the definition of `deleteItem(at:)`:
non-public func activationConfiguration(
for indexPath: IndexPath
) -> UIWindowScene.ActivationConfiguration? {
// 1
guard let be aware = dataSource.itemIdentifier(for: indexPath) else {
return nil
}
// 2
var information: [String: Any] = [
NoteUserInfoKey.id.rawValue: note.id,
NoteUserInfoKey.content.rawValue: note.content
]
// 3
if let knowledge = be aware.picture?.jpegData(compressionQuality: 1) {
information[NoteUserInfoKey.image.rawValue] = knowledge
}
// 4
let userActivity = ActivityIdentifier.element.userActivity(userInfo: information)
let choices = UIWindowScene.ActivationRequestOptions()
choices.preferredPresentationStyle = .distinguished
let configuration = UIWindowScene.ActivationConfiguration(
userActivity: userActivity,
choices: choices)
return configuration
}
It seems fairly lengthy; nonetheless, itās fairly easy:
- Get the
be awarepertaining to theindexPathfrom thecollectionViewāsdataSource. It could returnnil, so useguard-letsyntax and exit the tactic early if the index isnil. - The way in which to cross knowledge to the system for creating a brand new window is thru person actions. Every person exercise has
userInfo, in which you’ll retailer property record knowledge. SinceuserInfomakes use of a string-based key-value dictionary, lower potential errors by utilizing some predefined keys, that are contained in the starter undertaking. Right here, you retailer the be awareāsidandcontent material. - Examine if the be aware has an related picture. In that case, compress it to JPEG and reserve it to
userInfoasKnowledge. - Like earlier than, create a person exercise, set the request choices and return a configuration made with them.
Now, return to // MARK: - UICollectionViewDelegate and substitute 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:
- Change
actionsfrom aletto avar, so you possibly can add objects later. - Get an occasion of
UIWindowScene.ActivationConfigurationutilizingactivationConfiguration(for:), which youāll write later. Since it could benilin sure instances, you conditionally unwrap it. - Create a brand new activation motion as you probably did earlier, after which return the configuration you bought from step 2.
- Insert
newSceneActionon the prime ofactions.
As within the authentic code, this returns a menu utilizing the desired actions.
Construct and run. Invoke the context menu within the notes record by touching and holding or right-clicking. It’s possible you’ll now open the be aware in a brand new window.
Subsequent, youāll add pinch help on UICollectionView objects.
Pinching
First, implement a brand new delegate technique. 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 an activation configuration for every merchandise youād wish to help pinching.
Construct and run. Then, strive pinching open on a be aware.
All the 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:
- First, get the cell the person pinched.
- Discover the
imageViewcontained in the subviews of the cellāscontentViewthe placepictureisnātnil. - Set the
imageViewyou present in step 2 because thepreviewof the activation configuration.
Construct and run. Strive pinching another time. It seems rather more polished.
Be aware: To help this pinch gesture on views aside 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 essential. Nonetheless, itās equally essential 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 one of the best expertise, the scene state shouldn’t solely save the content material, but additionally the visible and interplay state similar to scroll and cursor place.
It’s best to 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 be aware 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 information: [String: Any] = [
NoteUserInfoKey.content.rawValue: noteVC.textView.text ?? "",
NoteUserInfoKey.contentInteractionState.rawValue:
noteVC.textView.interactionState
]
if let picture = noteVC.selectedImage?.jpegData(compressionQuality: 1) {
information[NoteUserInfoKey.image.rawValue] = picture
}
// 4
stateActivity.addUserInfoEntries(from: information)
return stateActivity
}
The system calls this technique to avoid wasting the state for a scene. It returns a person exercise, which the system provides again to you if you wish to restore the state.
Right here, you:
- 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 returnnil. - Create an empty person exercise for the be aware creation web page, as you probably did if you wished to request a brand new window.
- Retailer the values of the
textual contentandinteractionStateproperties oftextViewinto theuserInfodictionary.interactionStateis a brand new property ofUITextFieldandUITextViewon iPadOS 15 that allows you to save and restore cursor and scroll place. You additionally save thepictureasKnowledgeif itās accessible. - Add the contents of the
informationdictionary to the person exercise and return it.
To revive the state, implement the tactic beneath, extracting the information you saved into the person exercise and restoring it within the respective views. Add this technique beneath 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 knowledge = userInfo[NoteUserInfoKey.image.rawValue] as? Knowledge {
picture = UIImage(knowledge: knowledge)
} 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:
- First, you verify if the system has completed establishing the view controllers. You additionally verify if thereās any
userInfoaccessible to revive. - Subsequent, you set the
viewTypeofNoteViewControllerto.create. As you will have observed,NoteViewControlleris used for each creating and viewing a be aware. - Then, you verify if picture knowledge is out there inside
userInfo. If itās there and you may create aUIImagefrom it, you retailer itspicturevariable. - Subsequent, you set the contents of
textViewandselectedImage. - Lastly, after setting
textual contentonUITextView, you setinteractionStateif itās accessible. At all times set the interplay state after setting the content material.
Thatās it. Construct and run.
Now, observe these directions to see the save and restore mechanism in motion:
- Run the app from Xcode.
- Faucet the plus button.
- Add some textual content and maybe a picture.
- Transfer the cursor to someplace aside from the tip of the textual content.
- Swipe down on the three dots button of the note-creating window to attenuate it to the shelf.
- Kill the app from Xcode utilizing the Cease button. It will simulate the state of affairs the place the system kills the app course of.
- Run the app once more from Xcode.
- Faucet the New Be aware window from the shelf.
- Every thing 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 receivedāt get a persistent menu bar like Mac apps. Somewhat, if you maintain Command on the {hardware} keyboard linked to the iPad, youāll get a brand new menu system that appears just like the Mac implementation.
Listed below are a number of the options of this new system:
- Apps can categorize actions into teams.
- Customers can seek for accessible actions, similar to on macOS.
- The system robotically hides inactive actions as an alternative of disabling them.
- The API is just like the one used to create menu objects for a Catalyst app. In consequence, you donāt have to duplicate issues when including keyboard shortcuts for iPad and Mac Catalyst.
In NotesLite, there are a few keyboard shortcuts accessible.
Particularly, NoteViewController incorporates Save and Shut actions triggered by Command-S and Command-W. In NotesListViewController, you possibly can create a brand new be aware by urgent Command-N.
See the shortcut motion teams accessible proper now in NotesLite by holding the Command key:
The class for the motion is the identify of the app. When the builders of an app use the outdated mechanism for offering keyboard shortcuts, that is the way it seems. Subsequent, youāll replace to the trendy method.
Updating to the Menu Builder API
One of many outdated 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 in 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:
- Examine if the system is looking the menu builder API for the
essentialmenu bar. - Create
UIMenucases 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 isopenNewNote()inside NotesListViewController. - Make a menu merchandise for saving a be aware. This time, the set off is inside NoteViewController.
- Create a menu merchandise for closing the be aware window.
- 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 need.
Construct and run. Faucet the plus button or press Command-N, after which maintain the Command key.
The system even added textual content enhancing shortcuts below the Edit menu at no cost. Who doesnāt like free stuff?
Be aware: If the shortcuts donāt seem, ensure youāre returning true in utility(_:didFinishLaunchingWithOptions:) in AppDelegate.
Conditionally Disabling Sure Actions
Thereās a small challenge, although. What if you wish to conditionally disable sure actions? As an illustration, the Save motion doesnāt make sense when the NoteViewController isnāt in create mode.
To resolve this, override one other UIResponder technique known as canPerformAction(_:withSender:). Whenever you return true right here, the motion works; in any other case, itāll get ignored. Add this technique 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:
- The system calls this any time a selector reaches this view controller within the responder chain. In consequence, you should verify for
motionto behave primarily based on the enter. If itās thedismissselector, returntrueprovided thatsplitViewControllerisnil. Should you offered this web page inside a brand new window, there can be noUISplitViewControllerconcerned. Urgent Command-W will kill the app in the event you donāt do that verify. - If the motion is
saveNote, verify whether or not this view controller is increatemode. - In any other case, let the system resolve.
Construct and run.
Open a be aware 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 yr, it acquired 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, if 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 robotically in iPadOS 15.
For something aside from a UICollectionView, the brand new UIBandSelectionInteraction API lets you simply undertake this expertise.
Right hereās a GIF from the Recordsdata app:
Pointer Equipment
The second addition to the system pointer is the power to connect equipment.
In iPadOS 14 and earlier, you would 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.
Should you look carefully on the be aware element web page, thereās a deal with on the backside of the picture. Should you contact and drag it, you possibly can resize the picture. Youāll add equipment to the pointer, so itās clearer which you can resize the picture vertically.
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 record 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 fashion = UIPointerStyle(impact: .carry(preview))
// 4
fashion.equipment = [
.arrow(.top),
.arrow(.bottom)
]
// 5
area.latchingAxes = .vertical
return fashion
}
}
Within the code above, you:
- Override
pointerInteraction(_:styleFor:). The system consults this technique for a pointerās fashion on a sure view. - Create a focused preview with
dragHandler. You already know this API because you used it to customise the pinch transition. - Create a pointer-style object with the
carryimpact. Different choices arespotlightandhover. Carry seems greatest for this interplay. - 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.
- Being able to set
latchingAxesis new this yr. When set, the fashion related to this area will lock in and permit free-form motion alongside the desired axes.
Lastly, construct and run. Should youāre testing within the simulator, choose Enter āø Ship Pointer to System from the I/O menu.
Look how cool the pointer interplay is!
The place to Go From Right here?
You’ll be able to obtain the finished undertaking information by clicking Obtain Supplies on the prime or backside of this tutorial.
When youāve completed rather a lot in the present day, 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. When you’ve got any questions or feedback, please be part of the discussion board dialogue beneath!

























































