TabItem switching not working properly in iOS13 devices - ios

I have created demo of Tab bar with two tabItems. Each tab-item have view controller in it.
On switching tabs, it is not showing its respective UI.
This is happening on iOS 13 only.
Code:
struct ContentView: View {
private enum Tab: Hashable {
case one
case two
}
#State private var selectedIndex = Tab.one
var body: some View {
TabView(selection: $selectedIndex) {
DetestVXViewController(bgColor: .red).tabItem {
Text("123")
}.tag(Tab.one)
DetestVXViewController(bgColor: .green).tabItem {
Text("321")
}.tag(Tab.two)
}
}
}
====
Attaching images of iOS 13 and 15 both.

Using tag seems overkill unless you need to keep track of said tab for quick actions or another purpose. You can still use tag in this though if needed. You can use #State property for the selection also if needed. You can easily switch tabs with the following example.
struct ContentView: View {
var body: some View {
TabView {
ForEach(1..<3) { index in
SomeView(title: "\(index)")
.tabItem {
Image(systemName: "\(index).circle.fill")
Text("\(index)")3
}
//.tag(index)
}
}
}
}

Related

SwiftUI NavigationSplitView link is disabled in compact mode

When implementing my app, I want to embed a NavigationStack inside NavigationSplitView, as the documentation says. However, under compact mode like on iPhone, I encountered a bug.
To be specific, here's the example code:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationSplitView {
List {
NavigationLink("Link") {
NavigationStack {
Text("Destination")
}
}
}
} detail: {
}
}
}
When running the code above, as I tap the "Link", it navigate to "Destination" as expected. However, if I navigate back and tap again, this link won't navigate.
Is there any workaround? Thanks for your solution!

SwiftUI prevent List in Sheet from inheriting parent Form styles

How can I prevent a view within a Sheet from inheriting components from its parents?
I believed a Sheet would create a whole new view hierarchy, but apparently it does not completely. As seen in the Gif below, the ListView inherits the Form when it is attached to the Button inside the Form. When placing it outside the form, the List behaves as expected. Is there a way to prevent this from happening? As you can see, the list with its sections becomes pretty useless when inheriting the Form. This almost seems like a bug to me.
Tested in an empty project using Xcode Version 12.5 (12E262) and iOS 14.5
import SwiftUI
struct ContentView: View {
#State var isSheetPresented: Bool = false
var body: some View {
NavigationView {
Form {
NavigationLink ("Link", destination: ListView())
Button("Sheet") {
isSheetPresented = true
}
.sheet(isPresented: $isSheetPresented, content: {
NavigationView {
ListView()
}
})
}
}
}
}
struct ListView: View {
var body: some View {
List {
Button("1") { }
Button("2") { }
Button("3") { }
Section(header: Text("one")) {
Button("4") { }
}
}
.navigationBarTitle("List")
}
}
Use DefaultListStyle()
ListView().listStyle(DefaultListStyle())

SwiftUI View with StateObject, a Form element and a ForEach breaks bindings when trying to use NavigationLink Inside the form

OK something weird is going on and I want to see if anyone else have this issue.
Consider the following ViewModel class with one published property to use from a View:
final class ViewModel: ObservableObject {
#Published var isActive = false
}
When using this view:
struct MainView: View {
#StateObject var viewModel = ViewModel()
var body: some View {
NavigationView {
Form {
NavigationLink (
destination: ChildView(isActive: $viewModel.isActive),
isActive: $viewModel.isActive,
label: { Text("Go to child view") }
)
// Adding this ForEach causes the NavigationLink above to have a broken binding
ForEach(1..<4) {
Text("\($0)")
}
}
.navigationBarTitle("Test")
}
}
}
And this SubView:
struct ChildView: View {
#Binding var isActive: Bool
var body: some View {
Button("Go back", action: { isActive = false })
}
}
The issue
The expected result is when tapping on "Go to child view", navigating to the subview and tapping "Go back" to return to the main view - it should navigate back using the isActive binding.
But actually, the button "Go Back" Doesn't work.
BUT If I remove the ForEach element from the form in the main view, the button works again. And it looks like the ForEach breaks everything.
Additional findings:
Changing Form to VStack fixes the issue
Using a struct and a #State also fixes the issue
Extracting the ForEach to a subview fixes the issue but as soon as I pass the viewmodel or part of it to the subview as a binding or as a ObservedObject - it still broken
Can anything advise if there is a logical issue with the code or is it a SwiftUI bug?
Any suggestions for a workaround?
Video of the expected behavior:
https://i.stack.imgur.com/BaggK.gif
Apple developer forum discussion: https://developer.apple.com/forums/thread/674127
Update
It looks like the issue has been fixed in the latest iOS 14.5 Beta 2 🎉
The issue has been fixed on iOS 14.5

