当卡片使用 .matchedGeometryEffect() 位于 LazyVGrid 中时,我从未设法让它正常工作。所以这是我在项目中使用的滥用偏移和缩放的相当混乱的解决方案:
import SwiftUI
import PlaygroundSupport
struct GridTestView: View {
@State var flippedCard: Int?
@State var frontCard: Int?
let cards = [1,2,3,4,5,6,7,8,9,10]
var body: some View {
let columns = [
GridItem(.flexible(), spacing: 0),
GridItem(.flexible(), spacing: 0),
GridItem(.flexible(), spacing: 0)
]
GeometryReader { screenGeometry in
ZStack {
ScrollView {
LazyVGrid(columns: columns, alignment: .center, spacing: 0) {
ForEach(cards, id: \.self) { card in
let isFaceUp = flippedCard == card
GeometryReader { cardGeometry in
ZStack {
CardBackView(card: card)
.modifier(FlipOpacity(pct: isFaceUp ? 0 : 1))
.rotation3DEffect(Angle.degrees(isFaceUp ? 180 : 360), axis: (0,1,0))
.frame(width: cardGeometry.size.width, height: cardGeometry.size.height)
.scaleEffect(isFaceUp ? screenGeometry.size.width / cardGeometry.size.width: 1)
CardFrontView(card: card)
.modifier(FlipOpacity(pct: isFaceUp ? 1 : 0))
.rotation3DEffect(Angle.degrees(isFaceUp ? 0 : 180), axis: (0,1,0))
.frame(width: screenGeometry.size.width, height: screenGeometry.size.height)
.scaleEffect(isFaceUp ? 1 : cardGeometry.size.width / screenGeometry.size.width)
}
.offset(x: isFaceUp ? -cardGeometry.frame(in: .named("mainFrame")).origin.x: -screenGeometry.size.width/2 + cardGeometry.size.width/2,
y: isFaceUp ? -cardGeometry.frame(in: .named("mainFrame")).origin.y: -screenGeometry.size.height/2 + cardGeometry.size.height/2)
.onTapGesture {
withAnimation(.linear(duration: 1.0)) {
if flippedCard == nil {
flippedCard = card
frontCard = card
} else if flippedCard == card {
flippedCard = nil
}
}
}
}
.aspectRatio(1, contentMode: .fit)
.zIndex(frontCard == card ? 1 : 0)
}
}
}
}
.background(Color.black)
}
.coordinateSpace(name: "mainFrame")
}
}
struct FlipOpacity: AnimatableModifier {
var pct: CGFloat = 0
var animatableData: CGFloat {
get { pct }
set { pct = newValue }
}
func body(content: Content) -> some View {
return content.opacity(Double(pct.rounded()))
}
}
struct CardBackView: View {
var card: Int
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 10)
.fill(Color.red)
.padding(5)
Text("Back \(card)")
}
}
}
struct CardFrontView: View {
var card: Int
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 10)
.fill(Color.blue)
.padding(10)
.aspectRatio(1.0, contentMode: .fit)
Text("Front \(card)")
}
}
}
// Present the view controller in the Live View window
PlaygroundPage.current.setLiveView(GridTestView().frame(width: 400, height: 600))