[英]SwiftUI: remove view at animation end?
我有以下代碼:
enum AnimationDirection {
case opening
case closing
}
struct AnimtionStateMod: AnimatableModifier {
var progress: CGFloat = 0
private(set) var direction:AnimationDirection = .opening
var animatableData: CGFloat {
get { progress }
set {
direction = progress > newValue ? .opening : .closing
progress = newValue
print("progress: \(progress). direction: \(direction)")
}
}
func body(content: Content) -> some View {
content.opacity(1)
}
}
struct PersonDetails: View {
@State var person:Person
var body: some View {
ZStack {
Color.yellow
HStack {
Text("PERSON")
Spacer()
}
Text(person.name)
Spacer()
}
.border(.red)
}
}
struct Person: Identifiable {
let id = UUID()
let name: String
}
struct ContentView: View {
@State var persons = [Person(name: "A"), Person(name: "B"), Person(name: "C")]
@Namespace private var gridSpace
@State var selectedPerson:Person?
@State var expandingPersonDetails:Bool = false
var matchDetailsToPerson: Bool { !expandingPersonDetails }
@State var matchSelectionToGridItem = true
let c = GridItem(.adaptive(minimum: 200, maximum: 400), spacing: 20)
var body: some View {
ZStack {
ScrollView {
LazyVGrid(columns: [c]) {
ForEach(persons) { person in
ZStack {
Color.blue
Text(person.name)
.foregroundColor(.white)
}
.frame(width: 200, height: 200)
.onTapGesture {
print(person.name)
withAnimation {
selectedPerson = person
}
}
.matchedGeometryEffect(id: person.id, in: gridSpace, isSource: true)
}
}
}
.zIndex(1)
if let person = selectedPerson {
PersonDetails(person: person)
.matchedGeometryEffect(id: matchDetailsToPerson ? person.id : UUID() , in: gridSpace, isSource: false)
.frame(width: 600, height: 600)
.zIndex(2)
.onAppear {
withAnimation {
expandingPersonDetails = true
}
}
.onDisappear {
expandingPersonDetails = false
}
.transition(.identity)
.modifier(AnimtionStateMod(progress: expandingPersonDetails ? 1 : 0))
.onTapGesture {
withAnimation {
// selectedPerson = nil
expandingPersonDetails = false
}
}
}
}
}
它的行為如下:
我堅持的是:
我希望PersonDetails
在網格項目上完成動畫后被刪除。 打開的動畫(從網格到展開PersonDetails
)看起來就像我想要的那樣。 關閉動畫(當PersonDetails
縮小到相關的網格項目時)看起來就像我想要的那樣。 但是,我希望PersonDetails
一旦回到網格項目上就被刪除。
我想我可以在返回網格項目時使用AnimatableModifier
跟蹤動畫,然后將selectedPerson
觸發為零。 我想我可以使用這種方法,但是,我不確定在這種情況下我是否應該這樣做。
我該怎么辦?
只是添加反饋:
使用asperi
的答案我得到了不同的結果。 我也在使用更新版本的 Xcode,這是我現在唯一能想到的,但我想在這里提供反饋以了解上下文:
如果我正確地想象了您的需求(我仍然不確定),則可以以更簡單的方式實現效果 - 通過對選定的人進行動畫處理,並使用疊加匹配的人視圖來保持原點不變。
使用 Xcode 13.4 / iOS 15.5 測試
帶有慢速調試動畫以獲得更好的可見性
這是主要部分(已修復 iPadOS 更新):
ForEach(persons) { person in
ZStack {
if nil != selectedPerson {
PersonView(person: person)
} else {
PersonView(person: person)
.matchedGeometryEffect(id: person.id, in: gridSpace)
.onTapGesture {
if nil == selectedPerson {
selectedPerson = person
}
}}
}
.frame(width: 100, height: 100)
}
}
}
VStack { // << to remove fluently
if let person = selectedPerson {
PersonDetails(person: person)
.matchedGeometryEffect(id: person.id, in: gridSpace)
.transition(.scale(scale: 1))
.frame(width: 360, height: 360)
.onTapGesture {
selectedPerson = nil
}
}
}
.animation(.default, value: selectedPerson)
Asperi 的代碼非常簡單有效。 如果您想要一種不同的方法,盡管稍微復雜一點,您可以嘗試為動畫設置持續時間,然后 - 僅在此之后 - 將selectedPerson
設置為nil
。
首先,在ContentView
內部為效果持續時間設置一個常量:
// This is the duration of the animation
let effectDuration = 0.5
然后,使用基於expandingPersonDetails
變量的動畫過渡。 您可以完全刪除AnimatableModifier
。 在關閉人員詳細信息之前,首先更改變量expandingPersonDetails
以將視圖放回其原始位置。 只有在動畫結束后,使用.asyncAfter()
才能關閉selectedPerson
。 這里:
PersonDetails(person: person)
// Use simple transition
.transition(.opacity)
// The duration must match the .asyncAfter method below
.animation(.easeInOut(duration: effectDuration), value: expandingPersonDetails)
.matchedGeometryEffect(id: expandingPersonDetails ? UUID() : person.id , in: gridSpace, isSource: false)
.frame(width: 600, height: 600)
.zIndex(2)
.onAppear {
withAnimation {
expandingPersonDetails = true
}
}
.onTapGesture {
withAnimation {
// Change this variable first
expandingPersonDetails = false
// When the animation is over, un-select the person
DispatchQueue.main.asyncAfter(deadline: .now() + effectDuration) {
selectedPerson = nil
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.