SwiftUI NavigationLink not displaying view until physical rotation then all is ok? - swiftui-navigationlink

The opening view of App is blank with a Back Button. However, the intended view will appear after complete rotation of physical device (before touching anything) or by tapping the Back Button on the displayed empty view.
This is a weird bug. After that rotation (to landscape and back to protrait) everything is peachy-keen-o.
I am aware that adding: .navigationViewStyle(StackNavigationViewStyle()) to the NavigationView will sorta resolve the problem. But this solution is a poor fix for my App's needs.
Is there a command to intentionally rotate device in code to resolve this? Or some other fix to get that first view to appear without counting on the user to rotate the device?
I've tried various solutions with no luck.
Below is a quick setup of the problem.
struct FirstView: View {
#Binding var viewNum: Int?
var body: some View {
VStack {
Text("View One")
.padding(20)
Button {
viewNum = 2
} label: {
Text("Go to 2nd view")
}
}
.onAppear {
viewNum = 1
}
}
}
struct MainView: View {
#State var selection: Int? = 1
var body: some View {
// VStack {
NavigationView {
List {
NavigationLink("First View", tag: 1, selection: $selection){ FirstView(viewNum: $selection)}
NavigationLink("Second View", tag: 2, selection: $selection){
Text("View 2").padding(20)
Button {
selection = 1
} label: {
Text("Go to first view")
}
}
}
}
// .navigationViewStyle(StackNavigationViewStyle())
//}
}
}

Related

NavigationStack, NavigationLink and onLongPressGesture together

I have a view inside a NavigationStack (iOS16+) that shows a horizontal list of items (game). When tapping on it the app will proceed to the next screen in my app. But I also want to be able to show a sheet to be able to edit the details of game. I got both working, just not together. The edit sheet should be shown after a long press, but as soon as I add the onLongPress gesture, I no longer can scroll through my list, nor does the NavigationLink work. How to get this working?
.navigationDestination(for: Game.self) { game in
TestView(game: game)
}
(...)
// Show and edit game details
func gameDetailsView(for game: Game) {
gamesViewModel.selectedGame = game
showingGameDetailsView.toggle()
}
(...)
#ViewBuilder var horizontalList: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 20) {
ForEach(gamesViewModel.filteredGames(with: filterText)) { game in
NavigationLink(value: game) {
gameCard(game)
.listRowBackground(Color.clear)
.frame(width: uiProperties.isiPad ? getScreenRectangle().width / 3 : getScreenRectangle().width - 30)
.frame(height: uiProperties.isiPad ? getScreenRectangle().height / 1.5 : getScreenRectangle().height / 1.6)
.onLongPressGesture(minimumDuration: 0.3) {
gameDetailsView(for: game)
}
// .simultaneousGesture(LongPressGesture(minimumDuration: 0.3).onEnded { hasEnded in
// if hasEnded { gameDetailsView(for: game) }
// })
}
}
}
.padding(.horizontal)
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
Another solution would be to have two destinations for game, but I don't know if that's possible and how to do that ...

SwiftUI sheet modal background not working with edgesIgnoreSafeArea(.all) - WHY?

