Supply any string value to swiftUI form in different for textfield - ios

I have two view file. I have textfield. I want to supply string value to the textfield from another view
File 1 :- Place where form is created
struct ContentView: View {
#State var subjectLine: String = ""
var body: some View {
form {
Section(header: Text(NSLocalizedString("subjectLine", comment: ""))) {
TextField("SubjectLine", text: $subjectLine
}
}
}
}
File 2 :- Place where I want to provide value to the string and that will show in the textfield UI
struct CalenderView: View {
#Binding var subjectLine: String
var body : some View {
Button(action: {
subjectLine = "Assigned default value"
}, label: {
Text("Fill textfield")
}
}
})
}
}
This is not working. Any other way we can supply value to the textfield in other view file.

As i can understand you have binding in CalenderView
that means you want to navigate there when you navigate update there.
struct ContentView: View {
#State private var subjectLine: String = ""
#State private var showingSheet: Bool = false
var body: some View {
NavigationView {
Form {
Section(header: Text(NSLocalizedString("subjectLine", comment: ""))) {
TextField("SubjectLine", text: $subjectLine)
}
}
.navigationBarItems(trailing: nextButton)
.sheet(isPresented: $showingSheet) {
CalenderView(subjectLine: $subjectLine)
}
}
}
var nextButton: some View {
Button("Next") {
showingSheet.toggle()
}
}
}
CalendarView
struct CalenderView: View {
#Binding var subjectLine: String
#Environment(\.dismiss) private var dismiss
var body: some View {
Button {
subjectLine = "Assigned default value"
dismiss()
} label: {
Text("Fill textfield")
}
}
}

Related

SwiftUI view parameter does not update as expected

I am curious why this .fullScreenCover display of a view does not update properly with a passed-in parameter unless the parameter is using the #Binding property wrapper. Is this a bug or intended behavior? Is this the fact that the view shown by the fullScreenCover is not lazily generated?
import SwiftUI
struct ContentView: View {
#State private var showFullScreen = false
#State private var message = "Initial Message"
var body: some View {
VStack {
Button {
self.message = "new message"
showFullScreen = true
} label: {
Text("Show Full Screen")
}
}.fullScreenCover(isPresented: $showFullScreen) {
TestView(text: message)
}
}
}
struct TestView: View {
var text: String
var body: some View {
Text(text)
}
}
There is a different fullScreenCover for passing in dynamic data, e.g.
import SwiftUI
struct CoverData: Identifiable {
var id: String {
return message
}
let message: String
}
struct FullScreenCoverTestView: View {
#State private var coverData: CoverData?
var body: some View {
VStack {
Button {
coverData = CoverData(message: "new message")
} label: {
Text("Show Full Screen")
}
}
.fullScreenCover(item: $coverData, onDismiss: didDismiss) { item in
TestView(text: item.message)
.onTapGesture {
coverData = nil
}
}
}
func didDismiss() {
// Handle the dismissing action.
}
}
struct TestView: View {
let text: String
var body: some View {
Text(text)
}
}
More info and an example in the docs:
https://developer.apple.com/documentation/SwiftUI/AnyView/fullScreenCover(item:onDismiss:content:)

Removing multiple sheets after swiping down the last one swiftui

