The data I pass to another view is not working - ios

I'm new to swiftUI here and I want to try out to pass data between two views. But it doesn't seem to work.
I'm using Xcode 13.2 & iOS 15 for the simulator.
This is my code for the first view:
struct ContentView: View {
#State var myName: String = ""
var body: some View {
NavigationView {
VStack {
TextField("Enter your name", text: $myName)
Text(self.myName)
NavigationLink(destination: BView(myName: self.$myName), label: {
Image(systemName: "arrowshape.turn.up.left")
})
}//: VSTACK
.padding(.horizontal, 20)
}//:NAVIGATION VIEW
}
}
This is code for the second view:
struct BView: View {
#Binding var myName: String
var body: some View {
NavigationView {
Text("BView")
Text(self.myName)
}//:NAVIGATION VIEW
}
}
I want myName to be input in the first page which is ContentView() and then pass down the input data to BView().
Unfortunately, once I run it on the simulator, the input data doesn't;t show up.

Your code is fine just add VStack in BView.
struct BView: View {
#Binding var myName: String
var body: some View {
NavigationView {
VStack { // HERE
Text("BView")
Text(self.myName)
}
}//:NAVIGATION VIEW
}
}

Please use #EnvironmentObject to pass the data to view.
https://developer.apple.com/documentation/swiftui/environmentobject

Related

How can I reproduce Picker's selection binding?

I'm building a custom view and I'm trying to manipulate the active state of its children.
I have this:
struct Menu<Content>: View where Content: View {
#ViewBuilder var content: () -> Content
var body: some View {
content()
}
}
struct ScreenView: View {
var body: some View {
Menu {
Text("Home")
Text("Settings")
Text("Profile")
}
}
}
I would like to be able to pass a binding to the Menu view and based on that, to change the text color if the state is matching the actual text or id of the view. There is a Picker view example that does what I want to achieve. The Picker is managing the look and feel of the selected element. Am I wrong?
struct PickerViewExample: View {
#State var selection: Int
var body: some View {
Picker(selection: $selection, label: Text("Picker"), content: {
Text("1").tag(1)
Text("2").tag(2)
})
}
}
I'd like to know if there is a way to ForEach somehow the content ViewBuilder property in order to manipulate subviews. I like the way Apple solved this using tags. Any alternative is welcome.
I think, this will help
struct ContentView: View {
private var menuItem = ["Home", "Settings", "Profile"]
#State private var selectedMenu = "Home"
var body: some View {
VStack {
Picker("Menu", selection: $selectedMenuIndex, content: {
ForEach(menuItem, id: \.self, content: { title in
Text(title)
})
})
Text("Selected menu: \(selectedMenu)")
}
}
}

SwiftUI updating #Binding value in NavigationLink(destination:label) causes destination to reappear

I have a weird issue, where I navigate to EditView and edit a state variable from ContentView. After that I dismiss EditView with presentation.wrappedValue.dismiss(). The problem is, as soon as the view is dismissed, it reappears again.
I'm using XCode 12.4 and my iOS deployment target is set to 14.4
Observations:
EditView doesn't reappear if the value isn't edited
removing the changed value Text("Value: \(title)") >> Text("Value") from ContentView tree resolves the issue, but that obviously isn't a solution.
moving the NavigationLink from .toolbar e.g.
VStack {
Text("Value: \(title)")
NavigationLink(destination: EditView(title: $title)){
Text("Edit")
}
}
also resolves the issue, but that seems like a hack. Besides, I'd like to keep using .toolbar because I like the .navigationTitle animation and I can't have a button in the upper-right corner of the screen if I have a navigation title without the toolbar.
Here's the full code:
import SwiftUI
struct ContentView: View {
#State var title: String = "Title"
#State var isActive: Bool = false
var body: some View {
NavigationView {
Text("Value: \(title)")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink(destination: EditView(title: $title, isActive: $isActive), isActive: $isActive){
Text("Edit")
}
}
}
}
}
}
struct EditView: View {
#Environment(\.presentationMode) var presentation
#Binding var title: String
#Binding var isActive: Bool
var body: some View {
Button(action: {
title = "\(Date().timeIntervalSince1970)"
// presentation.wrappedValue.dismiss()
isActive = false
}){
Text("Done")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
As far as I can tell this is a .toolbar bug, and if it turns out that way I'll report it to Apple, but in the meantime, does anyone have a better solution and/or explanation for this?
Cheers!
EDIT:
I updated the code with isActive value for the NavigationLink. It doesn't work when written like that, but uncommenting the commented out line makes it work. But that's quite hacky.
You are mixing up 2 things NavigationLink will push the view on stack, just like NavigationController in swift. That’s why you can see back button after navigating to second view. When you hit back button, it will pop top most view out of stack. presentationMode is not needed , dismissing presented view will not pop it of the stack.
To present a view and dismiss it you can check below code.
import SwiftUI
struct ContentViewsss: View {
#State var title: String = "Title"
#State var isPresented = false
var body: some View {
NavigationView {
Text("Value: \(title)")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
isPresented.toggle()
}){
Text("Edit")
}
}
}
}.sheet(isPresented: $isPresented, content: {
EditView(title: $title, state: $isPresented)
})
}
}
struct EditView: View {
#Binding var title: String
#Binding var state: Bool
var body: some View {
Button(action: {
title = "\(Date().timeIntervalSince1970)"
state.toggle()
}){
Text("Done")
}
}
}
If you want NavigationLink functionality, you can just remove presentationMode code from second view, and keep ContentView as it is -:
struct EditView: View {
//#Environment(\.presentationMode) var presentation
#Binding var title: String
var body: some View {
Button(action: {
title = "\(Date().timeIntervalSince1970)"
// presentation.wrappedValue.dismiss()
}){
Text("Done")
}
}
}

