32

I have a custom view:

struct ImageContent: View {
    var body: some View {
        Image("smile")
            .resizable()
            .scaledToFit()
    }
}

Which is being placed into another view with a GeometryReader:

var body: some View {
    GeometryReader { geometry in
        ImageContent()
        //Image("smile").resizable().scaledToFit()
    }
}

The problem is, the ImageContent view is not centered on the screen, it is being placed on the top, however, by removing the ImageContent subview and directly adding the view's content into the geometry reader will fix the issue (see picture).

Also, removing the GeometryReader can fix the issue as well.

I need the subview because I will be implementing some additional logic, and also need the GeometryReader because there is a gesture added to the Image that uses it.

Any idea?

Screenshot

Tom Shen
  • 1,838
  • 3
  • 19
  • 40
  • @Asperi okay, I'm not too familiar with GeometryReader. Let me edit that out... The question still stands though, if there are any fix/workaround. – Tom Shen Feb 24 '20 at 10:30

4 Answers4

39

I'm not sure why this is happening but you can use what others have suggested, or use the midX and midY from GeometryProxy's frame. Like the following:

var body: some View {
    GeometryReader { geometry in
        ImageContent()
        .position(x: geometry.frame(in: .local).midX, y: geometry.frame(in: .local).midY)
    }
}
Ennabah
  • 2,303
  • 2
  • 20
  • 39
24

You can use the GeometryProxy value passed inside your GeometryReader body.

struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            ImageContent()
                .position(x: geometry.size.width / 2, y: geometry.size.height / 2)
        }
    }
}

This will define the exact position based on value provided.

richrad
  • 864
  • 1
  • 10
  • 19
user3441734
  • 16,722
  • 2
  • 40
  • 59
21

Update: retested with Xcode 13.3 / iOS 15.4

Try the following (built-in container by default expanded to size of GeometryReader and have explicit default alignment set to center by both dimensions). Tested with Xcode 11.2.

var body: some View {
    GeometryReader { geometry in
       VStack { // explicit container with center default alignment
        ImageContent()
       }
       .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
14

I just ran into the same problem and I don't like the solution of setting the position manually because it complicates the process of automatically generating layout. For me the problem persists even after wrapping my content in a VStack. However, if you wrap the content in a VStack AND also manually set its frame - everything works as expected:

var body: some View {
    GeometryReader { geometry in
       VStack {
        ImageContent()
       }
       .frame(width: geometry.size.width, height: geometry.size.height)
    }
}

I think this issue pops up because GeometryReader's internal layout acts like a ZStack and it needs more information.

shim
  • 9,289
  • 12
  • 69
  • 108
danylo.net
  • 253
  • 3
  • 7