swiftui - SwiftUI Hero Animation (matchedGeometryEffect) 问题
问题描述
我一直在网上查看不同的教程,试图拼凑出一个“简单”的英雄动画。图像位于 LazyHGrid 中,点击时应展开至第二张图像。我试图尽可能地压缩和简化下面的代码。
我已经让它在网格之外工作,只有一张图像。
import SwiftUI
struct Item: Hashable {
let id = UUID()
var text = "TEXT"
}
struct ContentView: View {
var items = [Item(text: "One"), Item(text: "Two"), Item(text: "Three"), Item(text: "Four"), Item(text: "Five"), Item(text: "Six"), Item(text: "Seven"),Item(text: "Eight"),Item(text: "Nine")]
@State private var isShowingDetail = false
@State private var selectedItemID: UUID? = nil
@Namespace var animation: Namespace.ID
var body: some View {
ZStack {
ScrollView(.horizontal) {
LazyHGrid(rows: [GridItem(.flexible())], spacing: 10, content: {
ForEach(items,id: \.id, content: { item in
VStack {
Image("Image2")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
.matchedGeometryEffect(id: item.id, in: animation)
.onTapGesture {
withAnimation(.spring()){
self.selectedItemID = item.id
isShowingDetail.toggle()
}
}
Text(item.text)
}
})
})
}
if isShowingDetail {
VStack {
Image("Image1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300)
.matchedGeometryEffect(id: selectedItemID, in: animation)
.onTapGesture {
withAnimation(.spring()){
selectedItemID = nil
isShowingDetail.toggle()
}
}
Spacer()
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
解决方案
看起来你selectedItemID
和isShowingDetail
正在互相争斗(并且是多余的,因为selectedItemID
是可选的。我已经注释掉了几行,它似乎正在工作:
struct ContentView: View {
@State var items = [Item(text: "One"), Item(text: "Two"), Item(text: "Three"), Item(text: "Four"), Item(text: "Five"), Item(text: "Six"), Item(text: "Seven"),Item(text: "Eight"),Item(text: "Nine")]
//@State private var isShowingDetail = false // <----- here
@State private var selectedItemID: UUID? = nil
@Namespace var animation: Namespace.ID
var body: some View {
ZStack {
ScrollView(.horizontal) {
LazyHGrid(rows: [GridItem(.flexible())], spacing: 10, content: {
ForEach(items,id: \.id, content: { item in
VStack {
Image("0")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 200)
.matchedGeometryEffect(id: item.id, in: animation)
.onTapGesture {
withAnimation(.spring()){
self.selectedItemID = item.id
//isShowingDetail.toggle() // <----- here
}
}
Text(item.text)
}
})
})
}
if let selectedItemID = selectedItemID { // <----- here
VStack {
Image("1")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 300)
.matchedGeometryEffect(id: selectedItemID, in: animation)
.onTapGesture {
withAnimation(.spring()){
self.selectedItemID = nil
//isShowingDetail.toggle() // <----- here
}
}
Spacer()
}
}
}
}
}
需要注意的是,如果在细节图像缩小时再次点击原始图像,似乎可能会进入一个有趣的状态。不确定这是代码的错误还是 matchGeometryEffect 本身的错误。
推荐阅读
- android - 当我打开android studio时,如何摆脱我的MAC上弹出的xcodebuild弹出窗口?
- aem - AEM Slightly - 如何调用名称存储在变量中的 java 方法 - 表达式中的表达式无法正常工作
- java - 从 IBM WebSphere 8.5 迁移到 JBoss EAP 7.0 - SOAP 请求无法解析,'ElementNSImpl 无法转换为 javax.xml.soap.SOAPElement'
- vue.js - 我的 eventBus 实现有什么问题?
- html - 表格单元格的多色边框
- flutter - 如何在PageStore颤动的小部件内传递参数
- python - Python登录验证(Tkinter)
- html - 是否可以将 Jekyll 中生成的集合页面中的数据传递给布局?
- java - 如何将 JComboBox 项目更改为整数
- python - 制作具有可变输入数量的网络