paperkit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

PaperKit

PaperKit

Beta-sensitive. PaperKit is new in iOS/iPadOS 26, macOS 26, and visionOS 26. API surface may change. Verify details against current Apple documentation before shipping.
PaperKit provides a unified markup experience — the same framework powering markup in Notes, Screenshots, QuickLook, and Journal. It combines PencilKit drawing with structured markup elements (shapes, text boxes, images, lines) in a single canvas managed by
PaperMarkupViewController
. Requires Swift 6.3 and the iOS 26+ SDK.
Beta版本注意事项:PaperKit是iOS/iPadOS 26、macOS 26和visionOS 26中的新增框架。API范围可能会发生变化。发布前请对照Apple官方文档确认细节。
PaperKit提供统一的标记体验——它是支持“备忘录”“截图”“快速查看”和“日志”应用中标记功能的同款框架。它将PencilKit绘图与结构化标记元素(形状、文本框、图片、线条)整合在由
PaperMarkupViewController
管理的单一画布中。需要Swift 6.3及iOS 26+ SDK。

Contents

目录

Setup

设置

PaperKit requires no entitlements or special Info.plist entries.
swift
import PaperKit
Platform availability: iOS 26.0+, iPadOS 26.0+, Mac Catalyst 26.0+, macOS 26.0+, visionOS 26.0+.
Three core components:
ComponentRole
PaperMarkupViewController
Interactive canvas for creating and displaying markup and drawing
PaperMarkup
Data model for serializing all markup elements and PencilKit drawing
MarkupEditViewController
/
MarkupToolbarViewController
Insertion UI for adding markup elements
PaperKit不需要权限或特殊的Info.plist配置项。
swift
import PaperKit
平台兼容性:iOS 26.0+、iPadOS 26.0+、Mac Catalyst 26.0+、macOS 26.0+、visionOS 26.0+。
三个核心组件:
组件作用
PaperMarkupViewController
用于创建和显示标记与绘图的交互式画布
PaperMarkup
用于序列化所有标记元素和PencilKit绘图的数据模型
MarkupEditViewController
/
MarkupToolbarViewController
用于添加标记元素的插入界面

PaperMarkupViewController

PaperMarkupViewController

The primary view controller for interactive markup. Provides a scrollable canvas for freeform PencilKit drawing and structured markup elements. Conforms to
Observable
and
PKToolPickerObserver
.
这是交互式标记的主视图控制器,提供可滚动画布以支持自由形式的PencilKit绘图和结构化标记元素。遵循
Observable
PKToolPickerObserver
协议。

Basic UIKit Setup

基础UIKit设置

swift
import PaperKit
import PencilKit
import UIKit

class MarkupViewController: UIViewController, PaperMarkupViewController.Delegate {
    var paperVC: PaperMarkupViewController!
    var toolPicker: PKToolPicker!

    override func viewDidLoad() {
        super.viewDidLoad()

        let markup = PaperMarkup(bounds: view.bounds)
        paperVC = PaperMarkupViewController(
            markup: markup,
            supportedFeatureSet: .latest
        )
        paperVC.delegate = self

        addChild(paperVC)
        paperVC.view.frame = view.bounds
        paperVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(paperVC.view)
        paperVC.didMove(toParent: self)

        toolPicker = PKToolPicker()
        toolPicker.addObserver(paperVC)
        paperVC.pencilKitResponderState.activeToolPicker = toolPicker
        paperVC.pencilKitResponderState.toolPickerVisibility = .visible
    }

    func paperMarkupViewControllerDidChangeMarkup(
        _ controller: PaperMarkupViewController
    ) {
        guard let markup = controller.markup else { return }
        Task { try await save(markup) }
    }
}
swift
import PaperKit
import PencilKit
import UIKit

class MarkupViewController: UIViewController, PaperMarkupViewController.Delegate {
    var paperVC: PaperMarkupViewController!
    var toolPicker: PKToolPicker!

