Open fatbobman opened 2 years ago
请教:如何在分栏情况下在 sideBar 里面嵌套 TabView 呢
刚才看错问题了。
struct ContentView: View {
@State var selection = 2
var body: some View {
NavigationSplitView(sidebar: {
TabView(selection: $selection) {
Text("1111")
.tag(1)
.tabItem {
Text("111")
}
Text("2222")
.tag(2)
.tabItem {
Text("222")
}
}
}, detail: {
Text("Hello world")
})
}
}
设置栏宽度好像不起作用
struct ContentView: View {
@State private var path: [Int] = []
@State private var value: Int?
var body: some View {
NavigationSplitView {
TabView {
NavigationStack(path: $path) {
List(0..<10, id: \.self) { item in
NavigationLink("\(item)", value: item)
}
.navigationDestination(for: Int.self) { item in
Button("\(item)") {
value = item
}
}
.navigationTitle("test")
}.tabItem {
Image(systemName: "house")
Text("Home")
}
Text("User").tabItem {
Image(systemName: "person")
Text("User")
}
Text("User").tabItem {
Image(systemName: "person")
Text("User")
}
}
.navigationSplitViewColumnWidth(400) //不起作用
} detail: {
ZStack {
if let value {
Text("\(value)")
} else {
Text("Hello")
}
}
}
}
}
经我的测试,目前 sidebar 好像最大支持到 320.因此 tabview 无法显示完整。
2022年7月12日 11:46,DouKing @.***> 写道:
设置栏宽度好像不起作用
struct ContentView: View {
@State private var path: [Int] = [] @State private var value: Int? var body: some View { NavigationSplitView { TabView { NavigationStack(path: $path) { List(0..<10, id: \.self) { item in NavigationLink("\(item)", value: item) } .navigationDestination(for: Int.self) { item in Button("\(item)") { value = item } } .navigationTitle("test") }.tabItem { Image(systemName: "house") Text("Home") } Text("User").tabItem { Image(systemName: "person") Text("User") } Text("User").tabItem { Image(systemName: "person") Text("User") } } .navigationSplitViewColumnWidth(400) //不起作用 } detail: { ZStack { if let value { Text("\(value)") } else { Text("Hello") } } } }
} — Reply to this email directly, view it on GitHub https://github.com/fatbobman/blogComments/issues/151#issuecomment-1181281234, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANIYIGMC5HKQHFRY3R3GAQ3VTTTAVANCNFSM5YVZHRWQ. You are receiving this because you authored the thread.
我在 tvOS 中使用 NavigationStack
时,发现List
点按触发导航的时候 .navigationDestination
会随机的调用 2 - 3 次,导致目的地 View 被初始化多次,一直无法找到问题何在。
var body: some View {
NavigationStack {
List {
ForEach(viewModel.userViewArray) { view in
NavigationLink(view.name ?? "", value: view)
}
}
.onAppear {
viewModel.requestUserViews()
}
.navigationDestination(for: ItemModel.self) { item in
CategoryPage(viewModel: CategoryViewModel(itemID: item.id ?? ""))
}
}
}
我在 tvOS 中使用
NavigationStack
时,发现List
点按触发导航的时候.navigationDestination
会随机的调用 2 - 3 次,导致目的地 View 被初始化多次,一直无法找到问题何在。
在 SwiftUI 中,无需太在意视图描述的实例( 注意,不是视图)被多次初始化。创建实例的过程是非常轻量级的( 因此不要在构造方法中使用任何会造成负担的操作 )。SwiftUI 可能会出于任意的目的多次创建实例,但通常只会用其中一个实例(通常是最后一个)来生成视图( 也就是通过该实例的 body 中来创建视图)。
例如,下面的代码,在 iPhone 下也会出现重复创建实例的情况,但 onAppear 只会打印一次( 视图在该次才正式被创建 )
struct StackTV:View {
var body: some View{
NavigationStack{
List(0..<10){ i in
NavigationLink("\(i)", value: i)
}
.navigationDestination(for: Int.self, destination: { i in
StackSubView(i: i)
})
}
}
}
struct StackSubView:View {
let i : Int
init(i:Int){
self.i = i
print("init \(i)")
}
var body: some View{
Text("\(i)")
.onAppear{
print("onAppear")
}
}
}
@fatbobman
我在 tvOS 中使用
NavigationStack
时,发现List
点按触发导航的时候.navigationDestination
会随机的调用 2 - 3 次,导致目的地 View 被初始化多次,一直无法找到问题何在。在 SwiftUI 中,无需太在意视图描述的实例( 注意,不是视图)被多次初始化。创建实例的过程是非常轻量级的( 因此不要在构造方法中使用任何会造成负担的操作 )。SwiftUI 可能会出于任意的目的多次创建实例,但通常只会用其中一个实例(通常是最后一个)来生成视图( 也就是通过该实例的 body 中来创建视图)。
例如,下面的代码,在 iPhone 下也会出现重复创建实例的情况,但 onAppear 只会打印一次( 视图在该次才正式被创建 )
struct StackTV:View { var body: some View{ NavigationStack{ List(0..<10){ i in NavigationLink("\(i)", value: i) } .navigationDestination(for: Int.self, destination: { i in StackSubView(i: i) }) } } } struct StackSubView:View { let i : Int init(i:Int){ self.i = i print("init \(i)") } var body: some View{ Text("\(i)") .onAppear{ print("onAppear") } } }
确实,我也做了类似的测试,init xx
会打印多次,但 onAppear
就一次
重新测试后更奇怪的事情发生了:
onAppear
调用 ViewModel 的方法请求数据,但数据还未返回之前,断点监测到页面发生了重绘@Published var userViewArray
被重新赋值后(因为 vm 都不是同一个了)页面无法正常重绘制。猜测还是因为在页面 .onAppear
之后,navigationDestination
的多次调用依然依然导致了页面被反复创建
struct CategoryPage: View {
@ObservedObject var viewModel = CategoryViewModel()
var body: some View {
List {
...
}
.onAppear {
viewModel.requestItemData(itemID: itemID)
}
}
}
@ObservedObject var viewModel = CategoryViewModel()
用法有问题。
原因请参阅 StateObject 与 ObservedObject 一文
@ObservedObject var viewModel = CategoryViewModel()
用法有问题。 原因请参阅 StateObject 与 ObservedObject 一文
写了一段时间 Objective-C,把这茬给忘了 😂
请问一下,mac 应用 这种结构下,能否动态的三列到sidebar和detail两列?我试了多种方式都不理想 NavigationSplitView(columnVisibility: $mode) { SideBarView() } content: { ContentColumnView() } detail: { DetailView() }
@LivenChief 可以根据需要(两列或三列)来调整 content 列的宽度,以实现你的需求。
struct ContentView: View {
@State var mode: NavigationSplitViewVisibility = .all
@State var columnMode = Mode.three
let contentDefaultWidth: CGFloat = 300
var body: some View {
NavigationSplitView(columnVisibility: $mode) {
Text("side")
}
content: {
Text("content")
.navigationSplitViewColumnWidth(columnMode == .three ? 300 : 0)
}
detail: {
Text("Detail")
.toolbar {
ToolbarItem {
Button {
switch columnMode {
case .two:
columnMode = .three
case .three:
columnMode = .two
}
} label: {
switch columnMode {
case .two:
Text("2")
case .three:
Text("3")
}
}
}
}
}
}
enum Mode {
case two, three
}
}
https://github.com/user-attachments/assets/1505a988-3156-4ffb-a3e6-9f1553f266d8
我也目前是這樣實現的,不過沒有大佬的方案好,感謝 NavigationSplitView { SidebarView(viewModel: viewModel)
} detail: {
HSplitView {
if viewModel.topicListVisibility {
TopicListView(viewModel: viewModel)
.frame(width: 210)
}
ArticleDetailView(
content: viewModel.selectedArticleContent,
tocVisibility: viewModel.tocVisibility
)
.background(.white)
}
}
https://www.fatbobman.com/posts/new_navigator_of_SwiftUI_4/
长久以来,开发者对 SwiftUI 的导航系统颇有微词。受 NavigationView 的能力限制,开发者需要动用各种技巧乃至黑科技才能实现一些本应具备基本功能(例如:返回根视图、向堆栈添加任意视图、返回任意层级视图 、Deep Link 跳转等 )。SwiftUI 4.0( iOS 16+ 、macOS 13+ )对导航系统作出了重大改变,提供了以视图堆栈为管理对象的新 API ,让开发者可以轻松实现编程式导航。本文将对新的导航系统作以介绍。