UI

Swift:仿文件 app 菜单 UIMenu 实现 @avai

2021-07-07  本文已影响0人  SoaringHeart

implement checkmark on dropdown menu like “Files” app on swift.

功能实现:

section1:单选,section2:多选

Screenshot:

WechatIMG22.jpeg

Example:

import UIKit
import SwiftExpand

@available(iOS 14.0, *)
class MenuActionChooseOneController: UIViewController {

    var menuData: [(String, [(String, UIImage?)])] {
        return [
            ("Menu", [
                (title: "选择", image: UIImage.checkmark_circle),
                (title: "新建文件夹", image: UIImage.folder_badge_plus),
                (title: "扫描文档", image: UIImage.doc_text_viewfinder),
                (title: "连接服务器", image: UIImage.rectangle_connected_to_line_below),
                ]
            ),
            ("Menu1", [
                (title: "图标", image: UIImage.square_grid_2x2),
                (title: "列表", image: UIImage.list_bullet),
                ]
            ),
            
            ("Menu2", [
                (title: "名称", image: UIImage.chevron_up),
                (title: "日期", image: UIImage.chevron_down),
                (title: "大小", image: UIImage.chevron_left),
                (title: "种类", image: UIImage.chevron_right),
                (title: "标签", image: nil),
                ]
            ),
        ]
    }
    
    lazy var menuBtn: UIButton = {
        let sender = UIButton(type: .custom)
        sender.setTitle("menu", for: .normal);
        sender.showsMenuAsPrimaryAction = true
        sender.menu = UIMenu.map(data: menuData, handler: { action in
            switch action.title {
            case "图标", "列表":
                action.handleStateChange(sender, section: 1, isSingleChoose: true) {
                    DDLog(sender.checkRow(by: 1))
            //        DDLog(sender.checkActions(by: 1))
                    let tmp = sender.checkActions(by: 1)
                    DDLog(tmp?.map({ $0.title }))
                }

            case "名称", "日期", "大小", "种类", "标签":
                action.handleStateChange(sender, section: 2, isSingleChoose: false) {
                    DDLog(sender.checkRow(by: 2))
            //        DDLog(sender.checkActions(by: 2))
                    let tmp = sender.checkActions(by: 2)
                    DDLog(tmp?.map({ $0.title }))
                }
                
            default:
                DDLog(action.title)
            }
        })
        return sender
    }()
    
    
    var isListMode: Bool{
        guard let row = menuBtn.checkRow(by: 1) else { return true }
        return row == 1
//        guard let menu1 = self.menuBtn.menu?.children[1] as? UIMenu,
//              let value = menu1.children[0].value(forKey: kActionState) as? Int
//              else { return true }
//        return value == 1
    }
    // MARK: -lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        edgesForExtendedLayout = []
        view.backgroundColor = .white
        title = "MenuActionChooseOne"
        
        navigationItem.rightBarButtonItem = UIBarButtonItem(customView: menuBtn)
    }
    
    // MARK: -funtions

}

UIMenu+Helper


/// UIAction: "_state"
public let kActionState = "_state"

@available(iOS 14.0, *)
public extension UIMenu{

    /// Data mapping UIMenu structure
    static func map(_ title: String = "", data: [(String, [(String, UIImage?)])], handler: @escaping UIActionHandler) -> UIMenu {
        return UIMenu(title: title, children: data.map {
            UIMenu(title: $0.0, options: .displayInline, children: $0.1.map({
                    return UIAction(title: $0.0, image: $0.1, handler: handler)
                })
            )
        })
    }
}

@available(iOS 14.0, *)
public extension UIAction{
    
    /// state change(.on/.off), Support single selection/multiple selection.
    func handleStateChange(_ sender: UIButton, section: Int, isSingleChoose: Bool, handler: (()->Void)?) {
        guard let menu = sender.menu?.children[section] as? UIMenu else { return }
        if isSingleChoose == false {
            if self.state == .off {
                self.setValue(1, forKey: kActionState)
            } else if self.state == .on {
                self.setValue( 0, forKey: kActionState)
            }
        } else {
            menu.children.forEach {
                $0.setValue($0 == self ? 1 : 0, forKey: kActionState)
            }
        }
        handler?()
    }
}


@available(iOS 14.0, *)
public extension UIButton {
        
    /// Actions (Support single selection/multiple selection)
    /// - Returns: row(state is on)
    func checkActions(by section: Int) -> [UIAction]?{
        guard let sectionMenu = menu?.children[section] as? UIMenu
              else { return nil }
        
        let firters = sectionMenu.children.filter {
            guard let action = $0 as? UIAction,
                  let value = action.value(forKey: kActionState) as? Int else { return false }
            return value == 1
        }
        return firters as? [UIAction]
    }
    
    /// row(Support single selection)
    /// - Returns: row(state is on)
    func checkRow(by section: Int) -> Int?{
        guard let sectionMenu = menu?.children[section] as? UIMenu
              else { return nil }
        
        let firters = sectionMenu.children.filter {
            guard let value = $0.value(forKey: kActionState) as? Int else { return false }
            return value == 1
        }

        guard let checkAction = firters.first as? UIAction else { return nil }
        return sectionMenu.children.firstIndex(of: checkAction)
    }
    
}

Github

上一篇下一篇

猜你喜欢

热点阅读