SwiftUI:垂直TextField嵌套ScrollView时自动滚动异常问题求助
解决ScrollView内垂直TextField自动滚动到底部的问题
针对ScrollView中垂直TextField获取焦点后卡顿滚动到底部的问题,试试这几个方案:
方案1:用ScrollViewReader锁定滚动位置
通过ScrollViewReader监听TextField焦点状态,在获取焦点时手动维持当前滚动位置,阻断系统自动滚动逻辑:
import SwiftUI struct ContentView: View { @State var longText: String = "Lorem ipsum dolor..." @State private var textFieldFocused = false @State private var keepScrollPosition: CGFloat = 0 var body: some View { ScrollView { TextField("", text: $longText, axis: .vertical) .padding() .focused($textFieldFocused) .onChange(of: textFieldFocused) { isFocused in if isFocused { // 记录当前滚动位置并强制回调 withAnimation(.none) { keepScrollPosition = UIScrollView.appearance().contentOffset.y } } } } .scrollDismissesKeyboard(.interactively) .onAppear { keepScrollPosition = UIScrollView.appearance().contentOffset.y } .onChange(of: keepScrollPosition) { pos in UIScrollView.appearance().setContentOffset(CGPoint(x: 0, y: pos), animated: false) } } }
方案2:禁用底层UITextView的自动滚动行为
通过访问TextField对应的底层UITextView,关闭自动滚动相关属性。可以用第三方库Introspect快速实现,也可以自定义封装UIKit组件:
用Introspect库实现
import SwiftUI import Introspect struct ContentView: View { @State var longText: String = "Lorem ipsum dolor..." var body: some View { ScrollView { TextField("", text: $longText, axis: .vertical) .padding() .introspectTextView { textView in // 禁用自动滚动到顶部 textView.*scrollsToTop* = false // 关闭TextView内部滚动,确保它随内容垂直扩展 textView.*isScrollEnabled* = false } } .scrollDismissesKeyboard(.interactively) } }
自定义UIViewRepresentable封装(无第三方依赖)
import SwiftUI struct AutoExpandingTextView: UIViewRepresentable { @Binding var text: String func makeUIView(context: Context) -> UITextView { let textView = UITextView() textView.isScrollEnabled = false textView.scrollsToTop = false textView.font = UIFont.systemFont(ofSize: 17) textView.delegate = context.coordinator return textView } func updateUIView(_ uiView: UITextView, context: Context) { uiView.text = text } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITextViewDelegate { var parent: AutoExpandingTextView init(_ parent: AutoExpandingTextView) { self.parent = parent } func textViewDidChange(_ textView: UITextView) { parent.text = textView.text // 强制更新高度,确保TextView随内容扩展 textView.invalidateIntrinsicContentSize() } } } // 使用示例 struct ContentView: View { @State var longText: String = "Lorem ipsum dolor..." var body: some View { ScrollView { AutoExpandingTextView(text: $longText) .padding() } .scrollDismissesKeyboard(.interactively) } }
UIKit替代方案的表现
在UIKit中,将UITextView放入UIScrollView时,默认也会出现键盘弹出时自动滚动到TextView的行为,但控制逻辑更直接:
- 直接设置UIScrollView的
*scrollsToTop* = false - 在
textViewDidBeginEditing代理方法中手动调整UIScrollView的contentOffset维持当前位置 - 关闭UITextView的
*isScrollEnabled*让它随内容自动扩展
这种场景下不会出现SwiftUI里的卡顿动画,因为可以更精细地控制滚动与布局的交互逻辑。
内容的提问来源于stack exchange,提问作者guiri_del_norte
相关产品推荐
相关产品推荐