What's the problem with picker control in Swift inside a form?

I don't know why the picker is not working inside of a form in Swift UI. The app will be crashing if the user is going to tap for the second time. The console will print the following output:
[TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window).
struct ContentView: View {
#State private var countryIndex = 0
var countries = ["US", "Germany", "Korea", "Russia"]
var body: some View {
NavigationView {
Form {
Section {
Picker(selection: $countryIndex, label: Text("Country")) {
ForEach(0 ..< countries.count) {
Text(self.countries[$0]).tag($0)
}
}
}
.navigationBarTitle(Text("Country"))
}
}
}
}
First, the warning you get is just a warning, so you shouldn't mind, but if you set .navigationBarTitle("xyz", displayMode: .inline), it'll go away.
Second, the navigation only working once is an issue only in simulator, if you build and run on a real device, it won't happen.

Why is SwiftUI picker in form repositioning after navigation?

After clicking the picker it navigates to the select view. The item list is rendered too far from the top, but snaps up after the animation is finished. Why is this happening?
Demo: https://gfycat.com/idioticdizzyazurevase
I already created a minimal example to rule out navigation bar titles and buttons, form sections and other details:
import SwiftUI
struct NewProjectView: View {
#State var name = ""
var body: some View {
NavigationView {
Form {
Picker("Client", selection: $name) {
Text("Client 1")
Text("Client 2")
}
}
}
}
}
struct NewProjectView_Previews: PreviewProvider {
static var previews: some View {
NewProjectView()
}
}
This happens in preview mode, simulator and on device (Xcode 11.2, iOS 13.2 in simulator, 13.3 beta 1 on device).
The obviously buggy behavior can be worked around when forcing the navigation view style to stacked:
NavigationView {
…
}.navigationViewStyle(StackNavigationViewStyle())
This is a solution to my problem, but I won‘t mark this as accepted answer (yet).
It seems to be a bug, even if it may be triggered by special circumstances.
My solution won‘t work if you need another navigation view style.
Additionally, it won‘t fix the horizontal repositioning mentioned by DogCoffee in the comments.
In my opinion, it has something to do with the navigation bar. In default (no mention of .navigationBarTitle extension), the navigation display mode is set to .automatic, this should be amend to .inline. I came across another post similar to this and use their solution to combine with yours, by using .navigationBarTitle("", displayMode: .inline) should help.
import SwiftUI
struct NewProjectView: View {
#State var name = ""
var body: some View {
NavigationView {
Form {
Picker("Client", selection: $name) {
Text("Client 1")
Text("Client 2")
}
}
.navigationBarTitle("", displayMode: .inline)
}
}
}
struct NewProjectView_Previews: PreviewProvider {
static var previews: some View {
NewProjectView()
}
}
Until this bug is resolved another way to work around this issue while retaining the DoubleColumnNavigationViewStyle for iPads would be to conditionally set that style:
let navView = NavigationView {
…
}
if UIDevice.current.userInterfaceIdiom == .pad {
return AnyView(navView.navigationViewStyle(DoubleColumnNavigationViewStyle()))
} else {
return AnyView(navView.navigationViewStyle(StackNavigationViewStyle()))
}
Thanks for this thread everyone! Really helped me understand things more and get a hold of one of my problems. To share with others, I was having this problem to but I was also having this problem when I set a section to appear in a if/else statement set on a section with a toggle. When the toggle was activated it would shift the section header horizontally a few pixels.
The following is how I fixed it
Section(header: Text("Subject Identified").listRowInsets(EdgeInsets()).padding(.leading)) {
Picker(selection: $subIndex, label: Text("Test")) {
ForEach(0 ..< subIdentified.count) {
Text(self.subIdentified[$0]).tag($0)
}
}
.labelsHidden()
.pickerStyle(SegmentedPickerStyle())
I'm still having horizontal shift on my picker selection view and not sure how to fix. I created another thread to received input. Thanks again! SwiftUI Shift Picker Text Horizontal

Resources