What exactly does the fixedSize() modifier do?

Here's some code:

import SwiftUI

struct RRectPlay: View {
    var body: some View {
        Canvas { gc, size in
            gc.translateBy(x: 20.0, y: 20.0)
            gc.stroke(
                Path(roundedRect: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0), cornerSize: CGSize(width: 2.0, height: 2.0)),
                with: .color(.black),
                lineWidth: 20.0
                )
        }
    }
}

struct RRectPlay_Previews: PreviewProvider {
    static var previews: some View {
        RRectPlay()
    }
}

It shows a rounded rect, as requested:

If I add the fixedSize modifier to the preview:

RRectPlay().fixedSize()

The rectangle disappears:

If I add a border to see what's happened, I get this:

It seems like the definiation of "Ideal Size" ought to be something closer to the bounding box of the figure if there are no other items on the screen.

Can anyone elucidate me?

Replies

I added a debug print statement to your code as follows:

Canvas { gc, size in
    gc.translateBy(x: 20.0, y: 20.0)
    gc.stroke(
        Path(roundedRect: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0), cornerSize: CGSize(width: 2.0, height: 2.0)),
            with: .color(.black),
            lineWidth: 20.0
        )
    print("Width: \(size.width) Height: \(size.height)")
}

...and changed ContentView to this:

VStack {
    RRectPlay()
    RRectPlay()
        .fixedSize()
}

…and got the following output in the console:

Width: 361.0 Height: 709.0
Width: 10.0 Height: 10.0

So I think it's obvious what's happening here: SwiftUI thinks that the "ideal size" of your custom view is 10x10, which is so small that basically everything gets clipped out.

Some ways that you could solve this problem:

  • Specify minimum, maximum, and ideal dimensions of your custom view using frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:) to modify your Canvas object.
  • Draw your Path using arguments calculated relative to size instead of using arbitrary values. This would allow the user of your view to specify their own frame size and have your drawing scale automatically.
  • If you need a rounded rectangle, consider using SwiftUI's RoundedRectangle which handles all of these concerns for you.