Disappearing animations

66 views Asked by At

I have a stack of cards on screen. I am trying to animate the movement from the stack to positions on a grid. The problem is, when I tap on the stack to move the cards to their positions, the stack disappears. Then the cards fly into place from off screen.

var body: some View {
    VStack {
        cardStack
        testGrid
    }
}

//MARK: - TESTING]

@Namespace var testSpace
struct TestCard: Identifiable, View {
    init(id: String) {
        self.id = id
    }
    
    let id: String
    let shape = RoundedRectangle(cornerRadius: 10)
    
    var body: some View {
        shape
            .padding()
    }
}

var testDeck: [TestCard] {
    var cards = [TestCard]()
    for cardIndex in 0..<10 {
        let card = TestCard(id: "\(cardIndex)")
        cards.append(card)
    }
    return cards
}

var testGrid: some View {
    AspectVGrid(testDeck, aspectRatio: 5 / 3) { card in
        if isDealtTest(card) {
            TestCard(id: card.id)
                .matchedGeometryEffect(id: card.id, in: testSpace)
                .transition(.asymmetric(insertion: .identity, removal: .identity))
        }
    }
}

@State private var dealtTest = Set<TestCard.ID>()

private func isDealtTest(_ card: TestCard) -> Bool {
    dealtTest.contains(card.id)
}
private var undealtCardsTest: [TestCard] {
    testDeck.filter { !isDealtTest($0) }
}

private var cardStack: some View {
    ZStack {
        ForEach(undealtCardsTest) { card in
            TestCard(id: card.id)
                .matchedGeometryEffect(id: card.id, in: testSpace)
                .transition(.asymmetric(insertion: .identity, removal: .identity))
        }
    }
    .onTapGesture {
        dealTest()
    }
}
    
    private func dealTest() {
        var delay: TimeInterval = 0
        for card in testDeck {
            withAnimation(.easeInOut(duration: 1).delay(delay)) {
                _ = dealtTest.insert(card.id)
            }
            delay += 0.15
        }
    }

I have tried using an array of cards that had nothing to do with my model, as well as cards which did not take an instance of the viewModel. They too disappeared when tapped. These only consisted of a rectangle and an id. I tried moving the position of the deck of cards around the VStack. I used the matchedGeometry and transition to move around a roundedRectangle and had no problem. In another project, I used essentially the same code to move cards from a stack to their positions on a grid.

1

There are 1 answers

0
Benzy Neez On

I think the main issue is that the cards take too much space.

Try setting a maximum size and also aspect ratio on TestCard and remove the padding:

struct TestCard: Identifiable, View {

    // init and properties as before

    var body: some View {
        shape
            .frame(maxWidth: 300, maxHeight: 500)
            .aspectRatio(CGSize(width: 3, height: 5), contentMode: .fill)
//            .padding()
    }
}

Then add .scaledToFit to the parent container in testGrid. You might like to add padding too. You didn't provide the implementation of AspectVGrid, so I improvised by using an HStack instead:

var testGrid: some View {
    HStack(spacing: 2) {
        ForEach(testDeck) { card in
            if isDealtTest(card) {
                TestCard(id: card.id)
                    .matchedGeometryEffect(id: card.id, in: testSpace)
                    .transition(.asymmetric(insertion: .identity, removal: .identity))
            }
        }
    }
    .scaledToFit() // <- ADDED
    .padding() // <- ADDED


//    AspectVGrid(testDeck, aspectRatio: 5 / 3) { card in
//        if isDealtTest(card) {
//            TestCard(id: card.id)
//                .matchedGeometryEffect(id: card.id, in: testSpace)
//                .transition(.asymmetric(insertion: .identity, removal: .identity))
//        }
//    }
}

If you want the cards to go straight to the smaller size, instead of shrinking as more cards are added to the grid, then just apply a fixed size to the cards in testGrid:

if isDealtTest(card) {
    TestCard(id: card.id)
        .frame(width: 30, height: 50) // <- ADDED
        .matchedGeometryEffect(id: card.id, in: testSpace)
        .transition(.asymmetric(insertion: .identity, removal: .identity))
}