TextField #State property value = "" - swiftui

I'm studying SwiftUI and I'm having a hard time dealing with TextField.
When I do onCommit, I tried to put "" in the #State Property value, but there was no response.
What I'm trying to do is click the'retrun' key in TextField and I want to show you the gap where the text created disappeared.
struct TodoTextFieldView: View {
#EnvironmentObject var listViewModel: ListViewModel
#State var textFieldText = ""
var title: String = "here typing line"
var body: some View {
VStack{
HStack(spacing: 5){
Text("🔥")
.font(.title)
TextField("\(title)",
text: $textFieldText,
onCommit:{ addItem()
//
})
.disableAutocorrection(true)
.underline()
.font(.headline)
}.padding(.leading, 40)
}.padding(16)
}
func addItem() {
listViewModel.addItem(title: textFieldText)
textFieldText = "" // This is where I want to do it.
print(textFieldText)
}
This is a parent view.
struct ContentView: View {
#EnvironmentObject var listViewModel: ListViewModel
var body: some View {
VStack {
TodayView()
Spacer()
TodoTextFieldView()
Spacer()
/// List view
List{
ForEach(listViewModel.items) { item in
ListView(item: item)
.onTapGesture {
withAnimation(.linear){
listViewModel.updateItem(item: item)
}
}
}
.onDelete(perform: listViewModel.deleteItem) // Delete
.onMove(perform: listViewModel.moveItem) // Edit
}.listStyle(PlainListStyle())
}.navigationBarItems(trailing: EditButton()) // Edit Button
.padding()
}
}
#State var textFieldText = ""
The value was directly added to the state property. But there is no reaction.
textFieldText = ""

Emptying the binding property of TextField inside the Task block works for me.
func addItem() {
listViewModel.addItem(title: textFieldText)
Task {
textFieldText = ""
}
}

Related

Changing a TextField text for items in a foreach NavigationLink SwiftUI and saving it

There is a list in on the Main View that has navigation links that bring you to a an Edit Birthday View where the textFieldName is saved with the onAppear method. I need help in allowing the user to change the text in the text field on the Edit Birthday View and having it save when the user dismisses and returns to that particular item in the foreach list. I have tried onEditingChanged and on change method but they don't seem to work. (Also, in my view model i append birthday items when they are created in the Add Birthday View). If you would like to see more code i will make updates. Thank you.
/// MAIN VIEW
import SwiftUI
struct MainView: View {
#EnvironmentObject var vm: BirthdayViewModel
#State var nameTextField: String = ""
var body: some View {
VStack(spacing: 20) {
List {
ForEach(vm.searchableUsers, id: \.self) { birthday in
NavigationLink(destination: EditBirthdayView(birthday: birthday)) {
BirthdayRowView(birthday: birthday)
}
.listRowSeparator(.hidden)
}
.onDelete(perform: vm.deleteBirthday)
}
}
.toolbar {
ToolbarItem {
NavigationLink(destination: AddBirthdayView(textfieldName: $nameTextField)) {
Image(systemName: "plus.circle")
}
}
}
}
}
/// EDIT BIRTHDAY VIEW
import SwiftUI
import Combine
struct EditBirthdayView: View {
#EnvironmentObject var vm: BirthdayViewModel
#State var textfieldName: String = ""
#Environment(\.presentationMode) var presentationMode
var birthday: BirthdayModel
var body: some View {
NavigationView {
VStack {
TextField("Name...", text: $textfieldName)
}
Button {
saveButtonPressed()
} label: {
Text("Save")
}
}
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now()) {
textfieldName = birthday.name
}
}
}
}
func saveButtonPressed() {
vm.updateItem(birthday: birthday)
presentationMode.wrappedValue.dismiss()
}
func updateTextField() {
textfieldName = birthday.name
}
}
struct MainView: View {
#EnvironmentObject var store: BirthdayStore
var body: some View {
List {
ForEach($store.birthdays) { $birthday in
NavigationLink(destination: EditBirthdayView(birthday: $birthday)) {
BirthdayRowView(birthday: birthday)
}
}
.onDelete(perform: deleteBirthday)
}
.listRowSeparator(.hidden)
.toolbar {
ToolbarItem {
NavigationLink(destination: AddBirthdayView() {
Image(systemName: "plus.circle")
}
}
}
}
}
struct EditBirthdayView: View {
#EnvironmentObject var store: BirthdayStore
#Binding var birthday: Birthday
...
TextField("Name", text: $birthday.name)

How dismiss keyboard in a sheet with inherited toolbar+button

A view has a TextField and the keyboard has a "Dismiss Keyboard" button (in the toolbar) to remove focus from the textField and dismiss the keyboard. That works fine but when a sheet appears that also contains a TextField the keyboard inherits the button from the previous view and will not dismiss the sheet's keyboard.
I have tried overwriting with a new ToolbarItemGroup within the sheet but it has no effect. The button references the first view. Is there a way to have each keyboard appearance reference the view within which the relevant TextField is situated?
import SwiftUI
struct ContentView: View {
#FocusState private var focusedField1: Bool
#State private var name1 = ""
#State private var showSheet = false
var body: some View {
VStack {
TextField("Hello", text: $name1)
.focused($focusedField1)
.textFieldStyle(.roundedBorder)
.padding()
Button("Show Sheet") { showSheet = true }
}
.toolbar {
toolBarContent1()
}
.sheet(isPresented: $showSheet) {
MySheet()
}
}
#ToolbarContentBuilder func toolBarContent1() -> some ToolbarContent {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button {
print("11111")
focusedField1 = false
} label: { Text("Dismiss Keyboard") }
}
}
}
struct MySheet: View {
#Environment(\.dismiss) var dismiss
#FocusState private var focusedField2: Bool
#State private var name2 = ""
var body: some View {
VStack {
TextField("Hello", text: $name2)
.focused($focusedField2)
.textFieldStyle(.roundedBorder)
.padding()
Button("Dismiss Sheet") {
focusedField2 = false
dismiss()
}
.toolbar {
toolBarContent2()
}
}
}
#ToolbarContentBuilder func toolBarContent2() -> some ToolbarContent {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button {
print("22222")
focusedField2 = false
} label: { Text("Dismiss Keyboard") }
}
}
}
Your code is fine. To make this work, just put your sheet inside a NavigationView{}. Code is below the image:
.sheet(isPresented: $showSheet) {
NavigationView {
MySheet()
}
}

