ShortcutItem

Before the iPhone 11, there was a home-screen interaction called 3D Touch, which has now been changed to Haptic Touch. It is a three-dimensional touch technology that can sense different touch pressures. By using this technology, you can set up up to 4 different ShortcutItem (shortcut menu) for App, which can be implemented in static and dynamic two ways.

  • Static configuration through the info.plist file.
<key>UIApplicationShortcutItems</key>
<array>
    <dict>
        <key>UIApplicationShortcutItemIconType</key>
        <string>UIApplicationShortcutIconTypeSearch</string>
        <key>UIApplicationShortcutItemSubtitle</key>
        <string>subtitle</string>
        <key>UIApplicationShortcutItemTitle</key>
        <string>The title</string>
        <key>UIApplicationShortcutItemType</key>
        <string>search</string>
    </dict>.</array>
Copy the code
  • Dynamic configuration is set by code.
extension AppDelegate {
    func shortcutItems(a) {
        / / icon
        let icon1 = UIApplicationShortcutIcon(systemImageName: "qrcode.viewfinder") // System image
        let icon2 = UIApplicationShortcutIcon(templateImageName: "settings") // Create a custom image
        let icon3 = UIApplicationShortcutIcon(type: .search) // System type

        / / the menu
        let item1 = UIApplicationShortcutItem(type: "1", localizedTitle: "Scan", localizedSubtitle: nil, icon: icon1, userInfo: nil)
        let item2 = UIApplicationShortcutItem(type: "2", localizedTitle: "Settings", localizedSubtitle: nil, icon: icon2, userInfo: nil)
        let item3 = UIApplicationShortcutItem(type: "3", localizedTitle: "Search", localizedSubtitle: nil, icon: icon3, userInfo: nil)

        / / set
        UIApplication.shared.shortcutItems = [item1, item2, item3]
    }
}
Copy the code
  • Click event Response.
Before iOS13, use the AppDelegate delegate delegate method
func application(_ application: UIApplication.performActionFor shortcutItem: UIApplicationShortcutItem.completionHandler: @escaping (Bool) - >Void) {
    if shortcutItem.type = = "1" {
        window?.rootViewController?.view.backgroundColor = .red
    } else if shortcutItem.type = = "2" {
        window?.rootViewController?.view.backgroundColor = .green
    } else if shortcutItem.type = = "3" {
        window?.rootViewController?.view.backgroundColor = .blue
    }
}

// After iOS13, the AppDelegate delegate delegate method will not be called, you need to use the SceneDelegate delegate method
func windowScene(_ windowScene: UIWindowScene.performActionFor shortcutItem: UIApplicationShortcutItem.completionHandler: @escaping (Bool) - >Void) {
    if shortcutItem.type = = "1" {
        window?.rootViewController?.view.backgroundColor = .red
    } else if shortcutItem.type = = "2" {
        window?.rootViewController?.view.backgroundColor = .green
    } else if shortcutItem.type = = "3" {
        window?.rootViewController?.view.backgroundColor = .blue
    }
}
Copy the code

UIMenu

  • UIMenu was introduced in iOS 13 to make it easy to create program menus and context menus.
import UIKit

class ViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // Displays the toolbar
        navigationController?.isToolbarHidden = false
        // The menu is bound to UIBarButtonItem (constructor for iOS 14)
        let addNewItem = UIBarButtonItem(systemItem: .add, primaryAction: nil, menu: createMenu())
        // Put it in the toolbar
        toolbarItems = [addNewItem]
    }

    func createMenu(a) -> UIMenu {
        // The first menu
        let favorite = UIAction(title: "Favorite", image: UIImage(systemName: "heart.fill")) { _ in
            print("favorite")}// The second menu
        let share = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up.fill")) { _ in
            print("share")}// The third menu
        let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash.fill"), attributes: [.destructive]) { _ in
            print("delete")}// Create a menu group
        let menuActions = [favorite, share, delete]
        / / create UIMenu
        let addNewMenu = UIMenu(children: menuActions)

        return addNewMenu
    }
}
Copy the code
  • Introduced in iOS 14UIDeferredMenuElementAllows you to create UIMenu asynchronously and dynamically configure the contents of the menu.
import UIKit

class ViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // Put it in the navigation bar
        navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .add, primaryAction: nil, menu: createMenu())
    }

    func createMenu(a) -> UIMenu {
        // Load the Bundle directly from the Bundle
        let menuItemsForUser = Bundle.main.decode([RemoteItem].self, from: "menu.json")
        / / create UIDeferredMenuElement
        let dynamicElements = UIDeferredMenuElement { completion in
            / / create the UIAction
            let actions = menuItemsForUser.map { item in
                UIAction(title: item.title, image: UIImage(systemName: item.icon)) { _ in
                    print("\(item.title) tapped")}}// Be sure to invoke the completion processing
            completion(actions)
        }

        return UIMenu(children: [dynamicElements])
    }
}

/ / the menu Model
struct RemoteItem: Codable {
    let title: String
    let icon: String
}

// Load the file and go to Model
extension Bundle {
    func decode<T: Decodable> (_ type: T.Type.from file: String) -> T {
        guard let url = self.url(forResource: file, withExtension: nil) else {
            fatalError("Failed to find \(file) in bundle.")}guard let data = try? Data(contentsOf: url) else {
            fatalError("Failed to load \(file) from bundle.")}guard let model = try? JSONDecoder().decode(T.self, from: data) else {
            fatalError("Failed to decode \(file) from bundle.")}return model
    }
}
Copy the code

The JSON content is as follows:

[{"title": "Favorite"."icon": "heart.fill"
    },
    {
        "title": "Share"."icon": "square.and.arrow.up.fill"
    },
    {
        "title": "Delete"."icon": "trash.fill"}]Copy the code

Context Menus

  • WWDC 2019 introduced Context Menus, which are also triggered by pressing. Unlike Haptic Touch, Context Menus are used to set Menus in the App.
  • If you want to enable a context menu, you need to create oneUIContextMenuInteractionAdd it to a triggered UIView, specify a delegate, create the UIMenu in the delegate method and return itUIContextMenuConfigurationCan.
import UIKit

class ViewController: UIViewController {    
    // Need to turn on User Interaction
    @IBOutlet weak var imageView: UIImageView!
    
    override func viewDidLoad(a) {
        super.viewDidLoad()
        
        / / create UIContextMenuInteraction
        let interaction = UIContextMenuInteraction(delegate: self)
        / / add UIContextMenuInteraction
        // Use any other UIView
        imageView.addInteraction(interaction)
    }
}

// Proxy method
extension ViewController: UIContextMenuInteractionDelegate {
    func contextMenuInteraction(_ interaction: UIContextMenuInteraction.configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {        
        // The first menu
        let favorite = UIAction(title: "Favorite", image: UIImage(systemName: "heart.fill")) { action in
            print("favorite")}// The second menu
        let share = UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up.fill")) { action in
            print("share")}// The third menu
        let delete = UIAction(title: "Delete", image: UIImage(systemName: "trash.fill"), attributes: [.destructive]) { action in
            print("delete")}/ / return UIContextMenuConfiguration
        return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
            UIMenu(children: [favorite, share, delete])
        }
    }
}
Copy the code