Left animation shift when using nested NavigationLink - swift

I am developing an application using SwiftUI (XCode 12.5.1) and every time one of my View appears after exactly two links of "NavigationLink" everything that is inside a Form is shifted slightly to the left, once the appearing animation is over. The following video shows whats going on : the first two times I open the view, everything is fine. The next two times, when the view is accessed from nested NavigationLink, a slight shift to the left is done once the appearing animation is over.
https://www.dropbox.com/s/k3gjc42xlqp2auf/leftShift.mov?dl=0
I have the same problem on both the simulator and a real device (an iPhone). Here is the project: https://www.dropbox.com/s/l8r5hktg6lz69ob/Bug.zip?dl=0 . The main code is available below.
Here is the main view ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
List {
NavigationLink(destination: PersonView()) {
Text("Person")
}
NavigationLink(destination: IndirectView()) {
Text("Indirect")
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Here is the indirect view, IndirectView.swift
import SwiftUI
struct IndirectView: View {
var body: some View {
List {
NavigationLink(destination: PersonView()) {
Text("Person")
}
}
}
}
and the person view, PersonView.swift
import SwiftUI
struct PersonView: View {
var body: some View {
Form {
VStack(alignment: .leading, spacing: 5) {
Text("Last Name")
.font(.system(.subheadline))
.foregroundColor(.secondary)
Text("Fayard")
}
}
}
}
Do you have any idea on what's causing this shift?
Thanks for your help
Francois

Frankly saying I have not idea what causes the problem, but here is the fix: add this line of code no your NavigaitonView
NavigationView {
// everything else
}.navigationViewStyle(StackNavigationViewStyle())

Related

SwiftUI App works fine in simulator, but not in preview

I'm trying to get preview working in Xcode. Just a simple test app written in Swift. Grabs rows from a Realm database and lists them.
It works fine when I build/run in the simulator but none of the data shows in the ContentView_Preview.
App in Simulator
App in Preview
Here's the code:
import SwiftUI
import RealmSwift
struct HeaderView: View {
var body: some View {
HStack(alignment: .firstTextBaseline) {
Text("Time Spent").font(.largeTitle)
Text("or waisted...").font(.headline)
}
}
}
struct GroupListView: View {
#ObservedResults(TaskGroup.self) var taskGroups
var body: some View {
NavigationView {
// Nothing from here shows in the preview.. but shows fine in the simulator
List(taskGroups) {
Text("Group: " + $0.name)
}
.navigationTitle("Task Groups (\(taskGroups.count))")
// Grrr
}
}
}
struct FooterView: View {
var body: some View {
HStack {
Text("🤬 Grr.. Preview isn't working.")
Spacer()
Text("Simulator works fine though.")
}
}
}
struct ContentView: View {
var body: some View {
VStack(alignment: .leading) {
HeaderView()
GroupListView()
FooterView()
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I've searched for hours and tried various different suggestions. No luck. Any help would be wonderful.
In your preview it's likely that taskGroups is empty. You could verify this by sticking something like
if taskGroups.isEmpty {
Text("test")
}
For your preview you should inject some placeholder content. Depending on how Realm works there may be a mechanism to do this already, or you may need to create an abstraction that allows you to do this.

Sheet Modal does not present whole View in SwiftUI

I am pretty new to SwiftUI programming and ran into the following problem that I cannot find an answer to.
I want to open a sheet modal from my Main View and want to present a simple View with an Rect on it (for testing purposes).
.sheet(isPresented: $api.showDrawing) {
DrawingViewView()
}
My DrawingViewView looks like:
struct DrawingViewView: View {
var body: some View {
Rectangle()
.fill(Color.red)
.frame(width: 1500, height: 1000)
}
}
No matter how big I make the Rect it is never shown bigger than:
Is there a way to make the sheet bigger in width?
EDIT:
I also thought of using a fullScreenCover, but if I open a PKCanvasView in a fullScreenCover pencilKit is acting weird. The lines I draw do not correspond with the pencilInput
EDIT: Apperently the problem is the horizontal orientation. If I turn my iPad vertical I have no problems at all!
Thanks a lot!
Jakob
I think this is the easiest way to do it.
import SwiftUI
struct FullScreenModalView: View {
#Environment(\.presentationMode) var presentationMode
var body: some View {
ZStack {
Color.red.edgesIgnoringSafeArea(.all)
Button("Dismiss Modal") {
presentationMode.wrappedValue.dismiss()
}
}
}
}
struct ContentView: View {
#State private var isPresented = false
var body: some View {
Button("Present!") {
isPresented.toggle()
}
.fullScreenCover(isPresented: $isPresented, content: FullScreenModalView.init)
}
}
struct ex_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Hope is what you expected!

SwiftUI sheet gets dismissed the first time it is presented

This bug is driving me insane. Sometimes (well most of the time) presented sheet gets dismissed first time it is opened. This is happening only on a device and only the first time the app is launched. Here is how it looks on iPhone 11 running iOS 14.1 built using Xcode 12.1 (can be reproduced on iPhone 7 Plus running iOS 14.0.1 as well):
Steps in the video:
I open app
Swiftly navigate to Details view
Open Sheet
Red Sheed gets dismissed by the system???
I open sheet again and it remains on the screen as expected.
This is SwitUI App project (using UIKIt App Delegate) and deployment iOS 14. Code:
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DetailsView()) {
Text("Open Details View")
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct DetailsView: View {
#State var sheetIsPresented: Bool = false
var body: some View {
VStack {
Button("Open") {
sheetIsPresented.toggle()
}
}.sheet(isPresented: $sheetIsPresented, content: {
SheetView()
})
}
}
struct SheetView: View {
var body: some View {
Color.red
}
}
I was able to fix this problem by removing line .navigationViewStyle(StackNavigationViewStyle()), but I need StackNavigationViewStyle in my project. Any help will be appreciated.
Updated: There is a similar post on Apple forum with sheet view acting randomly weird.
One solution that I found is to move sheet to the root view outside NavigationLink (that would be ContentView in my example), but that is not ideal solution.
I had the same problem in an app. After a great deal of research, I found that making the variable an observed object fixed the problem in SwiftUI 1, and it seems to be in SwiftUI 2. I do remember that it was an intermittent problem on an actual device, but it always happened in the simulator. I wish I could remember why, maybe when the sheet appears it resets the bound variable?, but this code fixes the problem:
import SwiftUI
import Combine
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: DetailsView()) {
Text("Open Details View")
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct DetailsView: View {
#ObservedObject var sheetIsPresented = SheetIsPresented.shared
var body: some View {
VStack {
Button("Open") {
sheetIsPresented.value.toggle()
}
}.sheet(isPresented: $sheetIsPresented.value, content: {
SheetView()
})
}
}
struct SheetView: View {
var body: some View {
Color.red
}
}
final class SheetIsPresented: NSObject, ObservableObject {
let objectWillChange = PassthroughSubject<Void, Never>()
static let shared = SheetIsPresented()
#Published var value: Bool = false {
willSet {
objectWillChange.send()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Tested on Xcode 12.1, iOS 14.1 in simulator.
Just add your NavigationView view to bellow code line
.navigationViewStyle(StackNavigationViewStyle())
Example :
NavigationView { }.navigationViewStyle(StackNavigationViewStyle())
Problem will be solved (same issues I was faced)

SwiftUI - Conditional based on ObservedObject doesn't work in subsequent Views

I have a very simple app which contains two views that are tied together with a NavigationLink. In the first view, ContentView, I can see updates to my ObservedObject as expected. However, when I go to the next View, it seems that the code based on the ObservedObject does not recognize changes.
ContentView.swift (The working view):
import SwiftUI
struct ContentView: View {
#ObservedObject var toggleObject = ToggleObject()
var body: some View {
NavigationView {
VStack(spacing: 15) {
Toggle(isOn: self.$toggleObject.isToggled) {
Text("Toggle:")
}
if self.toggleObject.isToggled == true {
Text("ON")
}
else {
Text("OFF")
}
NavigationLink(destination: ShowToggleView()) {
Text("Show Toggle Status")
}
}
}
}
}
ShowToggleView.swift (The view that does not behave as I expect it to):
import SwiftUI
struct ShowToggleView: View {
#ObservedObject var toggleObject = ToggleObject()
var body: some View {
Form {
Section {
if self.toggleObject.isToggled {
Text("Toggled on")
}
else {
Text("Toggled off")
}
}
}
}
}
All of this data is stored in a simple file, ToggleObject.swift:
import SwiftUI
class ToggleObject: ObservableObject {
#Published var isToggled = false
}
When I toggle it on in the first View I see the text "ON" which is expected, but when I go into the next view it shows "Toggled off" no matter what I do in the first View... Why is that?
Using Xcode 11.5 and Swift 5
You are almost doing everything correct. However, you are creating another instance of ToggleObject() in your second view, which overrides the data. You basically only create one ObservedObject and then pass it to your subview, so they both access the same data.
Change it to this:
struct ShowToggleView: View {
#ObservedObject var toggleObject : ToggleObject
And then pass the object to that view in your navigation link...
NavigationLink(destination: ShowToggleView(toggleObject: self.toggleObject)) {
Text("Show Toggle Status")
}

SwiftUI: NavigationLink not working if not in a List

I guess it might be a bug in beta 3 as the NavigationView is all broken. But a view like that:
struct GenreBadge : View {
#EnvironmentObject var store: Store<AppState>
let genre: Genre
var body: some View {
NavigationLink(destination: MoviesGenreList(genre: genre).environmentObject(store)) {
RoundedBadge(text: genre.name)
}
}
}
is not triggering any push in the navigation stack. The view doens't seems interactive at all. If anyone found a workaround would be good, unless Apple is documenting this behaviour I would consider it broken until beta 4.
There seems to be a bug with the navigation link in Xcode version 11.3(11C29) which I have reported to Apple.
Note: This problem only appears in simulator. It works fine on a real device. Thanks to #djr
The below code works as expect the first time you use the navigation link. Unfortunately it becomes unresponsive the second time around.
import SwiftUI
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: SomeView()) {
Text("Hello!")
}
}
}
}
}
struct SomeView: View {
var body: some View {
Text("Detailed View")
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Are you actually inside a NavigationView? The following works. But if I missed your point, maybe you can share a little more code.
import SwiftUI
struct ContentView : View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: SomeView()) {
Text("Go!")
}
}
}
}
}
struct SomeView: View {
var body: some View {
Text("Detailed View Here!")
}
}
NavigationLink
A button that triggers a navigation presentation when pressed. This is a replacement for pushViewController
NavigationView {
NavigationLink(destination:
Text("Detail")
.navigationBarTitle(Text("Detail"))
) {
Text("Push")
}.navigationBarTitle(Text("Master"))
}
Or make it more readable by use group destination into it own view DetailView
NavigationView {
NavigationLink(destination: DetailView()) {
Text("Push")
}.navigationBarTitle(Text("Master"))
}
In Xcode 11.3.1, I experienced the same issue but I just had to quit xcode and restart my computer. This apparently fixed an issue (of course its 2021 right now) but I was able to follow apple's swiftui tutorial without any issues. I copied this code and tried it out... worked fine for me. Maybe the issue is your "play" button on the bottom right of your screen was toggled.
Try this:
VStack{
NavigationLink(destination: DetailView()) {
Text("Push")
}.navigationBarTitle(Text("Your Text")).isDetailLink(false)
}
Try this:-
var body: some View {
NavigationView {
NavigationLink(destination: YourView()) {
Text("Go!")
}
}
}