SwiftUI:NavigationLink标签内系统图标点击全动画问题排查与解决
问题分析与解决方法
问题原因
你用了一个全局的@State private var tapped变量控制动画状态,List里的每一行收藏图标都绑定了这个变量。只要点击任意一个图标触发tapped值变化,所有行的图标都会响应这个状态变更,所以全部跟着动了。
解决方法
给每个列表项单独维护动画状态,不要用全局变量,以下是两种常用实现方式:
方式一:用字典存储每个项目的动画状态
把全局的tapped改成字典,键为动物名称,值对应该行是否触发动画的状态:
class Favourites: ObservableObject { var favAnimals: Set<String> = [] func contains(_ animal: String) -> Bool { favAnimals.contains(animal) } func add(_ animal: String) { objectWillChange.send() favAnimals.insert(animal) } func remove(_ animal: String) { objectWillChange.send() favAnimals.remove(animal) } } struct ContentView: View { let animals = ["Dog", "Cat", "Horse", "Sheep"] @StateObject var favourites = Favourites() // 用字典存储每个动物对应的动画状态 @State private var tappedStates: [String: Bool] = [:] var body: some View { NavigationView { List(animals, id: \.self) { animal in NavigationLink { Text("Animal Detail View") } label: { HStack { Text(animal) Spacer() Image(systemName: favourites.contains(animal) ? "heart.fill" : "heart") .foregroundColor(favourites.contains(animal) ? .red : .gray) .onTapGesture { // 更新当前动物的动画状态 tappedStates[animal] = true if favourites.contains(animal) { favourites.remove(animal) } else { favourites.add(animal) } DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { tappedStates[animal] = false } } .scaleEffect(tappedStates[animal, default: false] ? 1.2 : 1) .animation(.spring(response: 0.4, dampingFraction: 0.6), value: tappedStates[animal]) } } } .navigationTitle("Animals") } } }
方式二:拆分子View,每个子View维护自己的状态
把列表项抽成单独的AnimalRow子视图,每个子视图内部维护专属的tapped状态,实现状态隔离:
class Favourites: ObservableObject { var favAnimals: Set<String> = [] func contains(_ animal: String) -> Bool { favAnimals.contains(animal) } func add(_ animal: String) { objectWillChange.send() favAnimals.insert(animal) } func remove(_ animal: String) { objectWillChange.send() favAnimals.remove(animal) } } struct ContentView: View { let animals = ["Dog", "Cat", "Horse", "Sheep"] @StateObject var favourites = Favourites() var body: some View { NavigationView { List(animals, id: \.self) { animal in NavigationLink { Text("Animal Detail View") } label: { AnimalRow(animal: animal, favourites: favourites) } } .navigationTitle("Animals") } } } // 子视图单独维护动画状态 struct AnimalRow: View { let animal: String @ObservedObject var favourites: Favourites @State private var tapped = false var body: some View { HStack { Text(animal) Spacer() Image(systemName: favourites.contains(animal) ? "heart.fill" : "heart") .foregroundColor(favourites.contains(animal) ? .red : .gray) .onTapGesture { tapped.toggle() if favourites.contains(animal) { favourites.remove(animal) } else { favourites.add(animal) } DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { tapped = false } } .scaleEffect(tapped ? 1.2 : 1) .animation(.spring(response: 0.4, dampingFraction: 0.6), value: tapped) } } }
内容的提问来源于stack exchange,提问作者OxfordSi
相关产品推荐
相关产品推荐

