SwiftUI 菜单中的内联水平按钮

8
在SwiftUI中,有一种叫做菜单的东西,在其中你可以有按钮、分割线、其他菜单等。以下是我正在构建的一个示例:
import SwiftUI

func testing() {
    print("Hello")
}

struct ContentView: View {
    var body: some View {
        VStack {
            Menu {
                Button(action: testing) {
                    Label("Button 1", systemImage: "pencil.tip.crop.circle.badge.plus")
                }
                Button(action: testing) {
                    Label("Button 2", systemImage: "doc")
                }
            }
        label: {
            Label("", systemImage: "ellipsis.circle")
        }
        }
    }
}

所以,在SwiftUI Playgrounds应用程序中,他们有这个菜单:

enter image description here

我的问题是:
他们是如何制作这个带圈菜单选项的?我找到了几个其他类似的情况,都是在菜单中显示一组水平按钮,就像下面这个例子一样:

enter image description here

HStack和其他明显的尝试都失败了。我已经考虑添加MenuStyle,但是苹果的文档非常缺乏,只显示了将红色边框添加到菜单按钮的示例。不确定那是否是正确的路径。
我只能让Dividers()和Buttons()出现在菜单中:

enter image description here

我也只能找到显示这两个的代码示例,尽管在其他应用程序中看到了其他选项的示例。


这是一些我正在玩耍的带有菜单的 SwiftUI 代码,如果有帮助的话,可以看看:https://gist.github.com/adammenges/a8cc0dd63fe8d13ad5e5819b9ea31057 - adammenges
1
没有最小可复现示例,我们无法帮助你进行故障排除。所有的代码都应该包含在问题中。 - lorem ipsum
请展示一下你已经尝试过的内容。你看到了什么结果? - Ashley Mills
添加了我所看到的! - adammenges
这是一个棘手的问题,我尝试了Sections和Pickers但都无济于事。UIKit等效项是UIMenuElementSizeSmall,这可能有助于搜索。你见过哪些SwiftUI应用程序中使用它?我们可以反编译它们并找出答案。 - malhal
2个回答

6
从iOS17开始,我能够通过在菜单中使用ControlGroup来实现这一点。
Menu {
                        
    ControlGroup {

        Button {
                                
        } label: {
            Image(systemName: "1.circle.fill")
        }

        Button {
                                
        } label: {
            Image(systemName: "2.circle.fill")
        }

        Button {
                                
        } label: {
            Image(systemName: "3.circle.fill")
        }

                           
    }
 
 ....

}

5

目前看来,这只在UIKit中可用(仅限iOS 16+),通过设置

menu.preferredElementSize = .medium

如果想在您的应用程序中添加此功能,可以将 UIMenu 添加到 UIButton 中,然后使用 UIHostingController 将其添加到 SwiftUI 应用程序中。

以下是一个示例实现:

创建 UIButton 的子类

class MenuButton: UIButton {
    
    override init(frame: CGRect) {
        super.init(frame: frame)

        let inspectAction = self.inspectAction()
        let duplicateAction = self.duplicateAction()
        let deleteAction = self.deleteAction()

        setImage(UIImage(systemName: "ellipsis.circle"), for: .normal)
        menu = UIMenu(title: "", children: [inspectAction, duplicateAction, deleteAction])
        menu?.preferredElementSize = .medium
        showsMenuAsPrimaryAction = true

    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func inspectAction() -> UIAction {
        UIAction(title: "Inspect",
                 image: UIImage(systemName: "arrow.up.square")) { action in
           //
        }
    }
        
    func duplicateAction() -> UIAction {
        UIAction(title: "Duplicate",
                 image: UIImage(systemName: "plus.square.on.square")) { action in
           //
        }
    }
        
    func deleteAction() -> UIAction {
        UIAction(title: "Delete",
                 image: UIImage(systemName: "trash"),
            attributes: .destructive) { action in
           //
        }
    }

}

使用 UIViewRepresentable 创建一个菜单

struct Menu: UIViewRepresentable {
    func makeUIView(context: Context) -> MenuButton {
        MenuButton(frame: .zero)
    }
    
    func updateUIView(_ uiView: MenuButton, context: Context) {
    }
}

运行得非常顺利!

struct ContentView: View {
    var body: some View {
        Menu()
    }
}

enter image description here


哦,太好了!谢谢!你怎么在下面添加更多的常规按钮呢?就像第二张截图中那样。 - adammenges
2
苹果公司提供了一个可下载的项目,其中包含各种菜单。我建议您安装该项目并查看它们的操作。https://developer.apple.com/documentation/uikit/uicontrol/adding_context_menus_in_your_app - Ashley Mills

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