关闭键盘触发matchedGeometryEffect回退问题求助
问题解决:关闭键盘后matchedGeometryEffect元素回退原位置
问题分析
关闭键盘时,SwiftUI会重新计算布局,原本处于屏幕下方的元素所在列表(示例代码中为VStack)会因键盘收起恢复原布局空间,导致matchedGeometryEffect的参照位置发生变化,触发不必要的动画回退。而屏幕上方的元素原本不在键盘影响区域,布局变化幅度小,因此无异常。
解决步骤
- 彻底隐藏原列表的布局空间:原列表仅设置
opacity(0)时,布局仍会占据空间,键盘收起时会改变其位置,干扰matchedGeometryEffect的匹配逻辑。需同时添加hidden()移除布局占位。 - 关闭键盘时禁用动画:用
withAnimation(nil)包裹键盘收起代码,避免布局更新触发动画效果。 - 明确matchedGeometryEffect的匹配属性:添加
properties: .frame,限定仅匹配元素的尺寸和位置,减少布局变化的干扰。
修改后的代码
import SwiftUI struct NewsReplyView: View { @Namespace var namespace @State var text: String = "" @State var selected: String = "" @State var show = false @State var arr = ["1", "2", "3", "4", "5"] var body: some View { ZStack { VStack{ ForEach(arr.indices) { i in RoundedRectangle(cornerRadius: 20).frame(width: 100, height: 100) .id(arr[i]) .onTapGesture { withAnimation(.spring()){ show.toggle() selected = arr[i] } } .matchedGeometryEffect(id: selected, in: namespace, properties: .frame) } } // 同时隐藏布局和透明度 .opacity(show ? 0.0 : 1.0) .hidden(show) if show { VStack{ RoundedRectangle(cornerRadius: 20).frame(width: 100, height: 100) .id(selected) .matchedGeometryEffect(id: selected, in: namespace, properties: .frame) Spacer() TextField("", text: $text) .onSubmit { // 禁用动画关闭键盘 withAnimation(nil) { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } } } } } } }
额外优化(针对实际使用ScrollView的场景)
如果你的实际布局是ScrollView,需在展开状态下禁用滚动,避免布局偏移:
ScrollView { // 列表元素内容 } .disabled(show) // 展开时禁用滚动
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