I'm running iOS 13 simulator with a SwiftUI sheet modal - trying to paint the sheet background and ignore safe areas - but there's still white sheet showing. Any ideas on how to do this properly?
var body: some View {
VStack(alignment: .center, spacing: 0) {
... redacted ...
} // VStack
.background(Color.gray.edgesIgnoringSafeArea(.all))
iPhone Simulator with sheet modal
See the image (attached)
Any ideas what I'm doing wrong?
Expand top container (VStack in your case) to full sheet area, like
VStack {
// ... your content
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // << here !!
.background(Color.gray.edgesIgnoringSafeArea(.all))
Best way to paint the background is using a ZStack:
var body: some View {
ZStack {
// replace with the color you want
Color.green
.edgesIgnoringSafeArea(.all)
VStack {
// put view's Content here
}
}
}

Can I disable Navigationlink for a specified set of cells in my SwiftUI list?

I am working on a contacts app in SwiftUI for work which will display hundreds of phone numbers. Some contacts have a detail view with address and alternate numbers, while some contacts do not.
For example, Harry Smith will have basic phone extension listed in row while his cell number and address are listed in detail view.
But the number for the Second Floor Bathroom only needs the basic phone extension in the row, a detail view containing cell number and address for the bathroom is unnecessary.
How do I disable navigation link for those contacts who do not have pertinent detail info?
I prefer to add NavigationLink on condition.
I will have a "Cell" with some contents. (image/file detail)
A - build a "content" View:
struct MediumFileContentRow: View {
var file: MediumFile
var body: some View {
VStack (alignment: .leading) {
let (name, attribs) = file.getInfo() // get from model..
Text(name)
Spacer()
Text(attribs)
}// VStack
}
}
B - Your cell (MediumFileRow) will conditionally add link (NavigationLink) "around" our content view, and will give back different Views using AnyView:
struct MediumFileRow: View {
var file: MediumFile
var body: some View {
let enabled = NavigationLink(destination: Detail(t: file.name!)) {
MediumFileContentRow(file: file)
}
let disabled = MediumFileContentRow(file: file)
return file.isEmpty ? AnyView(disabled) : AnyView(enabled)
}
All (almoast..) The code:
struct MediumFileContentRow: View {
var file: MediumFile
var body: some View {
VStack (alignment: .leading) {
let (s,sd) = file.displayed()
Text(s)
Spacer()
Text(sd).font(.system(size: 9.0))
}// VStack
}
}
struct MediumFileRow: View {
var file: MediumFile
var body: some View {
let enabled = NavigationLink(destination: Detail(t: file.name!)) {
MediumFileContentRow(file: file)
}
let disabled = MediumFileContentRow(file: file)
return file.isEmpty ? AnyView(disabled) : AnyView(enabled)
}
...
..
In list You will have:
var body: some View {
NavigationView{
....
List {
ForEach(mediumFiles, id: \.self) { file in
MediumFileRow(file: file)
}
}
......
advantage: You can easily customise "disabled" cells.

How can I present an overlay above the keyboard in SwiftUI?

I have a screen in my app that automatically displays a keyboard when the screen is presented. The screen allows users to enter their mobile number. In order to select a dialling code, the user needs to tap a button which will then trigger the presentation of an overlay.
Problem
The overlay is being presented, but it's showing up behind the currently present keyboard.
Question
How can I make this overlay be the very top view?
There is no way for me to use the zIndex modifier on the keyboard for obvious reasons. I'm wondering if there is a way to make the overlay the top view when it's about to be presented, or if the overlay can be added to the window.
Thanks in advance
You should probably only have one source of input at any given time — either the keyboard should be presented to enter a number, or the overlay should be presented to pick the dialing code, not both. Here's an example which hides the keyboard when overlay appears, and vice versa. (Keyboard dismissal code from this answer.)
struct ContentView: View {
#State private var number = ""
#State private var showingOverlay = false
var body: some View {
GeometryReader { proxy in
ZStack(alignment: .top) {
// Just here to force ZStack to use the whole screen
Rectangle()
.fill(Color.clear)
VStack(alignment: .leading) {
Button("Select Dialing Code") {
UIApplication.shared.endEditing()
self.showingOverlay = true
}
TextField("Enter your number", text: self.$number, onEditingChanged: {
if $0 { self.showingOverlay = false }
})
.keyboardType(.phonePad)
}
Overlay(showing: self.$showingOverlay)
.frame(height: 400)
.offset(x: 0, y: proxy.size.height + (self.showingOverlay ? -300 : 100))
.animation(.easeInOut)
}
}
}
}
struct Overlay: View {
#Binding var showing: Bool
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 15)
.fill(Color(.systemGray4))
Button("Dismiss") {
self.showing = false
}
}
}
}
extension UIApplication {
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}

SwiftUI with ObservableObject - List having NavigationLink to details downloading it on scroll NOT on appear

I have list of cities
struct CityListView: View {
#ObservedObject private(set) var citiesViewModel: CitiesViewModel
var body: some View {
LoadingView(isShowing: .constant(citiesViewModel.cities?.isEmpty ?? false)) {
NavigationView {
List(self.citiesViewModel.cities ?? []) { city in
NavigationLink(destination: DetailView(cityName: city.name,
detailCityModel: DetailCityModel(cityId: city.id))) {
Text(city.name)
}
}
.navigationBarTitle(Text("Cities"), displayMode: .large)
}
}
}
}
and when I'm scrolling the list, the DetailCityModel inits and download data from API. How to downloading (or init DetailCityModel) on DetailView's appearance, not for showing item with NAvigationLink to DetailView?
You have to kick off the API call in onAppear() not in the initialiser of DetailView.