中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS開發之UIMenuController如何使用

發布時間:2022-07-20 17:01:07 來源:億速云 閱讀:240 作者:iii 欄目:開發技術

本文小編為大家詳細介紹“iOS開發之UIMenuController如何使用”,內容詳細,步驟清晰,細節處理妥當,希望這篇“iOS開發之UIMenuController如何使用”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

    簡介

    UIMenuController 是一個菜單編輯界面,在很多地方都能用到,通常用于剪切、復制、粘貼、選擇、全選和刪除命令等,也可以自定義想要的操作,它長這樣:

    iOS開發之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
    }
    // 上文提到的其他代碼忽略

    當當當當,成功了!!!

    iOS開發之UIMenuController如何使用

    實現 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)
    }
    // 上文提到的其他代碼忽略

    iOS開發之UIMenuController如何使用

    也就是說,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 有這個方法,根據線索可以查到對應關系

    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)
    }
    // 上文提到的其他代碼忽略

    添加之后效果如下:

    iOS開發之UIMenuController如何使用

    箭頭的方向

    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 處

    讀到這里,這篇“iOS開發之UIMenuController如何使用”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    济南市| 黔东| 新民市| 五华县| 县级市| 襄垣县| 清水河县| 广平县| 乐都县| 高州市| 灵璧县| 家居| 烟台市| 大兴区| 桂平市| 航空| 建宁县| 石屏县| 延庆县| 浏阳市| 顺义区| 桓台县| 东莞市| 丰顺县| 织金县| 南木林县| 高碑店市| 文成县| 修水县| 高安市| 寿宁县| 镇江市| 育儿| 惠来县| 敦化市| 晴隆县| 梁山县| 大城县| 加查县| 大洼县| 巧家县|