Ask Apple问答汇总之SwiftUI其三

339 阅读7分钟

近期,苹果开发者网站发起了Ask Apple活动,邀请开发人员直接与苹果专家沟通。

活动时间是2022年10月17-21日,目前活动已结束。

苹果为我们保留了本次活动中所有内容供开发者查阅。

我认为有必要在这里对一些感兴趣相关专题中问答内容进行汇总并翻译,供大家参考。

由于水平有限,文中的翻译可能有些不准确或有些小错误,还望大家在阅读过程中理解。如果您发现错误或有更好的想法,欢迎指正🙌🏻

本篇是关于SwiftUI的问答内容汇总。由于内容较多,为了控制篇幅,我会将所有该专题内容整理为三个部分,本文是第三部分。📚

这里是第一部分:Ask Apple问答汇总之SwiftUI其一

这里是第二部分:Ask Apple问答汇总之SwiftUI其二

SwiftUI

截屏2022-10-25 09.36.04 2.png

同步操作时.task.onAppear是否有区别?

Developer:

同步操作时.task.onAppear是否有区别?如果我编写Color.green.task { self.someState += },状态变化是否保证在视图首次出现之前运行?我这么问是因为我喜欢使用.task(id: …)代替.onAppear.onChange(of:)相结合的便利性。

Apple:

onappeartask都是在我们第一次在视图上运行body之前调用的。对于您的用例,它们实际上是行为等效的。

如何以编程方式向导航路径添加一个值?

Developer:

我想以编程方式向导航路径添加一个值。从本质上讲,我们过去能够对已弃用的isActive链接执行的操作。无论如何,有没有以编程方式在一个不可见的NavigationLink上执行此操作的方式? 有关更多信息,我昨天提出了一个堆栈溢出问题:stackoverflow.com/questions/7…

Apple:

如果你创建一个导航路径-- NavigationStack(path: $myPath),那么你可以只是添加到路径myPath.append(data)

Developer:

非常感谢。不知何故,我错过了这一点。从中我看到(如果使用选择而不是路径),您可以设置selection = .Destination。假设这也是正确的吗?

Apple:

是的!导航 API 的设计原则之一是,您应该能够以编程方式直接配置任何导航状态。

是否可以将参数附加到 macOS 上创建新窗口?

Developer:

是否可以将参数附加到 macOS 上创建新窗口? 我们将在子上下文中创建一个新的托管对象,并希望将这两个对象发送到新窗口。目前,我们通过在单例中保存对子上下文和托管对象的引用,然后使用在单例中检查上下文和托管对象的 URL 打开一个新窗口来执行此操作。 如果我们可以使用自定义参数启动新窗口,那会更好。这仍不可能,对吧?

Apple:

在macOS Ventura中,我们在窗口组上引入了新的 API,可让您在打开窗口时将数据传递到窗口。这也可以与开放窗口操作结合使用。

developer.apple.com/documentati…:)

developer.apple.com/documentati…

请注意,您的数据需要是可选的或指定默认值,因为在某些情况下,框架本身将创建窗口 - 例如,当选择新窗口菜单项时

数据也将保留,然后在还原时传递回窗口,前提是为用户启用了状态还原。

Developer:

天哪!这真是太棒了,正是我梦寐以求的!🤩

我在文档中看到这些功能也适用于iOS和iPadOS。如何在这些平台上打开新窗口?系统是将其作为模态呈现还是作为新场景呈现?

Apple:

请注意,它仅适用于iPadOS。我相信它会创造一个新的场景,即 - 2/3和1/3分裂。

Developer:

明白了,谢谢!🙇‍♂️

在 macOS 上的 Swift UI 中处理取消/不完整拖动的最佳方法是什么?

Developer:

在 macOS 上的 Swift UI 中处理取消/不完整拖动的最佳方法是什么?例如,考虑一个 Swift UI 视图,其中包含一堆可以拖动以重新排序的项。.onDrag.onDrop 视图方法可以处理成功执行拖放的情况。但是,如果用户将项目拖放到无效位置(例如,如果它被拖放到Mac菜单栏上),或者如果用户在拖动过程中键入Escape键,或者任何其他情况导致拖动结束而没有成功放置,该怎么办?

我对此很感兴趣,因为当丢弃未成功完成时,我需要运行一些代码,但我找不到任何类型的处理程序或回调来放置该代码。我正在寻找类似onDrag(_:preview:cancel:)的东西(而不仅仅当前存在于 Swift UI 中的onDrag(_:preview:)),我可以在其中设置在拖动被取消或未成功完成时将运行的代码。

Apple:

如果您还没有(找到解决方案),请通过 feedbackassistant.apple.com 提交描述您的用例的反馈,并在线程中分享反馈编号

Developer:

会的。我还没有提交任何内容,因为我不确定是否缺少一些现有的API。

Apple:

谢谢!

反馈总是值得赞赏的!如果你错过了一些现有的 API,通常会有人回复该信息。😊

Developer:

编号为FB11701751

Apple:

多谢!

什么是查找逐个视图设置导航栏格式的最佳方式?

Developer:

