I'm trying to figure out how to navigate to my secondary screen through a button alert. Firstly, the user inputs some fields through textfields in the primary screen.
At the bottom of this screen the user presses a submit button which then pops up an alert asking whether they would like to be taken to the secondary screen or cancel to not be taken. All the fields that have been entered through the primary screen then get passed onto the secondary screen. The user than has the option to navigate back to the primary screen if necessary once in the secondary screen.
Here's what I've tried:
struct View1: View {
#State var txtField1 : String = ""
#State var txtField2: String = ""
#State var txtField3: String = ""
#State var txtField4: String = ""
#State var txtField5 : String = ""
#State private var showingAlert = false
#State private var showingView = false
var body: some View {
HStack{
Button(action: {
self.showingAlert = true
}) {
Text("Submit")
.alert(isPresented:$showingAlert) {
Alert(title: Text("Would you like to go to second screen?"), message: Text("The second screen will pass all data from the first screen."), primaryButton:.destructive(Text("Continue")){
self.showingView = true
}, secondaryButton: .cancel(Text("Cancel")))
}
}
}.popover(isPresented: $showingView){
NavigationView{
View2(txtField1: self.$txtField1, txtField2: self.$txtField2, txtField3: self.$txtField4, txtField5: self.$txtField5)
}
}
When using the code above it does navigate to my secondary screen (View2) however its like a sheet. View2 has no navigation properties back to View1 and this is what I'm trying to achieve. Any help on this matter is greatly appreciated, Thank you!
To get the Back button you need a NavigationLink vs a popover. You can just "hide" the NavigationLink next to your Button
import SwiftUI
struct ConfirmNavView: View {
#State var txtField1 : String = ""
#State var txtField2: String = ""
#State var txtField3: String = ""
#State var txtField4: String = ""
#State var txtField5 : String = ""
#State private var showingAlert = false
#State private var showingView = false
var body: some View {
NavigationView{
HStack{
Button(action: {
self.showingAlert = true
}) {
Text("Submit")
.alert(isPresented:$showingAlert) {
Alert(title: Text("Would you like to go to second screen?"), message: Text("The second screen will pass all data from the first screen."), primaryButton:.destructive(Text("Continue")){
self.showingView = true
}, secondaryButton: .cancel(Text("Cancel")))
}
}
NavigationLink("View2", destination: View2(txtField1: self.$txtField1,
txtField2: self.$txtField2,
txtField3: self.$txtField3,
txtField4: self.$txtField4,
txtField5: self.$txtField5), isActive: $showingView).hidden().frame(width: 0, height: 0)
}
}
}
}
struct View2: View {
#Binding var txtField1 : String
#Binding var txtField2: String
#Binding var txtField3: String
#Binding var txtField4: String
#Binding var txtField5 : String
var body: some View {
VStack{
TextField("txtField1", text: $txtField1)
TextField("txtField2", text:$txtField2)
TextField("txtField3", text:$txtField3)
TextField("txtField4", text:$txtField4)
TextField("txtField5", text:$txtField5)
}
}
}
struct ConfirmNavView_Previews: PreviewProvider {
static var previews: some View {
ConfirmNavView()
}
}
Related
I want to log some text and clear the TextField after submitting without changing the value of the logged text. How I can achieve that?
Here's example of my code:
#State private var loggedText: String = ""
#State private var showLoggedText = false
var body: some View {
VStack {
if showLoggedText {
Text(loggedText)
}
HStack {
TextField(
"Add new set",
text: $loggedText
)
.onSubmit {
showLoggedText = true
loggedText = ""
}
}
}
Going off one of the comments. It seems as though that you need to assign loggedText to another variable like so:
#State private var loggedText: String = ""
#State private var showLoggedText = false
var body: some View {
VStack {
if showLoggedText {
Text(loggedText)
}
HStack {
TextField(
"Add new set",
text: $loggedText
)
.onSubmit {
showLoggedText = true
newText = loggedText
}
}
}
This will allow you to submit the text without it being cleared. The loggedText = "" clears everything that you had. Keep in mind that this code won't "lock" whatever's in loggedText. If you change the field after submitting. The text will be updated again.
#Environment(\.presentationMode) var presentationMode
#Environment(\.dismiss) var dismiss
I know just toggle State variable of 'fullScreenCover' or 'sheet' but I found another approach and both above doesn't work.
Here's simple code.
struct ContentView: View {
#Environment(\.presentationMode) var presentationMode
#Environment(\.dismiss) var dismiss
#State var sheetState = false
#State private var value = ""
var body: some View {
VStack {
Text(value)
Button("Present Sheet") {
sheetState.toggle()
}
}
.sheet(isPresented: $sheetState) {
Button("set1") {
value = "1"
//presentationMode.wrappedValue.dismiss()
dismiss()
}
}
}
}
When I press the button of sheet named 'set1' it change the 'value' set '1' and Text of VStack set "1" correctly but sheet doesn't dismiss.
It absolutely same both approach.
Am I using these things wrong?
here's my result.
https://imgur.com/a/5cjExyv
Technically you are trying to dismiss ContentView which makes no sense.
You have to create a separate View struct for the sheet.
struct ContentView: View {
#State private var sheetState = false
#State private var value = ""
var body: some View {
VStack {
Text(value)
Button("Present Sheet") {
sheetState.toggle()
}
}
.sheet(isPresented: $sheetState) {
SheetView(value: $value)
}
}
}
struct SheetView : View {
#Environment(\.dismiss) var dismiss
#Binding var value : String
var body: some View {
Button("set1") {
value = "1"
dismiss()
}
}
}
I am trying to edit the text of a binding value from another view. But text editor does not allow me to do so.
First I need to see the previous value of selectedNote.title in TextEditor and then I should be able to edit the title.
struct EditNotePageView: View {
#Binding var selectedNote: CDNoteModel!
#State var text = ""
var body: some View {
TextEditor(selectedNote.title!, text: $text)
}
}
I also tried like this. I can see my selectedNote.title in the simulator but when I tap on it it does nothing.
struct EditNotePageView: View {
#Binding var selectedNote: CDNoteModel!
#State var text = ""
var body: some View {
Text(selectedNote.title!)
.onTapGesture {
text = selectedNote.title!
TextEditor(text: $text)
}
}
}
ZStack Text and textEditor solved the problem with a little pinch of .onAppear
struct EditNotePageView: View {
#Binding var selectedNote: CDNoteModel!
#State var text = ""
var body: some View {
ZStack(alignment: .leading){
Text(selectedNote.title!)
.onAppear {
text = selectedNote.title!
}
TextEditor(text: $text)
}
}
}
You can use onChange property
struct EditNotePageView: View {
#Binding var selectedNote: CDNoteModel!
#State var text = ""
var body: some View {
TextEditor("", text: $text)
.onChange(of: text, perform: { value in
selectedNote.title = value
}
}
}
you could try this:
struct EditNotePageView: View {
#Binding var selectedNote: CDNoteModel
var body: some View {
TextEditor(text: $selectedNote.title)
}
}
I have tried much time on it but I couldn't figure out why it is not working.
The problem is when I tap the button, the new value inside the sheet is not updated. It always show the same value which is set up in start.
#State var value:String = "empty"
#State var explorePageIsEnabled:Bool = false
VStack{
Button("tap me"){
value = "the new one"
exploreStatusIsEnabled.toggle()
}
.sheet(isPresented: $exploreStatusIsEnabled, content: {
Text(value)
})
}
Deployment target is IOS 14+
Create a separate struct view for text and use Binding.
struct SheetView: View {
#Binding var value: String
var body: some View {
Text(value)
}
}
struct ContentView: View {
#State private var value: String = "empty"
#State private var explorePageIsEnabled: Bool = false
var body: some View {
VStack{
Button("tap me"){
value = "the new one"
explorePageIsEnabled.toggle()
}
.sheet(isPresented: $explorePageIsEnabled, content: {
SheetView(value: $value)
})
}
}
}
I use a modal sheet whose content is updated for each call. However, when the content is marked as #State, the view body is never updated.
Is anyone seeing this as well? Is a workaround available?
This is the calling view:
struct ContentView: View {
#State var isPresented = false
#State var i = 0
var body: some View {
List {
Button("0") {
self.i = 0
self.isPresented = true
}
Button("1") {
self.i = 1
self.isPresented = true
}
}
.sheet(
isPresented: $isPresented,
content: {
SheetViewNOK(i: self.i)
}
)
}
}
This does work:
struct SheetViewOK: View {
var i: Int
var body: some View {
Text("Hello \(i)") // String is always updated
}
}
This does not work. But obviously, in a real app, I need to use #State because changes made by the user need to be reflected in the sheet's content:
struct SheetViewNOK: View {
#State var i: Int
var body: some View {
Text("Hello \(i)") // String is never updated after creation
}
}
In your .sheet you are passing the value of your ContentView #State to a new #State. So it will be independent from the ContentView.
To create a connection or a binding of your ContentView #State value, you should define your SheetView var as #Binding. With this edit you will pass the binding of your state value to your sheet view.
struct SheetView: View {
#Binding var i: Int
var body: some View {
Text("Hello \(i)")
}
}
struct ContentView: View {
#State var isPresented = false
#State var i: Int = 0
var body: some View {
List {
Button("0") {
self.i = 0
self.isPresented = true
}
Button("1") {
self.i = 1
self.isPresented = true
}
}.sheet(
isPresented: $isPresented,
content: {
SheetView(i: self.$i)
})
}
}
There are 3 different ways
use a binding
use multiple .sheets
use $item
This is fully explained in this video.
Multiple Sheets in a SwiftUI View