Creating custom data from .sheet(isPresented) from array - ios

I am trying to have user click on image and take them to a different view where it has same image and text from array on that view and for each time they click on image in scollview the view pops up with that information. It will take data from array and show it on next view with the correct item from each toggle.
struct practice: View {
#State var show = false
var place = Placeinfo
var body: some View {
VStack {
ScrollView(.horizontal) {
ForEach(place) { item in
HStack(spacing: 30) {
VStack {
HStack {
VStack {
Text(item.title).font(.headline)
Text(item.subtitle).font(.caption)
Button(action:{
self.show.toggle()
}) {
Image(item.image).renderingMode(.original)
}.sheet(isPresented: self.$show) { Detail() }
}
}
}.padding(.leading)
}
}
}
}
}
}
struct places : Identifiable{
var id = UUID()
var title: String = ""
var subtitle: String = ""
var image: String = ""
}
let Placeinfo = [
places(title: "beach", subtitle: "Cozumel",
image: "beach1"),
places(title: "beach2", subtitle: "Caribbean", image: "beach2"),
places(title: "beach3", subtitle: "CostaRica", image: "beach3")
]

You can add a places variable in your Detail view and pass your place from ForEach to your destination ex: Detail(place: place)
In your Detail view bind your variable to relevant views

Related

How can I change the Index of an Array inside a Zip function in SwiftUI?

I have zipped my array of Strings and I don't know how to change the index of an array inside a zip Function in order to show the right image to the user.
Indeed, when the user chooses any row the same images are shown images[0].imagesString.
I want to show different images according to each row: When the row named super balloon is tapped, it shows an image of a balloon and superman, when sky good is tapped it shows an image of the sky and a thumb up tapped.
Do you have any suggestions?
Thank you so much :)
import SwiftUI
struct ImageInTheScreen:Identifiable {
var id = UUID()
let imagesString:[String]
let colorString: [Color]
let rowString:String
}
class ViewModel{
var images:[ImageInTheScreen] = [ImageInTheScreen(imagesString: ["super", "baloon"], colorString: [.red,.blue],rowString: " Super Baloon"),ImageInTheScreen(imagesString: ["sky","good"], colorString: [.red,.blue],rowString: "Sky good")]
var arrayForLoop : [(String,Color)] {
//when the user chooses any row the same images are shown images[0].imagesString.
let result =
zip(images[0].imagesString,images[0].colorString)
return result.map{($0.0,$0.1)}
}
}
struct ContentView: View {
let vm:ViewModel
var body: some View {
NavigationView{
List {
ForEach(vm.images) { sentence in
NavigationLink(
destination: QuestionView(),
label: {
Text(sentence.rowString)
})
}
}
}
}
}
struct QuestionView:View {
let vm = ViewModel()
var body: some View{
HStack{
ForEach(vm.arrayForLoop, id:\.0, content: {
image in
Image(image.0)
.resizable()
.frame(width: 140, height: 140)
.scaledToFit()
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(vm: ViewModel())
}
}

Supply any string value to swiftUI form in different for textfield

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")
}
}
}

How to stop recreating #state variable after recreating view in SwiftUI

#State var myDict: [String: Double] = [:]
var body: some View {
HStack(alignment: .top) {
Button(action: {
self.myDict[self.tag ?? ""] = amountValue
})
}
}
I have two user, when i select 1st user I add value to myDict, and when I select 2nd user I want to add another value to it (means myDict will have 2 object), but when i select 2nd user #state variable is refresh and have only one value of 2nd user. (means myDict have 1 object)
is there any way so that I can have both the value in dict not only one?
actually, this can happen that for both users self.tag is nil and ("") is used as a key for the dictionary
self.myDict[self.tag ?? ""] = amountValue
and if this happens you may want to make sure that self.tag is not nil
I have created a test environment just like your case but I have
import SwiftUI
struct swiftUIDoubt1: View {
#State var myDict: [String: Double] = [:]
var body: some View {
VStack{
Button(action: {
myDict["Hello, World!"] = 9.99999
print(myDict)
}, label: {
Text("\(myDict["Hello, World!"] ?? 0)")
.padding()
})
Button(action: {
myDict["bye, World!"] = 1.11111
print(myDict)
}, label: {
Text("\(myDict["bye, World!"] ?? 0)")
.padding()
})
}
.onAppear(perform: {
print(myDict)
})
}
}
now as you can see when my screen will appear my dictionary should be empty and an empty dictionary must be printed, as you can see in the image
console log when the app is first opened
when I click first button single item will be added and you can see in console log
and when I will click on the second button you can see I have two different items in my dictionary
let success = "two different items has been added to dictionary"
as #state variable to managed by swift UI and will not change with ui update
Small example : The add in the subview update the dictionnaire for the desired user in parent view
import SwiftUI
struct UpdateUsersDict: View {
#State var myDict: [String: Double] = [:]
#State var amount: Double = 100
var body: some View {
VStack {
HStack {
OneUserView(myDict: $myDict, amount: amount, tag: "user 1")
OneUserView(myDict: $myDict, amount: amount, tag: "user 2")
OneUserView(myDict: $myDict, amount: amount, tag: "user 3")
}
HStack {
Text("\(myDict["user 1"] ?? -1)")
Text("\(myDict["user 2"] ?? -1)")
Text("\(myDict["user 3"] ?? -1)")
}
}
}
}
struct OneUserView: View {
#Binding var myDict: [String: Double]
#State var amount: Double
var tag: String
var body: some View {
HStack(alignment: .top) {
Button(tag, action: {
self.myDict[self.tag] = amount
})
}
}
}
struct UpdateUserDict_Previews: PreviewProvider {
static var previews: some View {
UpdateUsersDict()
}
}

