I am trying to make a notes view where the individual notes will be displayed in a scrollable grid of two columns. I want to make it so that if a note card is tapped upon, it opens the full note and takes over the entire screen. I can't just use withAnimation because that contains the card inside the LazyVGrid that I am using. I tried using matchedGeometry as follows but that brings in the expanded view from the top left instead of expanding the card.
struct CardView: View {
let title: String
let nameSpace: Namespace.ID
var body: some View {
VStack() {
Text(title)
.font(.headline)
.foregroundStyle(.white)
}
.frame(width: 150, height: 200)
.background(.blue)
.matchedGeometryEffect(id: "card", in: nameSpace)
}
}
struct ExpandedCardView: View {
let title: String
let nameSpace: Namespace.ID
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
var body: some View {
VStack {
Text(title)
.font(.title)
.foregroundStyle(.white)
}
.frame(width: screenWidth, height: screenHeight)
.background(.blue)
.matchedGeometryEffect(id: "card", in: nameSpace)
}
}
struct ParentView: View {
@State private var cardExpanded: Bool = false
@Namespace private var nameSpace
var body: some View {
ZStack {
if (cardExpanded == false) {
CardView(title: "This is a title", nameSpace: nameSpace)
.onTapGesture {
withAnimation {
cardExpanded.toggle()
}
}
}
else {
ExpandedCardView(title: "This is a title", nameSpace: nameSpace)
.onTapGesture {
withAnimation {
cardExpanded.toggle()
}
}
.zIndex(1)
}
}
}
}
I am not sure how to make this work. The look I am trying to achieve is similar to how tabs look in the Safari app on iOS. It is also similar to how the Files app works on iOS.
I really liked the animation I got by using withAnimation but because of the card not being able to escape the LazyVGrid, it didn't work as intended. The code using withAnimation is as follows:
struct CardView: View {
@State var isExpanded: Bool = false
let title: String
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
var body: some View {
VStack() {
Text(title)
.font(.headline)
.scaleEffect(isExpanded ? 2 : 1)
.foregroundColor(.white)
}
.frame(
width: isExpanded ? screenWidth : 150,
height: isExpanded ? screenHeight : 200
)
.background(Color.blue)
.zIndex(isExpanded ? 1 : 0)
.onTapGesture {
withAnimation {
isExpanded.toggle()
}
}
}
}
struct ParentView: View {
private let columns = [
GridItem(.flexible(), spacing: 16),
GridItem(.flexible(), spacing: 16)
]
var body: some View {
ZStack {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(0..<20) { _ in
CardView(title: "This is a title")
}
}
}
}
}
}
I would appreciate if someone could help me understand what is correct architecture to achieive that look that I am trying to.