简介
UIMenuController
是一个菜单修正界面,在很多地方都能用到,一般用于剪切、复制、粘贴、挑选、全选和删除指令等,也能够自界说想要的操作,它长这样:
接口介绍
open class UIMenuController : NSObject {
open class var shared: UIMenuController { get }
open var isMenuVisible: Bool // default is NO
@available(iOS, introduced: 3.0, deprecated: 13.0, message: "Use showMenuFromView:rect: or hideMenuFromView: instead.")
open func setMenuVisible(_ menuVisible: Bool, animated: Bool)
@available(iOS, introduced: 3.0, deprecated: 13.0, message: "Use showMenuFromView:rect: instead.")
open func setTargetRect(_ targetRect: CGRect, in targetView: UIView)
@available(iOS 13.0, *)
open func showMenu(from targetView: UIView, rect targetRect: CGRect)
@available(iOS 13.0, *)
open func hideMenu(from targetView: UIView)
@available(iOS 13.0, *)
open func hideMenu()
@available(iOS 3.2, *)
open var arrowDirection: UIMenuController.ArrowDirection // default is UIMenuControllerArrowDefault
@available(iOS 3.2, *)
open var menuItems: [UIMenuItem]? // default is nil. these are in addition to the standard items
open func update()
open var menuFrame: CGRect { get }
}
open class UIMenuItem : NSObject {
public init(title: String, action: Selector)
open var title: String
open var action: Selector
}
从接口中能够看出 UIMenuController
应该运用它的单例目标,具体应该怎样运用它呢?咱们先来看一下 API
文档对 UIMenuController
的阐明:
The singleton UIMenuController instance is referred to as the editing menu. When you make this menu visible, UIMenuController positions it relative to a target rectangle on the screen; this rectangle usually defines a selection. The menu appears above the target rectangle or, if there is not enough space for it, below it. The menu’s pointer is placed at the center of the top or bottom of the target rectangle, as appropriate. Be sure to set the tracking rectangle before you make the menu visible. You are also responsible for detecting, tracking, and displaying selections.
The UIResponderStandardEditActions informal protocol declares methods that are invoked when the user taps a menu command. The canPerformAction(_:withSender:) method of UIResponder is also related to the editing menu. A responder implements this method to enable and disable commands of the editing menu just before the menu is displayed. You can force this updating of menu commands’ enabled state by calling the update() method.
You can also provide your own menu items via the menuItems property. When you modify the menu items, you can use the update() method to force the menu to update its display.
翻译如下:
UIMenuController 单例称为修正菜单。当你使这个菜单可见时,UIMenuController 将它相对于屏幕上的方针矩形定位;这个矩形一般界说一个挑选。菜单显现在方针矩形上方,假如没有满足的空间,则显现在其下方。菜单指针放置在方针矩形顶部或底部的中心,视情况而定。确保在使菜单可见之前设置盯梢矩形。您还担任检测、盯梢和显现挑选。
UIResponderStandardEditActions 协议声明了在用户点击菜单指令时调用的办法。 UIResponder 的 canPerformAction(_:withSender:) 办法也和修正菜单有关。响应者完成此办法以在菜单显现之前启用和禁用修正菜单的指令。您能够经过调用 update() 办法强制更新菜单指令的启用状态。
您还能够经过 menuItems 特点供给您自己的菜单项。修正菜单项时,能够运用 update() 办法强制菜单更新其显现。
运用探索
依据 API
阐明可知
-
UIMenuController
显现方位能够经过设置一个矩形来定位 - 要想显现
UIMenuController
,需求成为响应者 - 假如没有设置
menuItems
时有自己默许的菜单,也能够经过menuItems
增加自己的菜单
如何创立并显现 UIMenuController
首要,API
说的很清楚,UIMenuController
是单例,直接运用 UIMenuController.shared
即可,然后调用 open func showMenu(from targetView: UIView, rect targetRect: CGRect)
办法来显现,
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let menu = UIMenuController.shared
menu.showMenu(from: view, rect: CGRect(x: 50, y: 50, width: 20, height: 20))
}
运转代码发现并没有什么反应,回看 API
,还需求设置榜首响应者
override var canBecomeFirstResponder: Bool {
true
}
// 上文说到的其他代码疏忽
运转代码仍是没反应,回看 API
,UIResponder 的 canPerformAction(_:withSender:) 办法也和修正菜单有关。响应者完成此办法以在菜单显现之前启用和禁用修正菜单的指令
,咱们完成一下试试
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
true
}
// 上文说到的其他代码疏忽
当当当当,成功了!!!
完成 Item 点击事情
接下来,我鼠标轻轻的点在了菜单上 Cut
,成果奔溃了:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[SwiftTestiOS.ViewController cut:]: unrecognized selector sent to instance 0x7fec7300d480'
依据提示,咱们完成 cut
办法。
override func cut(_ sender: Any?) {
print("cut cut cut !!!")
}
// 上文说到的其他代码疏忽
nice,没有奔溃,成功打印 cut cut cut !!!
其他的菜单也能够增加对应的完成,哈哈哈…搞定!!!
菜单 Item 太多???
问题:我不需求这么多菜单,咋整?
之前没有因为没有完成 canPerformAction(_:withSender:)
办法时,UIMenuController
无法呈现,完成了之后就呈现了一大堆菜单,此办法有一个action
参数,是不是此办法决议了哪些action
能够显现呢,试试看:
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
let actions = [#selector(cut(_:)), #selector(copy(_:)),
#selector(paste(_:)), #selector(delete(_:))]
return actions.contains(action)
}
// 上文说到的其他代码疏忽
也便是说,canPerformAction(_:withSender:)
决议设置的哪些菜单能够收效。敲黑板,这点很重要!!!
UIResponderStandardEditActions 协议
依据 API
阐明,UIResponderStandardEditActions
协议界说了 UIMenuController
的一些系统默许办法,内容如下
public protocol UIResponderStandardEditActions : NSObjectProtocol {
@available(iOS 3.0, *)
optional func cut(_ sender: Any?)
@available(iOS 3.0, *)
optional func copy(_ sender: Any?)
@available(iOS 3.0, *)
optional func paste(_ sender: Any?)
@available(iOS 3.0, *)
optional func select(_ sender: Any?)
@available(iOS 3.0, *)
optional func selectAll(_ sender: Any?)
@available(iOS 3.2, *)
optional func delete(_ sender: Any?)
//... 其他办法略
}
而且上文完成 cut
办法的时候有override
,也便是 UIViewController
有这个办法,依据头绪能够查到对应关系
graph TD
UIViewController --> UIResponder --> UIResponderStandardEditActions
增加自界说菜单
假如系统供给的菜单不满足咱们自己的需求,能够经过 menuItems
增加自界说菜单
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let menu = UIMenuController.shared
let item1 = UIMenuItem(title: "hello", action: #selector(helloAction))
let item2 = UIMenuItem(title: "world", action: #selector(worldAction))
menu.menuItems = [item1, item2]
menu.showMenu(from: view, rect: CGRect(x: 50, y: 50, width: 20, height: 20))
}
@objc func helloAction() {
print(#function)
}
@objc func worldAction() {
print(#function)
}
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
let actions = [#selector(cut(_:)), #selector(copy(_:)),
#selector(paste(_:)), #selector(delete(_:)),
#selector(helloAction), #selector(worldAction)]
return actions.contains(action)
}
// 上文说到的其他代码疏忽
增加之后效果如下:
箭头的方向
UIMenuController
有个arrowDirection
特点,用于设置箭头的方位,它是ArrowDirection
类型的枚举
extension UIMenuController {
public enum ArrowDirection : Int, @unchecked Sendable {
case `default` = 0
case up = 1
case down = 2
case left = 3
case right = 4
}
}
默许的时候,会依据需求调整箭头方向,而箭头的方位依据 API
描述(菜单指针放置在方针矩形顶部或底部的中心,视情况而定)
是在设置的矩形区域的上下边的中心方位。
注意:假如强制设定了一个方向的话,而在该方向没有满足的空间,则不会显现菜单
实际运用
在显现 UIMenuController
的时候有一个办法 open func showMenu(from targetView: UIView, rect targetRect: CGRect)
,此办法主要是用来设置显现方位的,targetView
指明方位参照目标,rect
表明参照 targetView
的方位,如:
let position = label.bounds
menu.showMenu(from: label, rect: position)
上述代码能够理解成:菜单显现在相对于 label
的 position
处
总结
UIMenuController
的运用整体仍是比较简单的,主要是以下几点:
-
UIMenuController
是单例 - 显现默许的
UIMenuController
菜单需求- 成为榜首响应者
-
UIResponder 的 canPerformAction(_:withSender:)
返回能够增加的UIMenuItem
- 完成对应
UIMenuItem
的办法
- 自界说
UIMenuItem
- 经过
UIMenuController.menuItems
特点增加自界说的UIMenuItem
- 在
canPerformAction(_:withSender:)
对应UIMenuItem
的action
- 经过
- 箭头的方位
- 建议运用
ArrowDirection.default
- 运用其他值可能会看不见菜单,除非确认必定能够显现,否则不引荐运用
- 建议运用