Swift UIMenuController的简单运用和简单自定义

  • 认识系统 UIMenuController

系统 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、
UITextViewUIWebView这三种控件自带 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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值