iOS 14 Invalid frame dimension (negative or non-finite)

Viewed 17288

My App uses GeometryReader with some padding to setup a View frame dimension inside a NavigationView.

Since iOS 14 i get the following error message:

Invalid frame dimension (negative or non-finite)

Here is some example code to test:

import SwiftUI

struct ContentView: View {

    let padding:CGFloat = 16.0

    var body: some View {
        NavigationView {
            GeometryReader { p in
        Text("Hello, world!")
            .frame(width: p.size.width - padding)
            .padding()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Removing NavigationView fix the problem, but I need the current width and height of the container View inside the NavigationView.

Any suggestion?

8 Answers

I think it might be a static analysis issue as .frame(width: p.size.width - padding) could result in a negative value. Try:

.frame(width: abs(p.size.width - padding))

You can not use negative value for frame parameters. If you use .infinity or negative value for frame, change this with nil:

Wrong:

.frame(width: visible ? .infinity : 0,
                           height: visible ? .infinity : 0,
                           alignment: .bottomTrailing)

Correct:

.frame(width: visible ? nil : 0,
                           height: visible ? nil : 0,
                           alignment: .bottomTrailing)

When I tested with macOS 11.1, I found that GeometryReader could not return the actual size immediately at the beginning of the view init, the size obtained for the first time was incorrect, maybe need to do a dispatch async operation to avoid this warning

Warning: Invalid frame dimension (negative or non-finite)

I ran into the same issue. I didn't get to the bottom of why being in a NavigationView causes this, but a workaround is to wrap the whole NavigationView in a GeometryReader and pass the GeometryProxy down the tree.

this helped me:

i added a Group { } around my first Element (which was a VStack with a .frame) in the body. The group has no ".frame" etc. worked on my MacOS app to get rid of this stupid issue.

or you can add something like

.frame(minWidth: 300, idealWidth: 400, maxWidth: 600, minHeight: 300, idealHeight: 400, maxHeight: 500, alignment: .top)

to your VStack (or whatever) to clearly say what dimensions you want.

edit strange this error will appear again, but not immediatly...

As Patric Fu states it is normally an initialization issue that generates the warning message "Invalid frame dimension (negative or non-finite)."

In my case this warning was generated on the following statement

.frame(width: frameSide, height: frameSide)

When frameSide was generated with the following statement

let frameSide = min(innerRectangle.width, innerRectangle.height)

Changing the above statement to provide a default value as below

let frameSide = innerRectangle.width.isNaN ? 0 : min(innerRectangle.width, innerRectangle.height)

Resolved the issue and the warning is not generated.

The condition within the Ternary operator would, of course, vary depending on the construction of the variable "frameSide". I found this a simpler approach than using a "dispatch async operation". This answer would be more likely to help if it was attached as a comment to Patric Fu's original answer. However I have insufficient reputation to comment.

try this, it works for me ~

.frame(width:abs(GeometryReader_width)))
struct YouContentView: View {

   let padding:CGFloat = 26.0
   @State private var width:CGFloat = 0

    var body: some View {
        NavigationView {
         
        Text("Hello, world!")
                .background(
                    
                    GeometryReader(content: { geo in
                        Text("YouText Here")
                            .background(.red)
                            .frame(width: geo.frame(in: .global).width - padding)
                }))
            
          
        }
    }
}
Related