TabView does not change the view - swift

I have created a custom TabView that looks as follows:
and the code:
struct ContentView: View {
#State private var selectedItem: TabItemOption = .market
var body: some View {
ZStack {
VStack {
TabView(selection: $selectedItem){
MarketView().tag(TabItemOption.market.rawValue)
InterestView().tag(TabItemOption.interest.rawValue)
WalletView().tag(TabItemOption.wallet.rawValue)
}.toolbar(.hidden, for: .tabBar)
}
VStack {
Spacer()
TabBar(tappedItem: $selectedItem)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
For example, when I click on the second TabBarItem the view does not get changed. It always shows the MARKET view with Hello Market text in the middle of the screen.
However, the tag modifier is set to identify the view uniquely.
I have also checked if the variable selectedItem gets changed every time when different TabBarItem gets pressed and it changes the value properly corresponding what get pressed.
What am I doing wrong?

Related

Navigation Back Button not hidden in SwiftUI

Do you know why the back button still showing after I wrote
.navigationBarBackButtonHidden(true)
it seem that Xcode doesn't read it correctly.
import SwiftUI
import CoreData
struct ContentView: View {
#State var goToHome: Bool = false
var body: some View {
NavigationStack {
VStack {
Welcome(gotoSomewhere: $goToHome)
}
.navigationDestination(isPresented: $goToHome) { Home() }
.navigationBarBackButtonHidden(true) //HERE IS THE NAVIGATIONBAR HIDDEN
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
}
}
I tried to write an NavigationLink but then shows me the alert:
... was deprecated in iOS 16.0: use NavigationLink(value:label:)
inside a NavigationStack or NavigationSplitView
This modifier .navigationBarBackButtonHidden(true) should be on home.
Home().navigationBarBackButtonHidden(true)
And yes the NavigationLink will be deprecated in the future, it's up to you whether it's important or not to include at the moment in your app.

Show DisclosureGroup view based on state

I'm fairly new to SwiftUI, and I'm having trouble wrapping my head around the following issue I ran into. I have a button which toggles a state property, and I'd like to display a DisclosureGroup when the button's state is toggle on. For some reason, I can display any sort of view with my code below, with the exception of a DisclosureGroup:
#Binding var showing : Bool
#Binding var revealDetails : Bool
var body: some View {
if showing {
VStack {
DisclosureGroup("Monday", isExpanded: $revealDetails){
Text("7PM - 10PM").frame(height: 100)
}
.frame(width: 150)
.buttonStyle(PlainButtonStyle()).accentColor(.black)
}
}
}
}
The above code does not work when I present in my ContentView, however, the strange thing is, if I add some sort of empty view above the DisclosureGroup, it does work. So for now, I'm including a Text("") inside the VStack. Any thoughts on why this is?
I think you're not passing correct values to your bindings, i can tell you clearly after seeing your code in ContentView as you haven't attached it in the question but you can copy paste below code and customise it depending on your needs.
ContentView
import SwiftUI
struct ContentView: View {
// MARK: - PROPERTIES
#State private var showDiscloureGroup = false
#State private var showDetails = false
// MARK: - BODY
var body: some View {
VStack{
Toggle("Show Disclosure Group", isOn: $showDiscloureGroup)
Toggle("Show Details", isOn: $showDetails)
MyDiscloureGroup(showing: $showDiscloureGroup, revealDetails: $showDetails)
}//: VSTACK
.padding()
}
}
// MARK: - PREVIEW
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
MyDiscloureGroupView
import SwiftUI
struct MyDiscloureGroupView: View {
#Binding var showing : Bool
#Binding var revealDetails : Bool
var body: some View {
if showing {
VStack {
DisclosureGroup("Monday", isExpanded: $revealDetails){
Text("7PM - 10PM").frame(height: 100)
}
.frame(width: 150)
.buttonStyle(PlainButtonStyle()).accentColor(.black)
}
}
}
}
struct MyDiscloureGroup_Previews: PreviewProvider {
static var previews: some View {
MyDiscloureGroupView(showing: .constant(true), revealDetails: .constant(true))
}
}

Strange picker view hide animation in SwiftUI form

I am trying to show and hide a picker view with an animation. The code for this is pretty simple and although the code works for other views, I can't get it to work with a picker view. Hiding the picker view results in a very odd animation as you can see in the gif below.
When I delete the first or last row in the list, the animation seems correct. Replacing Form {} with a normal List {} also solves the issue. So it only happens in the "inset grouped style".
Issue:
Code:
import SwiftUI
struct ContentView: View {
static let options = ["One", "Two", "Three"]
#State private var showPicker = false
#State private var selectedOption = 0
var body: some View {
Form {
Text("First row") // Removing this row or the last row solves the issue
Button("Show Picker") {
withAnimation {
showPicker.toggle()
}
}
if showPicker {
Picker("Picker", selection: $selectedOption) {
ForEach(0 ..< ContentView.options.count) {
Text(ContentView.options[$0])
}
}.pickerStyle(InlinePickerStyle())
}
Text("Third row")
Text("Last row") // Removing this row or the first row solves the issue
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Does anyone know how to solve this issue? I guess it's a SwiftUI bug so a workaround would be very helpful as well.

Why doesn't the Text update when using #Binding?

The Working works as expected.
But using the #Binding in the NotWorking example, doesn't seem to update the Text control. Why doesn't the #Binding version work, what am I missing here?
Initial Launch:
After Typing:
struct Working: View {
//Binding from #State updates both controls
#State private var text = "working"
var body: some View {
VStack {
TextField("syncs to label...", text: $text)
Text($text.wrappedValue)
}
}
}
struct NotWorking: View {
//Using the #Binding only updates the TextField
#Binding var text: String
var body: some View {
//This does not works
VStack {
TextField("won't sync to label...", text: $text)
Text($text.wrappedValue)
}
}
}
struct Working_Previews: PreviewProvider {
#State static var text = "not working"
static var previews: some View {
VStack {
Working()
NotWorking(text: $text)
}
}
}
Static #States don't work. It's the fact that it being static means that the struct Working_Previews isn't mutated when text is changed, so it won't refresh.
We can test this by changing from a PreviewProvider to an actual View:
struct ContentView: View {
#State static var text = "not working"
var body: some View {
VStack {
Working()
NotWorking(text: ContentView.$text)
}
}
}
This code gives the following runtime message:
Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update.
Thanks to #George_E. I define #State in a wrapper view and display that for the preview. The WrapperView simply displays the control that I want to preview but it contains the State.
struct Working_Previews: PreviewProvider {
//Define the State in a wrapper view
struct WrapperView: View {
#State var text = "Preview is now working!!!"
var body: some View {
NotWorking(text: $text)
}
}
static var previews: some View {
VStack {
Working()
//Don't display the view that needs the #Binding
//NotWorking(text: $text)
//Use the WrapperView that has #State and displays the view I want to preview.
WrapperView()
}
}
}

SwiftUI - Presenting a View on top of the current View from AppDelegate

I am working on a project that at some point it receives a notification. When that happens, I need to show a View. I am not able to catch notification from any View so I am looking for a way to change to control it from outside of View structs. After the View's purpose is done, I need to dismiss it where the app left off. Think like the native behaviour when there is an active call.
I thought I could use sheet however I could not find any way to trigger it for every View that could be active when the notifications come. Or maybe trying to extend native View class would work but again, no luck finding a tutorial.
Any help will be appreciated.
Just update your model based on notification. There is not necessary to define .sheet (modal view) everywhere in your view hierarchy. Doing it in root view should be enough.
To demonstrate that (copy - paste - run) I create small project where I mimic notification with SwiftUI Toggle.
import SwiftUI
class Model: ObservableObject {
#Published var show = false
}
struct SubView: View {
#EnvironmentObject var model: Model
var tag: Int
var body: some View {
VStack {
NavigationLink(destination: SubView(tag: tag + 1).environmentObject(model)) {
Text("subview \(tag)")
}
if tag == 2 {
Toggle(isOn: $model.show) {
Text("toggle")
}.padding()
}
}.navigationBarTitle("subview \(tag)")
}
}
struct ContentView: View {
#ObservedObject var model = Model()
var body: some View {
NavigationView {
SubView(tag: 0).environmentObject(model)
}.sheet(isPresented: $model.show) {
Text("sheet")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
with the result