如何手动更改UIMenu中选择的UIAction?

7

目标: 尝试创建一个筛选选择屏幕(在卡片视图中),其中包含带有UIMenu项目的UIButtons。当我选择任何一个过滤器并点击应用过滤器按钮时,我关闭过滤器视图控制器并返回到集合视图屏幕以使用所选的过滤器刷新数据。

问题: 已选择过滤器时,当我想要再次返回更改任何过滤器时,单击过滤器按钮打开过滤器视图控制器,但显然没有保留任何UIMenu选择,因为它们将被重置为默认的第一个索引设置。

如何解决? 从filterVC将我的数据传回主列表屏幕时,我传递所选UIMenu的标题。我认为我可以将其传回到filterVC并将菜单默认为传入的数据(即可以搜索标题并使其成为UIMenu中选择的UIAction),但是似乎找不到一种手动选择哪个UIAction应该是UIMenu的选择状态!

    var spaceTypeMenu: UIMenu {
    return UIMenu(title: "Space Type", image: nil, identifier: nil, options: [], children: spaceTypeMenuItems)
}

    private var spaceTypeMenuItems: [UIAction] {
    return [
        UIAction(title: "All", handler: { (_) in }),
        UIAction(title: "Meeting Room", handler: { (_) in }),
        UIAction(title: "Desk", handler: { (_) in }),
        UIAction(title: "Boardroom", handler: { (_) in })
    ]
}

接下来是从viewdidload()调用的内容:

func createSpaceTypeMenu() {
    spaceTypeButton?.menu = spaceTypeMenu
    spaceTypeButton?.showsMenuAsPrimaryAction = true
}

在选择筛选器后,我将它们传回前一个 VC:

@IBAction func applyFiltersButtonPressed(_ sender: UIButton) {
    self.dismiss(animated: true) {
        let filter = Filters(site: self.siteButton?.titleLabel?.text,
                             spaceType: self.spaceTypeButton?.titleLabel?.text,
                             date: self.datePickerView.datePickerView?.date,
                             duration: self.selectedDuration)
        self.applyFiltersCallback?(filter)
    }
}

Site、Spacetype和duration是所有带有UIMenu的UI按钮,这些过滤选项目前都是硬编码的。

我想要的是,在调用applyFiltersButtonPressed()以关闭VC之前,如果我选择了“Desks”,当我回到这个FiltersVC时,“Desks”仍然被选中作为UIbutton中的文本,并且想要在“Desks”旁边打勾,而不希望菜单项默认返回到第一个选项(即“All”)。

希望这样说清楚了?

2个回答

8

我自己找到了如何做到这一点,希望能对其他和我有同样困惑的人有所帮助:

private func updateActionState(actionTitle: String? = nil, menu: UIMenu) -> UIMenu {
    if let actionTitle = actionTitle {
        menu.children.forEach { action in
            guard let action = action as? UIAction else {
                return
            }
            if action.title == actionTitle {
                action.state = .on
            }
        }
    } else {
        let action = menu.children.first as? UIAction
        action?.state = .on
    }
    return menu
}

并可以通过以下方式进行调用:

private func createSiteMenu(actionTitle: String? = nil) {
    let menu = UIMenu(title: "Site", image: nil, identifier: nil, options: [], children: siteMenuItems)
    siteButton?.menu = updateActionState(actionTitle: actionTitle, menu: menu)
    siteButton?.showsMenuAsPrimaryAction = true
}

这是一个很好的解决方案,但似乎对于嵌套的UIMenus并不有效。你能帮我处理嵌套菜单吗? - shuna

1

非常感谢,这个解决了我类似的问题。我正在使用ios15弹出和下拉菜单,但希望从枚举中填充菜单选项的原始值。

enum SortOrder: String, Codable, CaseIterable {
    case name = "Name"
    case category = "Category"
    case qty = "Quantity"
    case value = "Value"
    case token = "Token"
}
let sortClosure = { [self] (action: UIAction) in  
    // closure actions based on self.sortOrderPopup.currentTitle!
}

var sortOrderPopupOptions: [UIAction] = []
for sortOption in ListLibrary.SortOrder.allCases {
    sortOrderPopupOptions.append(UIAction(title: sortOption.rawValue, handler: sortClosure))
}

sortOrderPopup.menu = UIMenu(children: sortOrderPopupOptions)
menuSelection = currentList.sortOrder.rawValue

sortOrderPopup.menu = updateActionState(actionTitle: menuSelection, menu: sortOrderPopup.menu!)

您的解决方案完美地运行,并且可以调整以修改菜单的其他属性!


请提供完整的代码。 - Mihail Salari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接