You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关闭键盘触发matchedGeometryEffect回退问题求助

问题解决:关闭键盘后matchedGeometryEffect元素回退原位置

问题分析

关闭键盘时,SwiftUI会重新计算布局,原本处于屏幕下方的元素所在列表(示例代码中为VStack)会因键盘收起恢复原布局空间,导致matchedGeometryEffect的参照位置发生变化,触发不必要的动画回退。而屏幕上方的元素原本不在键盘影响区域,布局变化幅度小,因此无异常。

解决步骤

  1. 彻底隐藏原列表的布局空间:原列表仅设置opacity(0)时,布局仍会占据空间,键盘收起时会改变其位置,干扰matchedGeometryEffect的匹配逻辑。需同时添加hidden()移除布局占位。
  2. 关闭键盘时禁用动画:用withAnimation(nil)包裹键盘收起代码,避免布局更新触发动画效果。
  3. 明确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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 00:37:26