    override func viewDidLoad() {
        super.viewDidLoad()

        let markup = PaperMarkup(bounds: view.bounds)
        paperVC = PaperMarkupViewController(
            markup: markup,
            supportedFeatureSet: .latest
        )
        paperVC.delegate = self

        addChild(paperVC)
        paperVC.view.frame = view.bounds
        paperVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(paperVC.view)
        paperVC.didMove(toParent: self)

        toolPicker = PKToolPicker()
        toolPicker.addObserver(paperVC)
        paperVC.pencilKitResponderState.activeToolPicker = toolPicker
        paperVC.pencilKitResponderState.toolPickerVisibility = .visible
    }

    func paperMarkupViewControllerDidChangeMarkup(
        _ controller: PaperMarkupViewController
    ) {
        guard let markup = controller.markup else { return }
        Task { try await save(markup) }
    }
}

Key Properties

关键属性

PropertyTypeDescription
markup
PaperMarkup?
The current data model
selectedMarkup
PaperMarkup
Currently selected content
isEditable
Bool
Whether the canvas accepts input
isRulerActive
Bool
Whether the ruler overlay is shown
drawingTool
any PKTool
Active PencilKit drawing tool
contentView
UIView?
/
NSView?
Background view rendered beneath markup
zoomRange
ClosedRange<CGFloat>
Min/max zoom scale
supportedFeatureSet
FeatureSet
Enabled PaperKit features
属性类型描述
markup
PaperMarkup?
当前的数据模型
selectedMarkup
PaperMarkup
当前选中的内容
isEditable
Bool
画布是否接受输入
isRulerActive
Bool
是否显示标尺覆盖层
drawingTool
any PKTool
活跃的PencilKit绘图工具
contentView
UIView?
/
NSView?
标记层下方渲染的背景视图
zoomRange
ClosedRange<CGFloat>
最小/最大缩放比例
supportedFeatureSet
FeatureSet
启用的PaperKit功能

Touch Modes

触摸模式

PaperMarkupViewController.TouchMode
has two cases:
.drawing
and
.selection
.
swift
paperVC.directTouchMode = .drawing    // Finger draws
paperVC.directTouchMode = .selection  // Finger selects elements
paperVC.directTouchAutomaticallyDraws = true  // System decides based on Pencil state
PaperMarkupViewController.TouchMode
包含两种情况:
.drawing
.selection
swift
paperVC.directTouchMode = .drawing    // 手指用于绘图
paperVC.directTouchMode = .selection  // 手指用于选择元素
paperVC.directTouchAutomaticallyDraws = true  // 系统根据Pencil状态自动决定

Content Background

内容背景

Set any view beneath the markup layer for templates, document pages, or images being annotated:
swift
paperVC.contentView = UIImageView(image: UIImage(named: "template"))
可以在标记层下方设置任意视图,用于模板、文档页面或待注释图片:
swift
paperVC.contentView = UIImageView(image: UIImage(named: "template"))

Delegate Callbacks

代理回调

MethodCalled when
paperMarkupViewControllerDidChangeMarkup(_:)
Markup content changes
paperMarkupViewControllerDidBeginDrawing(_:)
User starts drawing
paperMarkupViewControllerDidChangeSelection(_:)
Selection changes
paperMarkupViewControllerDidChangeContentVisibleFrame(_:)
Visible frame changes
方法触发时机
paperMarkupViewControllerDidChangeMarkup(_:)
标记内容发生变化时
paperMarkupViewControllerDidBeginDrawing(_:)
用户开始绘图时
paperMarkupViewControllerDidChangeSelection(_:)
选中内容发生变化时
paperMarkupViewControllerDidChangeContentVisibleFrame(_:)
可见区域发生变化时

PaperMarkup Data Model

PaperMarkup数据模型

PaperMarkup
is a
Sendable
struct that stores all markup elements and PencilKit drawing data.
PaperMarkup
是一个
Sendable
结构体,用于存储所有标记元素和PencilKit绘图数据。

Creating and Persisting

创建与持久化

