面向开发者的 Touch on Mac:36 点、手势识别器与 Sidecar

Mac 上的触控会给 Mac 开发者带来哪些改变? 现有应用照常可用,因为 “macOS automatically translates touches into clicks”(macOS 会自动把触控转换为点按);三场 Tech Talks 给出了规则:手势识别器是 “the only way to get direct touches on macOS”(在 macOS 上获取直接触控的唯一途径),标准控件原生支持触控,触控目标为 36 点,悬停没有对应的触控操作,而通过 Sidecar 连接的 iPad 就是测试设备。1234 触控 API 已经在 macOS 27.0 SDK 里;系统手势开关和可在 macOS 上使用的 ActivityKit 则不在,至少在我检查过的两个 SDK 里没有,而 Xcode 27.3 beta 仍标着 “Coming soon”(即将推出)。25678

太长不看: Apple 为 MacBook Pro with PROLED XDR Display(14.2 英寸与 16.3 英寸,10月28日 开始预订,11月6日 进店)发布了 Touch,并在 10月28日 通过三场演讲告诉开发者如何适配。129 如果您的应用使用标准 AppKit 控件、SwiftUI 手势或 Mac Catalyst,演讲说它们 “just work”(直接可用),但下文的审查清单(点击目标、悬停)依然适用。自定义的 mouseDown(with:) 代码会一直处于模拟状态,直到改用控件事件或手势识别器;非 Apple 的 UI 框架则得到一层通用的模拟,一旦应用自己处理触控,就可以用 NSIsTouchNative 把它关掉。36 在 AppKit 中要接收直接触控,必须使用手势识别器,因为触控永远不会进入响应者链或事件监视器。36 设计演讲把触控目标定为 36 点,与 iOS 上的 44 点物理尺寸相同,并说明 macOS 有没有触控,外观都一样。4 测试请用通过 Sidecar 连接的 iPad;最新的组合是 macOS 27.2 和 Xcode 27.2 RC,这套配置我还没有跑过。311 触控 API 已经在 macOS 27.0 SDK 里。系统手势开关和可在 macOS 上使用的 ActivityKit,在我检查过的两个 SDK 里都没有,而 Xcode 27.3 beta 仍标着 “Coming soon”。2378

Apple 发布了什么,又没有发布什么

Apple 的发布是一篇新闻稿,而不是主题演讲;当天的完整记录见实时追踪文章。新闻稿中面向开发者的内容只有 “Touch Arrives on Mac” 一节里的三句话:先是 “Apple apps are optimized for the new MacBook Pro, and many existing apps work with Touch right away, because macOS automatically translates touches into clicks”(Apple 应用已针对新 MacBook Pro 优化,许多现有应用也能立即配合 Touch 使用,因为 macOS 会自动把触控转换为点按),接着是 “Updated system gesture APIs also enable developers to create intuitive experiences designed specifically for Touch”(更新后的系统手势 API 也让开发者能够打造专为 Touch 设计的直观体验),最后说明 “app developers can test how Touch performs in their iOS and iPadOS apps directly on the MacBook Pro display”(应用开发者可以直接在 MacBook Pro 显示屏上测试其 iOS 和 iPadOS 应用的 Touch 表现)。1 关于 macOS 的那一节说这台笔记本 “comes to life with macOS 27”,并提到 “Touch built for macOS 27”;它没有点名任何小版本。1

开发者这边在太平洋时间上午 11:47 之前已经上线:一篇新闻文章 “Say hello to Touch on Mac”,一个落地页 “Get ready for Touch on Mac”,内含三场 Tech Talks、11月18日 与 11月19日 的 Group Labs,以及三个标着 “Coming soon” 的板块:“Xcode 27.3 beta”、“Documentation resources” 和 “Design resources”。2 页面的 HTML 里,Apple 打算挂在这些板块上的链接放在注释中,标明待资源上线时重新启用:一篇 AppKit 文章 “Adopting gesture recognizers in your app”(目前返回 404)、现有的文件承诺(file promises)拖放示例,以及其他链接中的四个「人机界面指南」页面和 Apple Design Resources;我抓取的这些 HIG 页面都没有关于 Mac 显示屏触控的指导,Live Activities 页面的更新日志止于 10月13日。2710

因此,规则的一手来源是这几场演讲,以及 Apple 于 6月8日 发布的一篇技术说明 “TN3212: Adopting gesture recognizers for Sidecar touch support”。它的 Overview 写道 “In macOS 27, AppKit continues to standardize on gesture recognizers as the primary mechanism for input handling”(在 macOS 27 中,AppKit 继续以手势识别器作为输入处理的主要机制),而 “Explore updated APIs in macOS 27”、“Detect touch capability”、“Handle control events” 和 “Configure scroll behavior” 几节描述的 API 范围,正是 10月28日 的演讲所演示的。6 技术说明点名的每一个新符号,都出现在 Apple 文档中,introducedAt 为 macOS 27.0,没有 beta 标记(10月28日 中午太平洋时间获取);除两个 Info.plist 键外,它们也都已在 Xcode 27.1(27A9275)所带的 macOS 27.0 SDK 中声明,这是我在这台 Mac 上查看头文件和 Swift 接口得出的(作者分析)。7 演讲点名的三个系统手势符号不在其中,可在 macOS 上使用的 ActivityKit 也不在;两者都在下文讨论。

什么都不用做,也能得到什么

兼容性方面相当宽厚。AppKit 演讲开场就说:“The good news is that we’ve already made touch work great out of the box for all apps. Across our native frameworks, standard components just work with native touch. Existing gestures created in SwiftUI just work”(好消息是,我们已经让所有应用开箱即用地良好支持触控。在我们的原生框架中,标准组件直接支持原生触控,用 SwiftUI 创建的现有手势也直接可用)(0:30),Mac Catalyst 也一样 (0:52)。3 在 AppKit 中,“Standard buttons, controls, tables, collections, split views, tabs, scrolling, and more are all touch native” (1:10)。3

不是原生支持的部分会被模拟:“for existing custom AppKit mouse interactions, or if you use non-Apple UI frameworks, AppKit intelligently emulates the mouse”(对于现有的自定义 AppKit 鼠标交互,或者使用非 Apple 的 UI 框架时,AppKit 会智能地模拟鼠标)(1:17)。3 技术说明为第三方框架逐条写明了模拟方式:“A tap emulates a mouse-down followed immediately by a mouse-up”、“A touch and immediate pan emulates trackpad scroll events, even if the UI doesn’t respond to them”、“A long press without movement emulates a rightMouseDown(with:) (optionally followed by rightMouseDragged(with:)) with a rightMouseUp(with:) on touch lift”,以及 “A two-finger pinch or rotation simultaneously emulates both the trackpad magnify and rotate gestures”。6 演讲的说法是:“a one-finger scroll with momentum, click, drag with a small hold delay, and even pinch for rotation and magnification” (11:28)。3 这种模拟以窗口为单位,而且是通用的,因为 “AppKit can’t determine what kind of interactions are allowed at any particular location of your non-Apple UI framework content”(AppKit 无法判断非 Apple UI 框架内容中任一位置允许哪种交互)(11:17)。3

一旦加入了原生支持,就可以关闭模拟:“add an NSIsTouchNative entry to your Info.plist to let AppKit know you are touch native and no longer need the non-Apple UI toolkit mouse emulations” (11:47)。3 该键的文档标注为 macOS 27.0,页面上写着 “Most AppKit apps don’t need this key. It’s primarily intended for apps that embed a non-AppKit rendering or input framework and implement their own touch-handling pipeline.”(大多数 AppKit 应用不需要这个键,它主要面向嵌入了非 AppKit 渲染或输入框架、并自行实现触控处理流程的应用。)7