I currently have two sheets in a row and I want them to be dismissed to the view that called the first sheet once the last sheet is dismissed by the user. I am open to not pulling up views as sheets its just the way I learned how to easily pull up new views.
BookView is what I want to be returned after the PickDefinition sheet view has been dismissed.
BookView pulls up AddWord as a sheet.
AddWord is pulled up as a sheet and then in it PickDefinition is pulled up as a sheet.
After PickDefinition is dismissed I would like for it to go back to the BookView
struct BookView: View {
#ObservedObject var book: Book
#State var addingWord = false
#Environment(\.presentationMode) var presentationMode
var body: some View {
VStack {
List(Array(zip(book.words, book.definitions)), id: \.self.0) { (word, definition) in
Text("\(word) - \(definition)")
}
}
.onAppear(perform: {
DB_Manager().openBook(name: book.name, book: self.book)
})
.navigationBarTitle("\(book.name)")
.navigationBarItems(trailing: Button(action: {
self.addingWord = true
}) {
Image(systemName: "plus")
}
).sheet(isPresented: $addingWord) {
AddWord(book: self.book)
}
}
}
struct AddWord: View {
#ObservedObject var book: Book
#StateObject var currentArray = SaveArray()
#State var addingDefinition = false
#State var word = ""
#State var definition = ""
#State var allDefinitions: [String] = []
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
Form {
TextField("Word: ", text: $word)
}
.navigationBarTitle("Add word")
.navigationBarItems(trailing: Button("Add") {
if self.word != "" {
book.words.append(self.word)
getDef(self.word, book, currentArray)
addingDefinition = true
}
}).sheet(isPresented: $addingDefinition) {
PickDefinition(definitions: currentArray, book: book, word: self.word)
}
}
}
struct PickDefinition: View {
#ObservedObject var definitions: SaveArray
var book: Book
var word: String
#Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
VStack {
List {
ForEach(0 ..< definitions.currentArray.count) { index in
Button("\(self.definitions.currentArray[index])", action: {
print("hello")
DB_Manager().addWords(name: self.book.name, word: self.word, definition: self.definitions.currentArray[index])
book.definitions.append(self.definitions.currentArray[index])
self.presentationMode.wrappedValue.dismiss()
})
}
}
}
.navigationTitle("Choose")
}
}
}
You need to pass addingWord into the AddWord view, and then into the PickDefinition view, using Binding. When PickDefinition disappears, set the passed property to false to hide the AddWord sheet.
struct BookView: View {
var body: some View {
// ...
.sheet(isPresented: $addingWord) {
AddWord(book: self.book, presentAddingWord: $addingWord)
}
}
}
struct AddWord: View {
#Binding var presentAddingWord: Bool
// ...
var body: some View {
// ...
.sheet(isPresented: $addingDefinition) {
PickDefinition(/* ... */, presentAddingWord: $presentAddingWord)
}
}
}
struct PickDefinition: View {
#Binding var presentAddingWord: Bool
// ...
var body: some View {
// ...
.onDisappear {
presentAddingWord = false
}
}
}

How to notify view that the variable state has been updated from a extracted subview in SwiftUI

I have a view that contain users UsersContentView in this view there is a button which is extracted as a subview: RequestSearchButton(), and under the button there is a Text view which display the result if the user did request to search or no, and it is also extracted as a subview ResultSearchQuery().
struct UsersContentView: View {
var body: some View {
ZStack {
VStack {
RequestSearchButton()
ResultSearchQuery(didUserRequestSearchOrNo: .constant("YES"))
}
}
}
}
struct RequestSearchButton: View {
var body: some View {
Button(action: {
}) {
Text("User requested search")
}
}
}
struct ResultSearchQuery: View {
#Binding var didUserRequestSearchOrNo: String
var body: some View {
Text("Did user request search: \(didUserRequestSearchOrNo)")
}
}
How can I update the #Binding var didUserRequestSearchOrNo: String inside the ResultSearchQuery() When the button RequestSearchButton() is clicked. Its so confusing!
You need to track the State of a variable (which is indicating if a search is active or not) in your parent view, or your ViewModel if you want to extract the Variables. Then you can refer to this variable in enclosed child views like the Search Button or Search Query Results.
In this case a would prefer a Boolean value for the tracking because it's easy to handle and clear in meaning.
struct UsersContentView: View {
#State var requestedSearch = false
var body: some View {
ZStack {
VStack {
RequestSearchButton(requestedSearch: $requestedSearch)
ResultSearchQuery(requestedSearch: $requestedSearch)
}
}
}
}
struct RequestSearchButton: View {
#Binding var requestedSearch: Bool
var body: some View {
Button(action: {
requestedSearch.toggle()
}) {
Text("User requested search")
}
}
}
struct ResultSearchQuery: View {
#Binding var requestedSearch: Bool
var body: some View {
Text("Did user request search: \(requestedSearch.description)")
}
}
Actually I couldn't understand why you used two struct which are connected to eachother, you can do it in one struct and Control with a state var
struct ContentView: View {
var body: some View {
VStack {
RequestSearchButton()
}
}
}
struct RequestSearchButton: View {
#State private var clicked : Bool = false
var body: some View {
Button(action: {
clicked = true
}) {
Text("User requested search")
}
Text("Did user request search: \(clicked == true ? "YES" : "NO")")
}
}
if this is not what you are looking for, could you make a detailed explain.

SwiftUI set a Binding from the String result of a picker

