SwiftUI嵌套Button点击动画问题:子Button触发父Button动画
问题原因
SwiftUI的事件会向上传递,点击嵌套在父Button内的子Button时,父Button会同时接收点击事件,导致其ButtonStyle中的按压动画被触发。
解决方案
方案一:给子Button添加高优先级手势
通过给子Button设置高优先级手势,确保点击子Button时事件被优先处理,不会传递到父Button。
修改子Button代码,添加.highPriorityGesture(TapGesture()):
Button { print("on child") } label: { Text("Tap") } .buttonStyle(SmallButtonStyle()) .highPriorityGesture(TapGesture()) // 阻止事件向上传递
方案二:替换父Button为带手势的普通View(解决滚动问题)
如果需要更精确的控制,或者手势方案存在滚动冲突,可以将父级Button替换为普通View,手动通过@State变量控制按压状态和动画,同时处理滚动时的状态重置:
struct ContentView: View { let dataTypesArray = ["Item 1", "Item 2", "Item 3"] // 为每个行单独维护按压状态,避免复用问题 @State private var pressedRows: Set<String> = [] var body: some View { ScrollView { LazyVStack(spacing: 6) { ForEach(dataTypesArray, id: \.self) { each in HStack { Spacer() Text(each) Spacer() Button { print("on child") } label: { Text("Tap") } .buttonStyle(SmallButtonStyle()) } .frame(height: 44) .frame(maxWidth: .infinity) .background(Color.pink) .clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous)) .opacity(pressedRows.contains(each) ? 0.8 : 1) .scaleEffect(pressedRows.contains(each) ? 0.95 : 1) .gesture( TapGesture() .onChanged { _ in pressedRows.insert(each) } .onEnded { _ in pressedRows.remove(each) print("on parent") } ) // 滚动时重置按压状态,解决滚动冲突 .simultaneousGesture( DragGesture(minimumDistance: 5) .onChanged { _ in pressedRows.remove(each) } ) } } .padding(.horizontal, 8) .padding(.vertical, 10) } } }
说明:用Set<String>维护每个行的按压状态,避免多个行复用同一个状态的问题;通过DragGesture在滚动开始时重置按压状态,解决手势方案的滚动冲突问题。
内容的提问来源于stack exchange,提问作者Dim Roe
相关产品推荐
相关产品推荐

