SwiftUI - Text minimumScaleFactor not scaling only when needed - text

I have a Text that I want to modify with a .minimumScaleFactor(0.1) when the length of its string extends outside the view. However, the scaling applies every time, even when the original font size would be perfectly fine.
My view is structured thusly:
VStack(alignment: .center, spacing: 0) {
HStack {
Image("medal \(place)").resizable()
.foregroundColor(color)
.frame(width: 40, height: 40)
Spacer()
Text(username)
.font(.bold(16))
.lineLimit(1)
.minimumScaleFactor(0.1)
.frame(alignment: .trailing)
.foregroundColor(Color("mediumTextColor"))
}
Spacer()
Text(score)
.font(.extraBold(60))
.foregroundColor(color)
.lineLimit(1)
.minimumScaleFactor(0.7)
Spacer()
}
.frame(height: 96)
.padding(10)
.cornerRadius(16)
.overlay(RoundedRectangle(cornerRadius: 16)
.stroke(color, lineWidth: 2))

A continuation of answer above.
What is important is the order in which the modifiers are applied:
Text("This is a really long sentence.")
.minimumScaleFactor(0.5)
.font(.custom("OpenSans", size: 15))
.lineLimit(1)
.layoutPriority(1)
There isn't a need for the GeometryReader unless you need it for something else

Adding .lineLimit(1) to the Text will work well.
Xcode: 11.3.1

Important for that minimumScaleFactor() only does its job when it is needed, is the combination of .minimumScaleFactor AND .lineLimit(1); otherwise it will not work. layoutPriority(1) is not the key here.
Example - this works; Scale is only applied when needed:
Text("Something").minimumScaleFactor(0.5).lineLimit(1)

Adding a GeometryReader around the VStack that my two Text views were in solved this. As requested by #gohnjanotis:
GeometryReader { proxy in
VStack(alignment: .center, spacing: 0) {
HStack {
Image("medal \(self.place)").resizable()
.foregroundColor(self.color)
.frame(width: 40, height: 40)
Spacer()
Text(self.username)
.minimumScaleFactor(0.1)
.font(.bold(16))
.lineLimit(1)
.frame(alignment: .trailing)
.foregroundColor(Color("mediumTextColor"))
.layoutPriority(1)
}
.padding(.top, 10)
.padding(.horizontal, 10)
Spacer()
Text(self.score)
.font(.extraBold(60))
.foregroundColor(self.color)
.lineLimit(1)
.minimumScaleFactor(0.1)
.layoutPriority(1)
.padding(.horizontal, 10)
.padding(.bottom, 10)
.offset(y: -10)
}
.frame(width: proxy.size.width, height: proxy.size.height, alignment: .top)
}
.frame(maxHeight: 130)

Add .layoutPriority(1) modifier to your Text to make sure it takes the space if there is any.

After trying to figuring this out for a long while... playing with minimumScaleFactor, LineLimit, layoutPriority... I found out that using .frame() helps solve my problem.
My problem is that minimumScaleFactor applies to Text even if it is not needed.
Applying .frame() ad the last line solve my problem.
Something like this...
GeometryReader { geometry in
VStack{
Text("Hello")
.foregroundColor(Color.Black)
.font(.system(size: 50))
.minimumScaleFactor(0.1)
.lineLimit(1)
.frame(height: geometry.size.height)
}
}

Related

SwiftUI Stack Layout

