Reputation: 2028
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?
Upvotes: 41
Views: 18932
Reputation: 248
I've recently had a similar issue with the contents of a GeometryReader
not being aligned to the center.
It seems that the default behaviour has been changed somewhat recently from center to upper-left corner alignment.
The answers provided here did not work for me, so here's one which should be universal:
var body: some View {
GeometryReader { geo in
ZStack {
/* the views which you want to have aligned
not to the upper left corner go in this method */
contentView(geo)
}
.frame(
width: geo.size.width,
height: geo.size.height,
alignment: .center
)
}
}
func contentView(_ proxy: GeometryProxy) -> some View {
VStack {
// views
}
.frame(
width: proxy.size.width * 0.5, // you can, for example, use the GeometryProxy size directly here
height: proxy.size.height * 0.5,
alignment: .center
)
}
I've used the snippet provided above to create a popup which is half the container view's size and is aligned to the center.
Use it as a starting point in creating any layout you wish inside a GeometryReader
in a clean and manageable way.
Upvotes: 1
Reputation: 258345
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)
}
}
Upvotes: 33
Reputation: 2533
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)
}
}
Upvotes: 53
Reputation: 263
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.
Upvotes: 14
Reputation: 17572
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.
Upvotes: 28