UIEditMenuInteractionのメニューをカスタマイズする
iOS16からUIMenuControllerが非推奨になり、UIEditMenuInteractionを使うことになりました。
使い方
次のように、メニューを表示したいビューにUIEditMenuInteraction
をアタッチします。
editMenuInteraction = UIEditMenuInteraction(delegate: self)
view.addInteraction(editMenuInteraction!)
メニューを表示するときは、UIEditMenuInteraction
のpresentEditMenu(with:)
を呼びます
let configuration = UIEditMenuConfiguration(
identifier: "dev.noppe.app.editMenu.longpress",
sourcePoint: point
)
editMenuInteraction?.presentEditMenu(with: configuration)
メニューの構築はUIEditMenuInteractionDelegate
を利用します。
public func editMenuInteraction(_ interaction: UIEditMenuInteraction, menuFor configuration: UIEditMenuConfiguration, suggestedActions: [UIMenuElement]) -> UIMenu? {
// 表示したいメニューを返す
}
同じ画面で複数のメニューを出し分けたい場合は、configuration.identifier
を参照することでメニューの構築を分岐することができます。
メニューのカスタマイズ
標準メニューだけを表示する
標準メニューとはコピーや切り取りといったメニューです。
これらを表示したい場合は、特に設定する必要はありません。
UIEditMenuInteractionDelegate
でnilを返しても標準メニューだけを返すことができます。
自作のメニューだけを表示する
UIEditMenuInteractionDelegate
で、自作のUIMenuを作って返せば良いです。
return UIMenu(children: [
UIAction(title: "反転", handler: { _ in ... })
])
自作のメニューと標準メニューのどちらも出す
UIEditMenuInteractionDelegate
のsuggestedActions
に標準メニューが含まれているので、自作のメニューの中で追加してあげます。
return UIMenu(children: [
UIAction(title: "反転", handler: { _ in ... })
] + suggestedActions)
標準メニューの一部を出す
これがちょっとややこしいです。
NGパターンとしては、suggestedActions
のtitleなどを参照して取り出すのはローカライズなどに対応できないため正しくありません
// NG
return UIMenu(children: [
UIAction(title: "反転", handler: { _ in ... })
] + suggestedActions.filter { $0.title == "コピー" })
ではどうするかというと、UIMenuController
同様にUIResponder
のcanPerformAction
で制御します。
public override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
action == #selector(UIResponderStandardEditActions.copy)
}
これでメニューを絞ることができました。
UIMenuController
と異なり、ここでfalseが返却されても追加した自作メニューは影響を受けません。
Discussion