I need to implement view with two texts, and first text alignment need to be trailing, and second text alignment leading, but I have this..
please help me to build correct layout.
i tried to put another VStack inside the HStack and assign the trailing orientation to the first and the leading to the second
this is my code example:
var body: some View {
VStack {
HStack(spacing: 10) {
Text("test1")
.font(.system(size: 12))
.fontWeight(.bold)
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 10))
Text("testtest1")
.padding()
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 1)
)
Spacer()
}
.frame(width: UIScreen.screenWidth)
.padding(EdgeInsets(top: 0, leading: 40, bottom: 12, trailing: 0))
HStack(spacing: 10) {
Text("test23")
.font(.system(size: 12))
.fontWeight(.bold)
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 10))
Text(String("testtest12"))
.padding()
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 1)
)
Spacer()
}
.frame(width: UIScreen.screenWidth)
.padding(EdgeInsets(top: 0, leading: 40, bottom: 12, trailing: 0))
HStack(spacing: 10) {
Text("test345")
.font(.system(size: 12))
.fontWeight(.bold)
.frame(alignment: .trailing)
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 10))
Text("testtest1234")
.padding()
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 1)
)
Spacer()
}
.frame(width: UIScreen.screenWidth)
.padding(EdgeInsets(top: 0, leading: 40, bottom: 12, trailing: 0))
HStack {
Text("test6789")
.font(.system(size: 12))
.fontWeight(.bold)
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 10))
Text("testtest123456")
.padding()
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 1)
)
Spacer()
}
.frame(width: UIScreen.screenWidth)
.padding(EdgeInsets(top: 0, leading: 40, bottom: 12, trailing: 0))
HStack {
Text("test01234")
.font(.system(size: 12))
.fontWeight(.bold)
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 10))
Text("testtest56")
.padding()
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 1)
)
Spacer()
}
.frame(width: UIScreen.screenWidth)
.padding(EdgeInsets(top: 0, leading: 40, bottom: 12, trailing: 0))
HStack {
Text("test5")
.font(.system(size: 12))
.fontWeight(.bold)
// .padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 10))
Text("testtes78")
.padding()
.font(.system(size: 14))
.foregroundColor(.black)
.multilineTextAlignment(.center)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(Color.red, lineWidth: 1)
)
Spacer()
}
.frame(width: UIScreen.screenWidth)
.padding(EdgeInsets(top: 0, leading: 40, bottom: 12, trailing: 0))
}
}
But I want to make something like this:
Give the texts on the left fixed width and add the multiLineAlignment(.traling) to all.
Edit:
var body: some View {
VStack(spacing: 0) {
ForEach(0..<5) { i in
HStack(spacing: 0) {
Text("Left Text \(String(repeating: "XX", count: i))")
.font(.system(size: 12).bold())
.frame(width: 150, alignment: .trailing)
.padding(.trailing, 15)
Text("Right Text \(i)")
.font(.system(size: 12))
.padding()
.overlay(
RoundedRectangle(cornerRadius: 20, style: .continuous)
.stroke(.red)
)
Spacer()
}
.padding(.bottom, 15)
.frame(maxWidth: .infinity)
}
Spacer()
}
.padding()
.frame(maxWidth: .infinity)
}

In SwiftUI, is there a simple way to size the children with non-fixed size as a factor of remaining space available? (Flex Factor)