swift
// New empty model
let markup = PaperMarkup(bounds: CGRect(x: 0, y: 0, width: 612, height: 792))

// Load from saved data
let markup = try PaperMarkup(dataRepresentation: savedData)

// Save — dataRepresentation() is async throws
func save(_ markup: PaperMarkup) async throws {
    let data = try await markup.dataRepresentation()
    try data.write(to: fileURL)
}
swift
// 新建空模型
let markup = PaperMarkup(bounds: CGRect(x: 0, y: 0, width: 612, height: 792))

// 从已保存的数据加载
let markup = try PaperMarkup(dataRepresentation: savedData)

// 保存 — dataRepresentation()是异步抛出方法
func save(_ markup: PaperMarkup) async throws {
    let data = try await markup.dataRepresentation()
    try data.write(to: fileURL)
}

Inserting Content Programmatically

以编程方式插入内容

swift
// Text box
markup.insertNewTextbox(
    attributedText: AttributedString("Annotation"),
    frame: CGRect(x: 50, y: 100, width: 200, height: 40),
    rotation: 0
)

// Image
markup.insertNewImage(cgImage, frame: CGRect(x: 50, y: 200, width: 300, height: 200), rotation: 0)

// Shape
let shapeConfig = ShapeConfiguration(
    type: .rectangle,
    fillColor: UIColor.systemBlue.withAlphaComponent(0.2).cgColor,
    strokeColor: UIColor.systemBlue.cgColor,
    lineWidth: 2
)
markup.insertNewShape(configuration: shapeConfig, frame: CGRect(x: 50, y: 420, width: 200, height: 100), rotation: 0)

// Line with arrow end marker
let lineConfig = ShapeConfiguration(type: .line, fillColor: nil, strokeColor: UIColor.red.cgColor, lineWidth: 3)
markup.insertNewLine(
    configuration: lineConfig,
    from: CGPoint(x: 50, y: 550), to: CGPoint(x: 250, y: 550),
    startMarker: false, endMarker: true
)
Shape types:
.rectangle
,
.roundedRectangle
,
.ellipse
,
.line
,
.arrowShape
,
.star
,
.chatBubble
,
.regularPolygon
.
swift
// 文本框
markup.insertNewTextbox(
    attributedText: AttributedString("Annotation"),
    frame: CGRect(x: 50, y: 100, width: 200, height: 40),
    rotation: 0
)

// 图片
markup.insertNewImage(cgImage, frame: CGRect(x: 50, y: 200, width: 300, height: 200), rotation: 0)

// 形状
let shapeConfig = ShapeConfiguration(
    type: .rectangle,
    fillColor: UIColor.systemBlue.withAlphaComponent(0.2).cgColor,
    strokeColor: UIColor.systemBlue.cgColor,
    lineWidth: 2
)
markup.insertNewShape(configuration: shapeConfig, frame: CGRect(x: 50, y: 420, width: 200, height: 100), rotation: 0)

// 带箭头末端标记的线条
let lineConfig = ShapeConfiguration(type: .line, fillColor: nil, strokeColor: UIColor.red.cgColor, lineWidth: 3)
markup.insertNewLine(
    configuration: lineConfig,
    from: CGPoint(x: 50, y: 550), to: CGPoint(x: 250, y: 550),
    startMarker: false, endMarker: true
)
形状类型:
.rectangle
.roundedRectangle
.ellipse
.line
.arrowShape
.star
.chatBubble
.regularPolygon

Other Operations

其他操作