Can't transfer variable from one watchos view to another view, Using swiftui

I am trying to get data from one view to another.
I can not figure out how to get values from the fourth view array into the Third view.
I am not using storyboards. I tried using #EnvironmentObject but can not make it work. New to coding. In xcode I am using watchos without app.
I tried to strip out most of the code and leave just the important stuff that can be tested. I used NavigationLink(destination: )to transfer between views.
enter code here
class viewFromEveryWhere: ObservableObject {
#Published var testname2: String = "testTTname"
}
struct secondView: View {
var body: some View {
Text("second view")
List(1..<7) {
Text("\($0)")
}
}
}
struct thirdView: View {
#EnvironmentObject var testname2: viewFromEveryWhere
#EnvironmentObject var testSixTestArray: viewFromEveryWhere
#State var sixTestArray:[String] = ["ww","GS","DW","CD","TS","JW",]
var body: some View {
List(sixTestArray, id:\.self) {
Text($0)
}
}
}
struct fourthView: View {
#StateObject var testname2 = viewFromEveryWhere()
#State private var name: String = ""
#State var testSixTestArray:[String] = []
func collectName () {
print("collectName triggered")
if testSixTestArray.count < 5 {
// testSixTestArray.append(name)
print(name)
print(testSixTestArray)
}
// .enviromentObject(testSixTestArray)
}
var body: some View {
VStack(alignment: . leading) {
Text("Type a name")
TextField("Enter your name", text: $name)
Text("Click to add, \(name)!")
// Button("click this if \(name) is correct") {}
Button(action:{
print("Button Tapped")
collectName()
print(testSixTestArray.count)
name = ""
}) {
Text("Add \(name) to list")
}
// .buttonStyle(GrowingButton1())
}
Text("forth view")
// testSixTestArray.append(name)
.environmentObject(testname2)
}
}
/*func presentTextInputControllerWithSuggestions(forLanguage suggestionsHandler:
((String)-> [Any]?)?,
allowedInputMode inputMode:
WKTextInputMode,
completion: #escaping ([Any]?) -> Void) {}
*/
struct ContentView: View {
#State var sixNameArray:[String] = ["","","","","","",]
#State var messageTextBox: String = "Start"
#State var button1: String = "Button 1"
#State var button2: String = "Button 2"
#State var button3: String = "Button 3"
var body: some View {
NavigationView {
VStack{
Text(messageTextBox)
.frame(width: 120, height: 15, alignment: .center)
.truncationMode(.tail)
.padding()
NavigationLink(destination: secondView(),
label:{
Text(button1)
})
.navigationBarTitle("Main Page")
NavigationLink(destination: thirdView(),
label:{
Text(button2)
})
NavigationLink(destination: fourthView(),
label:{
Text(button3)
})
}
}
}
}
enter code here