Here's what I need to do: I have a parent view with a fixed width and 4 children. 2 of the children (1st and 3rd) have fixed width. The others (2nd and 4th) have flexible width. The default interpretation for flexible is that they would share equally the space available, but I don't want this, instead, I want to tell each flexible View how much of the remaining space it should take, for instance, the first should take 2/3 and the second 1/3.
For people familiar with the Flex Layout, this is equivalent to say I want my 2nd View to have flex: 2 and my 4th view to have flex: 1. See the example below:
In the example above, the parent view has the fixed width of 600px. The first child has 100px width, the third has 140px. The remaining space is 360px, so the second child gets 240px (2/3) and the fourth child gets 120px(1/3). If I change the width of the parent view, the size of the second and fourth children will adapt accordingly.
It is extremely simple to do this for the Web, see the code below:
<div style="width: 600; display: flex; flex-direction: row;">
<div style="width: 100; height: 100; background-color: red;"></div>
<div style="flex: 2; height: 100; background-color: green;"></div>
<div style="width: 140; height: 100; background-color: blue;"></div>
<div style="flex: 1; height: 100; background-color: purple;"></div>
</div>
It is also super-simple to do it in Flutter:
Row(
children: [
Container(height: 50, width: 50, color: Colors.red),
Flexible(flex: 2, child: Container(height: 50, color: Colors.green)),
Container(height: 50, width: 80, color: Colors.blue),
Flexible(flex: 1, child: Container(height: 50, color: Colors.purple)),
]
)
It's very similar in Jetpack Compose (Android):
Row {
Row(modifier = Modifier.height(50.dp).width(50.dp).background(color = Color.Red)) {}
Row(modifier = Modifier.height(50.dp).weight(2F).background(color = Color.Green)) {}
Row(modifier = Modifier.height(50.dp).width(80.dp).background(color = Color.Blue)) {}
Row(modifier = Modifier.height(50.dp).weight(1F).background(color = Color.Black)) {}
}
I tried a lot of things, but I couldn't find any simple way of achieving this behavior in SwiftUI. From my understanding, to size the children, SwiftUI first calculates the size of every child that can have its size calculated, i.e. every child that has a fixed size, after that it calculates the remaining space and divide it by the number of children with an undefined size telling each of them this is the maximum size they can occupy (this is the size we read when using a GeometryReader). Is there a way to tell SwiftUI to not divide the space available equally among the children with undefined size, but instead divide it according to a factor specified by each one of them?
Is there a different approach to this in a way I can obtain the same result as the other platforms I mentioned here?
For now, my strategy is much more complex than I'd like it to be. I render the first child with width = 50, the second child with width = 0 (should be flexible), the third child with width = 80, the fourth child with width = 0 (should be flexible) and an additional 5th child with width = .infinity. After the first render, I measure the size of the 5th child and update a state with this value, which represents the remaining space after the children with fixed size have been placed. After the state is updated, I can calculate the sizes of the flexible children and render everything a second time, now with the correct sizes. See the code below:
struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
}
struct ContentView: View {
private let totalFlexFactor = 3
#State private var freeSpace: CGSize? = nil
func getFlexibleWidth(parentWidth: CGFloat, factor: Int) -> CGFloat {
return (CGFloat(factor) / CGFloat(totalFlexFactor)) * (freeSpace?.width ?? 0)
}
var body: some View {
GeometryReader { parentGeometry in
HStack(spacing: 0) {
HStack() {}
.frame(maxWidth: 50, maxHeight: .infinity)
.background(Color.red)
HStack() {}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2), maxHeight: .infinity)
.background(Color.green)
HStack() {}
.frame(maxWidth: 80, maxHeight: .infinity)
.background(Color.blue)
HStack() {}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1), maxHeight: .infinity)
.background(Color.purple)
if (freeSpace == nil) {
HStack() {}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(
GeometryReader { geometryProxy in
Color.clear
.preference(key: SizePreferenceKey.self, value: geometryProxy.size)
}
)
}
}
.frame(maxWidth: .infinity, maxHeight: 50)
.background(Color.gray)
.onPreferenceChange(SizePreferenceKey.self) { newSize in
if (freeSpace == nil) {
freeSpace = newSize
}
}
}
}
}
Credits to Federico Zanetello for the code that measures the size of the children.
As I said before, I don't see this as a very elegant solution, mainly if we compare it to the other platforms. I'd appreciate any suggestion! Just keep in mind the example I gave: fixed sized views intercalated with flexibly sized views.
Edit: I'm trying to build a component called Flexbox. In my example, I set the widths of each view, but it's just for simplicity. In fact, inside the Flexbox component, I don't know the size of any of the children, that's why, in my solution, I had to measure them.
Example: I might call:
Flexbox {
ViewWith100Width()
Flexible(flex: 2) { ViewWithFlexibleSize() }
ViewWith80Width()
Flexible(flex: 1) { AnotherViewWithFlexibleSize() }
}
But I could also call:
Flexbox {
ViewWith40Width()
Flexible(flex: 2) { ViewWithFlexibleSize() }
ViewWith60Width()
Flexible(flex: 1) { AnotherViewWithFlexibleSize() }
}
The component Flexbox must be agnostic of the size of whichever child is passed to it. That's why I had to measure each non-flexible child.
I haven't mentioned this in the original formulation of the question because I didn't want to overcomplicate it, since I just want to know if there's an easier way to simulate the Flexbox behavior of web/flutter/compose in swiftui.
While I think PreferenceKeys are a great tool to have and use, this is not a case where they are needed. Your plan was overly complicated. This comes down to a simple math problem, but first there is a coding issue:
.frame(maxWidth: 50, maxHeight: .infinity)
gives you a flexible, not a fixed width. What you have told ViewBuilder to do is assign to the width of the frame any value up to 50, not a value of 50. I understand what you were doing, as you wanted to expand the height to the size of the view container. There are two alternatives:
.frame(minWidth: 50, maxWidth: 50, maxHeight: .infinity)
or
.frame(width: 50)
.frame(maxHeight: .infinity)
I chose the latter as it makes your intention very clear. Since they were fixed, I also assigned them to let constants to be used anywhere I needed them.
Also, while I did not test this, I suspect the PreferenceKey couldn't handle the disappearing/reappearing view. Since they were unnecessary, it didn't delve into it.
At this point, you can find your flexible space simply by parentGeometry less the two fixed widths. No PreferenceKeys needed. in the end, the code simplifies to:
struct ContentView: View {
private let totalFlexFactor: CGFloat = 3
#State private var freeSpace: CGSize? = nil
private let width1: CGFloat = 100
private let width2: CGFloat = 80
private func getFlexibleWidth(parentWidth: CGFloat, factor: CGFloat) -> CGFloat {
((parentWidth - (width1 + width2)) / totalFlexFactor) * factor
}
var body: some View {
GeometryReader { parentGeometry in
HStack(spacing: 0) {
HStack {
Text(width1.description)
}
.frame(width: width1)
.frame(maxHeight: .infinity)
.background(Color.red)
HStack {
Text(getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2).description)
}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 2), maxHeight: .infinity)
.background(Color.green)
HStack {
Text(width2.description)
}
.frame(width: width2)
.frame(maxHeight: .infinity)
.background(Color.blue)
HStack {
Text(getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1).description)
}
.frame(maxWidth: getFlexibleWidth(parentWidth: parentGeometry.size.width, factor: 1), maxHeight: .infinity)
.background(Color.purple)
}
.frame(maxWidth: .infinity, maxHeight: 50)
.background(Color.gray)
}
}
}
I also displayed the values for the widths of the various HStacks in the HStacks.
Also, with regard to SwiftUI syntax, it is not necessary to write HStack() unless you intend to use the optional values of alignment: and spacing:, otherwise we omit the ().
The main idea in to layout is where to use needed containers. Here (fixed-flex-fixed-flex) GeometryReader can be used only for three.
Tested with Xcode 13.3 / iOS 15.4
Main idea part is:
GeometryReader { gp in
HStack (spacing: 0) {
Color.green
.frame(width: (gp.size.width - fixed2) * 2/3)
Color.blue
.frame(width: fixed2)
Completed findings and report is here
Try .layoutPriority(1/0) to have grow and shrink behaviour
setting priority 1, lets view grow and shrink

UIView Top Point is Lower Then Expected

I have a format problem. How I want is the 2nd picture but for some reason, my view starts a little bit lower. You can see the gap between the pictures. I want to solve this problem without offset. Might be because of .navigationBarHidden(true) but I do not want navigation bar.
I added NavigationView to my code because I have a button down-right to add a new task.
Plus for some reason, this button is not clickable. Would be good if you give a hand to that problem.
import SwiftUI
struct TaskListView: View {
#State private(set) var data = ""
#State var isSettings: Bool = false
#State var isSaved: Bool = false
var body: some View {
NavigationView {
ZStack {
Color(#colorLiteral(red: 0.9333333333, green: 0.9450980392, blue: 0.9882352941, alpha: 1)).edgesIgnoringSafeArea(.all)
VStack {
TopBar()
HStack {
CustomTextField(data: $data, tFtext: "Find task", tFImage: "magnifyingglass")
Button(action: {
self.isSettings.toggle()
}, label: {
ZStack {
RoundedRectangle(cornerRadius: 15)
.frame(width: 50, height: 50, alignment: .center)
.foregroundColor(Color(#colorLiteral(red: 0.4274509804, green: 0.2196078431, blue: 1, alpha: 1)))
Image("buttonImage")
.resizable()
.frame(width: 30, height: 30, alignment: .center)
}
.padding(.horizontal, 15)
})
}
CustomSegmentedView()
ZStack {
TaskFrameView()
Button( action: {
self.isSaved.toggle()
}, label: {
ZStack {
RoundedRectangle(cornerRadius: 20)
.foregroundColor(Color(#colorLiteral(red: 1, green: 0.7137254902, blue: 0.2196078431, alpha: 1)))
Text("+")
.foregroundColor(.white)
.font(.title)
.fontWeight(.bold)
}
.frame(width: 40, height: 40)
.offset(x: 150, y: 220)
})
NavigationLink(
destination: NewTaskView(),
isActive: $isSaved,
label: {
Text("")
})
}
}
}
Spacer()
}
.navigationBarHidden(true)
}
}
struct TopBar: View {
var body: some View {
HStack {
Image("avatar")
.resizable()
.frame(width: 100, height: 100)
VStack(alignment: .leading){
DateView()
.font(Font.custom("SFCompactDisplay", size: 20))
.foregroundColor(.gray)
.padding(.vertical, 5)
Text("Hi, Random")
.font(Font.custom("SFCompactDisplay", size: 20))
}
Image(systemName: "ellipsis")
}
}
}
It is navigation view bar. The navigationBarHidden modifier should be inside NavigationView, like
}
.navigationBarHidden(true) // << here !!
Spacer()
} // end of NavigationView

The keyboard of a TextField doesn't show when I tap it in SwiftUI

The keyboard of a TextField doesn't show when I tap it on a physical device and I don't know why, here is my code:
VStack {
HStack {
Image(colorScheme == .light ? "user" : "userDark")
.resizable()
.frame(width: 30, height: 30)
Text(localName)
.font(.system(size: 20))
Spacer()
}.padding(.horizontal)
ZStack {
HStack {
TextField("Change name", text: $name)
.textFieldStyle(PlainTextFieldStyle())
.padding(.leading, 5)
.font(.system(size: 20))
.autocapitalization(.none)
.disableAutocorrection(true)
.zIndex(1)
if self.name != "" {
Spacer()
Button(action: {
// update name
})
{
Text("Update")
.padding()
}.padding()
}
}.padding(.horizontal)
}
}
Thank you in advance!

SwiftUI - Unable to reference #Published value outside Struct

I am new to SwiftUI and am hoping for some assistance with a project I am developing.
I am unable to reference #published value outside a struct.
All values are correctly functioning within the struct using:
#ObservableObject
#Publihsed
#ObservedObject
I have a Struct within ContentView which is linked to another View where I would like to display Quantity and Costs.
I have attempted various ways to access the values as can be seen in the struct NewOrders, but I keep getting zero and not getting the updated value.
Am I missing a step or executing code incorrectly?
Thanks in advance
class MealOrders: ObservableObject {
//Jollof Rice - Published
#Published var jollof = 0
//Swallow - Published
#Published var swallow = 0
//Pepper Soup - Published
#Published var pepperSoup = 0
}
struct ContentView: View {
var body: some View {
VStack {
NavigationView {
Section {
VStack(alignment: .leading) {
NavigationLink(destination: MenuOption()) {
Text("Meal Options")
}
Spacer()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight:
.infinity, alignment: .topLeading)
}.padding() //Vstack End
}
Section {
VStack {
Image("africanfoods")
.resizable()
.frame(width: 275.0, height: 250.0)
.clipShape(Circle())
.overlay(Circle().stroke(Color.black, lineWidth: 5))
.scaledToFit()
}
} //Section End
Section { //Social Media
VStack {
Spacer()
HStack {
Spacer()
Image("facebook")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding()
Image("instergram")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding()
Image("youtube")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding()
Image("twitter")
.resizable()
.frame(width:40, height: 40)
.scaledToFit()
.padding(.horizontal, 50)
}
} //Vstack End
} //Social Media
.navigationBarTitle(Text("African Foods Center"))
} //NavView End
} //VStack End
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct MenuOption: View {
//Object Observed Declarations
#ObservedObject var meals = MealOrders()
//Meal Prices
#State private var jolloRiceUnitCost = 14.95 //Jollof Rice Unit Cost
#State private var swallowUnitCost = 12.50 //Swallow Unit Cost
#State private var pepperSoupUnitCost = 13.50 //Pepper Soup Unit Cost
#State private var deliveryCost = 5.99 //Delivery Cost
#State private var menuItem = 0
var menuItems = ["Rice Meals", "Swallow Meals", "Pepper Soups"]
//Meals Calculator
var calculateMeal: Double {
var orderCost = 0.0
//Jollof Rice
if menuItems[menuItem] == "Rice Meals" {
orderCost = self.jolloRiceUnitCost * Double(self.meals.jollof)
return orderCost
//Swallow - Pounded Yam / Eba
} else if menuItems[menuItem] == "Swallow Meals" {
orderCost = self.swallowUnitCost * Double(self.meals.swallow)
} else if menuItems[menuItem] == "Pepper Soups" {
orderCost = self.pepperSoupUnitCost * Double(self.meals.pepperSoup)
}
return orderCost
}
var body: some View {
VStack(alignment: .leading) {
Section(header: Text("Select Meal").padding(.horizontal, 25)) {
Picker("Select Item", selection: $menuItem) {
ForEach(0 ..< menuItems.count) {
Text(self.menuItems[$0])
}
}.pickerStyle(SegmentedPickerStyle())
.padding(.horizontal, 25)
if menuItems[menuItem] == "Rice Meals" {
Text("Rice Meals:")
.foregroundColor(.black)
.padding(.horizontal, 25)
Spacer().frame(height:20)
`Text("Rice meals consist of Jollof Rice, Rice and Stew, Fried
Rice. You can option in meat, fish and or plantain with any of the meals")`
.foregroundColor(.blue)
.lineLimit(nil)
.padding(.horizontal, 25)
Spacer().frame(height:60)
//Insert image - Jollof Rice
Image("jollofRice")
.resizable()
.frame(width:250, height: 250)
.scaledToFit()
.border(Color.black, width: 4)
.padding(.horizontal, 100)
Spacer().frame(height:20)
HStack {
Stepper("Quantity (Max 5)",value: $meals.jollof, in: 0...5)
.padding(.horizontal, 45)
Text("\(meals.jollof): £\(calculateMeal, specifier: "%.2f")")
.padding()
}.padding()
Section { //Button Order
VStack {//Add Stepper for Quantity
Spacer()
HStack(alignment: .center, spacing: 140) {
Spacer()
Button(action: {}) {
NavigationLink(destination: Text("Jollof:: \(meals.jollof), £\(calculateMeal, specifier: "%.2f")")) {
Text("Create Order")
.font(.system(size: 14))
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
}.padding()
Spacer()
}
}
} //Vstack End
} //Button Section End
} else if menuItems[menuItem] == "Swallow Meals" {
Text("Swallow")
.foregroundColor(.green)
.padding(.horizontal, 25)
Spacer().frame(height:20)
`Text("Swallow is the colloqual word for Pounded Yam, Eba, Fufu or Amala. This is complemented with soups, such as Egusi, Okra etc. You could have this meal with either meat or fish")`
.foregroundColor(.blue)
.lineLimit(nil)
.padding(.horizontal, 25)
Spacer().frame(height:60)
//Inset Image
Image("poundedYamEgusi")
.resizable()
.frame(width:250, height:250)
.scaledToFit()
.border(Color.black, width: 4)
.padding(.horizontal, 100)
HStack {//Add Stepper for Quantity
Stepper("Quantity (Max 5)",value: $meals.swallow, in: 0...5)
.padding(.horizontal, 45)
Text("\(meals.swallow): £\(calculateMeal, specifier: "%.2f")")
.padding()
}.padding()
//Insert Order Button
Section {
VStack {
Spacer()
HStack(alignment: .center, spacing: 140) {
Spacer()
Button(action: {}) {
NavigationLink(destination: Text("Swallow: \(meals.swallow), £\(calculateMeal, specifier: "%.2f")")) {
Text("Create Order")
.font(.system(size: 14))
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
}.padding()
Spacer()
}
}
} //VStack End
} //Section End
} else if menuItems[menuItem] == "Pepper Soups" {
Text("Pepper Soup")
.foregroundColor(.red)
.padding(.horizontal, 25)
Spacer().frame(height:20)
`Text("Pepper soup is normally taken after one has had either Pounded Yam or rice meals. Depending on the audeience, the soup can be lightly spicy to very hot. Pepper soup can be had with either fish or meat")`
.foregroundColor(.blue)
.lineLimit(nil)
.padding(.horizontal, 25)
Spacer().frame(height:60)
//Insert Image
Image("pepperSoupYam")
.resizable()
.frame(width:250, height:250)
.scaledToFit()
.border(Color.black, width: 4)
.padding(.horizontal, 100)
HStack {//Add Stepper Quantity for Pepper Soup
Stepper("Quantity (5 Max)",value: $meals.pepperSoup, in: 0...5)
.padding(.horizontal, 45)
Text("\(meals.pepperSoup): £\(calculateMeal, specifier: "%.2f")")
.padding()
}.padding()
//Inset Order Button
Section {
VStack {
Spacer()
HStack(alignment: .center, spacing: 140) {
Spacer()
Button(action: {}) {
NavigationLink(destination: NewOrders()) {
Text("Create Order")
.font(.system(size: 14))
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(6)
}.padding()
Spacer()
}
}
}
}
}
Spacer()
}.font(.system(size: 14))
.foregroundColor(.purple)
} //Vstack Ending
} //View Ending
}
//This sis going to be the Orders Struct
struct NewOrders: View {
#ObservedObject var orderUpdatedV2 = MealOrders()
#State private var orderUpdate = MenuOption().meals.jollof
var body: some View {
//let mealsU: ContentView
NavigationView{
VStack {
List {
Text("")
}
}
}.navigationBarTitle("Meal Order")
}
}
This line below is incorrect because creates new value, that's why you have nil
#State private var orderUpdate = MenuOption().meals.jollof
instead you need to have (as far as I understood your code)
#Binding var orderUpdate: Int
and pass it in place of creating
NavigationLink(destination: NewOrders(orderUpdate: $meals.jollof)) {
Note: This is the idea, I'm not sure copy/paste will work, because provided your code snapshot is not compilable at my side.

Resources