ios 如何实现支持多选的下拉按钮?

xtupzzrd  于 2023-05-23  发布在  iOS
关注(0)|答案(2)|浏览(198)

我毫不费力地实现了一个弹出按钮,让用户从互斥的选项列表中进行选择。这在HIG的Pop-up buttons部分中有所介绍。
现在我想要类似的东西,但允许用户选择任何数量的选项从列表。HIG中的“弹出按钮”页面指出:
如果需要,请使用下拉按钮:【……】让人们选择多项
但是HIG的Pull-down buttons页面没有提到如何支持多项选择。
这是我目前为止尝试过的。我从弹出按钮代码开始(复制并粘贴到iOS Swift Playground中沿着玩):

import UIKit
import PlaygroundSupport

class MyVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let items = [ "Option 1", "Option 2", "Option 3", "Option 4" ]
        let actions: [UIAction] = items.map {
            let action = UIAction(title: $0) { action in
                print("Selected \(action.title)")
            }

            return action
        }
        let menu = UIMenu(children: actions)

        var buttonConfig = UIButton.Configuration.gray()
        let button = UIButton(configuration: buttonConfig)
        button.menu = menu
        button.showsMenuAsPrimaryAction = true
        button.changesSelectionAsPrimaryAction = true

        button.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
        ])
    }
}

PlaygroundPage.current.liveView = MyVC()

然后更新代码,使其成为下拉按钮。首先,禁用按钮的changesSelectionAsPrimaryAction属性。

button.changesSelectionAsPrimaryAction = false

然后给予按钮一个标题,这样它就不仅仅是一个小小的正方形。

buttonConfig.title = "Select Items"

现在我们有了一个按钮,当它被点击时会显示菜单。但现在没有复选标记,选择菜单也不会产生任何复选标记。所以在这里,我想更新UIAction的处理程序块,以切换动作的state

let action = UIAction(title: $0) { action in
    print("Selected \(action.title)")
    action.state = action.state == .on ? .off : .on
}

但是现在当你点击一个菜单项时,代码崩溃,并出现异常。当在真实的的iOS应用程序(而不是Playground)中运行时,错误是:
2023-05-21 10:40:56.038217-0600按钮菜单[63482:10716279]***Assert失败在-[_UIImmutableAction setState:],UIAction.m:387
2023-05-21 10:40:56.063676-0600 ButtonMenu[63482:10716279]***由于未捕获异常“NSInternalInconsistencyException’而终止应用程序,原因:'操作是不可变的,因为它是菜单的子项'
是否可以使用UIButtonUIMenu实现多选菜单?
如果是的话,我缺了什么?
如果没有,选择时应使用什么组件?理想情况下,如果用户可以点击按钮以调出菜单,选择菜单中的多个项目,然后再次点击按钮以关闭菜单,那就太好了。

rkttyhzu

rkttyhzu1#

我找到了一个变通办法您不需要尝试修改UIAction处理程序中提供的action,而是需要修改按钮菜单中的原始操作。
问题是你不能从UIAction得到UIMenu。在创建UIAction数组之前不能声明UIMenu。因此,您需要首先创建UIButton,然后才能在操作处理程序中访问按钮,然后操作处理程序允许您访问按钮的菜单并更新匹配的操作。
下面是更新后的代码,允许您在下拉菜单中选择多个项目:

import UIKit
import PlaygroundSupport

class MyVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        var buttonConfig = UIButton.Configuration.gray()
        buttonConfig.title = "Select Stuff"
        let button = UIButton(configuration: buttonConfig)

        let items = [ "Option 1", "Option 2", "Option 3", "Option 4" ]
        let actions: [UIAction] = items.map {
            let action = UIAction(title: $0) { action in
                print("Selected \(action.title)")

                // The following line causes a crash
                //action.state = action.state == .on ? .off : .on

                // The following updates the original UIAction without crashing
                if let act = button.menu?.children.first(where: { $0.title == action.title }), let act = act as? UIAction {
                    act.state = act.state == .on ? .off : .on
                }
            }

            return action
        }

        let menu = UIMenu(children: actions)
        button.menu = menu
        button.showsMenuAsPrimaryAction = true

        button.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(button)
        NSLayoutConstraint.activate([
            button.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
            button.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
        ])
    }
}

PlaygroundPage.current.liveView = MyVC()

现在我终于弄清楚了如何使这个工作,我意识到它有两个大的用户体验问题。1)按钮不像弹出按钮那样反映当前选择状态。2)如果用户想要选择多于一个项目,则用户需要点击按钮以呈现用于每个期望选择的菜单。
问题1可以通过在操作处理程序中,在更新操作状态的代码之后添加以下行来解决:

button.configuration?.title = button.menu?.selectedElements.map { $0.title }.joined(separator: ", ") ?? "None"

我不知道有什么好办法可以解决问题2。我把这个问题留给另一个问题。
最初的问题和这个答案没有解决这个任务的另一个现实世界部分-最初选择了一些菜单项。我把它留给读者作为练习。

fd3cxomn

fd3cxomn2#

这听起来像是HIG的弹出菜单部分中关于使用下拉菜单进行多重选择的内容只是在吹牛。这不是我第一次在苹果的文档、WWDC视频等中看到这种情况。
我建议使用不同的接口,即。不要尝试使用内置的按钮-> UIMenu界面来执行此操作。
相反,当用户做了他应该做的任何事情(点击按钮),你就呈现了一个呈现的视图控制器;现在你负责界面,你可以使用多选表视图,带开关的表视图,等等。(您可以看到一些关于某些选项here的相当老的讨论。)所呈现的视图可以是任何大小和位置;我喜欢用一个弹出的演示文稿为这种事情。
我认为这比“对抗框架”更好。

相关问题