设计演讲的表述,决定了「什么都不用做」在视觉上意味着什么:“macOS on a device that supports touch doesn’t look any different than macOS on a device that doesn’t. The resolution, the size of windows, text and UI controls haven’t changed” (0:41),以及 “Touch is a secondary input for macOS, and therefore has little impact on how macOS looks”(触控是 macOS 的辅助输入方式,因此对 macOS 的外观影响很小)(1:06)。4 没有触控模式,也没有紧凑布局。这与 iPhone Duo 的情况正好相反,在那台设备上,内屏在两个维度上都报告 regular 尺寸类别。

手势识别器是唯一的入口

统领其余一切的那句话出现在 AppKit 演讲的 3:45:“In fact, gesture recognizers are the only way to get direct touches on macOS.”(事实上,手势识别器是在 macOS 上获取直接触控的唯一途径。)3 在此之前是 “Starting with macOS Golden Gate, gesture recognizers are the preferred approach in AppKit” (3:33),以及 “gesture recognizers have become the shared input language across SwiftUI, Mac Catalyst, and now AppKit”(手势识别器已经成为 SwiftUI、Mac Catalyst 以及如今 AppKit 共通的输入语言)(3:38)。3 技术说明从另一个方向说了同一件事:“AppKit doesn’t deliver Sidecar touch events through the responder chain or through event monitors”(AppKit 不会通过响应者链或事件监视器传递 Sidecar 触控事件),并在一条注释中写道 “Local and global event monitors don’t receive touch events. Touch events don’t go through NSApp or sendEvent(_:).”6

这对一个 AppKit 代码库有三层影响。

第一,跟踪循环。演讲中的工程师重建了一个接线谜题,原本用的是 “a custom NSView with a mouseDown(with:) override that uses the standard tracking loop technique”(一个重写了 mouseDown(with:)、采用标准跟踪循环技巧的自定义 NSView)(3:13),反复调用 nextEvent(matching:) 直到鼠标松开;他说 “Migrate your mouse tracking loops to gesture recognizers” (3:51)。3 迁移不必一步到位:“tracking loops are still supported and can coexist with touch-only gesture recognizers. You may find that adding touch-only gesture recognizers is the fastest and least risky path for a dot release of your app”(跟踪循环仍受支持,并且可以与仅限触控的手势识别器共存。对于应用的小版本更新,添加仅限触控的手势识别器可能是最快、风险最低的路径)(3:58)。3 第一步是演讲在添加任何东西之前先做的重构:“The first step is to refactor my tracking loop into separate start, continue, end, and cancel tracking functions” (4:11),这样鼠标循环和触控识别器就能共用它们。3 Apple 的代码清单,原文照录:

// Refactored tracking functions
func startTracking(at viewLocation: NSPoint) { /* ... */ }

func continueTracking(at viewLocation: NSPoint) { /* ... */ }

func endTracking(at viewLocation: NSPoint) { /* ... */ }

func cancelTracking() { /* ... */ }

之后,仅限触控的识别器只需两次属性赋值:“set the buttonMask to 0 and allowedTouchTypes to .direct on an initialized NSPanGestureRecognizer” (4:29)。3

// Add touch-only pan gesture recognizer
let touchRecognizer = NSPanGestureRecognizer(
    target: self,
    action: #selector(touchPan)
)

touchRecognizer.buttonMask = 0x0
touchRecognizer.allowedTouchTypes = .direct

wiringPanelView.addGestureRecognizer(touchRecognizer)

动作方法把识别器的 .began、.changed、.ended 和 .cancelled 状态分别交给这四个函数。需要取消路径的理由,与演讲讲按钮时给出的一样:“If tracking is canceled due to a system gesture like Exposé, scroll, or any other reason, I can revert any unintended changes”(如果跟踪因 Exposé、滚动之类的系统手势或其他原因被取消,我可以撤销任何非预期的更改)(2:41);技术说明的规则则是 “Handle cancellation.”36

// Pan gesture recognizer action function
@objc func touchPan(_ recognizer: NSPanGestureRecognizer) {
    switch recognizer.state {
    case .began:
        startTracking(at: recognizer.location(in: wiringPanelView))
    case .changed:
        continueTracking(at: recognizer.location(in: wiringPanelView))
    case .ended:
        endTracking(at: recognizer.location(in: wiringPanelView))
    case .cancelled:
        cancelTracking()
    default:
        break
    }
}

NSPanGestureRecognizer 早在 macOS 10.10 就已存在,allowedTouchTypes 则始于 10.12.2;这套做法里没有任何新东西。7

第二,识别器带来的规则。技术说明写道:“If your view is covered by another, often transparent, view, your gesture recognizer won’t be triggered”(如果您的视图被另一个视图覆盖,而那个视图往往是透明的,手势识别器就不会被触发),以及 “You can’t place views on top of standard framework controls, because those controls now use gesture recognizers internally”(不能把视图放在标准框架控件之上,因为这些控件如今在内部使用手势识别器),并给出了它自己的解法:“If necessary, rearrange the siblings, or override the occluding view’s hitTest(_:) method and return nil to ensure it doesn’t block events going to underlying controls.”6 自定义识别器必须有始有终:“End your active gesture recognizer by transitioning to ended, failed, or cancelled. If you don’t, recognizers are blocked from activating.”(请把活动中的手势识别器转换到 ended、failed 或 cancelled 来结束它,否则识别器会被阻止激活。)6 还有一项行为变更,仅针对用新 SDK 构建的子类:“In apps built with the macOS 27 SDK and Xcode 27, location(in:) on NSGestureRecognizer returns NSZeroPoint and logs an error if the receiver’s class doesn’t override the method”,因为 “Subclasses of NSGestureRecognizer must implement location(in:) to report a meaningful location.”6

第三,会失去什么。关于控件动作,技术说明说 NSControl 改用识别器后 “changes the timing of when AppKit delivers control action messages with respect to event processing”(改变了 AppKit 相对于事件处理传递控件动作消息的时机),因此 currentEvent “no longer returns the event that triggered an action”(不再返回触发动作的那个事件),并建议改用 NSEvent.pressedMouseButtons 和类级别的 modifierFlags,同时补充 “a touch is not part of pressedMouseButtons”。6 重写了鼠标左键方法的子类也要付出代价:“If you subclass an AppKit control and override any of the left-mouse responder methods, that control falls back to a tracking loop path for compatibility.”(如果您继承某个 AppKit 控件并重写了任何鼠标左键响应方法,该控件会为兼容性退回到跟踪循环路径。)6

控件:用事件取代 mouseDown

AppKit 演讲的第一个重构对象是一个按钮。原来的写法继承 NSButton 并重写 mouseDown(with:),以得知跟踪何时开始与结束;在触控下,“the buttons work, but AppKit must emulate mouse events to pass to the mouseDown override”(按钮能用,但 AppKit 必须模拟鼠标事件,传给重写的 mouseDown)(2:17)。3 替代方案是 NSControl 事件,“directly on NSButton without the need to subclass” (2:27);演讲页面上 2:24 的代码清单在按钮上注册了三次 addTarget(_:action:for:),分别对应 [.trackingBegan, .trackingEntered]、[.trackingExited, .trackingEndedInside] 和 .trackingCancelled,而这些事件还暴露了重写鼠标方法时从未见过的状态:“If tracking is canceled due to a system gesture like Exposé, scroll, or any other reason, I can revert any unintended changes” (2:41)。3 这些事件并不新:“NSControl events are available for standard AppKit controls, and most control events are available all the way back to macOS 11”(标准 AppKit 控件都可以使用 NSControl 事件,大多数控件事件最早可追溯到 macOS 11)(2:51)。3 演讲为这种模式指向一场它称为 “Modernizing your AppKit app” 的 WWDC26 讲座;技术说明列为相关视频的讲座则叫 “Modernize your AppKit app”(WWDC26 第 289 场)。36

