Reputation: 17
struct SlideView: View {
@State var isClicked = false
var body: some View {
HStack{
Rectangle()
.fill(.gray)
.ignoresSafeArea()
.frame(width: isClicked ? UIScreen.main.bounds.width * 0.75 : 0)
VStack{
Text("This gets squished")
HStack{
Button{
withAnimation(.spring()) {
isClicked.toggle()
}
} label: {
Image(systemName: "menucard.fill")
.padding(.leading)
}
Spacer()
}
Spacer()
}
}
}
}
So I have this view that kind of "slides in" and it's pretty close to what I want but not exactly, the view that slides in ends up squishing the other view and compressing it to be about 25% of it's size. Of course this makes sense because it's all in a HStack and I end up taking 75% of the HStack's space but I was wondering if anybody had an idea of how I could do something like this but without squishing the second view that gets pushed away? So basically keep it the same size and just have the first 1/4 of the view visible and the other 3/4 just be gone I guess.
Upvotes: 1
Views: 891
Reputation: 6637
Personally, I think it would make more sense to just use .offset
, and put them in a ZStack
:
ZStack {
VStack {
HStack {
Spacer()
Text("yellow")
Spacer()
}
Spacer()
}
.background(.yellow)
VStack {
Text("red")
HStack {
Button{
withAnimation(.spring()) {
isClicked.toggle()
}
} label: {
Image(systemName: "menucard.fill")
.padding(.leading)
}
Spacer()
}
Spacer()
}
.background(.red)
.offset(.init(width: isClicked ? UIScreen.main.bounds.width * 0.75 : 0, height: 0))
}
And you can add another .offset
modifier to the yellow one to make it looks slidein:
VStack {
//...
}
.background(.yellow)
.offset(.init(width: isClicked ? 0 : -UIScreen.main.bounds.width * 0.75, height: 0))
Upvotes: 0
Reputation: 9675
The problem is the view that gets squished has no explicit width. Understand how views get sized in SwiftUI. The parent view proposes a size, and the child view responds with the size it wants. Before you click the button, the parent view (the HStack
) is proposing 100% to the view. That view says that I can do 100%, so no squishing. However, when you make the other view 75% of the parent, the parent can only offer 25% to the first view. The view responds, I can fit if I squish, so it does. See Laying out a simple view.
To fix it, you simply need to explicitly set the width of the first view to 100%, and then it will get pushed over like you were expecting without compression.
struct SlideInView: View {
@State var isClicked = false
var body: some View {
// I swapped out UIScreen.main.bounds for a GeometryReader
// UIScreen.main.bounds.width always returns the width of the screen
// even if the parent view does not have that much space to offer, and
// can lead to some interesting results.
GeometryReader { geometry in
HStack{
Rectangle()
.fill(.gray)
.ignoresSafeArea()
.frame(width: isClicked ? geometry.size.width * 0.75 : 0)
VStack{
Text("This gets squished")
HStack{
Button{
withAnimation(.spring()) {
isClicked.toggle()
}
} label: {
Image(systemName: "menucard.fill")
.padding(.leading)
}
Spacer()
}
Spacer()
}
.frame(width: geometry.size.width) // Explicitly set width here
}
}
}
}
Upvotes: 2