Popover displaying inaccurate information inside ForEach

I'm having a problem where I have a ForEach loop inside a NavigationView. When I click the Edit button, and then click the pencil image at the right hand side on each row, I want it to display the text variable we are using from the ForEach loop. But when I click the pencil image for the text other than test123, it still displays the text test123 and I have absolutely no idea why.
Here's a video. Why is this happening?
import SwiftUI
struct TestPopOver: View {
private var stringObjects = ["test123", "helloworld", "reddit"]
#State private var editMode: EditMode = .inactive
#State private var showThemeEditor = false
#ViewBuilder
var body: some View {
NavigationView {
List {
ForEach(self.stringObjects, id: \.self) { text in
NavigationLink( destination: HStack{Text("Test!")}) {
HStack {
Text(text)
Spacer()
if self.editMode.isEditing {
Image(systemName: "pencil.circle").imageScale(.large)
.onTapGesture {
if self.editMode.isEditing {
self.showThemeEditor = true
}
}
}
}
}
.popover(isPresented: $showThemeEditor) {
CustomPopOver(isShowing: $showThemeEditor, text: text)
}
}
}
.navigationBarTitle("Reproduce Editing Bug!")
.navigationBarItems(leading: EditButton())
.environment(\.editMode, $editMode)
}
}
}
struct CustomPopOver: View {
#Binding var isShowing: Bool
var text: String
var body: some View {
VStack(spacing: 0) {
HStack() {
Spacer()
Button("Cancel") {
self.isShowing = false
}.padding()
}
Divider()
List {
Section {
Text(text)
}
}.listStyle(GroupedListStyle())
}
}
}
This is a very common issue (especially since iOS 14) that gets run into a lot with sheet but affects popover as well.
You can avoid it by using popover(item:) rather than isPresented. In this scenario, it'll actually use the latest values, not just the one that was present when then view first renders or when it is first set.
struct EditItem : Identifiable { //this will tell it what sheet to present
var id = UUID()
var str : String
}
struct ContentView: View {
private var stringObjects = ["test123", "helloworld", "reddit"]
#State private var editMode: EditMode = .inactive
#State private var editItem : EditItem? //the currently presented sheet -- nil if no sheet is presented
#ViewBuilder
var body: some View {
NavigationView {
List {
ForEach(self.stringObjects, id: \.self) { text in
NavigationLink( destination: HStack{Text("Test!")}) {
HStack {
Text(text)
Spacer()
if self.editMode.isEditing {
Image(systemName: "pencil.circle").imageScale(.large)
.onTapGesture {
if self.editMode.isEditing {
self.editItem = EditItem(str: text) //set the current item
}
}
}
}
}
.popover(item: $editItem) { item in //item is now a reference to the current item being presented
CustomPopOver(text: item.str)
}
}
}
.navigationBarTitle("Reproduce Editing Bug!")
.navigationBarItems(leading: EditButton())
.environment(\.editMode, $editMode)
}.navigationViewStyle(StackNavigationViewStyle())
}
}
struct CustomPopOver: View {
#Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
var text: String
var body: some View {
VStack(spacing: 0) {
HStack() {
Spacer()
Button("Cancel") {
self.presentationMode.wrappedValue.dismiss()
}.padding()
}
Divider()
List {
Section {
Text(text)
}
}.listStyle(GroupedListStyle())
}
}
}
I also opted to use the presentationMode environment property to dismiss the popover, but you could pass the editItem binding and set it to nil as well (#Binding var editItem : EditItem? and editItem = nil). The former is just a little more idiomatic.

Unable to apply a value to a Published Variable

I am having difficulty assign a value to a Published variable, (weeklyAllowance).
There are 4 variables in total, of which 3 are populated outside of a button action (TextFields) working as expected
The last variable (WeeklyAllowance) must get value from with the action button.
Thanks in advance
class Users: ObservableObject {
#Published var firstName = ""
#Published var lastName = ""
#Published var age = ""
#Published var weeklyAllowance = ""
}
import SwiftUI
struct ContentView: View {
#ObservedObject var myDetails = Users()
var body: some View {
NavigationView {
VStack {
TextField("Enter Firstname",text: $myDetails.firstName)
TextField("Enter Lastname",text: $myDetails.lastName)
TextField("Enter Age",text: $myDetails.age)
Text("My name is \(myDetails.firstName)")
Text("My Last name is \(myDetails.lastName)")
Text("My age is \(myDetails.age)")
//Spacer()
VStack {
//Now Update the details
TextField("Name Update",text: $myDetails.lastName)
Text("Lastname update \(myDetails.lastName)")
}
Spacer()
//Link to new view
Button(action: {
//Assign period in the
self.myDetails.objectWillChange.send()
self.myDetails.weeklyAllowance = "Weekly"
}) {
NavigationLink(destination: detailUpdate(UpdateFirstname: $myDetails.firstName, UpdateLastname: $myDetails.lastName, UpdateAge: $myDetails.age,periodWkly: $myDetails.weeklyAllowance)) {
Text("The Link")
}
}
}.padding()
}
}
}
This is a update Test
struct detailUpdate: View {
#Binding var UpdateFirstname: String
#Binding var UpdateLastname: String
#Binding var UpdateAge: String
#Binding var periodWkly : String
var body: some View {
VStack {
Text("My First Name Update is \(UpdateFirstname)")
Text("My Last Name Update is \(UpdateLastname)")
Text("My Age Update is \(UpdateAge)")
Text("This is a \(periodWkly) allowance")
}.padding()
}
}
In your code button does not work, but works directly a link (it does not matter that you place it in button's label - on tap activated a link, not a button).
Here is your ContentView that activates link on button click:
struct ContentView: View {
#ObservedObject var myDetails = Users()
#State private var activatedLink = false
var body: some View {
NavigationView {
VStack {
TextField("Enter Firstname",text: $myDetails.firstName)
TextField("Enter Lastname",text: $myDetails.lastName)
TextField("Enter Age",text: $myDetails.age)
Text("My name is \(myDetails.firstName)")
Text("My Last name is \(myDetails.lastName)")
Text("My age is \(myDetails.age)")
//Spacer()
VStack {
//Now Update the details
TextField("Name Update",text: $myDetails.lastName)
Text("Lastname update \(myDetails.lastName)")
}
Spacer()
//Link to new view
Button(action: {
//Assign period in the
self.myDetails.weeklyAllowance = "Weekly"
self.activatedLink = true
}) {
Text("The Link")
}
NavigationLink(destination: detailUpdate(UpdateFirstname: $myDetails.firstName, UpdateLastname: $myDetails.lastName, UpdateAge: $myDetails.age, periodWkly: $myDetails.weeklyAllowance), isActive: $activatedLink) {
EmptyView()
}
}.padding()
}
}
}
You may not have to embed a navigationLink inside a button. Just use it directly.
NavigationLink(destination: detailUpdate(UpdateFirstname: $myDetails.firstName, UpdateLastname: $myDetails.lastName, UpdateAge: $myDetails.age,periodWkly: $myDetails.weeklyAllowance)) {
Text("The Link")
}.onDisappear{
self.myDetails.weeklyAllowance = "Weekly"
}