根据技术说明 “Handle control events” 一节,macOS 27 为 NSControl.Events 新增了几个成员:trackingRepeated(“An event when multiple mouseDown(with:) events with a click count greater than 1 occur”)、valueChanged(“An event when the value changes on continuous controls, such as sliders”)、primaryActionTriggered、menuActionTriggered(“An event that triggers when a menu gesture occurs, but before the menu presents”),以及留给您自己使用的 applicationReserved。67

然后是排他性。“By default, only one view can be interacted with at a time”(默认情况下,同一时间只能与一个视图交互)(7:20),演讲称之为手势排他性,技术说明则从兼容性角度解释:“For maximum compatibility, AppKit restricts gesture activations to a single view hierarchy at a time”,以及 “Unlike in iOS, the person can’t perform multiple interactions simultaneously, though scrolling is a notable exception”(与 iOS 不同,用户无法同时进行多个交互,不过滚动是一个明显的例外)。36 可以按视图选择退出:“The API to control gesture exclusivity is the exclusiveGestureBehavior property on NSView” (7:48)。该属性的默认值 “inherits its parent’s exclusive gesture behavior” (7:57),而 “By setting the exclusiveGestureBehavior property on the stove view to .notExclusive, the child slider subviews all become non-exclusive as well”(把灶台视图的 exclusiveGestureBehavior 设为 .notExclusive 后,其中的滑块子视图也都变为非排他)(8:01);整个应用则可以通过 Info.plist 键 NSViewGestureRecognizerIsExclusive 退出。367 演讲说这个属性 “is available in the next SDK” (7:54)。Apple 的文档把它列为 macOS 27.0,没有 beta 标记;6月的技术说明描述了它;Xcode 27.1 所带的 macOS 27.0 SDK 在 NSView.h 中以 API_AVAILABLE(macos(27.0)) 声明了它,注释为 “Defaults to .inherit”。因此,演讲所说的「下一个」SDK,在演讲上线时其实已经发布了(作者依据已安装的头文件分析)。367

36 点

设计演讲三次给出这个数字,AppKit 演讲也重复了它。“Touch on macOS uses a touch target of 36 points. This creates the same physical size on display as iOS’s 44 points”(macOS 上的触控使用 36 点的触控目标,在显示屏上的物理尺寸与 iOS 的 44 点相同)(9:17)。4 这个目标被刻意设计为不可见:“All macOS’s framework controls have been updated to use this new touch target, but notice it’s invisible. The controls haven’t changed size and therefore don’t require a new layout”(macOS 的所有框架控件都已更新为使用这一新的触控目标,但请注意它是不可见的。控件尺寸没有变,因此不需要新的布局)(9:26)。4

对自定义视图,指导是扩大点击区域,而不是扩大控件。AppKit 演讲中的接线节点 “a little tricky to touch”(有点难以触碰)(5:14),于是工程师加了一个 expandHitRect 参数,它 “expands the size of the target rect to a minimum of 36 points on each axis. This makes it easier for a touch to hit a node while still requiring the mouse to be precise and without modifying the layout”(把目标矩形在每个轴上扩大到至少 36 点,这样触控更容易命中节点,同时仍要求鼠标精确,也不改动布局)(5:50);他推荐把这一技巧用于 “for small resize or grab handles for selected objects in a canvas view”(画布视图中选中对象的小型缩放或抓取手柄)(6:07)。3 设计演讲针对非 Apple 控件的说法是:“consider increasing the touch target area around your control instead of changing the control size” (9:51)。4

控件尺寸不变。“When designing inspectors or other control-heavy areas, medium-sized controls continue to be the default control size. Window toolbars use extra-large-sized controls by default. Large and extra-large controls should not be used outside of the toolbar”(设计检查器或其他控件密集的区域时,中号控件仍是默认尺寸。窗口工具栏默认使用特大号控件。大号和特大号控件不应在工具栏之外使用)(9:58),以及 “They should only be used sparingly to emphasize key moments or in apps of which content consumption is the primary use case” (10:14)。4 对于类似设置的视图,“use FormStyle. Here as well, each row by default measures the 36-point height” (10:28)。4 小号和迷你控件依然可以使用:“They fully support touch regardless of their size” (10:46),对自定义控件只有一条规则:“If your app is using custom small controls, ensure touch works, even though the tap target might be small” (10:50),因为 “touch events should never be ignored”(触控事件绝不应被忽略)(11:00)。4

对于三种无法做到 36 点的控件,框架承担了难点:“the stepper, dial, and slider”(步进器、旋钮和滑块)(13:54) “now expand in place when interacting via touch”(如今在触控交互时会原地展开)(14:07),展开的那次轻点不会改变它们的值 (14:26),并且 “collapse themselves when I’m not interacting with them” (14:41);对滑块而言这是一个选项,因为 “sliders have the option to expand when presented small” (15:36)。4 菜单也会适配:“when using touch, the menu shows slightly larger rows to help make selection easier” (11:23),临时视图同样可以:“views in your app that are briefly presented, such as popovers or custom menus, can show slightly altered layouts depending on the input used to invoke them”(应用中短暂呈现的视图,例如弹出框或自定义菜单,可以根据调出它们的输入方式显示略有不同的布局)(11:29)。4

悬停不复存在

“Direct touches don’t have an equivalent to mouseMoved events”(直接触控没有与 mouseMoved 事件对应的东西)(10:38),因此凡是在指针悬停时才显示的内容,都需要做出取舍。3 AppKit 演讲的规则是:“don’t change your app experience to permanently show hidden controls” (10:49),“Static data like tooltips shouldn’t be revealed on touch” (10:53),以及 “for hidden essential controls, install a touch-only click gesture recognizer to temporarily show the element on a touch tap”(对于隐藏的关键控件,安装一个仅限触控的点按手势识别器,在轻点时临时显示该元素)(10:57)。3 技术说明确认指针路径没有变化:“Hovering via mouseMoved(with:) is still managed with NSTrackingArea.”6

设计演讲从用户一侧给出了同样的规则。“hover actions that are purely showing information, like tooltips, are not required to work with touch”(纯粹显示信息的悬停操作,例如工具提示,不必支持触控)(11:53);触控已经能轻松完成的操作不需要额外的提示,比如轮播的滚动按钮,它们 “remain hidden during a touch interaction” (12:22),因为 “horizontal scroll is always possible via touch” (12:19);“only the most important hover actions relevant to that content should reveal themselves”(只有与该内容相关的最重要的悬停操作才应该显示出来)(12:30),Safari 在用户触碰页面时恰好显示两个 (12:36);以及 “actions that appear on hover be duplicated elsewhere in your UI”(悬停时出现的操作应在界面的其他位置也提供一份)(13:05),例如在触控下,“提醒事项”的共享按钮放在了该行的上下文菜单里 (13:20)。4

滚动、长按、拖移与文本