swift
markup.append(contentsOf: otherMarkup)       // Merge another PaperMarkup
markup.append(contentsOf: pkDrawing)          // Merge a PKDrawing
markup.transformContent(CGAffineTransform(...)) // Apply affine transform
markup.removeContentUnsupported(by: featureSet) // Strip unsupported elements
PropertyDescription
bounds
Coordinate space of the markup
contentsRenderFrame
Tight bounding box of all content
featureSet
Features used by this data model's content
indexableContent
Extractable text for search indexing
Use
suggestedFrameForInserting(contentInFrame:)
on the view controller to get a frame that avoids overlapping existing content.
swift
markup.append(contentsOf: otherMarkup)       // 合并另一个PaperMarkup
markup.append(contentsOf: pkDrawing)          // 合并PKDrawing
markup.transformContent(CGAffineTransform(...)) // 应用仿射变换
markup.removeContentUnsupported(by: featureSet) // 移除不支持的元素
属性描述
bounds
标记的坐标空间
contentsRenderFrame
所有内容的紧密边界框
featureSet
此数据模型内容使用的功能集
indexableContent
可提取用于搜索索引的文本
可以使用视图控制器的
suggestedFrameForInserting(contentInFrame:)
方法获取一个避免与现有内容重叠的插入区域。

Insertion Controllers

插入控制器

MarkupEditViewController (iOS, iPadOS, visionOS)

MarkupEditViewController(iOS、iPadOS、visionOS)

Presents a popover menu for inserting shapes, text boxes, lines, and other elements.
swift
func showInsertionMenu(from barButtonItem: UIBarButtonItem) {
    let editVC = MarkupEditViewController(
        supportedFeatureSet: .latest,
        additionalActions: []
    )
    editVC.delegate = paperVC  // PaperMarkupViewController conforms to the delegate
    editVC.modalPresentationStyle = .popover
    editVC.popoverPresentationController?.barButtonItem = barButtonItem
    present(editVC, animated: true)
}
弹出菜单,用于插入形状、文本框、线条等元素。
swift
func showInsertionMenu(from barButtonItem: UIBarButtonItem) {
    let editVC = MarkupEditViewController(
        supportedFeatureSet: .latest,
        additionalActions: []
    )
    editVC.delegate = paperVC  // PaperMarkupViewController遵循此代理协议
    editVC.modalPresentationStyle = .popover
    editVC.popoverPresentationController?.barButtonItem = barButtonItem
    present(editVC, animated: true)
}

MarkupToolbarViewController (macOS, Mac Catalyst)

MarkupToolbarViewController(macOS、Mac Catalyst)

Provides a toolbar with drawing tools and insertion buttons.
swift
let toolbar = MarkupToolbarViewController(supportedFeatureSet: .latest)
toolbar.delegate = paperVC
addChild(toolbar)
toolbar.view.frame = toolbarContainerView.bounds
toolbarContainerView.addSubview(toolbar.view)
toolbar.didMove(toParent: self)
Both controllers must use the same
FeatureSet
as the
PaperMarkupViewController
.
提供包含绘图工具和插入按钮的工具栏。
swift
let toolbar = MarkupToolbarViewController(supportedFeatureSet: .latest)
toolbar.delegate = paperVC
addChild(toolbar)
toolbar.view.frame = toolbarContainerView.bounds
toolbarContainerView.addSubview(toolbar.view)
toolbar.didMove(toParent: self)
两个控制器必须与
PaperMarkupViewController
使用相同的
FeatureSet

FeatureSet Configuration

FeatureSet配置

FeatureSet
controls which markup capabilities are available.
PresetDescription
.latest
All current features — recommended starting point
.version1
Features from version 1
.empty
No features enabled
FeatureSet
用于控制哪些标记功能可用。
预设描述
.latest
包含所有当前功能——推荐作为初始配置
.version1
包含版本1的功能
.empty
未启用任何功能

Customizing

自定义配置

swift
var features = FeatureSet.latest
features.remove(.stickers)
features.remove(.images)

// Or build up from empty
var features = FeatureSet.empty
features.insert(.drawing)
features.insert(.text)
features.insert(.shapeStrokes)
swift
var features = FeatureSet.latest
features.remove(.stickers)
features.remove(.images)

// 或者从空集开始构建
var features = FeatureSet.empty
features.insert(.drawing)
features.insert(.text)
features.insert(.shapeStrokes)

Available Features

可用功能

