Post

Replies

Boosts

Views

Activity

SwiftUI NavigationView initial selection (iOS 15)
I'm trying to get a NavigationView to pre select an initial view but it seems impossible to get it working across both iPhone and iPad. Here's a very basic model with 3 views: struct SomeView: Hashable { let title: String let view: Text func hash(into hasher: inout Hasher) { hasher.combine(title) } } let destinations = [ SomeView(title: "View0", view: Text("View0")), SomeView(title: "View1", view: Text("View1")), SomeView(title: "View2", view: Text("View2")) ] and here's a very simple navigation view: struct ContentView: View { @State var initialSelection: SomeView? = destinations[0] var body: some View { NavigationView { SideBar(selected: $initialSelection) } } } struct SideBar: View { @Binding var selected: SomeView? var body: some View { List { ForEach(destinations, id: \.self) { d in NavigationLink(d.title, destination: d.view, tag: d, selection: $selected) } } } } When launched on an iPhone 13 Pro Max in Portrait mode, it correctly shows View0. When launched in Landscape mode, we get a blank screen with a back button. So it appears that the selection property of the NavigationLink will only work if that NavigationLink is drawn on the screen. I guess that makes sense. We can fix it by adding our default view to the NavigationView stack like this: var body: some View { NavigationView { SideBar(selected: $initialSelection) initialSelection?.view } } Now in Landscape mode we get the View0 showing. However when we tap the back button, nothing happens on the first tap. This is because tapping back, loads up the List view which triggers the selection property to show our default view. Tapping back for a second time, works. I tried to fix this using some logic to know if the NavigationView had actually shown the second column view or not, however it seems that even on an iPhone in portrait when it displays as a stack, the .onAppear code (shown below) still fires because the view was loaded and the logic is pointless. struct ContentView: View { @State var initialSelection: SomeView? @State var secondColumnShown = false var body: some View { NavigationView { SideBar(selected: $initialSelection) initialSelection?.view .onAppear(perform: { secondColumnShown = true }) } .navigationViewStyle(.columns) } } Is there a way to force the draw open for it to trigger the selection of the NavigationLink? Or is there some better logic I can use to only set the initialSelection view if it's on a small screen and the draw hasn't been shown? I've been battling this for a long time, and there's many stack overflow questions about this but no solutions that I can get to work on iOS 15
0
1
1.8k
Oct ’21
SwiftUI size to fit Font using GeometryReader, font is too big
I am using GeometryReader to calculate the size of font to use to fit several lines of text, however it is always too big. What can be wrong with my calculation? Here's a simply Playground import SwiftUI import PlaygroundSupport struct MainView : View { var body: some View { VStack { SomeView() .frame(width: 508.0, height: 246.5) } } } struct SomeView: View { let newData = ["1", "2", "3", "4", "5", "6", "7", "8"] var lines: Int { newData.count } var body: some View { GeometryReader { geometry in VStack(alignment: .leading, spacing: 0) { ForEach(0..<lines) { idx in Text(newData[idx]) .padding(0) } } .font(.system(size: geometry.size.height / CGFloat(lines))) .onAppear { print(geometry.size) print(lines) print(geometry.size.height / CGFloat(lines)) } } } } PlaygroundPage.current.setLiveView(MainView()) This gives me this result which I need to show all 8 lines:  The GeometryReader correctly reports the height of the box to be 246.5 and the number of lines to be 8 which results in a 30.8125 font size. It seems the font size needs some additional padding but how do I calculate this? I want to be able to supply an unknown amount of data and have it fill the box. (Well I am actually using a LazyVGrid which is suffering the same issue).
0
0
2.1k
Sep ’21