Need help getting two HStack views to be the same size based on one of them

Hi there!

I am trying to get two HStack views with the same ZStack parent to be the same size where one of the HStack views dictates the size. This works, initially, but there's a bug that I just can't seem to find a solution for.

I posted this somewhere else with images to show what is happening, unfortunately I can't do that here so I'm hoping the code and explanation will be sufficient to get a clear picture of what's going on.

I have a CardView that looks like this:

Code Block
@State private var cardDimension = CGSize.zero
var body: some View {
ZStack {
/* This HStack is for the swipe action markers */
HStack {...}
.frame(width: cardDimension.width, height: cardDimension.height)
/* This HStack has the content and dictates the size */
HStack {...}
.background(
GeometryReader { geo in
Text("")
.onAppear(perform: {
self.cardDimension = geo.size
})
}
)
}
}


The CardView is being rendered inside a LazyVStack within a Scrollview like so:

Code Block
NavigationView {
ZStack {
Color("backgroundPrimary")
.ignoresSafeArea(.all)
ScrollView {
ForEach(items) { item in
CardView(item: item)
}
}
}
}


This works and has the desired result.

However, this is where things get interesting. On the bottom side of the screen, I want to add a button. This is easy enough, we're in a ZStack so all it needs is some alignment and we're good to go. So the code looks like this:

Code Block
NavigationView {
ZStack {
Color("backgroundPrimary")
.ignoresSafeArea(.all)
ScrollView {
ForEach(items) { item in
CardView(item: item)
}
}
/* This View has the button */
VStack {...}
}
}

What happens now is that the first CardView inside the ScrollView no longer measures its size correctly and has a lot of height and a little width. The weird thing about this is that all the cards work perfectly fine except for the very first one.

Removing the card will ensure the view that is now the first view has the desired result, however reloading the application has the bug again.

It all works until I add the button on the bottom of the screen, that's when it all goes south.

I've tried using PreferenceKeys instead, no luck there. I'm a bit lost now and I can't seem to figure this out. Any help would be much appreciated!

Accepted Reply

After weeks of trial and error I ended up finding a solution myself! The onAppear() runs, obviously, as soon as the view appears. This is, however, too fast. Adding a 0.01s delay using DispatchQueue like so:

Code Block
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {...}


There's probably better solutions out there, but this definitely works!

Replies

After weeks of trial and error I ended up finding a solution myself! The onAppear() runs, obviously, as soon as the view appears. This is, however, too fast. Adding a 0.01s delay using DispatchQueue like so:

Code Block
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {...}


There's probably better solutions out there, but this definitely works!