Invalid frame dimension (negative or non-finite) - swiftui

I'm new to this platform but swift is giving me a headache it is seeming to have a problem with the value (Infinity) although what should I put instead?
.bold()
.frame(width: .infinity, height: 20, alignment: .topLeading)
Text(course.type)
.font(.system(size: 15, weight: .light))
.frame(width: .infinity, height: 10, alignment: .topLeading )
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
Button {
openURL(URL(string: course.link)!)
}
label: {
Text("GET").bold()
.frame(width: 35, height: 1)
.padding()
.foregroundColor(Color(.white))
.background(Color(.orange))
.cornerRadius(25)
}
}.frame(width: .infinity, height: .infinity)
.padding()

An infinite width or height doesn't make sense. If instead you want the view to expand as much as possible, use the maxWidth and maxHeight variants instead:
.frame(maxWidth: .infinity, maxHeight: .infinity)

Try only setting a frame when you have to, and use .none instead of .infinity.

Related

Button has two different colors, even if only specified one

I want to fit a button to the whole screen of my apple watch. But there is a lighter red and a dark red like in this picture.
This is my code: I want the whole screen to have only one color if this is possible. Thanks
Button(action: {
Task {
if (!muteWatch) {
WKInterfaceDevice.current().play(.failure)
}
Task {
await isWorkingSince()
}
}
}, label: {
Text("Stop ".localized() + stopTimeString).padding().frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity,
alignment: .topLeading
).background(Color.red)
}).padding().frame(
minWidth: 0,
maxWidth: .infinity,
minHeight: 0,
maxHeight: .infinity,
alignment: .topLeading
).background(Color.red)
You need plain button style, like
Button(action: {}) {
Text("Hello, World!")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.red)
}
.buttonStyle(.plain) // << here !!
Tested with Xcode 13.4 / watchOS 8.5
Button(action: {self. buttonTapped()}) {
Text("Button")
padding(. all, 12)
foregroundColor(. white)
background(Color. red)
}

How do you center Text in ScrollView at SwiftUI

How do you center text here ?
Texts are at the left side of scrollViews.
What is .center for ?
var scrolls = ["One", "Two", "Three"]
VStack {
Spacer()
ForEach(0..<scrolls.count
, id: \.self) { index in
ScrollView(.horizontal, showsIndicators: true) {
Text(" \(scrolls[index])")
.frame(maxWidth: .infinity,
maxHeight: .infinity,
alignment: .center)
.background(Color.gray)
}
.frame(maxWidth: .infinity,
maxHeight:50,
alignment:
.center)
.background(Color.green)
}.frame(alignment: .bottom)
}
}
You can use GeometryReader and frame(minWidth: for that, like below.
Tested with Xcode 13.2 / iOS 15.2
var body: some View {
GeometryReader { gr in
VStack {
Spacer()
ForEach(0..<scrolls.count
, id: \.self) { index in
ScrollView(.horizontal, showsIndicators: true) {
Text(" \(scrolls[index])")
.frame(minWidth: gr.size.width, // << here !!
maxHeight: .infinity,
alignment: .center)
.background(Color.gray)
}
.frame(maxWidth: .infinity,
maxHeight:50,
alignment:
.center)
.background(Color.green)
}.frame(alignment: .bottom)
}
}
}

pin view to bottom of screen and ignore bottom safe area

Layout question - how do I setup for a view block to expand over the bottom safe area? I've looked through various sources for ignoresSafeAreas() but can't achieve quite the result I'm looking for.
I want, later, to be able to expand this view upwards but start it short. If that makes sense.
var body: some View {
VStack{
Spacer()
HStack(alignment: .center) {
Text ("Expand to fill bottom safe area ...?")
.foregroundColor(.white)
}
.frame(minWidth: 100, maxWidth: .infinity, minHeight: 50, maxHeight: 100)
.background(Color.red)
.ignoresSafeArea()
}
}
Option 1
Put ignoresSafeArea inside background. This will let the red color extend over to the device edges, but the HStack's position will stay the same.
struct ContentView: View {
var body: some View {
VStack{
Spacer()
HStack(alignment: .center) {
Text ("Expand to fill bottom safe area ...?")
.foregroundColor(.white)
}
.frame(minWidth: 100, maxWidth: .infinity, minHeight: 50, maxHeight: 100)
.background(Color.red.ignoresSafeArea()) /// inside `background`
}
}
}
Option 2
Put ignoresSafeArea on the VStack, and everything will ignore the safe area.
struct ContentView: View {
var body: some View {
VStack{
Spacer()
HStack(alignment: .center) {
Text ("Expand to fill bottom safe area ...?")
.foregroundColor(.white)
}
.frame(minWidth: 100, maxWidth: .infinity, minHeight: 50, maxHeight: 100)
.background(Color.red)
}
.ignoresSafeArea() /// attached to `VStack`
}
}
Result:
Option 1
Option 2

Custom table view SwiftUI iOS

I need to create a table so that the text in the cell expands to the desired size.
I create Content View:
struct ContentView: View {
let items: [String] = [
"1 One Line",
"1 One Line",
"1 One Line"
]
var body: some View {
ScrollView {
VStack(spacing: 1) {
ForEach(self.items, id: \.hash) { (item) in
HStack(spacing: 1) {
Text(item)
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.white)
Text("One Line")
.frame(width: 70)
.background(Color.white)
Text("One Line")
.frame(width: 70)
.background(Color.white)
}
}
// MARK: Total
HStack(spacing: 1) {
Text("Title")
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.white)
Text("One Line")
.frame(width: 141)
.background(Color.white)
}
}
.padding(1)
.background(Color.orange)
}
.padding(15)
}
}
and it works well:
But if the text becomes multi-line, then the table breaks:
let items: [String] = [
"1 One Line",
"2 Two Line\nTwo Line",
"3 Three lines\nThree lines\nThree lines"
]
borders are getting wider:
if you make maxHeight = infinity then this solves the problem with borders, but the lines become equal to the maximum height.
The possible solution is to use maxHeight: .infinity with .fixedSize
var body: some View {
ScrollView {
VStack(spacing: 1) {
ForEach(self.items, id: \.hash) { (item) in
HStack(spacing: 1) {
Text(item)
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.white)
Text("One Line")
.frame(maxHeight: .infinity, alignment: .center)
.background(Color.white)
Text("One Line")
.frame(maxHeight: .infinity, alignment: .center)
.background(Color.white)
}
.fixedSize(horizontal: false, vertical: true) //<---Here
}
// MARK: Total
HStack(spacing: 1) {
Text("Title")
.frame(maxWidth: .infinity, alignment: .center)
.background(Color.white)
Text("One Line")
.frame(width: 137)
.background(Color.white)
}
}
.padding(1)
.background(Color.orange)
}
.padding(15)
}

