ScrollView 不以 Geometry Reader 作为子项滚动

Ser*_*iaz 5 swift swiftui

一些上下文:我目前正在尝试创建一个视图,其中包含嵌入 ScrollView 中的用户可编辑的 TextField() 。我想让它在用户单击文本字段进行输入时屏幕自动滚动到文本字段(不会被键盘阻止)。我想出了如何通过使用导航中心并在打开键盘时实现伪代码 view.offset(y: KeyboardHeight) 来实现此功能。

我遇到的问题是,有时,当用户进一步向下滚动并且 TextField 在屏幕上较高时,有时偏移会导致视图过度补偿,并且 TextField 在屏幕上方的区域中移位。因此,您必须再次滚动才能看到 TextField。

我的解决方案:使用 2 个几何读取器来确定用户在屏幕上滚动了多远,并相应地调整文本字段的偏移量(当键盘打开时)。为此,我有一个更复杂的以下代码版本。

struct OverallView: View {

    var body: some View {
    
        GeometryReader { outer in
    
            ScrollView (.vertical, showIndicators: false) {
    
               GeometryReader { inner in
    
                  VStack {
                      Text("This is filler text").padding(.vertical, 100)
                      Text("This is filler text").padding(.vertical, 100)
                      Text("This is filler text").padding(.vertical, 100)
                      Text("This is filler text").padding(.vertical, 100)
                      Text("This is filler text").padding(.vertical, 100)
                  }
               }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题:理想情况下,我能够获得内部和外部 GeometryProxies 的 minY 并减去它们以查看用户滚动了多远。问题是,当我运行此代码时,内部 GeometryReader (出于我未知的原因)不再允许我滚动。我意识到这是因为 GeometryReader 的高度设置为屏幕的高度,因此当我将其高度设置为 9000 之类的值时,我可以再次滚动。我尝试将内部几何读取器的高度设置为外部几何读取器的高度,但这不起作用。我还尝试了各种其他解决方案,包括切换哪些视图是父母/孩子——这个以及我的其他解决方案也不起作用。

所以,我想知道是否有人知道为什么这个 GeometryReader 不允许我滚动以及如何修复它。或者,如果有人有更好的方法来解决我的整体问题,但不涉及此方法,我将不胜感激听到您的建议。

非常感谢你的帮助!

Asp*_*eri 7

GeometryReader不是一个普通的孩子,你不能在未知大小的区域(即ScrollView)中使用它,因为当父子期望彼此的大小时,你会陷入先有鸡还是先有蛋的问题。

相反,在内容背景上使用内部几何读取器,因此内容已定义大小,您可以读取其在其他(全局)坐标系中的位置,例如

ScrollView (.vertical, showIndicators: false) {
  VStack {
      Text("This is filler text").padding(.vertical, 100)
      Text("This is filler text").padding(.vertical, 100)
      Text("This is filler text").padding(.vertical, 100)
      Text("This is filler text").padding(.vertical, 100)
      Text("This is filler text").padding(.vertical, 100)
  }.background(
     GeometryReader { inner in
          // use proxy here
     })
}
Run Code Online (Sandbox Code Playgroud)