WWDC Quick Look 💓 By SwiftGGTeam
What's new in Mac Catalyst

What's new in Mac Catalyst

观看原视频

Highlight

macOS Monterey 为 Mac Catalyst 带来了四类原生 Mac 体验:四种按钮模式(Push/Toggle/Pull-down/Pop-up)、ToolTip 悬停提示、打印菜单集成、窗口副标题,让 iPad 应用在 Mac 上更像原生应用。

核心内容

按钮系统的 Mac 化

Mac 用户习惯了特定的按钮交互方式:Push Button 按下执行、Toggle Button 切换状态、Pull-down Menu 展开菜单、Pop-up Button 选择后标题跟随变化。iPad 应用直接搬到 Mac 上,按钮行为往往”不对味”。

macOS Monterey 通过两个属性解决了这个问题:showsMenuAsPrimaryActionchangesSelectionAsPrimaryAction。四个布尔组合对应四种按钮类型,代码只需几行。

悬停提示填补信息缺口

Mac 用户看到界面元素时,会本能地把鼠标悬停上去等待提示。iPad 应用没有这个功能,导致很多控件的含义要靠猜。

UIToolTipInteraction 让任何 UIView 都能显示悬停提示。UILabel 还支持 showsExpansionTextWhenTruncated,截断时悬停显示完整文本。

打印和窗口副标题

打印是 Mac 应用的基础功能。新增 UIApplicationSupportsPrintCommand plist 键自动添加 File > Print 菜单,printContent 响应者方法处理打印逻辑。

窗口副标题 scene.subtitle 为窗口标题栏增加上下文信息,比导航栏标题更符合 Mac 习惯。

详细内容