FeatureDescription
.drawing
Freeform PencilKit drawing
.text
Text box insertion
.images
Image insertion
.stickers
Sticker insertion
.links
Link annotations
.loupes
Loupe/magnifier elements
.shapeStrokes
Shape outlines
.shapeFills
Shape fills
.shapeOpacity
Shape opacity control
功能描述
.drawing
自由形式的PencilKit绘图
.text
插入文本框
.images
插入图片
.stickers
插入贴纸
.links
链接注释
.loupes
放大镜元素
.shapeStrokes
形状轮廓
.shapeFills
形状填充
.shapeOpacity
形状透明度控制

HDR Support

HDR支持

Set
colorMaximumLinearExposure
above
1.0
on both the
FeatureSet
and
PKToolPicker
:
swift
var features = FeatureSet.latest
features.colorMaximumLinearExposure = 4.0
toolPicker.maximumLinearExposure = features.colorMaximumLinearExposure
Use
view.window?.windowScene?.screen.potentialEDRHeadroom
to match the device screen's capability. Use
1.0
for SDR-only.
FeatureSet
PKToolPicker
上将
colorMaximumLinearExposure
设置为大于
1.0
的值:
swift
var features = FeatureSet.latest
features.colorMaximumLinearExposure = 4.0
toolPicker.maximumLinearExposure = features.colorMaximumLinearExposure
可以使用
view.window?.windowScene?.screen.potentialEDRHeadroom
来匹配设备屏幕的能力。仅支持SDR的设备使用
1.0

Shapes, Inks, and Line Markers

形状、墨水和线条标记

swift
features.shapes = [.rectangle, .ellipse, .arrowShape, .line]
features.inks = [.pen, .pencil, .marker]
features.lineMarkerPositions = .all  // .single, .double, .plain, or .all
swift
features.shapes = [.rectangle, .ellipse, .arrowShape, .line]
features.inks = [.pen, .pencil, .marker]
features.lineMarkerPositions = .all  // .single、.double、.plain或.all

Integration with PencilKit

与PencilKit集成

PaperKit accepts
PKTool
for drawing and can append
PKDrawing
content.
swift
import PencilKit

// Set drawing tool
paperVC.drawingTool = PKInkingTool(.pen, color: .black, width: 3)

// Merge existing PKDrawing into markup
markup.append(contentsOf: existingPKDrawing)
PaperKit接受
PKTool
用于绘图,并且可以追加
PKDrawing
内容。
swift
import PencilKit

// 设置绘图工具
paperVC.drawingTool = PKInkingTool(.pen, color: .black, width: 3)

// 将现有PKDrawing合并到标记中
markup.append(contentsOf: existingPKDrawing)

Tool Picker Setup

工具选择器设置

swift
let toolPicker = PKToolPicker()
toolPicker.addObserver(paperVC)
paperVC.pencilKitResponderState.activeToolPicker = toolPicker
paperVC.pencilKitResponderState.toolPickerVisibility = .visible
Setting
toolPickerVisibility
to
.hidden
keeps the picker functional (responds to Pencil gestures) but not visible, enabling the mini tool picker experience.
swift
let toolPicker = PKToolPicker()
toolPicker.addObserver(paperVC)
paperVC.pencilKitResponderState.activeToolPicker = toolPicker
paperVC.pencilKitResponderState.toolPickerVisibility = .visible
toolPickerVisibility
设置为
.hidden
会使选择器保持功能可用(响应Pencil手势)但不可见,从而实现迷你工具选择器的体验。

Content Version Compatibility

内容版本兼容性

FeatureSet.ContentVersion
maps to
PKContentVersion
:
swift
let pkVersion = features.contentVersion.pencilKitContentVersion
FeatureSet.ContentVersion
PKContentVersion
相对应:
swift
let pkVersion = features.contentVersion.pencilKitContentVersion

SwiftUI Integration

SwiftUI集成

Wrap
PaperMarkupViewController
in
UIViewControllerRepresentable
:
swift
struct MarkupView: UIViewControllerRepresentable {
    @Binding var markup: PaperMarkup

