在 iPad 上的 SwiftUI 中呈现 ActionSheet

2024-01-20

我已经得到了一个可以在 iPhone 设备上很好地呈现的 ActionSheet。但它在 iPad 上会崩溃。说它需要弹出窗口的位置。有人对这段代码感到幸运吗?我正在使用 iOS 13 beta 3 和 Xcode 11 beta 3。(这使用了 beta 2 中不可用的呈现 ActionSheet 的版本)

import SwiftUI

struct ContentView : View {
    @State var showSheet = false

    var body: some View {
        VStack {
            Button(action: {
                self.showSheet.toggle()
            }) {
                Text("Show")
            }
            .presentation($showSheet) { () -> ActionSheet in
                ActionSheet(title: Text("Hello"))

            }
        }
    }
}

#if DEBUG
struct ContentView_Previews : PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

遗憾的是,这个 bug 尚未在 iOS 13 最终版本中得到修复。开发者论坛 https://forums.developer.apple.com/message/389028#389028,我已经提交了反馈(FB7397761),但暂时需要通过使用其他 UI 来解决这个问题UIDevice.current.userInterfaceIdiom == .pad.

根据记录,(无用的)异常消息是:

2019-10-21 11:26:58.205533-0400 LOOksTape[34365:1769883] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Your application has presented a UIAlertController (<UIAlertController: 0x7f826e094a00>) of style UIAlertControllerStyleActionSheet from _TtGC7SwiftUI19UIHostingController… 
The modalPresentationStyle of a UIAlertController with this style is UIModalPresentationPopover. 
You must provide location information for this popover through the alert controller's popoverPresentationController. 
You must provide either a sourceView and sourceRect or a barButtonItem.  
If this information is not known when you present the alert controller, you may provide it in the UIPopoverPresentationControllerDelegate method -prepareForPopoverPresentation.'

作为解决方法,这popSheet函数将在 iPad 上显示一个弹出框并显示ActionSheet其他地方:

public extension View {
    /// Creates an `ActionSheet` on an iPhone or the equivalent `popover` on an iPad, in order to work around `.actionSheet` crashing on iPad (`FB7397761`).
    ///
    /// - Parameters:
    ///     - isPresented: A `Binding` to whether the action sheet should be shown.
    ///     - content: A closure returning the `PopSheet` to present.
    func popSheet(isPresented: Binding<Bool>, arrowEdge: Edge = .bottom, content: @escaping () -> PopSheet) -> some View {
        Group {
            if UIDevice.current.userInterfaceIdiom == .pad {
                popover(isPresented: isPresented, attachmentAnchor: .rect(.bounds), arrowEdge: arrowEdge, content: { content().popover(isPresented: isPresented) })
            } else {
                actionSheet(isPresented: isPresented, content: { content().actionSheet() })
            }
        }
    }
}

/// A `Popover` on iPad and an `ActionSheet` on iPhone.
public struct PopSheet {
    let title: Text
    let message: Text?
    let buttons: [PopSheet.Button]

    /// Creates an action sheet with the provided buttons.
    public init(title: Text, message: Text? = nil, buttons: [PopSheet.Button] = [.cancel()]) {
        self.title = title
        self.message = message
        self.buttons = buttons
    }

    /// Creates an `ActionSheet` for use on an iPhone device
    func actionSheet() -> ActionSheet {
        ActionSheet(title: title, message: message, buttons: buttons.map({ popButton in
            // convert from PopSheet.Button to ActionSheet.Button (i.e., Alert.Button)
            switch popButton.kind {
            case .default: return .default(popButton.label, action: popButton.action)
            case .cancel: return .cancel(popButton.label, action: popButton.action)
            case .destructive: return .destructive(popButton.label, action: popButton.action)
            }
        }))
    }

    /// Creates a `.popover` for use on an iPad device
    func popover(isPresented: Binding<Bool>) -> some View {
        VStack {
            ForEach(Array(buttons.enumerated()), id: \.offset) { (offset, button) in
                Group {
                    SwiftUI.Button(action: {
                        // hide the popover whenever an action is performed
                        isPresented.wrappedValue = false
                        // another bug: if the action shows a sheet or popover, it will fail unless this one has already been dismissed
                        DispatchQueue.main.async {
                            button.action?()
                        }
                    }, label: {
                        button.label.font(.title)
                    })
                    Divider()
                }
            }
        }
    }

    /// A button representing an operation of an action sheet or popover presentation.
    ///
    /// Basically duplicates `ActionSheet.Button` (i.e., `Alert.Button`).
    public struct Button {
        let kind: Kind
        let label: Text
        let action: (() -> Void)?
        enum Kind { case `default`, cancel, destructive }

        /// Creates a `Button` with the default style.
        public static func `default`(_ label: Text, action: (() -> Void)? = {}) -> Self {
            Self(kind: .default, label: label, action: action)
        }

        /// Creates a `Button` that indicates cancellation of some operation.
        public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Self {
            Self(kind: .cancel, label: label, action: action)
        }

        /// Creates an `Alert.Button` that indicates cancellation of some operation.
        public static func cancel(_ action: (() -> Void)? = {}) -> Self {
            Self(kind: .cancel, label: Text("Cancel"), action: action)
        }

        /// Creates an `Alert.Button` with a style indicating destruction of some data.
        public static func destructive(_ label: Text, action: (() -> Void)? = {}) -> Self {
            Self(kind: .destructive, label: label, action: action)
        }
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 iPad 上的 SwiftUI 中呈现 ActionSheet 的相关文章

随机推荐

  • iOS 中如何保存数据

