1
votes

I have created a SwiftUI view with a ZStack containing a Text and a Rectangle. Note the different values in the position of each, yet they end up in approximately the same location in portrait orientation. In landscape orientation, the Text stays in the same position relative to the top left corner of the screen, yet the rectangle moves. When I make the position values the same, the Rectangle appears to be consistently above and to the left of the Text, yet by different amounts in landscape vs. portrait orientations. I observe this same behaviour both in the Simulator running iOS 14.4 (iPhone and iPad both), and also on a physical iPad running iOS 14.3.

My view:

import SwiftUI

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .leading) {
            Text("abc").position(x: 150, y: 150)
            Rectangle().size(width: 50, height: 50).stroke().position(x: 320, y: 450)
        }
    }
}

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

And the result:

Portrait orientation

Landscape orientation

Why is the position treated differently for Text and Rectangle elements in a View? And how can I position both in the same location?

2

2 Answers

1
votes

The behavior you are seeing due to the following reasons:

  1. The .size modifier of a Shape does not change the size of the Shape's frame; instead it returns a Shape of the same frame size, but with only its contents (Path) drawn using the size provided. You can see this in action if you add a background to your Rectangle like so and noting too that the smaller contents are drawn at the top left corner of the frame:

    Rectangle()
          .size(width: 50, height: 50)
          .stroke()
          .background(Color.blue.opacity(0.7))
          .position(x: 350, y: 450)
  2. The .position modifier places the center of the view at the specified coordinates of the parent view.

So, if you take the above two together you are placing the center of the original much larger Rectangle() - not 50x50 - at the coordinates provided, which causes the behavior your are seeing.

To fix this you could use the .frame modifier instead of .size as was mentioned in another answer.

0
votes

Use frame and same position.

struct ContentView: View {
    let position = CGPoint(x: 150, y: 150)
    var body: some View {
        ZStack(alignment: .top) {
            Text("abc").position(x: position.x, y: position.y)
            Rectangle().stroke()
                .frame(width: 50, height: 50)
                .position(x: position.x + 10, y: position.y + 5)
        }
    }
}