    func makeUIViewController(context: Context) -> PaperMarkupViewController {
        let vc = PaperMarkupViewController(markup: markup, supportedFeatureSet: .latest)
        vc.delegate = context.coordinator
        let toolPicker = PKToolPicker()
        toolPicker.addObserver(vc)
        vc.pencilKitResponderState.activeToolPicker = toolPicker
        vc.pencilKitResponderState.toolPickerVisibility = .visible
        context.coordinator.toolPicker = toolPicker
        return vc
    }

    func updateUIViewController(_ vc: PaperMarkupViewController, context: Context) {
        if vc.markup != markup { vc.markup = markup }
    }

    func makeCoordinator() -> Coordinator { Coordinator(parent: self) }

    class Coordinator: NSObject, PaperMarkupViewController.Delegate {
        let parent: MarkupView
        var toolPicker: PKToolPicker?
        init(parent: MarkupView) { self.parent = parent }

        func paperMarkupViewControllerDidChangeMarkup(
            _ controller: PaperMarkupViewController
        ) {
            if let markup = controller.markup { parent.markup = markup }
        }
    }
}
PaperMarkupViewController
包装在
UIViewControllerRepresentable
中:
swift
struct MarkupView: UIViewControllerRepresentable {
    @Binding var markup: PaperMarkup

    func makeUIViewController(context: Context) -> PaperMarkupViewController {
        let vc = PaperMarkupViewController(markup: markup, supportedFeatureSet: .latest)
        vc.delegate = context.coordinator
        let toolPicker = PKToolPicker()
        toolPicker.addObserver(vc)
        vc.pencilKitResponderState.activeToolPicker = toolPicker
        vc.pencilKitResponderState.toolPickerVisibility = .visible
        context.coordinator.toolPicker = toolPicker
        return vc
    }

    func updateUIViewController(_ vc: PaperMarkupViewController, context: Context) {
        if vc.markup != markup { vc.markup = markup }
    }

    func makeCoordinator() -> Coordinator { Coordinator(parent: self) }

    class Coordinator: NSObject, PaperMarkupViewController.Delegate {
        let parent: MarkupView
        var toolPicker: PKToolPicker?
        init(parent: MarkupView) { self.parent = parent }

        func paperMarkupViewControllerDidChangeMarkup(
            _ controller: PaperMarkupViewController
        ) {
            if let markup = controller.markup { parent.markup = markup }
        }
    }
}

Common Mistakes

常见错误

Mismatched FeatureSets

不匹配的FeatureSet

swift
// DON'T
let paperVC = PaperMarkupViewController(markup: m, supportedFeatureSet: .latest)
let editVC = MarkupEditViewController(supportedFeatureSet: .version1, additionalActions: [])

// DO — use the same FeatureSet for both
let features = FeatureSet.latest
let paperVC = PaperMarkupViewController(markup: m, supportedFeatureSet: features)
let editVC = MarkupEditViewController(supportedFeatureSet: features, additionalActions: [])
swift
// 错误示例
let paperVC = PaperMarkupViewController(markup: m, supportedFeatureSet: .latest)
let editVC = MarkupEditViewController(supportedFeatureSet: .version1, additionalActions: [])

// 正确示例 — 两者使用相同的FeatureSet
let features = FeatureSet.latest
let paperVC = PaperMarkupViewController(markup: m, supportedFeatureSet: features)
let editVC = MarkupEditViewController(supportedFeatureSet: features, additionalActions: [])

Ignoring Content Version on Load

加载时忽略内容版本

swift
// DON'T
let markup = try PaperMarkup(dataRepresentation: data)
paperVC.markup = markup

// DO — check version compatibility
let markup = try PaperMarkup(dataRepresentation: data)
if markup.featureSet.isSubset(of: paperVC.supportedFeatureSet) {
    paperVC.markup = markup
} else {
    showVersionMismatchAlert()
}
swift
// 错误示例
let markup = try PaperMarkup(dataRepresentation: data)
paperVC.markup = markup