在显示屏上滚动用一根手指,在触控板上用两根 (4:39)。4 当一根手指应该用来绘制而不是滚动时,AppKit 演讲把 “the decorating view’s enclosing scroll view to require two touches minimum for touch scrolling” (6:40);对应的属性是 NSScrollView.minimumNumberOfTouchesForScrolling,macOS 27.0,旁边还有 maximumNumberOfTouchesForScrolling、isTouchScrollingEnabled 和 scrollGestureForRelationships。37 应当让位于滚动的识别器可以设置 isCancellableByScrollGesture;“NSScrollView now supports pull-to-refresh functionality”(NSScrollView 现在支持下拉刷新),通过 NSRefreshController 实现;在 NSPanGestureRecognizer 上,minimumNumberOfTouches 与 maximumNumberOfTouches 这一对属性 “replace numberOfTouchesRequired”,后者在 27.0 中已被弃用。67

在 Mac 上,长按同时对应拖移和上下文菜单,由 AppKit 负责仲裁。“When a draggable item is long pressed, it should hint at its draggability with a lift animation. To get the drag-and-drop lift preview, use the existing drag-and-drop delegate APIs on NSTableView, NSOutlineView, and NSCollectionView”(长按可拖移的项目时,它应以抬起动画提示自己可以拖移。要获得拖放的抬起预览,请使用 NSTableView、NSOutlineView 和 NSCollectionView 上现有的拖放委托 API)(9:49)。3 至于菜单,“Use the menu property on NSView or override menu(for:). AppKit will detect this and automatically install the appropriate gesture recognizers, which include a control-tap gesture recognizer as an accelerator” (10:11),以及 “When using both this menu API and the container view drag-and-drop delegate APIs, AppKit will coordinate when a long press becomes a drag-and-drop operation or a context menu one, even allowing the user to switch between them”(同时使用这一菜单 API 和容器视图的拖放委托 API 时,AppKit 会协调长按何时变成拖放操作、何时变成上下文菜单操作,甚至允许用户在两者之间切换)(10:25)。3 设计演讲展示了用户看到的样子:照片 “scales up under my finger” (3:50),它的上下文菜单出现在旁边 (3:58),开始拖移后菜单随即消失 (4:05);用触控拖移时,Shift 和 Option 键依然有效 (4:13)。4 对自定义视图,beginDraggingSession(items:gesture:source:) 用于开始 “a drag from a gesture recognizer”,是 27.0 的新 API。67

文本是薄弱环节。技术说明只有一句:“NSTextSelectionManager allows custom text engines to support standard text gestures”,该类在文档中标注为 macOS 27.0,摘要是 “An object that coordinates text selection behavior for custom text views.”67 头文件补全了它的约定(作者分析):该类 “provides a centralized way to manage text selection interactions using a set of gesture recognizers”(通过一组手势识别器集中管理文本选择交互),带有三种交互模式(可编辑、仅可选择、不可交互)、一个保存选择的委托,以及一个布局数据源。7 两场演讲都没有讲到触控下的插入点、选择手柄或编辑菜单;设计演讲关于选择的指导针对的是项目,即 “on macOS we recommend to allow modeless selection through click and tap” (2:42),单击轻点为选择,双击轻点为打开 (3:10)。4

系统手势,以及那个没有文档的开关

macOS 在显示屏上占用了一组多指手势,它们 “controlled by macOS and are therefore not available to any app running”(由 macOS 控制,因此任何运行中的应用都无法使用)(8:05):三指上推打开调度中心,三指下推打开应用程序 Exposé (8:13);拇指加三指捏合显示应用,张开则显示桌面 (8:22);三指左右滑动切换空间 (8:32);从顶部和底部边缘轻扫,调出隐藏的菜单栏和程序坞 (8:37);在灵动岛上轻扫呼出 Siri (8:46);从边缘轻扫打开通知中心和控制中心 (8:51)。4

AppKit 演讲用三个滑块碰到了冲突:“if I try to control three or more sliders in the same direction at the same time, I get the system gesture instead”(如果我试图同时朝同一方向操作三个或更多滑块,得到的反而是系统手势)(8:17),并展示了开关:“I can control system gesture availability at the window level with the disablesDirectTouchSystemGestures property on NSWindow. SwiftUI and Mac Catalyst also have similar API on UIViewController and View” (8:25),同时提醒 “Only disable system gestures if the interaction capabilities they open up are critical for the window”(只有当禁用系统手势所带来的交互能力对该窗口至关重要时,才应禁用)(8:42)。3 演讲页面上的代码清单点名了全部三个:NSWindow 上的 disablesDirectTouchSystemGestures、UIViewController 上的 prefersDirectTouchSystemGesturesDisabled,以及 SwiftUI View 上的 directTouchSystemGesturesDisabled()。3 截至 10月28日,这三个都不在 Apple 的文档中;对应的 JSON 端点返回 404,AppKit、UIKit 和 SwiftUI 的索引里也没有这些符号。7 以下是我的解读,而非 Apple 的说法:它们是最明确的迹象,表明演讲所依据的 SDK,正是那个标着 “Coming soon” 的版本。

SwiftUI 与 Mac Catalyst

SwiftUI 只新增了一个类型:“if you have a specialized need to distinguish between mouse and direct touch input, you can use the new GestureInputKinds gesture modifier API”(如果您有区分鼠标与直接触控输入的特殊需求,可以使用新的 GestureInputKinds 手势修饰符 API)(0:43)。3 GestureInputKinds 在全部七个平台上都以 27.0 列入文档,成员有 .directTouch(“A person is touching content directly”)、.pointer(“A person is pressing a mouse or a trackpad button while the pointer is pointing at content”)、.indirectTouch、.pencil 和 .all;onTapGesture、onLongPressGesture 以及 TapGesture、SpatialTapGesture、LongPressGesture、DragGesture、MagnifyGesture 和 RotateGesture 的初始化方法都新增了 inputKinds: 参数。7 技术说明的原话是 “Use GestureInputKinds to limit gestures to specific types of input in SwiftUI.”6

Mac Catalyst 使用的是 UIKit 自 iOS 9 以来就有的东西:演讲说的是 “UITouch.touchType and UIGestureRecognizer’s allowedTouchTypes” (0:59);文档中的属性其实是 UITouch.type,枚举为 UITouch.TouchType,而 UIGestureRecognizer 上的 allowedTouchTypes 标注为 Mac Catalyst 13.1。37 演讲里的说法是口误,并不是新 API。

Mac 上的 Live Activities,先于文档

第三场演讲很短,却提出了一个很大的说法。“The Dynamic Island has come to the Mac. To fully take advantage of its capabilities, Mac apps now support native Live Activities”(灵动岛来到了 Mac。为充分发挥其能力,Mac 应用现在支持原生 Live Activities)(0:05),以及 “now in macOS Golden Gate, applications running on the Mac can create Live Activities directly” (0:57)。5 “Universal applications with existing Live Activities will work on the Mac with no code change, and native macOS apps can create Live Activities directly through the Live Activities API”(已有 Live Activities 的通用应用无需修改代码即可在 Mac 上运行,原生 macOS 应用则可以通过 Live Activities API 直接创建 Live Activities)(1:03)。5 显示位置:“On a Mac with Dynamic Island, Live Activities blend in seamlessly into the top edge of the device. On other devices and displays, they are shown in the menu bar”(在有灵动岛的 Mac 上,Live Activities 无缝融入设备顶部边缘;在其他设备和显示器上,它们显示在菜单栏中)(1:14)。5 代码就是 iOS 的代码:数据模型在 ActivityAttributes 中 (2:36);紧凑与最小呈现在 ActivityConfiguration 中,配合灵动岛视图构建器 (3:24);唯一一种 Mac 专属的呈现方式是 “The menu bar expanded Live Activity view is created along with the ActivityConfiguration as a simple view” (3:52),而 “Expanded Live Activities in the Dynamic Island are defined with the Dynamic Island view builder” (4:02);“This same code works on iOS and macOS” (4:30);启动可以是立即的、预定的或推送的 (4:40);可以与 “with existing backgrounding technologies on the Mac, like background tasks and user agents” 集成 (4:54);操作通过 App Intents 实现 (5:56);以及 “If you have an iOS activity, there’s no code to port”(如果您已有 iOS 上的 activity,就没有需要移植的代码)(7:09)。5 有两条规则沿用自 iOS:“Only a single Live Activity can be expanded at a time” (3:12),以及 “An activity is only expanded when interacted with or if explicitly triggered through an alert request” (3:06)。5

