Hello folks,
I am attempting stanfords 2020 193p assignment 3 and am having trouble regarding a part with explicit animation.
When I am starting a new game, the cards start flying from off screen to on screen. When I click the card to choose it, it shows a yellow rectangle but instead of showing it on the card during the offset traansition, it's showing that on the card's final location. I am assuming the reason it's doing that is because as far as SwiftUI knows, the cards location is already there and all animation is doing it is showing the transition to the location.
Here's is how the animation first happens. What I want to happen when choosing a card during the offset transition, I want card itself to turn yellow during the transition.
Here's my code for the main view SetGameView.swift (I have removed irrelevant code):
import SwiftUI
struct SetGameView: View {
@ObservedObject var viewModel: CardSetGame
@State private var cardsFaceUp: Array<SetGameEngine.Card> = Array<SetGameEngine.Card>()
let duration : Double = 10.0
private func updateFaceUpCards() {
withAnimation(.linear(duration: duration)) {
cardsFaceUp = self.viewModel.cardsFaceUp
}
}
private func randomLocationOffScreen(for size: CGSize) -> CGSize {
let width = CGFloat.random(in:0..<size.width)
let height = CGFloat.random(in:0..<size.height)
return CGSize(width: width, height: height)
}
var body: some View {
VStack {
GeometryReader { geometry in
Grid(cardsFaceUp) { card in
CardView(card: card).onTapGesture {
self.viewModel.choose(card:card)
self.updateFaceUpCards()
}.transition(.offset(randomLocationOffScreen(for: geometry.size)))
.padding(5)
.aspectRatio(2/3, contentMode: .fit)
}.onAppear {
self.updateFaceUpCards()
}
}
}
}
}
struct CardView: View {
var card: SetGameEngine.Card
var body: some View {
GeometryReader { geometry in
self.body(for: geometry.size)
}
}
func body(for size: CGSize) -> some View {
ZStack {
VStack {
ForEach(0..<card.numberOfSymbols) { _ in
self.createContent()
}.frame( maxHeight: size.height/6)
}
.frame(maxWidth: size.width * maxCardContentWidthFactor, maxHeight: size.height * maxCardContentHeightFactor, alignment: .center)
} .cardify(isChosen: card.isChosen)
}
@ViewBuilder
func createContent() -> some View {
//Returns a View
}
func colour() -> Color {
//returns a Color
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
SetGameView(viewModel: CardSetGame())
}
}
Here's my code for Cardify.swift
struct Cardify: ViewModifier {
var isChosen: Bool
func body(content: Content) -> some View {
ZStack {
if isChosen {
RoundedRectangle(cornerRadius: cornerRadius).fill(Color.yellow)
.transition(.identity)
} else {
RoundedRectangle(cornerRadius: cornerRadius).fill(Color.white)
}
RoundedRectangle(cornerRadius: cornerRadius).stroke(lineWidth: edgeLineWidth)
content
}
}
let cornerRadius: CGFloat = 10.0
let edgeLineWidth: CGFloat = 3.0
}
extension View {
func cardify(isChosen: Bool) -> some View {
self.modifier(Cardify(isChosen: isChosen))
}
}
Since animation shows only changes, I thought I should modify the code as this stanford lecture and use opacity to determine to show card w/ yellow highlight or not.
Here's the new modified Cardify.swift file:
struct Cardify: ViewModifier {
var isChosen: Bool
func body(content: Content) -> some View {
ZStack {
RoundedRectangle(cornerRadius: cornerRadius).fill(Color.yellow)
.opacity(isChosen ? 1 : 0)
.transition(.identity)
RoundedRectangle(cornerRadius: cornerRadius).fill(Color.white)
.opacity(isChosen ? 0 : 1)
.transition(.identity)
RoundedRectangle(cornerRadius: cornerRadius).stroke(lineWidth: edgeLineWidth)
content
}
}
let cornerRadius: CGFloat = 10.0
let edgeLineWidth: CGFloat = 3.0
}
At this point I almost have what I want. When I click the cards during its transition, it's highlighting them yellow as desired but it's still using the default opacity transition even though I specify it to use the .identity transition and I don't know why.
Here's the video after making the opacity change.