我尝试为更大的、可用于生产的 SwiftUI 应用程序构建架构。我一直在遇到同样的问题,这指向 SwiftUI 中的一个主要设计缺陷。
仍然没有人能给我一个完整的工作,生产就绪的答案。
如何做SwiftUI包含导航的可重用视图?
由于它SwiftUI NavigationLink与视图有很强的联系,这根本不可能以这样的方式在更大的应用程序中扩展。NavigationLink在那些小样本应用程序中,是的 - 但不是当您想在一个应用程序中重用许多视图时。也可能在模块边界上重用。(例如:在 iOS、WatchOS 等中重用 View...)
设计问题:导航链接被硬编码到视图中。
NavigationLink(destination: MyCustomView(item: item))
Run Code Online (Sandbox Code Playgroud)
但是如果包含这个的视图NavigationLink应该是可重用的,我就不能对目的地进行硬编码。必须有一种机制来提供目的地。我在这里问了这个问题并得到了很好的答案,但仍然不是完整的答案:
这个想法是将目标链接注入可重用视图。一般来说,这个想法可行,但不幸的是,这并不能扩展到真正的生产应用程序。一旦我有多个可重用的屏幕,我就会遇到一个逻辑问题,即一个可重用的视图 ( ViewA) 需要一个预配置的视图目标 ( ViewB)。但是如果ViewB还需要一个预配置的 view-destinationViewC呢?我需要建立ViewB在这样的方式已经ViewC被注入已经ViewB在我注入ViewB到ViewA。等等......但由于当时必须传递的数据不可用,整个构造失败。
我的另一个想法是使用Environmentas 依赖注入机制为NavigationLink. 但我认为这或多或少应该被视为一种黑客行为,而不是大型应用程序的可扩展解决方案。我们最终会基本上将环境用于所有事情。但是因为 Environment 也只能在 View 内部使用(而不是在单独的 Coordinators 或 ViewModels 中),所以在我看来这将再次创建奇怪的构造。
就像业务逻辑(例如视图模型代码)和视图必须分开,导航和视图也必须分开(例如协调器模式)UIKit因为我们访问视图UIViewController和UINavigationController …
我正在使用 Xcode 12 进行 iOS 14.0 的部署。
应用程序上的导航功能正常(当我单击其中一个子视图上的 NavigationLink 时,它导航到正确的视图,当我单击后退按钮时,它会关闭视图。)但是,当我单击后退按钮时,控制台打印以下错误:
Trying to pop to a missing destination at /Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-103/Shared/NavigationBridge_PhoneTV.swift:337
Run Code Online (Sandbox Code Playgroud)
除了错误日志之外,该应用程序运行良好,所以我打算暂时忽略该错误......但我想知道它意味着什么?我的代码中没有任何名为“Monoceros”的内容。我猜这与 TabView 作为 NavigationView 的子视图有关?
编辑:
几个月后,这个问题仍然存在。这是可重现的代码。打开 ContentView(),在 FirstScreen() 上单击 NavigationLink,然后单击后退按钮。它会打印出 Monoceros 哈哈
Trying to pop to a missing destination at /Library/Caches/com.apple.xbs/Sources/Monoceros/Monoceros-103/Shared/NavigationBridge_PhoneTV.swift:337
Run Code Online (Sandbox Code Playgroud) 我已经尝试了该网站上发布的示例的不同版本,但没有任何进展。
我也尝试过遵循此处列出的示例:
我在这篇文章的标题中收到关于弃用 NavigationLink(destination:isActive) 的警告
struct PhoneLogin: View {
@StateObject var phoneLoginData = PhoneLoginViewModel()
@State var isSmall = UIScreen.main.bounds.height < 750
var body: some View {
VStack {
VStack {
Text("Continue With Phone")
.font(.title2)
.fontWeight(.bold)
.foregroundColor(.black)
.padding()
Image("phone_logo")
.resizable()
.aspectRatio(contentMode: .fit)
.padding()
Text("You'll receive a 4-digit code \n to verify next")
.font(isSmall ? .none : .title2)
.foregroundColor(.gray)
.multilineTextAlignment(.center)
.padding()
// Mobile Number Field . . . . .
HStack {
VStack(alignment: .leading, spacing: 6) {
Text("Enter Your Number")
.font(.caption) …Run Code Online (Sandbox Code Playgroud) 鉴于这个简单NavigationView:
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
NavigationView当目标视图被推入/弹出堆栈时,有没有人找到禁用动画的方法?
从 iOS2.0 开始,这在 UIKit 中已经成为可能!我认为从框架中提出的要求并不过分。我在所有视图上尝试了各种修饰符(即NavigationView容器、目标视图NavigationLink、 等)
这些是我尝试过的一些修饰符:
.animation(nil)
Run Code Online (Sandbox Code Playgroud)
.transition(.identity)
Run Code Online (Sandbox Code Playgroud)
.transaction { t in t.disablesAnimations = true }
Run Code Online (Sandbox Code Playgroud)
.transaction { t in t.animation = nil }
Run Code Online (Sandbox Code Playgroud)
没有任何区别。我没有发现任何有用的东西EnvironmentValues:-(
我是否遗漏了一些非常明显的东西,或者功能还不存在?
在新版本的iOS和Xcode中
NavigationLink(isActive: , destination: , label: )
Run Code Online (Sandbox Code Playgroud)
已弃用。
那么我们如何控制NavigationLink的状态呢?
自从安装 Xcode 14 以来,我现在在控制台中打印以下错误消息:
呈现值的 NavigationLink 必须出现在基于 NavigationContent 的 NavigationView 内。链接将被禁用。
我的应用程序的结构如下:
我将视图 A 包裹在导航视图中。导航视图内部有一个链接到视图 B 的导航链接。
我的视图 B 没有导航视图,但有一个指向视图 C 的导航链接。视图 B 继承了视图 A 中定义的导航视图
当我按下视图 B 上的后退按钮,弹出回视图 A 时,会打印警告。当我将视图 B 包装在导航视图中时,警告消失,但这当然现在在两个导航视图中显示视图 B,这不是什么我想。
我不确定为什么会打印此警告,因为视图 B 继承了视图 A 中定义的 NavigationView。
swiftui swiftui-navigationlink swiftui-navigationview ios16 xcode14
I've added a .toolbar to the top level of a NavigationView that will eventually be used to select items in a list without using swipe gestures (up button, down button, etc.). I also have a .navigationBar going on, to access other views for Account and Settings.
For the most part it's looking really good, but when I follow a NavigationLink (in .navigationBarItems) within NavigationView, and then use the built-in back navigation, my .toolbar disappears from the top level.
Am …
我的 macOS app\xe2\x80\x99s 侧边栏中有一个列表。当我添加.onDrag修改器时,拖动NSItemProvider可以正常工作,但单击/选择项目会触发被阻止NavigationLink。
struct ContentView: View {\n var body: some View {\n NavigationView {\n List(Data.items) { item in\n NavigationLink(\n destination: Text(item.text),\n label: {\n Text(item.text)\n .lineLimit(5)\n // Enabling dragging with .onDrag {} disables click and selection:\n .onDrag { return NSItemProvider(object: item.url as NSURL) }\n })\n }\n Text("Placeholder")\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n如何添加拖动行为,同时保持正常的列表选择行为不变?
\n这是最小可重现示例的其余部分:
\nimport SwiftUI\n\n@main\nstruct ListDragExampleApp: App {\n var body: some Scene {\n WindowGroup {\n ContentView()\n }\n }\n}\n\nstruct Data {\n struct Item: …Run Code Online (Sandbox Code Playgroud) 我想使用 SwiftUI 构建一个非常简单的 iOS 14 侧边栏。该设置是相当简单,我有三个观点HomeView,LibraryView与SettingsView和枚举代表每个屏幕。
enum Screen: Hashable {
case home, library, settings
}
Run Code Online (Sandbox Code Playgroud)
我的最终目标是根据大小类在选项卡视图和侧边栏之间自动切换,但有些事情并没有按预期工作。
全局状态由 拥有MainNavigationView,它也是 my 的根视图WindowGroup。
struct MainNavigationView: View {
@State var screen: Screen? = .home
var body: some View {
NavigationView {
SidebarView(state: $screen)
}
.navigationViewStyle(DoubleColumnNavigationViewStyle())
}
}
Run Code Online (Sandbox Code Playgroud)
这SidebarView是一个简单的List包含三个NavigationLink,每个一个Screen。
struct SidebarView: View {
@Binding var state: Screen?
var body: some View {
List {
NavigationLink(
destination: HomeView(), …Run Code Online (Sandbox Code Playgroud) 当我从向下推 2+ 层的视图中的数组更新绑定属性时,导航会在属性更改后立即弹出。
Xcode 13.3 测试版、iOS 15。
我创建了一个简单的演示,代码如下。
更新列表标题(一个视图深)就可以了,导航堆栈保持不变,如果我返回,更改就会发布。但是,当调整部分标题(两层深)时,只要我对属性进行一次更改,导航就会弹出。
我有一种感觉,我在这里缺少基本的基础知识,而且我有一种感觉,它一定与列表有关id?但我正在努力弄清楚或解决它。
动图
楷模:
struct ShoppingList {
let id: String = UUID().uuidString
var title: String
var sections: [ShoppingListSection]
}
struct ShoppingListSection {
let id: String = UUID().uuidString
var title: String
}
Run Code Online (Sandbox Code Playgroud)
查看型号:
final class ShoppingListsViewModel: ObservableObject {
@Published var shoppingLists: [ShoppingList] = [
.init(
title: "Shopping List 01",
sections: [
.init(title: "Fresh food")
]
)
]
}
Run Code Online (Sandbox Code Playgroud)
内容查看:
struct ContentView: View {
var body: some View …Run Code Online (Sandbox Code Playgroud)