Apple 的文档还没有这么说。ActivityKit 框架页面的摘要提到了 “the Mac”,但它的 Overview 写的是 “On Mac, it appears in the Menu bar”,平台列表为 iOS、iPadOS 和 Mac Catalyst 16.1,而 Activity、ActivityAttributes、ActivityConfiguration、DynamicIsland 以及 NSSupportsLiveActivities 键都没有列出 macOS 平台。87 HIG 的 Live Activities 页面(更新日志止于 10月13日)仍然只描述配对 iPhone 的路径:“Active Live Activities automatically appear in the Menu bar of a paired Mac”、“Clicking the Live Activity launches iPhone Mirroring to display your app”,以及在 “macOS dimensions” 标题下的 “Use the provided iOS dimensions”。10 SDK 与文档一致,而与演讲不一致:在 Xcode 27.1 所带的 macOS 27.0 SDK 和 Xcode 27.2 beta(27B5019j)所带的 macOS 27.2 SDK 中,ActivityKit 的 macOS 接口都把 ActivityAttributes、Activity、每一个 request 和 update 标为 @available(macOS, unavailable),这是我在这台 Mac 上检查的结果(作者分析)。因此,写进计划里的应该是那句措辞收窄的话:演讲说这项能力在 macOS Golden Gate 中已经存在,但无论文档还是我检查过的任一 SDK,目前都还不能让您把它构建出来。状态机那篇文章展示了共通的启动、更新与结束模型在 iOS 上的一种实现;Mac 自己的时长、关闭与后台限制,目前没有任何来源给出。

设计:macOS 本身不变

设计演讲收尾的几条规则很短,值得完整保留。“Avoid redesigning your app just to support touch. Your app on a Mac that supports touch should have no visual distinction from your app on a Mac that doesn’t”(不要仅为支持触控而重新设计应用。您的应用在支持触控的 Mac 上,与在不支持触控的 Mac 上,外观上不应有任何区别)(16:05)。“Use gestures to navigate your app and directly manipulate your content” (16:14)。“Use 36 points as a touch target on macOS, and use Apple frameworks to get touch-optimized layouts and expandable controls” (16:18)。“Most apps will work great with touch right away” (16:28)。“Keep keyboard and mouse as a primary input”(让键盘和鼠标继续作为主要输入方式)(16:31)。4

唯一一条与空间有关的规则,关乎的是手,而不是姿态。“The edges of the display are easy to touch by grabbing the side of the display with my hand”(用手握住显示屏侧边时,很容易触碰到显示屏的边缘)(6:17),因此 “The left and right side of my app window are therefore best used to show rich controls and dense UI, such as inspectors and navigation sidebars” (6:29),而 “the center of the display is best used for coarse, imprecise and big gestures”(显示屏中央最适合粗略、不精确的大幅手势)(6:46)。4 自定义手势有三条约束:“your gestures should work with touch and trackpad and possibly Magic Mouse” (7:00),“Avoid adding gestures that only work with touch” (7:05),以及 “The action your gesture does should be duplicated elsewhere in the UI, for example in a menu” (7:37)。4 演讲也允许了 Mac 从未有过的东西:“macOS now allows multiple touch gestures at the same time”(macOS 现在允许同时进行多个触控手势)(5:30),例子是在 Logic 里用两根手指操作两个滑块 (5:45)。4 这就是前文那个排他性属性在用户一侧的体现:AppKit 默认同一时间只允许一个视图层级,而 .notExclusive 是应用放开其余层级的方式。36

现在就能测试:Sidecar,以及还没到的 SDK

您不需要这台笔记本。“With the latest macOS beta and developer tools, all the touch features of the Mac with Touch Display are available with an iPad connected to your Mac with Sidecar”(借助最新的 macOS beta 和开发者工具,通过 Sidecar 连接到 Mac 的 iPad 可以使用触控显示屏 Mac 的全部触控功能)(11:59),以及 “The fastest way to get started with touch on Mac is with the Sidecar tools you already own” (12:09)。3 技术说明要求 iPad 运行 iPadOS 27,并为触控能力检查(NSScreen.touchCapabilities,一个带有 .multiTouch 位的选项集)加了一条注意事项:在 macOS 27 中,该检查 “returns true for all displays when a touch-capable Sidecar display is connected, not just for the Sidecar display”(连接了支持触控的 Sidecar 显示屏时,对所有显示屏都返回 true,而不仅是 Sidecar 显示屏),并建议 “it’s better to handle events regardless of input source and decide on an alternate presentation based on the interaction type, if needed”。67

演讲的审查步骤,按它自己的顺序:“start testing your application with touch on macOS with Sidecar. Then audit your code for mouseDown(with:) overrides. Determine if you can use control events or delegate methods instead, or if you need to add your own touch-specific gesture recognizers. Look for areas that have small hit targets and expand them for touch. And finally, add an affordance or use a tap to reveal essential hidden UI” (12:24)。3 另外还有一个技能(skill):“there’s a gesture modernization skill that has an understanding of the features and changes I’ve talked about” (12:16);落地页的 Xcode 板块里带着一条占位注释 TK skill,没有任何来源给出它的名字。23

已发布的 SDK 里有什么,以下是我依据这台 Mac 上的头文件和 Swift 接口做的作者分析:Xcode 27.1(27A9275)所带的 macOS 27.0 SDK 声明了 NSScreen.TouchCapabilities、五个新的 NSControl 事件成员、NSScrollView 的触控属性、NSRefreshController、beginDraggingSession(items:gesture:source:) 和 exclusiveGestureBehavior,全部为 API_AVAILABLE(macos(27.0));SwiftUICore 的 macOS 接口(由 SwiftUI 重新导出)声明了 GestureInputKinds。三个系统手势开关既不在这个 SDK 中,也不在 Xcode 27.2 beta(27B5019j)所带的 macOS 27.2 SDK 中,无论是 AppKit 的头文件、SwiftUI 的接口还是 Mac Catalyst 的 UIKit 头文件;两个 SDK 里 ActivityKit 的 macOS 接口也都把它的 API 标为不可用。78

这就是我检查过的两个 SDK;Xcode 27.2 RC(27B48)在 Apple 发布订阅源中的日期是 10月19日,比那个 beta 更新,我没有检查,所以上述缺失只对所列的 SDK 成立,不能外推。11