SwiftUI: Is it possible to layer these views without each one being scrollable?

I am presenting a sheet that will present a slider within a section which is within a form. I was trying to add my subview AddDoujin into this view as well. But the problem is, is that both views are scrollable and aren't layering on top of each other and seems like it is being added to the bottom (if that makes sense). My goal is to make the AddDoujin view right under the slider rather than both being each their own view and both of them being scrollable. Sorry if this is unclear and you need more information.
import SwiftUI
struct TestingAddDoujin: View {
//Varaibles
#State private var InputDoujin:String = ""
var DoujinApi:DoujinAPI
#Binding var isPresented:Bool
#State private var RedoEntry:Bool = false
var PickerOptions = ["Doujin", "Hentai"]
#State var PickerSelected = ""
#State var CurrentSelectionForPicker = 0
var body: some View {
GeometryReader { geo in
NavigationView{
VStack {
ZStack{
Form{
Section(header: Text("What you you looking for?")) {
Picker(selection: $CurrentSelectionForPicker, label: Text("Please select one")) {
ForEach(0..<PickerOptions.count) {
Text("\(self.PickerOptions[$0])")
}
}
.pickerStyle(SegmentedPickerStyle())
}
}
}
AddDoujin(DoujinApi: DoujinApi, isPresented: $isPresented)
}
}
}
}
}
struct TestingAddDoujin_Previews: PreviewProvider {
static var previews: some View {
TestingAddDoujin(DoujinApi: DoujinAPI(), isPresented: .constant(false))
}
}
It seems like if you just move AddDoujin(DoujinApi: DoujinApi, isPresented: $isPresented) right below .pickerStyle(SegmentedPickerStyle()) You will get the desired result.
I'm guessing you've tried this. So maybe show and tell us more about what you are trying to accomplish.
btw. In Swift it's not convention to capitalize the first letter of a variable.

SwiftUI Infinite Subview Hierarchy and Breadcrumbs

what I am trying to achieve is creating a hierarchical view. I understand that iOS simply doesn't like to use breadcrumbs but I need to navigate from a main view in to deeper subviews. they need to be nested and infinite.
you can see what I've done so far in the code and gif below. As I'm a beginner developer I'm not sure if this is the right way to achieve this kind of structure (infinite sub-views nested inside sub-views). Also when I navigate back in views, added buttons(struct A) disappears. What seems to be the problem?
Thanks in advance!
code in action gif
import SwiftUI
struct A: View, Identifiable {
#EnvironmentObject var documentB: classB
var id: Int
var text: String
var destinationLink: B?
var body: some View {
NavigationLink(destination: self.destinationLink) {
VStack{
Rectangle()
.frame(width: 35, height:25)
.background(Color.red)
Text("\(text)")
}
}
}
}
struct B: View, Identifiable {
#EnvironmentObject var documentB: classB
#State var arrayA: [A] = []
var id: Int
var text: String
var mainText: String = "Placeholder"
var body: some View {
NavigationView {
VStack {
Spacer()
ForEach(arrayA){ item in
item
}
Spacer()
Button(action: {
let newB = B(id:self.documentB.arrayB.count+1, text:"B \(self.documentB.arrayB.count+1)")
self.documentB.arrayB.append(newB)
self.arrayA.append(A(id:self.arrayA.count+1, text:"AA \(self.arrayA.count+1)", destinationLink: newB))
}) {
Text("Add A \(self.arrayA.count), B Count: \(self.documentB.arrayB.count)")
}
}
.navigationBarTitle(text)
}
}
}
class classB: ObservableObject {
#Published var arrayB: [B] = [B(id:1, text:"MainView")]
}
struct ContentView: View {
#ObservedObject var documentB = classB()
var body: some View {
VStack {
documentB.arrayB[0]
}
.environmentObject(documentB)
}
}
You just need to move NavigationView into ContentView, because the only one is needed on one view hierarchy, so
struct ContentView: View {
#ObservedObject var documentB = classB()
var body: some View {
NavigationView { // << move it here from B
VStack {
documentB.arrayB[0]
}
}
.environmentObject(documentB)
}
}

Use #EnvironmentObject with PresentationButton in SwiftUI

I am trying to pass data through an #EnvironmentObject, but it works only if I go to the next view through NavigationButton, however, I want to present the next view modally (PresentationButton)
struct ContentView : View {
#EnvironmentObject var settings: UserSettings
var body: some View {
NavigationView {
VStack {
// A button that writes to the environment settings
Button(action: {
self.settings.score += 1
}) {
Text("Increase Score")
}
NavigationButton(destination: DetailView()) {
Text("Show Detail View")
}
}
}
}
}
struct DetailView: View {
#EnvironmentObject var settings: UserSettings
var body: some View {
// A text view that reads from the environment settings
VStack {
Text("Score: \(settings.score)")
}
}
}
What I am trying to use :
PresentationButton( Text("Show Detail View"), destination: DetailView())
Try supplying the bindable object to the DetailView using environmentObject:
PresentationButton(Text("Show Detail View"),
destination: DetailView().environmentObject(settings))

Resources