What textfield / view to show and edit text in SwiftUI?

I would like to edit an item, for example, I have an item named "Jacket", then I would like to edit with a new name "Gray Jacket"
Now I'll have the list of my items, and when I press the "Jacket" item, it will go to the DetailItem and when it appears, I want that textfield / view already filled with "Jacket" text then I able to edit it. Please note I want to use real text not placeholder when the item name first shows up.
Does anyone know what element should I use, or if textfield how? Because I couldn't find how to set textfield with name when it first appears.
UPDATE:
Here's what I've tried, this code I took it from here. It basically took the previous text and make it a placeholder, while actually I want it to be editable.
struct CustomTextField: View {
var placeholder: Text
#Binding var text: String
var editingChanged: (Bool)->() = { _ in }
var commit: ()->() = { }
var body: some View {
ZStack(alignment: .leading) {
if text.isEmpty { placeholder }
TextField("", text: $text, onEditingChanged: editingChanged, onCommit: commit)
}
}
}
struct UsageCustomTxtField: View {
#State var text = ""
var body: some View {
CustomTextField(
placeholder: Text("placeholder").foregroundColor(.black),
text: $text
)
}
}
Here is a possible solution:
import SwiftUI
struct ContentView: View {
#ObservedObject var myItems: ItemViewModel = ItemViewModel()
#State var myNewName: String = "" // Will set the new name
var body: some View {
VStack {
TextField(self.myItems.myList[0].name, // when it appears, I want that textfield / view already filled with "Jacket" text
text: self.$myNewName,
onCommit: {
self.myItems.changeNameOfListItemTo(newName: self.myNewName, index: 0) I would like to edit with a new name "Gray Jacket"
self.myNewName = "" //empty the textfield again so name from item itself will be displayed
})
}
}
}
struct Item { // I have an item named "Jacket"
var name: String
init(name: String) {
self.name = name
}
}
class ItemViewModel: ObservableObject {
#Published var myList: Array<Item> = [Item(name: "Jacket")] //your item list
func changeNameOfListItemTo(newName: String, index: Int) { //function to change the name of an item
self.myList[0].name = newName
}
}

SwiftUI: how to update a variable transiting from a parent view only when wanted?

I would like to pass a variable from a parent to a child view, but in this child view, use it in a text field but update this value only when a SAVE button is pressed.
I tried this:
ParentView
struct ParentView: View {
#State private var name: String = ""
var body: some View {
HStack {
Text("User name: \(name)")
Spacer()
NavigationLink(
destination: ChildView(name: name),
label: {
Text("Update name")
}
)
}
}
}
ChildView
struct ChildView: View {
#State private var name: String = ""
#Binding var passedName: String
var body: some View {
VStack {
Form {
TextField("Update name", text: $name)
Button(action: {
passedName = name
}, label: {
Text("SAVE")
})
}
}
}
init(name: String) {
self._passedName = .constant(name)
self.name = name
}
}
Since I don't want to update the variable directly, I tried to use a name value and then only set the value of the binded passedName when the OK button is tapped. But it doesn't work.
I don't know how to do what I want to.
Thank you for your help
Your general approach is correct - have a state variable to represent a temporarily typed name, but a binding to represent the name "returned" to the parent.
Because the child modifies the data owned by the parent, it needs to accept a binding - not a plain String:
struct ChildView: View {
#State private var name: String
#Binding var passedName: String
var body: some View {
VStack {
Form {
TextField("Update name", text: $name)
Button(action: {
passedName = name
}, label: {
Text("SAVE")
})
}
}
}
init(name: Binding<String>) {
self._passedName = name
self._name = State(initialValue: name.wrappedValue)
}
}
Then, pass in a binding from the parent:
ChildView(name: $name)

Resources