目標
假設我有 aList或 a LazyVGrid,它顯示嵌套在 a 中的多個專案ScrollView。我使用ForEach視圖來生成單個專案視圖:
ForEach(items) { item in
ItemView(item)
}
該items陣列可能是@State視圖本身的一個@Published屬性,也可能是符合以下條件的視圖模型上的一個屬性@ObservableObject(我將在本示例中使用第一個)。
現在,當我items通過插入或洗掉元素來更改陣列時,我希望以特定的方式對更改進行影片處理,因此我添加了 atransition和一個animation修飾符,如下所示:
ScrollView {
LazyVGrid(columns: 2) {
ForEach(items) { item in
ItemView(item)
.transition(.scale)
}
}
}
.animation(.default, value: items)
這很好用。
問題
唯一的問題是,ScrollView當視圖首次出現時,此代碼還會導致整體從零縮放到其完整大小。(這是有道理的,因為在從商店中獲取專案之前,專案陣列最初是空的,因此該陣列確實發生了變化。)
解決方案嘗試
為了解決這個問題,我顯然需要使影片依賴于在視圖出現和加載專案陣列之前不會改變的屬性。所以我創建了一個普通布林值這樣的屬性,并在items陣列更改時切換它,但只有在didAppear被呼叫之后:
@State var changedState: Bool = false
@State var didAppear: Bool = false
@State var items: [Item] = [] {
didSet {
if didAppear {
changedState.toggle()
}
}
}
然后我value將影片修改器更改為這個新屬性:
.animation(.default, value: changedState)
? 解決問題。但是,它感覺非常“丑陋”,并且需要很多開銷。
問題
還有其他(更優雅/更簡潔)的方法來禁用初始縮放影片嗎?
????? 編輯:最小代碼示例
struct ContentView: View {
@State var items: [Int] = []
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: [GridItem(), GridItem()]) {
ForEach(items, id: \.self) { item in
Rectangle()
.frame(height: 50)
.foregroundColor(.red)
.transition(.scale)
}
}
}
.animation(.default, value: items)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
let newItem = items.last.map { $0 1 } ?? 0
items.append(newItem)
} label: {
Text("Add Item")
}
}
}
}
.onAppear {
items = [Int](0...10)
}
}
}
這是初始影片的樣子:
→
→

uj5u.com熱心網友回復:
你didSet不會按照你期望的方式作業,這就是我們有的原因.onChange(),但正如你所懷疑的那樣,確實有一種更簡單的方法。您只想影片將專案附加到串列(顯示在螢屏上)。最簡單的方法是添加一個@State布林值,并將其用作.animation()值。然后,當您像這樣添加到陣列時,您只需在按鈕中切換它:
struct ContentView: View {
@State var items: [Int] = []
@State var animate = false // Variable for animation
var body: some View {
ScrollView {
LazyVGrid(columns: [GridItem(), GridItem()]) {
ForEach(items, id: \.self) { item in
Rectangle()
.frame(height: 50)
.foregroundColor(.red)
.transition(.scale)
}
}
}
// Use animate as a flag to allow items to be the value
// for .animation
.animation(.default, value: (animate ? items : []))
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
let newItem = items.last.map { $0 1 } ?? 0
items.append(newItem)
animate.toggle() // <- Switch it here
} label: {
Text("Add Item")
}
}
}
.onAppear {
items = [Int](0...10)
// The DispatchQueue is necessary to delay changing
// the flag until the initial view is loaded.
DispatchQueue.main.asyncAfter(deadline: .now()) {
animate = true
}
}
}
}
編輯:
上面的代碼已更改以反映評論。這應該適合您的需求。
uj5u.com熱心網友回復:
我發現將.animation修飾符應用到LazyVGrid而不是ScrollView像您期望的那樣起作用。
struct ContentView: View {
@State var items: [Int] = []
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: [GridItem(), GridItem()]) {
ForEach(items, id: \.self) { item in
Rectangle()
.frame(height: 50)
.foregroundColor(.red)
.transition(.scale)
}
}
.animation(.default, value: items) // <- New Place
}
// <- Old Place
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
let newItem = items.last.map { $0 1 } ?? 0
items.append(newItem)
} label: {
Text("Add Item")
}
}
}
}
.onAppear {
items = [Int](0...10)
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/459071.html
標籤:动画片 迅捷 swiftui-动画 出现 swiftui-过渡
下一篇:在顫動中點擊影片時如何切換影片