今天用来测试该装什么,以下我未亲自验证:macOS 27.2(26B123,订阅源显示 10月26日 发布)和 Xcode 27.2 RC,再加一台运行 iPadOS 27、通过 Sidecar 连接的 iPad;技术说明描述 Sidecar 触控在 macOS 27 中可用,而截至 10月28日,订阅源里没有 macOS 27.3 beta。611 RC 自己的说明里有一条需要注意:“macOS, watchOS, tvOS, and visionOS SDKs in Xcode 27.2 incorrectly report 27.1 as a valid deployment target”(Xcode 27.2 中的 macOS、watchOS、tvOS 和 visionOS SDK 错误地把 27.1 报告为有效的部署目标),以及 “Mac Catalyst builds with a 27.1 or 27.2 deployment target might be unable to use newly introduced API”。所以不要把 27.1 选作 macOS 的部署目标(发布订阅源列有 macOS 27.0.1 和 27.2,没有 macOS 27.1);如果部署目标为 27.1 或 27.2 的 Mac Catalyst 构建看不到某个新 API,应把它当作这个已知问题,而不是符号缺失。11

那么,还没到的是:落地页承诺的 Xcode 27.3 beta、它链接的那篇 AppKit 文章、三个系统手势符号,以及可在 macOS 上使用的 ActivityKit(在检查过的两个 SDK 中缺失,在 27.2 RC 中未经核实),还有任何关于模拟器的说明。Xcode 27.2 RC 的说明只提到触控一次,是 Device Hub 的一项修复,针对 “after a period of inactivity”(闲置一段时间后)停止响应的输入;macOS 27.2 的说明里则没有任何关于触控、手势或 Live Activities 的条目。11 触控 API 已随 Xcode 27.1 发布,规则已经公布,而落地页把接下来的东西标为 “Coming soon”。

适用于任何 Mac 应用的触控审查

以下是作者分析,而非 Apple 的指导:把演讲的四个步骤按顺序整理成一份检查清单。目前还没有任何运行时测试为它背书。

  1. 用 Sidecar 连接一台运行 iPadOS 27 的 iPad,使用最新的 macOS 和 Xcode(macOS 27.2 与 Xcode 27.2 RC),在改动任何东西之前,先把应用的每一个界面都用触控走一遍。
  2. 搜索所有 mouseDown(with:) 重写和 nextEvent(matching:) 循环,为每一处确定去向:控件事件、委托方法,或手势识别器。
  3. 过一遍小型控件和点击区域,在有帮助的地方扩大触控区域,不改动布局;演讲允许控件较小,只要触控在它上面仍然可用。
  4. 列出所有在指针悬停时出现的内容,逐项决定:工具提示保持仅限鼠标;触控已能轻松完成的操作无需处理;关键控件则配一个仅限触控的点按识别器,并在界面的其他位置(例如上下文菜单)也放一份。

这份审查唯一不会产出的,就是重新设计,因为设计演讲的第一条规则就是不应有视觉上的区别;唯一可以随输入方式改变的布局是临时性的布局,即弹出框或自定义菜单。

Apple 还没有说明的事

以下每一项都是来源未作回答的问题,核对范围包括新闻稿、落地页、三场演讲、技术说明、规格页面、Xcode 27.2 RC 与 macOS 27.2 的发行说明,以及四个 HIG 页面。

  • 哪个 macOS 小版本为内置显示屏带来 Touch,哪个 SDK 带来三个未入文档的符号。新闻稿说的是 “macOS 27”,只在 Siri AI 的脚注里提到 macOS 27.2;落地页写的是 “Xcode 27.3 beta”、“Coming soon”。
  • 用旧 SDK 构建的二进制文件,能否获得与用 macOS 27 SDK 重新构建的版本相同的触控行为。演讲说的是 “all apps”;技术说明只把 location(in:) 的变更与新 SDK 挂钩。
  • 显示屏是否支持 Apple Pencil 或压感,玻璃能否在手指触碰之前感知到它。演讲讨论的是缺少类似鼠标的悬停状态;没有任何来源提到触控笔、压感或接近感应,而 GestureInputKinds.pencil 与其他成员一样列为 macOS 27.0,同时没有任何来源说这块显示屏能感知触控笔。7
  • 外接显示器上或合盖模式下的触控,以及用户能否关闭 Touch。
  • 用触控编辑文本:插入点、手柄、放大镜和编辑菜单。
  • 触控显示屏下的辅助功能。规格页面把 AssistiveTouch 和 Touch Accommodations(触控调节)列为这台笔记本的功能,但没有说明它们对 Mac 而言是否是新功能。9
  • “Designed for iPad” 应用在 Mac 显示屏上如何接收触控,以及这与 Mac Catalyst 是否不同。
  • 在没有 iPad 的情况下,是否有模拟器或 Device Hub 路径来测试 Mac 触控。
  • 网页内容:WKWebView 和 Safari 向页面传递的是触控事件还是指针事件。
  • 窗口和全屏内容与灵动岛如何相处,以及由哪个安全区域 API 报告它。
  • macOS 上 Live Activities 的具体细节:哪个小版本和 SDK、是否需要 NSSupportsLiveActivities、推送启动和 APNs 注册在 Mac 上如何运作,以及 Mac 原生 activity 的尺寸。

时间表

  • 10月28日:在 30 个国家和地区开始预订;开发者页面和三场演讲上线;技术说明自 6月8日 起就已发布。126
  • 11月6日:笔记本送达顾客并进入门店。1
  • 11月18日 太平洋时间上午 9 点至 10 点,以及 11月19日 太平洋时间下午 6 点至 7 点:Touch on Mac Group Labs,线上举行,有 Apple 工程师和设计师参与。2
  • “Coming soon”:Xcode 27.3 beta、文档资源、设计资源。2
  • 今年 11月:Apple Creator Studio 更新,新闻稿描述了其中 Logic Pro 和 Final Cut Pro 的触控功能;新闻稿点名的第三方应用 “will be available later this year”(将于今年晚些时候推出)。1

关键要点

对 AppKit 开发者: 标准控件现在原生支持触控;您自定义的 mouseDown(with:) 代码会一直处于模拟状态,直到改用控件事件或手势识别器;一个设置了 buttonMask = 0 和 allowedTouchTypes = .direct 的仅限触控 NSPanGestureRecognizer,就是演讲为小版本更新推荐的路径;这些 API 都在您已经拥有的 macOS 27.0 SDK 中。37

对 SwiftUI 与 Catalyst 开发者: 您的手势已经可以工作;GestureInputKinds 是 SwiftUI 唯一的新类型,Catalyst 的对应方案是 UITouch.type 和 allowedTouchTypes。37

对设计师: 36 点,不可见;不要重新设计;关键的悬停操作要能用触控触达,并在界面其他位置(例如上下文菜单)也提供一份,工具提示除外;密集的界面放在边缘,粗略的手势放在中央。4

对规划: 现在就用 Sidecar 测试;在构建任何禁用系统手势或创建 Mac 原生 Live Activity 的功能之前,先确认已安装的 SDK 声明了这些 API,因为本文检查过的两个 SDK 都没有,Xcode 27.2 RC 也未经核实;Apple 承诺的下一个 SDK 是 Xcode 27.3 beta。278

常见问题

我现有的 Mac 应用能配合 Touch 使用吗?

Apple 说大多数应用可以:“many existing apps work with Touch right away, because macOS automatically translates touches into clicks”(许多现有应用能立即配合 Touch 使用,因为 macOS 会自动把触控转换为点按),AppKit 演讲也说,标准的 AppKit、SwiftUI 和 Mac Catalyst 组件以及现有手势都 “just work”。13 自定义的鼠标跟踪代码会一直处于模拟状态,直到改用控件事件或手势识别器;非 Apple 的 UI 框架会得到一层通用的模拟,一旦应用自己处理触控,就可以用 NSIsTouchNative 把它关掉。36

