- 认识系统 UIMenuController
* 创建系统 UIMenuController
// 要让添加 menu 的目标控件成为第一响应者,否则某些功能会错乱,例如 label 未成为第一响应者但是 label 的 menu 有 paste 功能会直接 paste 到第一响应者上
label.becomeFirstResponder()
// 由于系统只允许一个 UIMenuController 存在,所以创建 UIMenuController 是以单例的形式获取的
let menu = UIMenuController.shared
// 设置箭头方向
menu.arrowDirection = .default
// 设置添加上 menu 的目标控件的 rect 和目标控件
menu.setTargetRect(label.bounds, in: label)
// 令 Menu 可见
menu.setMenuVisible(true, animated: true)
- 设置系统菜单显示的菜单条目的条件
// 能够在菜单中显示的条目有两个条件
// 1. 在 menu 的属性 menuItems 中拥有该条目 (UITextField、
UITextView、UIWebView这三种控件自带 menu 菜单,其中有系统为其添加的
几个Item,例如:copy、cut、paste、select、selectAll 等等)
// 2. 在控件的 canPerformAction(_:withSender:) 方法中让 Item 对
应的方法显示
// 4. 必须实现 Items 中各个 Item 的方法
// 3. 如果是非自定义 Menu,那么需要该控件所在的控制器成为第一响应者。
// 3.1 成为让控制器成为第一响应者有两种方式
// 3.1.1 在控制器中将 canBecomeFirstResponder 属性设置为 true
// 3.1.2 如果控制器中有 UITextField 等点击能够成为第一响应者的控件,
那么点击该控件,控制器会自动的成为第一响应者。但是这样会有问题.
// 3.3.2.1 问题所在
// 例如给 UILabel 通过长按添加一个 UIMenuController,这时需要 UILabel
所在的控制器成为第一响应者,从而调用到控制器中 canPerformAction 的方法。
通过点击 UITextField 让控制器成为第一响应者,由于此时真正的第一响应者是 UITextField,
所以通过长按显示的 UIMenuController 的 items 是 UITextField 中 canPerformAction
方法中显示的 items,而非期望中 label 显示的 Menu。
所以为了避免这种错误,推荐使用自定义控件
创建自定义的继承 UILabel 的控件 SQMenuLabel 中添加 UIMenuController
期望效果
// 在 init(frame:) 或者 awakeFromNib()中创建长按手势
// 创建长按手势
func setupLabelLongPressGes(){
let longPressGes = UILongPressGestureRecognizer(target: self, action: #selector(labelLongPressAction))
// 长按手势最小触发时间
longPressGes.minimumPressDuration = 1
// 需要点击的次数
// longPressGes.numberOfTapsRequired = 1
// 长按手势需要的同时敲击触碰数(手指数)
longPressGes.numberOfTouchesRequired = 1
// 长按有效移动范围(从点击开始,长按移动的允许范围 单位 px
longPressGes.allowableMovement = 15
self.addGestureRecognizer(longPressGes)
}
// 实现 labelLongPressAction 方法
@objc func labelLongPressAction(){
// 如果 Menu 已经被创建那就不再重复创建 menu
if (UIMenuController.shared.isMenuVisible){
return
}
// 要成为第一响应者否则某些功能会错乱,例如 label 未成为第一响应者
但是 label 的 menu 有 paste 功能会直接 paste 到第一响应者上,并且在显示
Menu 的时候系统会自动调用第一响应者中的 canPerformAction(_:withSender:) 方法
self.becomeFirstResponder()
// 由于系统只允许一个 UIMenuController 存在,所以创建 UIMenuController 是以单例的形式获取的
let menu = UIMenuController.shared
// 设置 Menu 所显示的 items,items 的方法可以不同,这里为了方便写了同一个方法
menu.menuItems = [UIMenuItem(title: "item1", action: #selector(objAction)),
UIMenuItem(title: "item2", action: #selector(objAction)),
UIMenuItem(title: "item3", action: #selector(objAction)),
UIMenuItem(title: "item4", action: #selector(objAction))]
// 设置箭头方向
menu.arrowDirection = .default
// 设置添加上 menu 的目标控件的 rect 和目标控件
menu.setTargetRect(self.bounds, in: self)
// 令 Menu 可见
menu.setMenuVisible(true, animated: true)
}
// 自定义 Item 方法
@objc func objAction(){
print("successed!")
}
// 在 canPerformAction(_:withSender:) 中让 items 所对应的方法得以显示
override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
print(action)
if action == #selector(objAction){
return true
}
return false
}
参考资料:http://www.jianshu.com/p/ddd59867909a
http://www.jianshu.com/p/a504c6a20808