// 正确示例 — 检查版本兼容性
let markup = try PaperMarkup(dataRepresentation: data)
if markup.featureSet.isSubset(of: paperVC.supportedFeatureSet) {
    paperVC.markup = markup
} else {
    showVersionMismatchAlert()
}

Blocking Main Thread with Serialization

使用序列化阻塞主线程

swift
// DON'T — dataRepresentation() is async, don't try to work around it

// DO — save from an async context
func paperMarkupViewControllerDidChangeMarkup(_ controller: PaperMarkupViewController) {
    guard let markup = controller.markup else { return }
    Task {
        let data = try await markup.dataRepresentation()
        try data.write(to: fileURL)
    }
}
swift
// 错误示例 — dataRepresentation()是异步方法,不要尝试绕过它

// 正确示例 — 在异步上下文执行保存
func paperMarkupViewControllerDidChangeMarkup(_ controller: PaperMarkupViewController) {
    guard let markup = controller.markup else { return }
    Task {
        let data = try await markup.dataRepresentation()
        try data.write(to: fileURL)
    }
}

Forgetting to Retain the Tool Picker

忘记保留工具选择器

swift
// DON'T — local variable gets deallocated
func viewDidLoad() {
    let toolPicker = PKToolPicker()
    toolPicker.addObserver(paperVC)
}

// DO — store as instance property
var toolPicker: PKToolPicker!
swift
// 错误示例 — 局部变量会被释放
func viewDidLoad() {
    let toolPicker = PKToolPicker()
    toolPicker.addObserver(paperVC)
}

// 正确示例 — 存储为实例属性
var toolPicker: PKToolPicker!

Wrong Insertion Controller for Platform

为平台选择错误的插入控制器

swift
// DON'T — MarkupEditViewController is iOS/iPadOS/visionOS only

// DO
#if os(macOS)
let toolbar = MarkupToolbarViewController(supportedFeatureSet: features)
#else
let editVC = MarkupEditViewController(supportedFeatureSet: features, additionalActions: [])
#endif
swift
// 错误示例 — MarkupEditViewController仅适用于iOS/iPadOS/visionOS

// 正确示例
#if os(macOS)
let toolbar = MarkupToolbarViewController(supportedFeatureSet: features)
#else
let editVC = MarkupEditViewController(supportedFeatureSet: features, additionalActions: [])
#endif

Review Checklist

检查清单

  • import PaperKit
    present; deployment target is iOS 26+ / macOS 26+ / visionOS 26+
  • PaperMarkup
    initialized with bounds matching content size
  • Same
    FeatureSet
    used for
    PaperMarkupViewController
    and insertion controller
  • dataRepresentation()
    called in async context
  • PKToolPicker
    retained as a stored property
  • Delegate set on
    PaperMarkupViewController
    for change callbacks
  • Content version checked when loading saved data
  • Correct insertion controller per platform (
    MarkupEditViewController
    vs
    MarkupToolbarViewController
    )
  • MarkupError
    cases handled on deserialization
  • HDR:
    colorMaximumLinearExposure
    set on both
    FeatureSet
    and
    PKToolPicker
  • 已添加
    import PaperKit
    ;部署目标为iOS 26+ / macOS 26+ / visionOS 26+
  • PaperMarkup
    初始化时使用的边界与内容尺寸匹配
  • PaperMarkupViewController
    和插入控制器使用相同的
    FeatureSet
  • 在异步上下文调用
    dataRepresentation()
  • PKToolPicker
    被存储为实例属性
  • 已为
    PaperMarkupViewController
    设置代理以接收变更回调
  • 加载已保存数据时检查版本兼容性
  • 根据平台选择正确的插入控制器(
    MarkupEditViewController
    vs
    MarkupToolbarViewController
  • 反序列化时处理
    MarkupError
    情况
  • HDR支持:在
    FeatureSet
    PKToolPicker
    上都设置了
    colorMaximumLinearExposure

References

参考资料