如何在 AppKit 中接收直接触控?

用手势识别器。演讲说 “gesture recognizers are the only way to get direct touches on macOS”,技术说明则说触控事件不经过响应者链、事件监视器、NSApp 或 sendEvent(_:)。36 仅限触控的识别器把 buttonMask 设为 0,把 allowedTouchTypes 设为 .direct。3

macOS 上的触控目标是多大?

36 点,“the same physical size on display as iOS’s 44 points”(在显示屏上的物理尺寸与 iOS 的 44 点相同)。框架控件无需改变尺寸就已满足这一要求;对自定义视图,应扩大其点击区域,而不是扩大视图本身。43

没有新 MacBook Pro,如何测试 Touch?

通过 Sidecar 连接一台运行 iPadOS 27 的 iPad。演讲给出的前提是 “With the latest macOS beta and developer tools” (11:59),而 macOS 27.3 beta 尚未推出,所以我会尝试的配置是 macOS 27.2 加 Xcode 27.2 RC,这一点我未亲自验证。3611

触控 API 现在已经在 SDK 里了吗?

是的,演讲演示的内容都在,只有系统手势开关和 Mac 原生 Live Activities 除外,它们在本文检查过的两个 SDK 中都不存在(Xcode 27.2 RC 未检查)。Xcode 27.1 所带的 macOS 27.0 SDK 声明了 NSScreen.TouchCapabilities、新的 NSControl 事件成员、NSScrollView 的触控属性、NSRefreshController、exclusiveGestureBehavior 和基于手势的拖移会话,SwiftUICore 的接口声明了 GestureInputKinds;Apple 的文档把它们列为 macOS 27.0,没有 beta 标记。7 用于系统手势的窗口、视图控制器和视图开关,既不在文档中,也不在 Xcode 27.1 或 27.2 beta 的 SDK 中;ActivityKit 在这两个 SDK 中都把其 API 标为在 macOS 上不可用;落地页则把 Xcode 27.3 beta 标为 “Coming soon”。278

Mac 应用能创建 Live Activities 吗?

演讲说在 macOS Golden Gate 中可以,使用与 iOS 相同的 ActivityKit 和 WidgetKit 代码,在没有灵动岛的 Mac 上以菜单栏形式呈现。5 ActivityKit 的文档和 HIG 目前都没有把 macOS 列为应用自建 activity 的平台,它们描述的是配对 iPhone 的菜单栏路径;Xcode 27.1 和 27.2 beta SDK 中的 ActivityKit 接口也把该 API 标为在 macOS 上不可用。108

本文的事实出自哪里?

新闻稿、开发者新闻文章和落地页、三场 Tech Talks 的英文字幕轨(每段引文的第一个字幕时间点标在括号中)、6月的技术说明、文中点名的每个符号的 Apple 文档 JSON、规格页面、Xcode 27.2 RC 与 macOS 27.2 的发行说明,以及四个 HIG 页面,均取回于 2026年10月28日;此外还有我这台 Mac 上 macOS 27.0 与 27.2 beta SDK 的头文件和 Swift 接口,这部分属于作者分析。媒体报道不作为来源。

