I have two views, one view has an HStack
that displays a list of views, each containing an image and text. When one view is clicked, a detail view is displayed which will contain the image and text of the selected view.
The problem is the matchedgeometryeffect
seems to fade in when transitioning between views. I tried different solution here on stackoverflow such as using .zIndex()
and .transition(.scale(scale: 1))
but nothing worked for me.
Here is the behavior I get in simulator: video
Here is the code:
struct Test: View {
var body: some View {
VStack {
if let selectedCard = selectedCard {
VStack {
cardView(card: selectedCard)
.onTapGesture {
withAnimation() {
self.selectedCard = nil
}
}
}
} else {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(topCardsAsTemplates) { topCardAsTemplate in
TopTemplatesCardView(card: topCardAsTemplate)
.padding()
.onTapGesture {
withAnimation() {
selectedCard = topCardAsTemplate
}
}
}
}
}
}
}
}
@ViewBuilder
func TopTemplatesCardView(card: Card) -> some View {
if card.uuid != selectedCard?.uuid {
VStack {
Image(systemName: "person.circle")
.resizable()
.matchedGeometryEffect(id: card.uuid.uuidString + "image", in: namespace)
.scaledToFit()
.frame(width: 80)
Text(card.backgroundType.rawValue)
.matchedGeometryEffect(id: card.uuid.uuidString + "text", in: namespace, properties: .position)
.foregroundColor(.black)
// .matchedGeometryEffect(id: card.uuid.uuidString + "text", in: namespace)
}
.padding()
.background(
RoundedRectangle(cornerRadius: 20, style: .continuous)
.matchedGeometryEffect(id: card.uuid.uuidString + "back", in: namespace)
.frame(width: cardSize + 50, height: cardSize + 50)
.background(.clear)
.foregroundColor(.gray)
)
} else {
Color.clear.frame(width: cardSize, height: cardSize)
}
}
@ViewBuilder
func cardView(card: Card) -> some View {
VStack {
Image(systemName: "person.circle")
.resizable()
.matchedGeometryEffect(id: card.uuid.uuidString + "image", in: namespace)
.scaledToFit()
.frame(width: 120)
Text(card.backgroundType.rawValue)
// .matchedGeometryEffect(id: card.uuid.uuidString + "text", in: namespace)
.matchedGeometryEffect(id: card.uuid.uuidString + "text", in: namespace, properties: .position)
.foregroundColor(.black)
}
.padding()
.background(
RoundedRectangle(cornerRadius: 20, style: .continuous)
.matchedGeometryEffect(id: card.uuid.uuidString + "back", in: namespace)
.frame(width: cardSize + 200 , height: cardSize + 200)
.background(.clear)
.foregroundColor(.gray)
)
}
}
How can I make the transition smoother so that the fading-in and out are not shown? Any suggestions please?
Edit:
After a lot of trial and error, adding .frame(maxWidth: .infinity, maxHeight: .infinity)
to the HStack
seems to solve the problem for me.
Here is how the HStack
looks like now:
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(topCardsAsTemplates) { topCardAsTemplate in
TopTemplatesCardView(card: topCardAsTemplate)
.padding()
.onTapGesture {
print("display card uuid: \(topCardAsTemplate.uuid.uuidString)")
withAnimation(.spring()) {
selectedCard = topCardAsTemplate
}
}
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
Hope this helps other people.