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

来源:互联网 发布:小电影下载软件 编辑:程序博客网 时间:2024/06/15 10:57
  • 认识系统 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

原创粉丝点击