    我正在制作游戏 当我关闭应用程序 在多任务管理器中关闭 时 我的所有数据都消失了 所以 我的问题很简单 我如何保存数据 假设您要保存分数和级别 它们都是名为 dataHolder 的对象的属性 DataHolder 可以创建为单例 因此您不
  • 将 Crystal Reports 连接到 SQL Server

    所以我进入了 数据库专家 但我似乎不知道如何将数据库添加到报告中 有任何想法吗 附 我正在使用 CR 13 和 SQL Server 2012 我们正在使用 CR 11 R2 我不确定 CR 2013 的选项是否已更改 但在 CR 11 R
  • JavaScript 对象使用 .检索值[重复]

    这个问题在这里已经有答案了 可能的重复 如何使用动态键访问对象 https stackoverflow com questions 6921803 how to access object using dynamic key 我有多个具有不
  • Spring:类文件版本错误 61.0,应该是 55.0

    我正在使用 Java 11 的 Maven 和 IntelliJ IDEA 上的 Maven 我正在尝试创建一个 JsonTset 类 如下所示 import org junit BeforeClass import org junit T
  • Jersey - 有没有办法用参数实例化每个请求资源?

    假设我有这样的课程 Path test public class TestResource private TestService testService public TestResource TestService testServic
  • 如何解决 Argo 输出参数大小限制?

    我有一个在 JSON 数组上循环的 Argo 工作流程 当列表变得太大时 我会收到如下错误 time some time level fatal msg Pod some pod name is invalid metadata annot
  • MongoDB 副本集状态未从启动更改为辅助

    我已经设置了一个包含 3 个节点的 MongoDB 副本集 虚拟机运行 CentOS 一个节点成为主节点 另外 2 个节点陷入启动状态 当这两个节点将其状态从启动更改为辅助时 aryabhata PRIMARY gt rs status s
  • Python:使用 lineno 引发语法错误

    我正在为特定于域的语言实现一个解析器 并且希望能够引发语法错误 引发此异常时如何设置文件名 行号和偏移量 例外 语法错误 当解析器遇到语法时引发 错误 这可能发生在 import 语句 exec 语句 调用内置函数 eval 或 input
  • 树枝变量中的树枝变量

    我有一个树枝变量html 为了在树枝模板中显示它 我这样做 html 该变量看起来像 div region top div div region center div region 也是一个变量 当 Twig 解析我的html变量 它不解析
  • 检测 jQuery 中 input[type=text] 的值变化

    我想在每次特定输入框的值发生变化时执行一个函数 它almost与 input keyup function 但是例如 将文本粘贴到框中时什么也不会发生 input change function 仅在输入模糊时触发 那么我如何立即知道文本框
  • GCC 相当于 MS 的 /bigobj

    我们正在大量使用boost serialization和一般模板 一切似乎都很顺利 不过 我们在 Windows 构建上遇到了障碍 这似乎会导致目标文件太大的问题 我们使用 MinGW Msys 和 g 4 7 0 c mingw bin
  • Flutter 删除所有路由

    我想开发一个注销按钮 它将把我发送到登录路线并从登录路线中删除所有其他路线Navigator 该文档似乎没有解释如何制作RoutePredicate或具有任何类型的removeAll 功能 我能够使用以下代码来完成此操作 Navigator
  • 我可以将参数传递给 rake db:seed 吗?

    我的一部分seeds rb将大量数据加载到数据库中 我希望能够有选择地加载这些数据 例如 rake db seed or rake db seed 0 只会加载运行网站所需的数据 而 rake db seed 1 也会将我的大数据文件加载到
  • Ember 数据无法读取未定义的属性“async”

    将 Ember v1 8 beta 3 与 Ember Data 1 0 beta 10 一起使用 您会收到以下错误 Error while processing route index Cannot read property async
  • 生成指定范围内的随机数 - 各种情况(int、float、inclusive、exclusive)

    given a Math random 返回 0 1 之间的数字的函数min max值来指定范围 我们如何为以下情况生成数字 我们想要的案例integer A min max B min max return Math floor Math
  • 如何更改jquery对话框按钮

    我想用我自己的按钮图像替换 jquery 对话框按钮 这样做最简洁的方法是什么 按钮上不会覆盖任何文本 我正在使用 jquery 1 4 2 和 jquery ui 1 8 1 不要应用 jQuery UI 使用的 CSS 选择器 使用具有
  • Global.asax 事件:Application_OnPostAuthenticateRequest

    我在用Application OnPostAuthenticateRequest事件在global asax to get a 经过身份验证的用户的角色和权限我还制作了自定义主体类来获取用户详细信息以及角色和权限 b 获取对该用户而言保持不
  • Jquery 动画无法正确处理列表项

    我有一个垂直的项目列表 每个项目都有一个删除按钮 当我点击其中一个的删除时 我希望下面的那些能够平滑地向上滑动 此时它们正在跳跃 下面是代码 http codepen io ovesyan19 pen chDgy http codepen
  • 这个&符号是什么意思? [复制]

    这个问题在这里已经有答案了 可能的重复 只需观看一些 Railscast 即可看到如下代码 Category Product Person each delete all 我知道它会删除这些模型的所有记录 但我不知道这是什么 delete
  • 在 iPad 上的 SwiftUI 中呈现 ActionSheet

    我已经得到了一个可以在 iPhone 设备上很好地呈现的 ActionSheet 但它在 iPad 上会崩溃 说它需要弹出窗口的位置 有人对这段代码感到幸运吗 我正在使用 iOS 13 beta 3 和 Xcode 11 beta 3 这使