Make a VStack height according to content in SwiftUI - swiftui

I want to make a "card" but the height depends a list of items, I don't how to set a different value according to my sizes list... Example:
ContentView Struct
struct ContentView: View {
#State private var orderList : [Order] = [
Order(id: 0, productList: [Product(id: 0, name: "itemA", quantity: "24", isEvaluated: true), Product(id: 0, name: "itemB", quantity: "2", isEvaluated: false)]),
Order(id: 1, productList: [Product(id: 0, name: "itemC", quantity: "4", isEvaluated: true), Product(id: 0, name: "itemD", quantity: "12", isEvaluated: false),Product(id: 0, name: "itemE", quantity: "6", isEvaluated: false), Product(id: 0, name: "itemF", quantity: "5", isEvaluated: false)]),
Order(id: 2, productList: [Product(id: 0, name: "itemG", quantity: "24", isEvaluated: true)]),
Order(id: 3, productList: [Product(id: 0, name: "itemH", quantity: "5", isEvaluated: true), Product(id: 0, name: "itemI", quantity: "2", isEvaluated: false),Product(id: 0, name: "itemJ", quantity: "16", isEvaluated: false), Product(id: 0, name: "itemK", quantity: "4", isEvaluated: false), Product(id: 0, name: "itemL", quantity: "2", isEvaluated: false)]),
Order(id: 4, productList: [Product(id: 0, name: "itemM", quantity: "8", isEvaluated: true)])
]
var body: some View {
VStack{
ForEach(orderList, id: \.self){order in
ScrollView(showsIndicators: false){
VStack(alignment: .leading){
Group{
HStack{
Text("#Order " + "\(order.id)").multilineTextAlignment(.center)
Spacer()
Text("In Progress").multilineTextAlignment(.center)
}.padding([.bottom],5)
}
Group{
VStack{
ForEach(order.productList.indices) { currentIndex in
ItemRow(getProduct(productList: order.productList, index: currentIndex))
.padding(.bottom, 5)
}
}
}.padding([.bottom], 10)
HStack{
Text("Products")
Spacer()
Text("$00.00")
}
HStack{
Text("Shipping Expenses")
Spacer()
Text("$00.00")
}
HStack{
Text("Total")
Spacer()
Text("$0.00")
}
Spacer()
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
.padding(10)
}
.background(
RoundedRectangle(cornerRadius: 2)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2)
)
.padding(.bottom, 10)
}
}
.padding(16)
}
func getProduct(productList: [Product], index: Int)-> Product{
return productList[index]
}
}
ItemRow Struct
struct ItemRow: View {
let currentProduct: Product
init(_ currentProduct: Product) {
self.currentProduct = currentProduct
}
var body: some View {
HStack{
HStack{
Text("• \(currentProduct.name)")
Spacer()
}
HStack{
Text("quantity \(currentProduct.quantity)")
Spacer()
}
if !currentProduct.isEvaluated{
HStack{
Spacer()
Button(action:{
// do sth
}){
Text("rate now!")
}
}
}
}
}
}
PS. in itemsList you must create a struct called Order like this: (Don't mind on hardcode values, I made it to make the example easier)
struct Order: Hashable {
var id: Int
var productList: [Product]
}
PS2. in productList you must create a struct called Product like this:
struct Product: Hashable {
var id: Int
var name: String
var quantity : String
var isEvaluated : Bool
}

If I understand you correctly you want the cards (red frame) to take as much space as they need to display the content they have without the need of scrolling on the card itself?
Short answer. You don't need to.
SwiftUI does it for you. You only have one small mistake in your code in ContentView. Move the ScrollView up to the level where you have the VStack and remove the VStack. You ContentView body should now look like this:
var body: some View {
ScrollView {
ForEach(orderList, id: \.self){order in
VStack(alignment: .leading){
Group{
HStack{
Text("#Order " + "\(order.id)").multilineTextAlignment(.center)
Spacer()
Text("In Progress").multilineTextAlignment(.center)
}.padding([.bottom],5)
}
Group{
VStack{
ForEach(order.productList.indices) { currentIndex in
ItemRow(getProduct(productList: order.productList, index: currentIndex))
.padding(.bottom, 5)
}
}
}.padding([.bottom], 10)
HStack{
Text("Products")
Spacer()
Text("$00.00")
}
HStack{
Text("Shipping Expenses")
Spacer()
Text("$00.00")
}
HStack{
Text("Total")
Spacer()
Text("$0.00")
}
Spacer()
}.background(
RoundedRectangle(cornerRadius: 2)
.fill(Color.white)
.shadow(color: .gray, radius: 2, x: 0, y: 2)
)
.padding(.bottom, 10)
}
}
.padding(16)
}
This gives you the following result:

Related

How can I change button status in SwiftUI?

I am trying to change the color programmatically of some buttons in SwiftUI.
The buttons are stored in a LazyVGrid. Each button is built via another view (ButtonCell).
I'm using a #State in the ButtonCell view to check the button state.
If I click on the single button, his own state changes correctly, just modifying the #State var of the ButtonCell view. If I try to do the same from the ContentView nothing is happening.
This is my whole ContentView (and ButtonCell) view struct:
struct ContentView: View {
private var gridItemLayout = [GridItem(.adaptive(minimum: 30))]
var body: some View {
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
ScrollView {
LazyVGrid(columns: columns, spacing: 0) {
ForEach(0..<10) { number in
ButtonCell(value: number + 1)
}
}
}
Button(action: {
ButtonCell(value: 0, isEnabled: true)
ButtonCell(value: 1, isEnabled: true)
ButtonCell(value: 1, isEnabled: true)
}){
Rectangle()
.frame(width: 200, height: 50)
.cornerRadius(10)
.shadow(color: .black, radius: 3, x: 1, y: 1)
.padding()
.overlay(
Text("Change isEnabled state").foregroundColor(.white)
)
}
}
struct ButtonCell: View {
var value: Int
#State var isEnabled:Bool = false
var body: some View {
Button(action: {
print (value)
print (isEnabled)
isEnabled = true
}) {
Rectangle()
.foregroundColor(isEnabled ? Color.red : Color.yellow)
.frame(width: 50, height: 50)
.cornerRadius(10)
.shadow(color: .black, radius: 3, x: 1, y: 1)
.padding()
.overlay(
Text("\(value)").foregroundColor(.white)
)
}
}
}
}
How I may change the color of a button in the LazyVGrid by clicking the "Change isEnabled state" button?
You need a different approach here. Currently you try to change the State of ButtonCell from the outside. State variables should always be private and therefore should not be changed from outside. You should swap the state and parameters of ButtonCell into a ViewModel. The ViewModels then are stored in the parent View (ContentView) and then you can change the ViewModels and the child views automatically update. Here is a example for a ViewModel:
final class ButtonCellViewModel: ObservableObject {
#Published var isEnabled: Bool = false
let value: Int
init(value: Int) {
self.value = value
}
}
Then store the ViewModels in the ContentView:
struct ContentView: View {
let buttonViewModels = [ButtonCellViewModel(value: 0), ButtonCellViewModel(value: 1), ButtonCellViewModel(value: 2)]
private var gridItemLayout = [GridItem(.adaptive(minimum: 30))]
var body: some View {
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
ScrollView {
LazyVGrid(columns: columns, spacing: 0) {
ForEach(0..<3) { index in
ButtonCell(viewModel: buttonViewModels[index])
}
}
}
Button(action: {
buttonViewModels[0].isEnabled.toggle()
}){
Rectangle()
.frame(width: 200, height: 50)
.cornerRadius(10)
.shadow(color: .black, radius: 3, x: 1, y: 1)
.padding()
.overlay(
Text("Change isEnabled state").foregroundColor(.white)
)
}
}
}
And implement the ObservedObject approach in ButtonCell.
struct ButtonCell: View {
#ObservedObject var viewModel: ButtonCellViewModel
var body: some View {
Button(action: {
print (viewModel.value)
print (viewModel.isEnabled)
viewModel.isEnabled = true
}) {
Rectangle()
.foregroundColor(viewModel.isEnabled ? Color.red : Color.yellow)
.frame(width: 50, height: 50)
.cornerRadius(10)
.shadow(color: .black, radius: 3, x: 1, y: 1)
.padding()
.overlay(
Text("\(viewModel.value)").foregroundColor(.white)
)
}
}
}

How can the navigation bar title be set as the item's name upon tapping on a specific item?

I'm creating a dinner menu with various food item's that can be tapped. Each item is wrapped in a NavigationLink that leads to it's detail page.
How can the item's name be placed as the navigation bar title for each item? Here's the entire MenuItemsView struct and a gif to demonstrate where I'd like the food item title just as in the previous Menu screen.
struct MenuItemsView: View {
let food = (1...12).map { "Food \($0)" }
let drinks = (1...8).map { "Drink \($0)" }
let dessert = (1...4).map { "Dessert \($0)" }
let columns = [
GridItem(.adaptive(minimum: 80))
]
var body: some View {
NavigationView {
ScrollView {
VStack {
Text("Food")
.frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
.font(.title)
.padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
LazyVGrid(columns: columns, spacing: 5.0) {
ForEach(food, id: \.self) { item in
NavigationLink(destination: MenuItemDetailsView()) {
VStack {
ColorSquare(color: .black)
Text(item)
}
.padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
}
}
}
}
VStack {
Text("Drinks")
.frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
.font(.title)
.padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
LazyVGrid(columns: columns, spacing: 5.0) {
ForEach(drinks, id: \.self) { item in
VStack {
ColorSquare(color: .black)
Text(item)
}
.padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
}
}
}
VStack {
Text("Desert")
.frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
.font(.title)
.padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
LazyVGrid(columns: columns, spacing: 5.0) {
ForEach(dessert, id: \.self) { item in
VStack {
ColorSquare(color: .black)
Text(item)
}
.padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
}
}
}
}
.navigationBarTitle("Menu")
.navigationBarItems(trailing:
Button(action: {
print("Edit button pressed...")
}) {
NavigationLink(destination: MenuItemsOptionView()) {
Image(systemName: "slider.horizontal.3")
}
}
)
}
}
}
Food Details Demonstration
As a bonus, if anyone can tell me how to properly line up the Color Squares with their respective category name and Menu title, I'd appreciate it a lot lol. Thanks!
#State itemname:String
var body: some View {
...
.navigationTitle(){
Text(itemname)
}
I was able to figure out this issue. Here's how:
I passed in itemName: item as a NavigationLink parameter as the destination. In the MenuItemDetailsView file, the body was set up with a Text view and navigationBarTitle modifier with itemName passed in. itemName was created above the MenuItemDetailsView struct before being passed of course. Here is the MenuItemDetailsView and MenuItemsView code that solved the problem as well as a quick demonstration:
MenuItemDetailsView
import SwiftUI
struct MenuItemDetailsView: View {
var itemName: String
var body: some View {
Text(itemName)
.navigationBarTitle(itemName)
}
}
struct MenuItemDetailsView_Previews: PreviewProvider {
static var previews: some View {
let food = (1...12).map { "Food \($0)" }
return Group {
ForEach(food, id: \.self) { item in
NavigationView {
MenuItemDetailsView(itemName: item)
}
.previewDisplayName(item)
}
}
}
}
MenuItemsView
import SwiftUI
struct ColorSquare: View {
let color: Color
var body: some View {
color
.frame(width: 100, height: 100)
}
}
struct MenuItemsView: View {
let food = (1...12).map { "Food \($0)" }
let drinks = (1...8).map { "Drink \($0)" }
let dessert = (1...4).map { "Dessert \($0)" }
let columns = [
GridItem(.adaptive(minimum: 80))
]
var body: some View {
NavigationView {
ScrollView {
VStack {
Text("Food")
.frame(maxWidth: .infinity, alignment: .leadingFirstTextBaseline)
.font(.title)
.padding(.init(top: -5, leading: 16, bottom: 0, trailing: 0))
LazyVGrid(columns: columns, spacing: 5.0) {
ForEach(food, id: \.self) { item in
NavigationLink(destination: MenuItemDetailsView(itemName: item)) {
VStack {
ColorSquare(color: .black)
Text(item)
}
.padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
}
}
}
}...more code
Food Item Nav Title Solved Demo

SwiftUI Binding Data

trying to bring data from LeadDetailUI to formUI to be able to edit the data in formUI and for the life of me can't figure this out, not sure on way to go (Bindings or environmentObject). eighthor way can't get it to work. I tried with bindings couldn't get it to work. please help with example on how to do this.
struct LeadDetailUI: View {
#ObservedObject var viewModel: getCustomerData
#State var tbl11 = ""
#State var tbl12 = ""
#State var tbl13 = ""
#State var tbl14 = ""
#State var tbl15 = ""
#State var tbl16 = ""
#State var tbl17 = ""
#State var tbl21 = ""
#State var tbl22 = 0
#State var tbl23 = 0
#State var tbl24 = 0
#State var tbl25 = 0
#State var tbl26 = ""
#State var tbl27 = ""
#State var l11 = ""
#State var l12 = ""
#State var l13 = ""
#State var l14 = ""
#State var l15 = ""
#State var l16 = ""
#State var l17 = ""
#State var l21 = ""
#State var l22 = ""
#State var l23 = ""
#State var l24 = ""
#State var l25 = ""
#State var l26 = ""
#State var l27 = ""
var body: some View {
NavigationView {
VStack() {
ScrollView(self.height > 700 ? .init() : .vertical, showsIndicators: true) {
VStack(alignment: .trailing, spacing: 13) {
HStack {
TextField("Peter Balsamo", text: $name).font(.title)
.padding(.top, 3)
.padding(.leading, 20)
.padding(.bottom, -10)
//.redacted(reason: .placeholder)
Text("Following").font(.headline)
.padding(.top, 10)
Button(action: {
}) {
Image(systemName: "star.fill")
.resizable()
.frame(width: 20, height: 20)
.foregroundColor(Color.orange)
.padding(.top, 7)
.padding(.trailing, 15)
}
}
Divider()
VStack {
HStack {
VStack(alignment: .leading, spacing: 5, content: {
TextField("Amount", text: $amount).font(.largeTitle)
.offset(y: -3)
TextField("Address", text: $address).font(.title3)
TextField("City", text: $city).font(.title3)
TextField("Sale Date:", text: $l1datetext).font(.caption2)
.padding(.top, 15)
TextField("Date:", text: $date).font(.headline)
.padding(.top, -5)
})
.padding(.bottom, 0)
.padding(.leading, 15)
Spacer()
VStack(alignment: .trailing, spacing: 0, content: {
Image("taylor_swift_profile")
.resizable()
.frame(width: 115, height: 115)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 2))
.padding(.top, -25)
TextField("Lead#", text: $id).font(.caption2)
.multilineTextAlignment(.trailing)
.padding(.top, 15)
})
.frame(width: 120)
.padding(.trailing, 10)
Spacer()
}
HStack {
VStack(alignment: .leading, spacing: 0, content: {
HStack {
Toggle("", isOn: $showingSold.animation(.spring()))
.frame(width:80, height: 30)
.toggleStyle(SwitchToggleStyle(tint: .blue))
.clipShape(RoundedRectangle(cornerRadius: 10))
if showingSold {
Text("Priority").font(.headline)
.background(Color.red.cornerRadius(10))
.foregroundColor(.white)
.padding(.leading, 10)
}
}
})
Spacer()
Button(action: {
showFullscreen.toggle()
}) {
Text("Map")
.fontWeight(.bold)
.frame(width:115, height: 30)
.foregroundColor(.white)
.background(Color(.systemBlue))
.clipShape(RoundedRectangle(cornerRadius: 10))
}
.padding(.trailing, 20)
}
.padding(.bottom, 30)
}
.fullScreenCover(isPresented: $showFullscreen, content: {
HomeMap()
})
}
.foregroundColor(self.color == 0 ? Color.black : Color.white)
.background(self.color == 0 ? Color.yellow : Color.purple)
.clipShape(CustomShape(corner: .bottomLeft, radii: 55))
ScrollView(self.height > 800 ? .init() : .vertical, showsIndicators: false) {
let first = DataUI(name: tbl11, label: l11)
let second = DataUI(name: tbl12, label: l12)
let third = DataUI(name: tbl13, label: l13)
let fourth = DataUI(name: tbl14, label: l14)
let fifth = DataUI(name: tbl15, label: l15)
let sixth = DataUI(name: tbl16, label: l16)
let seventh = DataUI(name: tbl17, label: l17)
let eighth = DataUI(name: tbl21, label: l21)
let ninth = DataUI(name: "\(tbl22)", label: l22)
let tenth = DataUI(name: "\(tbl23)", label: l23)
let eleven = DataUI(name: "\(tbl24)", label: l24)
let twelve = DataUI(name: "\(tbl25)", label: l25)
let thirteen = DataUI(name: tbl26, label: l26)
let fourteen = DataUI(name: tbl27, label: l27)
let customers = [first, second, third, fourth, fifth, sixth, seventh, eighth, ninth, tenth, eleven, twelve,thirteen, fourteen]
List(customers) { customer in
CenterViewUI(formData: customer)
}
}
.edgesIgnoringSafeArea(.all)
.statusBar(hidden: true)
.animation(.default)
BottomViewUI(comments: self.$comments, lnewsTitle: self.$lnewsTitle, index: $index)
}
.shadow(color: Color.white.opacity(0.2), radius: 5, x: 0, y: 2)
}
.navigationTitle("Profile")
.navigationBarHidden(false)
.navigationBarTitleDisplayMode(.inline)
.navigationBarItems (
leading:
Button(action: {
showActionSheet.toggle()
}) {
Image(systemName: "square.and.arrow.up")
.resizable()
.frame(width: 20, height: 20)
},
trailing:
//NavigationLink(destination: FormUI(frm11: $tbl11)) {
Button(action: {
showSheet.toggle()
}, label: {
Text("Edit")
.actionSheet(isPresented: $showActionSheet, content: getActionSheet)
.sheet(isPresented: $showSheet, content: {
FormUI()
})
.foregroundColor(self.color == 0 ? Color.yellow : Color.purple)
}
}
struct DataUI: Identifiable {
var id = UUID().uuidString
var name: String
var label : String
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
Group {
LeadDetailUI(viewModel: getCustomerData())
.preferredColorScheme(.dark)
}
}
}
public struct FormUI: View {
#Environment(\.presentationMode) var presentationMode
#EnvironmentObject var viewModel: getCustomerData
private var db = Firestore.firestore()
#State var frm11 = ""
#State var frm12 = ""
#State var frm13 = ""
#State var frm14 = ""
#State var frm15 = ""
#State var frm16 = ""
#State var frm17 = ""
#State var frm18 = ""
#State var frm19 = ""
public var body: some View {
NavigationView {
VStack {
ScrollView(self.height > 800 ? .init() : .vertical, showsIndicators: false) {
VStack {
//ForEach(self.viewModel.data) { i in
Form {
Section {
HStack{
VStack{
Image("taylor_swift_profile")
.resizable()
.frame(width: 75, height: 75)
.clipShape(Circle())
.overlay(Circle().stroke(Color.white, lineWidth: 2))
.padding()
Button(action: {}, label: {
Text("Edit")
.font(.caption)
.padding(.top, -15)
.foregroundColor(self.color == 0 ? Color.purple : Color.red)
})
}
.padding(.leading, -30)
Divider()
Spacer()
VStack(spacing: 12) {
TextField("First", text: $frm11)
TextField("Last", text: $frm12)
Picker(selection: $selection, label:
TextField("Company", text: $callback)) {
ForEach(0 ..< pickContractor.count) {
Text(self.pickContractor[$0])
}
}
}
.font(.system(size: 20.0))
.multilineTextAlignment(.leading)
}
}
.font(.headline)
.padding(.leading, 18)
Section(header: Text("Customer Info")) {
HStack {
Text("Address:")
.formTextStyle()
Spacer()
TextField("address", text: $address)
.formStyle()
}
HStack {
Text("City:")
.formTextStyle()
Spacer()
TextField("city", text: $city)
.formStyle()
}
HStack {
Text("State:")
.formTextStyle()
.multilineTextAlignment(.leading)
Spacer()
TextField("state", text: $state)
.formStyle()
.frame(minWidth: 50, maxWidth: 60)
.autocapitalization(.allCharacters)
.multilineTextAlignment(.leading)
//.padding(.leading, )
Spacer()
Text("Zip:")
.formTextStyle()
TextField("zip", text: $zip)
.formStyle()
.frame(minWidth: 100, maxWidth: 145)
.keyboardType(.numberPad)
}
HStack {
Text("Phone:")
.formTextStyle()
Spacer()
TextField("phone", text: $phone)
.formStyle()
.keyboardType(.numberPad)
}
HStack {
Text("Amount:")
.formTextStyle()
Spacer()
Stepper(
onIncrement: {
stepperValue += 1000
},
onDecrement: {
stepperValue -= 1000
},
label: {
TextField("amount", text: $amount)
.formStyle()
})
}
HStack {
Text("Email:")
.formTextStyle()
Spacer()
TextField("email", text: $email)
.formStyle()
.keyboardType(.emailAddress)
}
}
Section {
HStack {
Text("Salesman:")
.formTextStyle()
Spacer()
TextField("salesman", text: $salesman)
}
HStack {
Text("Job:")
.formTextStyle()
Spacer()
TextField("job", text: $jobName)
.formStyle()
}
HStack {
Text("Product:")
.formTextStyle()
Spacer()
TextField("product", text: $adName)
.formStyle()
}
HStack {
Text("Quantity:")
.formTextStyle()
Spacer()
TextField("quantity", text: $frm25)
.formStyle()
.keyboardType(.numberPad)
}
HStack {
Text("Apt Date:")
.formTextStyle()
Spacer()
DatePicker(selection: $selDate, displayedComponents: .date) {
TextField("", text: $aptdate)
.formStyle()
}
}
HStack {
Text("Comments:")
.formTextStyle()
Spacer()
TextEditor(text: $comment)
}
}
Section(header: Text("Misc")) {
HStack {
Toggle(isOn: $isOn) {
Text("\(self.isOn == true ? "Active":"Not Active")")
.formTextStyle()
}
.toggleStyle(SwitchToggleStyle(tint: .purple))
}
HStack {
Text("Date")
.formTextStyle()
Spacer()
DatePicker(selection: $selDate, displayedComponents: .date, label: {
TextField("", text: $date)
})
}
HStack {
Text("Spouse")
.formTextStyle()
Spacer()
TextField("spouse", text: $spouse)
}
HStack {
Text("Called Back")
.formTextStyle()
Spacer()
Picker(selection: $selection, label:
TextField("", text: $callback)) {
ForEach(0 ..< callbackPicker.count) {
Text(self.callbackPicker[$0])
}
}
}
HStack {
Text("Rate")
.formTextStyle()
Spacer()
Picker(selection: $selection, label:
TextField("", text: $rate)) {
ForEach(0 ..< pickRate.count) {
Text(verbatim: self.pickRate[$0])
}
}
}
HStack {
Text("Photo")
.formTextStyle()
Spacer()
TextField("photo", text: $photo)
}
}
}
.font(.system(size: 20.0))
.padding(.top, -40)
}
}
}
.navigationTitle("Data Entry")
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: {
presentationMode.wrappedValue.dismiss()
}) {
Image(systemName: "xmark.circle").font(.largeTitle)
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
//if !frm11.isEmpty && !frm12.isEmpty {
saveData()
resetTextFields()
self.alert.toggle()
}, label: {
Text("Save")
}
}
.alert(isPresented: $alert) {
Alert(title: Text("Upload Complete"), message: Text("Successfully updated the data"), dismissButton: .default(Text("Ok")))
}
}
.accentColor(self.color == 0 ? Color.purple : Color.red)
}
private func saveData() {
let uid = Auth.auth().currentUser!.uid
var ref: DocumentReference? = nil
ref = db.collection("Customers").addDocument(data: [
"active": frm30,
"custId": frm12,
"custNo": custNo,
"leadNo": leadNo,
"first": frm11,
"lastname": frm12,
"contractor": frm13,
"city": city,
"state": state,
"zip": zip,
"phone": phone,
"amount": Int(amount) as Any,
"email": email,
"rate": rate,
"salesNo": saleNo,
"jobNo": jobNo,
"adNo": adNo,
"quan": Int(frm25) as Any,
"start": NSNull(),
"completion": NSNull(),
"lastUpdate": Timestamp(date: Date()),
"creationDate": Timestamp(date: Date()),
"aptdate": aptdate,
"comments": comment,
"spouse": spouse,
"photo": photo,
"uid": uid,
]) { error in
if let error = error {
print("Error adding document: \(error)")
} else {
print("Document added with ID: \(ref!.documentID)")
}
}
}
func updateData() {
db.collection("Customer")
.document()
.setData(["active":self.frm30,"custId":self.frm12,"custNo":self.custNo,"leadNo":self.leadNo,"first":self.frm11,"lastname":self.frm12,"contractor":self.frm13,"city":self.city,"state":self.state,"zip":self.zip,"phone":self.phone,"amount":self.amount,"email":self.email,"rate":self.rate,"salesNo":self.saleNo,"jobNo":self.jobNo,"adNo":self.adNo,"start":self.start,"lastUpdate":Timestamp(date:Date()),"aptdate":self.aptdate,"comments":self.comment,"spouse":self.spouse,"photo":self.photo]) { (error) in
if error != nil{
print((error?.localizedDescription)!)
return
}
//self.presentation.wrappedValue.dismiss()
}
}
}
struct FormUI_Previews: PreviewProvider {
static var previews: some View {
FormUI()
.preferredColorScheme(.dark)
}
}

How to create cell rows of text that align like cells in SwiftUI

I'd like to create something like this (without the "pipes" between each "cell" in SwiftUI. Assume each "cell" is a fixed size.
I have the following:
import Foundation
struct Activity {
let id: Int
let date: String
let imageURL: String
let distance: Double
let elevation: Int
}
extension Activity {
static func all() -> [Activity] {
return [
Activity(id: 1, date: "10/10/2021", imageURL: "map1", distance: 120, elevation: 452),
Activity(id: 2, date: "10/10/2021", imageURL: "map2", distance: 90, elevation: 34),
Activity(id: 3, date: "10/10/2021", imageURL: "map3", distance: 460, elevation: 345),
Activity(id: 4, date: "10/10/2021", imageURL: "map4", distance: 70, elevation: 21),
Activity(id: 5, date: "10/10/2021", imageURL: "map5", distance: 40, elevation: 345)
]
}
}
struct ContentView: View {
let activities = Activity.all()
var body: some View {
List(self.activities, id: \.id) { activity in
VStack(alignment: .center) {
Image(activity.imageURL)
.resizable()
.frame(width: 300, height: 200)
.cornerRadius(16)
HStack(alignment: .lastTextBaseline) {
Text("Date").fixedSize().font(.system(size: 10))
Spacer()
Text("Distance").fixedSize().font(.system(size: 10))
Spacer()
Text("Elevation").fixedSize().font(.system(size: 10))
}
HStack(alignment: .lastTextBaseline) {
Text(activity.name).fixedSize()
Spacer()
Text(String(activity.distance)).fixedSize()
Spacer()
Text(String(activity.elevation)).fixedSize()
}
}
}
}
}
But clearly this isn't the right approach. Any ideas on how I can create this ?
As far as I understood it can be done as
var body: some View {
List(self.activities, id: \.id) { activity in
VStack(alignment: .center) {
Image(activity.imageURL)
.resizable()
.frame(width: 300, height: 200)
.cornerRadius(16)
HStack(alignment: .lastTextBaseline) {
VStack(alignment: .leading) {
Text("Date").fixedSize().font(.system(size: 10))
Text(activity.date).fixedSize()
}
Spacer()
VStack(alignment: .leading) {
Text("Distance").fixedSize().font(.system(size: 10))
Text(String(activity.distance)).fixedSize()
}
Spacer()
VStack(alignment: .leading) {
Text("Elevation").fixedSize().font(.system(size: 10))
Text(String(activity.elevation)).fixedSize()
}
}
}
}
}

List Based view from Data SwiftUI

new code with error. This is what I am getting the error with. I have 2 sets of data that will be shows in 2 groups. a Location 1 with employees, and a location 2 with a different set of employees. When I add the second list if employees then I get the error Cannot convert value of type 'DataUI' to expected argument type 'Data on the NavigationLink(destination: DetailView(data: listedPeople)) { line of the Loc2 file.
hope this explains it well enough.
Place in 1 file called ContentView
struct Home: View {
var body: some View {
TabView {
loc1()
.tabItem {
VStack{
Image(systemName: "person.3.fill")
Text ("Location 1")
}
}
.tag(2)
loc2()
.tabItem {
VStack{
Image(systemName: "person.fill")
Text ("Location 2")
}
}
}
}
}
Place in file 2 Named loc1
struct Data: Identifiable{
var id = Int ()
let title, imageUrl, Dev, URL: String
}
struct loc1: View {
let data:[Data] = [
Data(id: 0, title: "Cook", imageUrl: "hh",Dev:"John", URL: "school"),
Data(id: 1, title: "Staff", imageUrl: "JJ",Dev:"Harper", URL: "home" ),
Data(id: 2, title: "Busser", imageUrl: "uu",Dev:"Matt", URL: "Table"),
Data(id: 3, title: "Host", imageUrl: "tt",Dev:"Jacob", URL: "Door")]
var body: some View {
NavigationView {
List(data) { listedPeople in
NavigationLink(destination: DetailView(data: listedPeople)) {
HStack{
Image(listedPeople.imageUrl)
.resizable()
.cornerRadius(12)
.frame(width:30, height:30)
VStack (alignment: .leading){
Text(listedPeople.title)
.font(.headline)
Text(listedPeople.Dev)
.font(.subheadline)
}
}
}.navigationBarTitle(Text("location 1"))
}
}
}
}
Place code in new file named loc2 (this is where the error is for me)
import SwiftUI
struct DataUI: Identifiable{
var id = Int ()
let title, imageUrl, Dev, URL: String
}
struct loc2: View {
let data:[DataUI] = [
DataUI(id: 0, title: "Cook", imageUrl: "hh",Dev:"Bob", URL: "school"),
DataUI(id: 1, title: "Staff", imageUrl: "JJ",Dev:"Joe", URL: "home" ),
DataUI(id: 2, title: "Busser", imageUrl: "uu",Dev:"Nick", URL: "Table"),
DataUI(id: 3, title: "Host", imageUrl: "tt",Dev:"Hunter", URL: "Door")]
var body: some View {
NavigationView {
List(data) { listedPeople in
NavigationLink(destination: DetailView(data: listedPeople)) {
HStack{
Image(listedPeople.imageUrl)
.resizable()
.cornerRadius(12)
.frame(width:30, height:30)
VStack (alignment: .leading){
Text(listedPeople.title)
.font(.headline)
Text(listedPeople.Dev)
.font(.subheadline)
}
}
}.navigationBarTitle(Text("Location2"))
}
}
}
}
Create a new file named DetailView
import SwiftUI
struct DetailView : View{
var data: Data
var body: some View {
NavigationView{
List {
HStack{
Image(data.imageUrl)
.resizable()
.frame(width:70, height:60)
.clipShape(Circle())
.shadow(radius: 10)
.overlay(Circle().stroke(Color.black, lineWidth: 1))
VStack{
Text(data.title)
.font (.title)
HStack{
Image(systemName: "envelope.fill")
.resizable()
.frame(width:20, height: 15)
Text("Data.URL")
.font (.subheadline)
}
}
}.navigationBarTitle(Text("Data.title"))
}
}
}
}
check this out!
struct Data: Identifiable{
var id = Int ()
let title, imageUrl, Dev, URL: String
}
struct ContentView: View {
let data:[Data] = [
Data(id: 0, title: "Cook", imageUrl: "hh",Dev:"John", URL: "school"),
Data(id: 1, title: "Staff", imageUrl: "JJ",Dev:"Harper", URL: "home" ),
Data(id: 2, title: "Busser", imageUrl: "uu",Dev:"Matt", URL: "Table"),
Data(id: 3, title: "Host", imageUrl: "tt",Dev:"Jacob", URL: "Door")]
var body: some View {
NavigationView {
List(data) { listedPeople in
NavigationLink(destination: DetailView(data: listedPeople)) {
HStack{
Image(listedPeople.imageUrl)
.resizable()
.cornerRadius(12)
.frame(width:30, height:30)
VStack (alignment: .leading){
Text(listedPeople.title)
.font(.headline)
Text(listedPeople.Dev)
.font(.subheadline)
}
}
}.navigationBarTitle(Text("Restraunt"))
}
}
}
}
struct DetailView : View{
var data: Data
var body: some View {
NavigationView{
List {
HStack{
Image(data.imageUrl)
.resizable()
.frame(width:70, height:60)
.clipShape(Circle())
.shadow(radius: 10)
.overlay(Circle().stroke(Color.black, lineWidth: 1))
VStack{
Text(data.title)
.font (.title)
HStack{
Image(systemName: "envelope.fill")
.resizable()
.frame(width:20, height: 15)
Text("Data.URL")
.font (.subheadline)
}
}
}.navigationBarTitle(Text("Data.title"))
}
}
}
}
you have mixed Data and DataUI ...that was the problem. I really don't know why you defined two structs with different names and they are completely identical?
I corrected this and now it runs,
here is the solution:
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
loc1()
.tabItem {
VStack{
Image(systemName: "person.3.fill")
Text ("Location 1")
}
}
.tag(2)
loc2()
.tabItem {
VStack{
Image(systemName: "person.fill")
Text ("Location 2")
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct loc1: View {
let dataUI:[DataUI] = [
DataUI(id: 0, title: "Cook", imageUrl: "hh",Dev:"John", URL: "school"),
DataUI(id: 1, title: "Staff", imageUrl: "JJ",Dev:"Harper", URL: "home" ),
DataUI(id: 2, title: "Busser", imageUrl: "uu",Dev:"Matt", URL: "Table"),
DataUI(id: 3, title: "Host", imageUrl: "tt",Dev:"Jacob", URL: "Door")]
var body: some View {
NavigationView {
List(dataUI) { listedPeople in
NavigationLink(destination: DetailView(dataUI: listedPeople)) {
HStack{
Image(listedPeople.imageUrl)
.resizable()
.cornerRadius(12)
.frame(width:30, height:30)
VStack (alignment: .leading){
Text(listedPeople.title)
.font(.headline)
Text(listedPeople.Dev)
.font(.subheadline)
}
}
}.navigationBarTitle(Text("location 1"))
}
}
}
}
struct loc1_Previews: PreviewProvider {
static var previews: some View {
loc1()
}
}
struct DataUI: Identifiable{
var id = Int ()
let title, imageUrl, Dev, URL: String
}
struct loc2: View {
let dataUI:[DataUI] = [
DataUI(id: 0, title: "Cook", imageUrl: "hh",Dev:"Bob", URL: "school"),
DataUI(id: 1, title: "Staff", imageUrl: "JJ",Dev:"Joe", URL: "home" ),
DataUI(id: 2, title: "Busser", imageUrl: "uu",Dev:"Nick", URL: "Table"),
DataUI(id: 3, title: "Host", imageUrl: "tt",Dev:"Hunter", URL: "Door")]
var body: some View {
NavigationView {
List(dataUI) { listedPeople in
NavigationLink(destination: DetailView(dataUI: listedPeople)) {
HStack{
Image(listedPeople.imageUrl)
.resizable()
.cornerRadius(12)
.frame(width:30, height:30)
VStack (alignment: .leading){
Text(listedPeople.title)
.font(.headline)
Text(listedPeople.Dev)
.font(.subheadline)
}
}
}.navigationBarTitle(Text("Location2"))
}
}
}
}
struct DetailView : View{
var dataUI: DataUI
var body: some View {
NavigationView{
List {
HStack{
Image(dataUI.imageUrl)
.resizable()
.frame(width:70, height:60)
.clipShape(Circle())
.shadow(radius: 10)
.overlay(Circle().stroke(Color.black, lineWidth: 1))
VStack{
Text(dataUI.title)
.font (.title)
HStack{
Image(systemName: "envelope.fill")
.resizable()
.frame(width:20, height: 15)
Text("Data.URL")
.font (.subheadline)
}
}
}.navigationBarTitle(Text("Data.title"))
}
}
}
}