implement checkmark on dropdown menu like “Files” app on swift.
功能实现:
section1:单选,section2:多选
Screenshot:
WechatIMG22.jpegExample:
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)
}
}
网友评论