四种按钮配置(02:26

// Push Button — 标准按下按钮
let pushButton = UIButton(type: .system)

// Toggle Button — 点击切换选中状态
let toggleButton = UIButton(type: .system)
toggleButton.changesSelectionAsPrimaryAction = true

// Pull-down Menu — 点击展开菜单
let pullDownButton = UIButton(type: .system)
pullDownButton.menu = UIMenu()
pullDownButton.showsMenuAsPrimaryAction = true

// Pop-up Button — 选择后按钮标题跟随变化
let popupButton = UIButton(type: .system)
popupButton.menu = UIMenu()
popupButton.showsMenuAsPrimaryAction = true
popupButton.changesSelectionAsPrimaryAction = true

关键点:

  • showsMenuAsPrimaryAction = true:左键直接展开菜单(Mac 习惯),不再依赖长按或右键
  • changesSelectionAsPrimaryAction = true:按钮标题自动跟踪菜单中的选中项
  • 四种组合覆盖 Mac 上所有标准按钮类型
  • 采用 Mac idiom 时,未配置菜单的按钮通过长按触发菜单;iPad idiom 则通过右键

为控件添加 ToolTip(03:50

// 方式一:为任意 UIView 添加 ToolTip
let toolTipInteraction = UIToolTipInteraction(defaultToolTip: "Iguaçu Falls in Brazil")
imageView.addInteraction(toolTipInteraction)

// 方式二:为 UIControl 快速设置 ToolTip
let switchControl = UISwitch()
switchControl.toolTip = "Enable automatic updates"

// 方式三:截断标签悬停显示完整文本
let label = UILabel()
label.text = "Very long title that will be truncated"
label.showsExpansionTextWhenTruncated = true

关键点:

  • UIToolTipInteraction 适用于任意 UIView,需要创建 interaction 对象
  • UIControl 的 toolTip 属性是快捷方式,一行代码即可
  • showsExpansionTextWhenTruncated 只在文本被截断时显示 ToolTip,保持界面整洁

窗口副标题(06:01

// 在 scene 连接时设置副标题
func scene(_ scene: UIScene, willConnectTo session: UISceneSession,
           options connectionOptions: UIScene.ConnectionOptions) {
    scene.subtitle = "Countries"
}

// 或根据导航动态更新
func updateSubtitle(for selection: String) {
    guard let scene = view.window?.windowScene else { return }
    scene.subtitle = selection
}

关键点:

  • 副标题显示在窗口标题栏,比导航栏标题更符合 Mac 设计规范
  • 不同 toolbarStyle 下副标题的显示位置不同,需要实验调整
  • 适合展示当前选中项或应用状态上下文

打印支持(04:52

先在 Info.plist 中添加:

<key>UIApplicationSupportsPrintCommand</key>
<true/>

然后通过响应者链处理打印:

// DetailViewController.swift
override func printContent(_ sender: Any?) {
    let printInteractionController = UIPrintInteractionController.shared
    // 配置打印内容
    printInteractionController.present(animated: true)
}

override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    if action == #selector(self.printContent(_:)) {
        // 当前有选中内容时才允许打印
        return selectedItem != nil
    }
    return super.canPerformAction(action, withSender: sender)
}

// Root SplitViewController 中统一调度
override func target(forAction action: Selector, withSender sender: Any?) -> Any? {
    switch action {
    case #selector(UIResponder.printContent(_:)):
        // 根据业务逻辑决定由哪个子控制器处理打印
        return currentPrintTarget
    default:
        return super.target(forAction: action, withSender: sender)
    }
}

关键点:

  • UIApplicationSupportsPrintCommand 自动添加 File > Print 和 Export as PDF 菜单项
  • printContent 是 UIResponder 的新 action,通过响应者链查找实现
  • canPerformAction 控制当前状态下是否允许打印
  • target(forAction:withSender:) 在根控制器中统一调度,避免强制 becomeFirstResponder

保持 iPad 按钮样式(07:34

Mac idiom 默认使用原生 Mac 控件,但有时需要保持 iPad 风格的按钮(如大面积填充按钮):

let button = UIButton(configuration: .filled(), primaryAction: nil)
button.configuration?.image = UIImage(systemName: "leaf")
button.preferredBehavioralStyle = .pad
button.configuration?.preferredSymbolConfigurationForImage =
    UIImage.SymbolConfiguration(pointSize: 60)
button.changesSelectionAsPrimaryAction = true
button.configurationUpdateHandler = colorUpdateHandler

关键点:

  • preferredBehavioralStyle = .pad 强制使用 iPad 布局行为,按钮背景会拉伸填充
  • 仅在特定控件上使用,不建议全局采用
  • 与 Mac idiom 的 77% 缩放规则不同,iPad 样式保持原始大小

核心启发

  1. 做什么:为现有的 iPad 笔记应用添加 Mac Catalyst 支持,用 ToolTip 展示工具栏按钮功能

    • 为什么值得做:Mac 用户依赖悬停提示理解界面,添加 ToolTip 后应用 instantly 更像原生 Mac 应用
    • 怎么开始:为每个工具栏按钮设置 toolTip 属性,为截断的文档标题启用 showsExpansionTextWhenTruncated
  2. 做什么:在 Mac 版文件管理应用中加入打印功能,支持打印当前选中的文件列表

    • 为什么值得做:打印是 Mac 用户的基础预期,UIApplicationSupportsPrintCommand 一行 plist 配置就能添加标准菜单
    • 怎么开始:添加 plist 键,在文件列表控制器中实现 printContentcanPerformAction
  3. 做什么:为 Mac 版设置应用使用 Pop-up Button 替代原来的 Segmented Control

    • 为什么值得做:Pop-up Button 是 Mac 标准控件,比 Segmented Control 更节省空间且符合用户习惯
    • 怎么开始:用 UIButton + changesSelectionAsPrimaryAction = true + showsMenuAsPrimaryAction = true 创建 Pop-up Button
  4. 做什么:在 Mac 版浏览器/文件管理器中使用窗口副标题展示当前路径

    • 为什么值得做:副标题比导航栏标题更符合 Mac 设计规范,且不占用内容区域空间
    • 怎么开始:在 UISceneDelegate 中设置 scene.subtitle,在导航变化时更新

关联 Session

评论

GitHub Issues · utterances