I am tearing out my hair trying to figure out how to bind the picked value in my SwiftUI view:
The picker needs to be bound to the Int returned from the tags. I need to covert this Int to the String and set the Binding. How?
struct ContentView: View {
#Binding var operatorValueString:String
var body: some View {
Picker(selection: queryType, label: Text("Query Type")) {
ForEach(0..<DM.si.operators.count) { index in
Text(DM.si.operators[index]).tag(index)
}
}.pickerStyle(SegmentedPickerStyle())
}
}
How and where can I set my operatorValueString ?
operatorValueString = DM.si.operators[queryType] //won't compile.
You can achieve the result, using your own custom binding that sets the string, whenever the picker's selection changes:
struct ContentView: View {
#State private var operatorString = ""
var body: some View {
VStack {
Subview(operatorValueString: $operatorString)
Text("Selected: \(operatorString)")
}
}
}
struct Subview: View {
#Binding var operatorValueString: String
#State private var queryType: Int = 0
let operators = ["OR", "AND", "NOT"]
var body: some View {
let binding = Binding<Int>(
get: { self.queryType },
set: {
self.queryType = $0
self.operatorValueString = self.operators[self.queryType]
})
return Picker(selection: binding, label: Text("Query Type")) {
ForEach(operators.indices) { index in
Text(self.operators[index]).tag(index)
}
}.pickerStyle(SegmentedPickerStyle())
}
}

How can we add `Button` and `TextField` by using `SwiftUI`

I am learning SwiftUI (New framework provided by Apple with iOS 13 and Xcode 11 : SwiftUI by Apple).
I want to add Button and TextField in ListView with action. I want one textfield in that user can add any one number from 1 to 10 and then hit SEND button. Anyone have any idea how to add button in it and also how can we handle touch event of Button with SwiftUI ?
Any help would be appreciate.
Here is a simple view what contains a textfield and a button in a horizontal stack.
To handle the user interaction with in your Button, just overwrite the action closure.
import SwiftUI
struct ButtonAndTextFieldView : View {
#State var text: String = ""
var body: some View {
HStack {
TextField($text,
placeholder: Text("type something here..."))
Button(action: {
// Closure will be called once user taps your button
print(self.$text)
}) {
Text("SEND")
}
}
}
}
#if DEBUG
struct ButtonWithTextFieldView_Previews : PreviewProvider {
static var previews: some View {
ButtonWithTextFieldView()
}
}
#endif
For the Login page design you can use this code section. With textFieldStyle border textfield and content type set.
struct ButtonAndTextFieldView : View {
#State var email: String = ""
#State var password: String = ""
var body: some View {
VStack {
TextField($email,
placeholder: Text("email"))
.textFieldStyle(.roundedBorder)
.textContentType(.emailAddress)
TextField($password,
placeholder: Text("password"))
.textFieldStyle(.roundedBorder)
.textContentType(.password)
Button(action: {
//Get Email and Password
print(self.$email)
print(self.$password)
}) {
Text("Send")
}
}
}
You can add button like that
Button(action: {}) {
Text("Increment Total")
}
And text field.
#State var bindingString: Binding<String> = .constant("")
TextField(bindingString,
placeholder: Text("Hello"),
onEditingChanged: { editing in
print(editing)
}).padding(.all, 40)
You can write a custom TextField which will return you the event in the closure once the user taps on the button. This Custom textfield would contain a HStack with a textfield and a button. Like this.
struct CustomTextField : View {
#Binding var text: String
var editingChanged: (Bool)->() = { _ in }
var commit: ()->() = { }
var action : () -> Void
var buttonTitle : String
var placeholder: String
var isSecuredField = false
var body : some View {
HStack {
if isSecuredField {
SecureField(placeholder, text: $text, onCommit: commit)
} else {
TextField(placeholder, text: $text, onEditingChanged: editingChanged, onCommit: commit)
}
Button(action: action) {
Text(buttonTitle)
}
}
}
}
And to you can use this custom TextField like this. I have used an example from the above-listed answers to make it more clear.
struct ListView: View {
#State var text: String = ""
var body: some View {
List {
ForEach (1..<2) {_ in
Section {
CustomTextField(
text: self.$text,
action: {
print("number is .....\(self.text)")
},
buttonTitle: "Submit",
placeholder: "enter your number")
}
}
}
}
}
ListView with textfield and button. You will need an identifier for each row in case you want to have multiple rows in the List.
struct ListView: View {
#State var text: String = ""
var body: some View {
List {
ForEach (1..<2) {_ in
Section {
HStack(alignment: .center) {
TextField(self.$text, placeholder: Text("type something here...") ).background(Color.red)
Button(action: {
print(self.$text.value)
} ) {
Text("Send")
}
}
}
}
}
}
}

Resources