查找逐个视图设置导航栏格式的最佳方式。当前使用 UIView 控制器可表示,并将外观和滚动边缘外观应用于导航控制器,但希望在 SwiftUI 中使用修饰符。

myView
 .navigationBarBackground(mode: .onlyWhenScrolling) {
Material.bar
}

举个例子,但字体颜色,背景,是我想自定义的两件事,当不滚动我的视图时。

Apple:

您可以查看toolbarBackground()修饰符,以获取所需的一定数量的自定义(此处为文档)。请提交反馈,了解您仍然缺少的自定义支持。

Developer:

谢谢!我目前的目标是iOS 15,所以我错过了,但我会调查并提交未来的反馈。

sheet的动画是否与显示键盘的动画冲突

Developer:

我们有一个 SwiftUI 视图,它有一个@FocusState变量,称为"focusedField",其类型是枚举。视图显示为另一个视图顶部的sheet。在sheet视图中,我们尝试将focusedField设置为onAppear{...}函数中枚举的特定值。但是,呈现sheet的动画似乎阻止了focusedField实际设置其焦点。从本质上讲,视图尚未准备好设置其焦点(因为它仍在呈现中)。如果我们在onAppear{…}上调用它时稍加延迟,它就会起作用。这几乎就像我们需要的onDidAppear{…} 我们是否需要在 .sheet 中执行一些特殊操作来设置@FocusState onAppear?sheet的动画是否与显示键盘的动画冲突(当字段聚焦时会发生这种情况)?

Apple:

嗨 David,在这种情况下,您不需要做任何特殊的事情,而且听起来确实像模式sheet演示正在中断焦点更改。你能提交一份关于它的反馈报告吗?在这里包括#,我可以看一看。

有没有一种方法可以用视图结构的参数初始化@StateObject?

Developer:

有没有一种方法可以用视图结构的参数初始化@StateObject?

Apple:

今天可以通过在初始化 init 函数中的@StateObject来做到这一点:

@StateObject var store: Store

init(id: UUID) {
    self._store = StateObject(wrappedValue: Store(id: id))
}	

Developer:

它现在已经官方支持了吗?

Apple:

是的,这是官方支持的。

Developer:

哇哦。我还以为这是将来可能行不通的事情。

关于Transferable的问题

Developer:

我在 macOS 上遇到关于Transferable的麻烦

  • 我无法使用严重依赖拖放的应用程序,所以我搁置了它。
  • 无法从FolderDetail列表中拖动多个汽车项目。
  • 列表中的单个项目可拖动,但多个项目不可拖动。

代码如下

struct ContentView: View {
    @StateObject private var dataStore = DataStore()
    @State private var selectedFolder: Folder?
    var body: some View {
        NavigationSplitView {
            FolderList(selectedFolder: $selectedFolder,
                       dataStore: dataStore)
        } detail: {
            FolderDetail(folder: selectedFolder,
                         dataStore: dataStore)
        }
    }
}
struct FolderList: View {
    @Binding var selectedFolder: Folder?
    @ObservedObject var dataStore: DataStore
    var body: some View {
        List(dataStore.folders, selection: $selectedFolder) { folder in
            NavigationLink(value: folder) {
                Text(folder.name)
                    .dropDestination(for: Car.self) { cars, location in
                        print("cars = \(cars) location = \(location)")
                        if let existingCars = dataStore.cars[folder.id] {
                            dataStore.cars[folder.id] = existingCars + cars
                        } else {
                            dataStore.cars[folder.id] = cars
                        }
                        return true
                    }
            }
        }
    }
}
struct FolderDetail: View {
    let folder: Folder?
    @ObservedObject var dataStore: DataStore
    @State private var selectedCarIDs = Set<Int>()
    var body: some View {
        if let folder {
            List(dataStore.cars[folder.id] ?? [], selection: $selectedCarIDs) { car in
                Text(car.name)
                    .draggable(car)
            }
        } else {
            Text("no folder selected")
        }
    }
}

Apple:

感谢您描述您的使用案例!我们正在研究改进这一点的方法,同时我建议使用 itemProvider 修改器而不是draggable

Developer:

非常感谢Julia,是的,我一直在使用itemProvider,但它也有一些奇怪的限制,我已经提交了反馈。希望修复后,我可以恢复我的项目。

@Julia V (Apple)我也面临着macOS上的TransferRepresentation的麻烦。(iOS上工作正常)。将文件从我的应用程序拖放到Finder不起作用(相同的代码在iOS上有效)这是一个已知问题吗? 反馈 - “FB11275037”

Apple:

是的,这是我们正在研究的问题。我在可能的改进列表中得到了这样的反馈

Developer:

@Julia V (Apple) 原始问题的反馈ID是FB10128110 。多谢!!

为什么navigationdestination有时会重复加载

Developer:

navigationdestination的奇怪的行为,为什么在某些情况下它只是一次又一次地加载相同的视图

Apple:

很抱歉,您在使用 API 时遇到问题。我们在 16.1 beta 版中修复了一个出现该症状的错误。你试过最新的测试版吗?

Developer:

这是我昨天问的问题之一。在我的应用程序中,它在第一次出现视图时调用路由器关闭三次,然后每次之后调用两次。这就是你所看到的吗?

Label有时(错误地)用于为某个值提供文本标题的问题

Developer:

Label有时(错误地)用于为某个值提供文本标题(例如,帐户余额 10 美元),但一些开发人员没有意识到该标题不会在 VoiceOver 中阅读。除了我们创建一个LabeledValue组件之外,SwiftUI 是否附带了解决方案?

Apple:

SwiftUI 现在有一个LabeledContent视图,您可以使用该视图用标签对某些内容进行注释。

developer.apple.com/documentati…

LabeledContent甚至内置了格式化程序支持,如果你正在标记可遗忘的内容!即LabeledContent("Age", value: person.age, format: .number)

Developer:

很好,看起来我会在后移植后面弃用我们自己的组件。感谢您介绍此内容!几乎相同的API。

是否有可能仅使用SwiftUI使应用程序符合HCI

Developer:

我的 macOS SwiftUI 应用程序被App Review拒绝,因为它违反了 HCI 指南,其中Window菜单不包含在关闭时重新打开主窗口 (Cmd+0) 的条目。我无法在 SwiftUI 中找到执行此操作的方法,因此应用程序审阅接受了我在主窗口关闭时退出应用程序的解决方法。解决方法并不理想,所以我想知道是否有可能仅使用SwiftUI使应用程序符合HCI。

Apple:

嗨 - 很抱歉您在这里遇到了App Review问题。对于 WindowGroup 场景,我们默认将菜单项添加到File菜单中,用于创建绑定到该场景的新窗口实例。 从 macOS 文图拉开始,我们还添加了一个新的场景类型Window,它会在窗口菜单中创建一个菜单项。使用单个窗口实例定义的应用也将在窗口本身关闭时退出。 这些菜单项也可以通过键盘剪切修改器进行自定义。 如果您还没有,请就您的问题提交反馈吗?我想确保我们调查应用程序评论也拒绝您的应用程序的原因。

Developer:

我刚刚提交了FB9855975

我使用 AppDelegate 强制应用程序在所有窗口关闭时退出,并且该视图感到满意

但我认为想要支持 macOS 11 和 12 的开发人员仍然必须使用windowgroup,并且在尝试将应用提交给 MAS 时仍会遇到此问题。

Apple:

好的,谢谢你提供这些信息。

contextMenu``alert不显示的问题

Developer:

在我们的contextMenu中,我们更新了按钮的alert,为用户提供了取消或确认操作的选项,该操作以前仅通知正在发生的操作。现在,alert将不再显示,因此无法确认操作。关于我们可能错过或做错了什么的任何想法?

Apple:

@Sofia 你能更详细地介绍一下吗?哪个平台?如果您能提供一个片段,我们也许可以提供帮助

Developer:

Button(action: {
                galleryInfo = true
            }, label: {
                Label("Add to Gallery", systemImage: "rectangle.stack.badge.plus")
                    .offset(x: 0, y: 2)
            })
            .alert(
                "Upload to Gallery?",
                isPresented: $galleryInfo,
                actions: {
                    Button {
                        Task {
                            do {
                                isLoading = true
                                guard isRecipeValidForGallery() else {
                                    invalidRecipe = true
                                    isLoading = false
                                    return
                                }
                                let _ = try await Share.share(recipe: recipe, isAddedToGallery: true)
                                recipeShared = true
                            } catch {
                                shareFailed = true
                            }
                            isLoading = false
                        }
                    } label: {
                        Text("Yes, upload!")
                    }
                    Button("No thanks", role: .cancel){
                    }
                },
                message: {
                    Text("You're about to upload this recipe to the Kookin Gallery for anyone to see. Do you wish to proceed?")
                })
            .alert(
                "Yaay!",
                isPresented: $recipeShared,
                actions: {
                    Text("Ok")
                },
                message: {
                    Text("\(recipe.safeName) is now available in the Gallery for everyone to see.")
                })

问题出现在iOS上,这是我们遇到问题的第一个alert,第二个alert按预期工作。谢谢!

Apple:

这似乎应该起作用。但是,也许与contextMenu相关的某些内容正在妨碍您?这对我们来说可能是一个错误。您可以尝试删除上下文菜单,然后查看其行为是否正确。另外,您可能希望在任务块上方设置 isLoading = true

Developer:

谢谢!明天会看看,这里已经很晚了😊

是否有选项可以在iOS和macOS上自定义TabView

Developer:

是否有选项可以在iOS和macOS上自定义TabView?目前,您可以更改背景颜色,但如果不创建自定义 TabView,则无法更改字体或字体大小。这在将来的操作系统版本中是否可行?

Apple:

也许可以执行类似 UITabBar.appearance().propertyToCustomise = blah 之类的操作作为解决方法

Developer:

感谢!

到这里,Ask Apple问答汇总的SwiftUI三部分都已经整理完成,当然因为SwiftUI内容过多,分三部分仍不足以涵括所有,还有少数问题未在本系列汇总中整理,感兴趣的可以在官方专题中查看。