参考来源


  1. Apple Newsroom,Apple unveils groundbreaking MacBook Pro with PROLED XDR Display,2026年10月28日,太平洋时间上午 10:09 首次出现在 Newsroom 订阅源中(订阅源的 updated 时间戳为 17:09:28Z)。引用章节:“Touch Arrives on Mac”、“Say Hello to the Dynamic Island on Mac” 和 “macOS 27 Golden Gate”;价格与供货;关于第三方应用的脚注 4。 ↩↩↩↩↩↩↩↩

  2. Apple Developer,Say hello to Touch on Mac,2026年10月28日,以及 Get ready for Touch on Mac,取回于 2026年10月28日 太平洋时间上午 11:49:三场演讲;“Touch on Mac Group Labs”,时间为 11月18日 太平洋时间上午 9 点至 10 点,以及 11月19日 太平洋时间下午 6 点至 7 点;“Xcode 27.3 beta”、“Documentation resources” 和 “Design resources” 三个板块,均标有 “Coming soon”,其链接保存在 HTML 注释中。 ↩↩↩↩↩↩↩↩↩↩↩↩

  3. Apple Developer,Tech Talk Bring Touch to your Mac app,13:19,Raleigh Ledet,2026年10月28日。引文出自英文字幕轨;括号中的时间是所引片段的第一个字幕时间点。演讲页面上的代码清单包括:“Use NSControl events to detect tracking” (2:24)、“Refactored tracking functions” (4:11)、“Add a touch-only pan gesture recognizer” (4:24)、“Pan gesture recognizer action” (4:52)、“Require two touches for scrolling” (6:40)、“Allow simultaneous slider interaction” (7:48)、“Disable system gestures” (8:25)、“Declare touch-native support in Info.plist” (11:47);文中转载的三段清单均逐字复制自该页面。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  4. Apple Developer,Tech Talk Design for touch on Mac,16:52,Cas Lemmens,2026年10月28日。引文出自英文字幕轨,括号中为第一个字幕时间点。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  5. Apple Developer,Tech Talk Bring Live Activities to Mac,7:40,Jonathan Tilley,2026年10月28日。引文出自英文字幕轨,括号中为第一个字幕时间点。 ↩↩↩↩↩↩↩

  6. Apple Developer Documentation,TN3212: Adopting gesture recognizers for Sidecar touch support,修订历史 “2026-06-08 First published”,取回于 2026年10月28日 太平洋时间中午。引用章节:Overview、“Understand how gesture recognizers gather events”、“Handle Sidecar touch input”、“Update your event-handling code”、“Implement custom gesture recognizers”、“Handle tracking loop compatibility”、“Update to gesture recognizer behavior”、“Support third-party UI frameworks”、“Explore updated APIs in macOS 27”、“Detect touch capability”、“Handle control events”、“Configure scroll behavior”、“Work with text and dragging” 和 “Handle deprecations and behavior changes”。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  7. Apple 文档 JSON(developer.apple.com/tutorials/data/documentation/<path>.json,即此处所链页面背后的数据),取回于 2026年10月28日 太平洋时间上午 11:55 至中午 12:05。列为 macOS 27.0 且无 beta 标记的有:NSScreen.TouchCapabilities 及 .multiTouch;NSControl.Events 的 .trackingRepeated、.valueChanged、.primaryActionTriggered、.menuActionTriggered 和 .applicationReserved;NSScrollView 的 .isTouchScrollingEnabled、.minimumNumberOfTouchesForScrolling、.maximumNumberOfTouchesForScrolling、.scrollGestureForRelationships 和 .refreshController;NSRefreshController;NSPanGestureRecognizer.minimumNumberOfTouches 和 .maximumNumberOfTouches;NSGestureRecognizer.isCancellableByScrollGesture;NSView.exclusiveGestureBehavior 和 ExclusiveGestureBehavior;NSView.beginDraggingSession(items:gesture:source:);NSTextSelectionManager;NSIsTouchNative(其页面写道:“Most AppKit apps don’t need this key. It’s primarily intended for apps that embed a non-AppKit rendering or input framework and implement their own touch-handling pipeline.”);NSViewGestureRecognizerIsExclusive;以及 GestureInputKinds 及其成员(全部七个平台均为 27.0)。较早的有:NSGestureRecognizer 及其具体子类(macOS 10.10)、allowedTouchTypes(10.12.2)、NSControl.Events 的跟踪成员(11.0)、UITouch.type 和 UIGestureRecognizer.allowedTouchTypes(iOS 9.0,Mac Catalyst 13.1);numberOfTouchesRequired 在 27.0 中弃用。未找到(HTTP 404,框架索引中也没有):NSWindow.disablesDirectTouchSystemGestures、UIViewController.prefersDirectTouchSystemGesturesDisabled、SwiftUI 的 directTouchSystemGesturesDisabled(),以及文章 “Adopting gesture recognizers in your app”。2026年10月28日 的 SDK 检查(作者分析),对象为 Xcode 27.1(27A9275)所带的 MacOSX27.0.sdk:NSView.h 第 583 行为 @property NSViewExclusiveGestureBehavior exclusiveGestureBehavior API_AVAILABLE(macos(27.0));,上方注释为 “Defaults to .inherit”;NSScreen.h 声明了 NSScreen.TouchCapabilities 和 touchCapabilities;NSControl.h 声明了 NSControlEventTrackingRepeated、ValueChanged、PrimaryActionTriggered、MenuActionTriggered 和 ApplicationReserved;NSScrollView.h 声明了 touchScrollingEnabled、minimumNumberOfTouchesForScrolling、maximumNumberOfTouchesForScrolling(第 148 行)、scrollGestureForRelationships 和 refreshController;NSRefreshController.h 声明了该类;NSPanGestureRecognizer.h 声明了 minimumNumberOfTouches 和 maximumNumberOfTouches,并把 numberOfTouchesRequired 标为弃用,替代项为 minimumNumberOfTouches;NSGestureRecognizer.h 声明了 cancellableByScrollGesture;NSTextSelectionManager.h 声明了该类及其 Mode,注释为 “provides a centralized way to manage text selection interactions using a set of gesture recognizers”;NSView.h 声明了 beginDraggingSession(items:gesture:source:);以上均为 API_AVAILABLE(macos(27.0))。SwiftUICore.swiftmodule/arm64e-apple-macos.swiftinterface 在第 25274 行以 @available(anyAppleOS 27.0, *) 声明了 GestureInputKinds;SwiftUI 的接口(重新导出该类型)在 onTapGesture、onLongPressGesture(第 22962 行)以及 SpatialTapGesture、LongPressGesture、DragGesture、MagnifyGesture 和 RotateGesture 的初始化方法上声明了 inputKinds: 参数,而 TapGesture.init(count:inputKinds:) 位于 SwiftUICore 的接口中(第 18305 行)。DirectTouchSystemGestures 在该 SDK 以及 Xcode 27.2 beta(27B5019j)所带的 MacOSX27.2.sdk 中,既不出现在任何 AppKit 头文件里,也不出现在任何 SwiftUI 或 SwiftUICore 的 macOS Swift 接口里,也不出现在任何 Mac Catalyst UIKit 头文件里。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩

  8. Apple Developer Documentation,ActivityKit,取回于 2026年10月28日:摘要为 “Share live updates from your app as Live Activities on iPhone, iPad, Apple Watch, and the Mac”,Overview 为 “On Mac, it appears in the Menu bar”,平台为 iOS、iPadOS 和 Mac Catalyst 16.1;Activity、ActivityAttributes、ActivityContent(iOS 和 iPadOS 16.1 或 16.2)、WidgetKit 的 ActivityConfiguration 和 DynamicIsland(iOS 和 iPadOS 16.1),以及 NSSupportsLiveActivities(iOS 和 iPadOS 16.1),均未列出 macOS。Displaying live data with Live Activities,摘要:“Display up-to-date data and offer quick interactions in the Dynamic Island, on the Lock Screen, in CarPlay, and on a paired Mac or Apple Watch.” SDK 检查(作者分析):MacOSX27.2.sdk(Xcode 27.2 beta,27B5019j)中的 ActivityKit.swiftmodule/arm64e-apple-macos.swiftinterface 在 ActivityAttributes、Activity、每一个 request 重载和 update 上都标有 @available(macOS, unavailable);MacOSX27.0.sdk(Xcode 27.1,27A9275)中的 arm64e-apple-macos.swiftinterface 带有相同的标记。 ↩↩↩↩↩↩↩

  9. Apple,MacBook Pro with PROLED XDR Display Technical Specifications,取回于 2026年10月28日 太平洋时间上午 11:57:“14.2-inch (diagonal) tandem OLED display”,“3024-by-1986 native resolution at 254 pixels per inch”;“16.3-inch (diagonal) tandem OLED display”,“3472-by-2266 native resolution at 254 pixels per inch”;显示屏条目 “Touch”、“Multi-Touch gesture support” 和 “Dynamic Island”;以及 “ProMotion technology with adaptive refresh rates from 10Hz to 120Hz”。 ↩↩

  10. Apple Developer,Human Interface Guidelines,Gestures(更新日志 “September 9, 2024”)、Pointing devices(“June 21, 2023”)、Designing for macOS 和 Live Activities(“October 13, 2026 | Added guidance for limited width layouts, and updated supported platforms and specifications.”),均取回于 2026年10月28日;都没有提到 Mac 显示屏上的触控。Live Activities 页面,Platform considerations,macOS:“Active Live Activities automatically appear in the Menu bar of a paired Mac using the compact, minimal, and expanded presentations”、“Clicking the Live Activity launches iPhone Mirroring to display your app”,以及在 “macOS dimensions” 标题下的 “Use the provided iOS dimensions”。 ↩↩↩

  11. Apple Developer Documentation,Xcode 27.2 RC Release Notes,取回于 2026年10月28日:“Xcode 27.2 RC includes Swift 6.4 and SDKs for iOS 27.2, iPadOS 27.2, tvOS 27.2, watchOS 27.2, macOS 27.2, and visionOS 27.2”;Device Hub,Resolved Issues:“Fixed: Device Hub stopped sending touch and button input to a connected device after a period of inactivity. (182695157) (FB23873443).”;Known Issues:“macOS, watchOS, tvOS, and visionOS SDKs in Xcode 27.2 incorrectly report 27.1 as a valid deployment target. Builds and other functionality might have unexpected behavior if this deployment target is used. Mac Catalyst builds with a 27.1 or 27.2 deployment target might be unable to use newly introduced API.” macOS 27.2 Golden Gate Release Notes,同日取回:没有任何条目提到触控、手势、Sidecar 或 Live Activities。Apple Developer,Releases,RSS 订阅源,取回于 2026年10月28日:“Xcode 27.2 RC (27B48)” 日期为 Mon, 19 Oct 2026 10:00:00 PDT,“macOS 27.2 (26B123)” 日期为 Mon, 26 Oct 2026 10:00:00 PDT,没有任何条目提到 macOS 27.3 或 Xcode 27.3。 ↩↩↩↩↩↩

相关文章

菜单项图像在 macOS 27 与 iPadOS 27 中消失了

macOS 27 与 iPadOS 27 默认隐藏菜单项图像,而具体消失哪些,取决于您链接的 SDK。三套框架,三种不同的修复方式。

10 分钟阅读

可调整大小的 iPhone 时代:在 9 月之前让你的 App 做好准备

iOS 27 把可调整大小的分界线画在了你所使用的 SDK 上。检查清单:排查固定尺寸的假设、采用自适应布局、在 Xcode 27 中测试。

8 分钟阅读

Mac App Store 不允许窗口管理器存在,我还是把它上架了

App Sandbox 禁用了每一款窗口平铺工具都需要的 API,Apple 让我在商店之外发布。941 Tiles 却在商店里上架了:移动窗口的是 Apple 自己的 Shortcuts 引擎。

9 分钟阅读