SwiftUI WidgetKit text and image alignment

I'm attempting to make a widget extension with two text labels and an image. The two labels need to be in the top left and the image in the bottom right. I've been unable to get this working correctly.
Is there a proper way of doing this without having to use a Spacer() or an overlay image which isn't what I need. Very new to SwiftUI. Any help or pointers would be greatly appreciated.
VStack (alignment: .leading){
Text("Title")
.font(.headline)
.fontWeight(.regular)
.lineLimit(1)
Text("subtitle")
.font(.title3)
.fontWeight(.bold)
.lineLimit(1)
.allowsTightening(true)
HStack {
Spacer(minLength: 15)
Image("fish")
.resizable()
.frame(width: 120, height: 80)
}
}
.padding(.top)
.padding(.leading)
There are a bunch of ways to build a layout like that. What you have is almost working, you just need a Spacer between the text and image to shove the image down:
VStack (alignment: .leading) {
Text("Title")
.font(.headline)
.fontWeight(.regular)
.lineLimit(1)
Text("subtitle")
.font(.title3)
.fontWeight(.bold)
.lineLimit(1)
.allowsTightening(true)
Spacer(minLength: 0) // <-- add spacer here
HStack {
Spacer(minLength: 15)
Image("fish")
.resizable()
.frame(width: 120, height: 80)
}
}
.padding(.top)
.padding(.leading)
The only other change I would suggest is avoiding the hard-coded image size, since widgets are different sizes on different phones. You could have the image expand to fit the available width while preserving your image’s 3:2 aspect ratio like this:
VStack(alignment: .leading) {
Text("Title")
.font(.headline)
.fontWeight(.regular)
Text("subtitle")
.font(.title3)
.fontWeight(.bold)
.allowsTightening(true)
Spacer(minLength: 0)
Image("fish")
.resizable()
.aspectRatio(3/2, contentMode: .fit)
}
.lineLimit(1)
.padding(.leading)
.padding(.top)
Or if you want the fixed-size image and would prefer to have the text overlap it on smaller screens, you could use a ZStack like this:
ZStack(alignment: .bottomTrailing) {
Image("fish")
.resizable()
.frame(width: 120, height: 80)
VStack (alignment: .leading) {
Text("Title")
.font(.headline)
.fontWeight(.regular)
Text("subtitle")
.font(.title3)
.fontWeight(.bold)
.allowsTightening(true)
}
.lineLimit(1)
.padding()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
As I said, there are a bunch of ways to solve this!
I think I've managed to get this working, well as close as I could get it. Seems to be a bit better than before. Mildly satisfied but working now.
ZStack {
VStack (alignment: .leading){
Text("Title")
.font(.body)
.fontWeight(.bold)
.lineLimit(1)
.allowsTightening(true)
Text("subtitle")
.font(.title)
.fontWeight(.regular)
HStack(alignment: .bottom){
Spacer()
Image("fish")
.resizable()
.frame(width: 120, height: 80)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing)
.offset(x: 5, y: -10)
// padding for images with frame bigger than actual image
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .leading)
}
.padding(12)
}
.background(Color(UIColor.secondarySystemBackground))