-
Qualities of a great Mac Catalyst app
Discover best practices, tools, and techniques to help craft the best possible Mac Catalyst app. We'll take you through key considerations when you bring your iPad app to macOS, explore detailed code examples for refining your interface and experience, and show you how to distribute your Mac app to everyone.
To get the most out of this session, we recommend a basic familiarity with Mac Catalyst. Watch “What's new in Mac Catalyst” from WWDC21 to get an overview of the latest features for bringing your iPad app to Mac. And for more on improving your macOS experience, watch “Optimize the interface of your Mac Catalyst app” from WWDC20.Ressources
- Building and improving your app with Mac Catalyst
- Bring an iPad App to the Mac with Mac Catalyst
- Accessibility design for Mac Catalyst
- Human Interface Guidelines: Mac Catalyst
- Mac Catalyst
- Adding menus and shortcuts to the menu bar and user interface
Vidéos connexes
WWDC21
- Focus on iPad keyboard navigation
- Meet the UIKit button system
- Qualities of great iPad and iPhone apps on Macs with M1
- Take your iPad apps to the next level
- What's new in Mac Catalyst
- What's new in UIKit
WWDC20
-
Rechercher dans cette vidéo…
-
-
6:50 - System button
let button = UIButton(type: .system) button.setTitle("Button", for: .normal) -
7:06 - Pull-down button
button.menu = UIMenu(...) button.showsMenuAsPrimaryAction = true -
7:44 - Pop-up button
button.menu = UIMenu(...) button.showsMenuAsPrimaryAction = true button.changesSelectionAsPrimaryAction = true -
8:24 - Checkbox
let checkbox = UISwitch() if checkbox.style == .checkbox { checkbox.title = "Checkbox" } -
13:20 - Delegating actions
final class MyView: UIView { override func target(forAction action: Selector, withSender sender: Any?) -> Any? { if action == #selector(Model.setAsFavorite(_:)) { return myModel } else { return super.target(forAction: action, withSender: sender) } } } -
14:43 - Requesting a new scene
let viewDetailActivityType = "viewDetail" let itemIDKey = "itemID" final class MyView: UIView { @objc func viewDoubleClicked(_ sender: Any?) { let userActivity = NSUserActivity(activityType: viewDetailActivityType) userActivity.userInfo = [itemIDKey: selectedItem.itemID] UIApplication.shared.requestSceneSessionActivation(nil, userActivity: userActivity, options: nil, errorHandler: { error in //... }) } //... } -
15:57 - Responding to a new scene request
let viewDetailActivityType = "viewDetail" final class AppDelegate: UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { if let activity = options.userActivities.first { if activity.activityType == viewDetailActivityType { return UISceneConfiguration(name: "DetailViewer", sessionRole:session.role) } } return UISceneConfiguration(name: "Default Configuration", sessionRole: session.role) } //... } -
17:13 - Setting item ID on new scene's root view controller
let itemIDKey = "itemID" final class SceneDelegate: UIWindowSceneDelegate { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options: UIScene.ConnectionOptions) { if let userActivity = connectionOptions.userActivities.first { if let itemId = userActivity.userInfo?[itemIDKey] as? ItemIDType { // Set item ID on new view controller } } //... } //... -
17:47 - Saving state for later restoration
final class SceneDelegate: UIWindowSceneDelegate { func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? { //... } } -
17:57 - State restoration
final class AppDelegate: UIApplicationDelegate { func application(_ application: UIApplication, configurationForConnecting session: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { //... } } -
18:42 - Handle both new scene requests and state restoration
let itemIDKey = "itemID" final class SceneDelegate: UIWindowSceneDelegate { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity { if let itemId = userActivity.userInfo?[itemIDKey] as? ItemIDType { // Set item ID on new view controller } } } } -
20:20 - Provide sharing configuration for the scene
final class RootViewController: UIViewController { override var activityItemsConfiguration: UIActivityItemsConfigurationReading? { get { UIActivityItemsConfiguration(objects: [image]) } //... } } -
20:56 - Support sharing through context menu
final class MyView: UIView { override var activityItemsConfiguration: UIActivityItemsConfigurationReading? { get { UIActivityItemsConfiguration(objects: images) } //... } func viewDidLoad() { let contextMenuInteraction = UIContextMenuInteraction(delegate: self) addInteraction(contextMenuInteraction) } } -
22:08 - Supporting continuity camera
final class MyView: UIView { override var pasteConfiguration: UIPasteConfiguration? { get { UIPasteConfiguration(forAcceptingClass: UIImage.self) } //... } func willMove(toWindow: UIWindow) { addInteraction(contextMenuInteraction) } override func paste(itemProviders: [NSItemProvider]) { for itemProvider in itemProviders { if itemProvider.canLoadObject(ofClass: UIImage.self) { if let image = try? await itemProvider.loadObject(ofClass:UIImage.self) { insertImage(image) } //...
-