ScrollViewProxy 如何通过 ScrollViewProxy.scroll(to:) 修改父内容偏移量?

问题描述

借助 SwiftUI 2.0,我们可以:

ScrollView() {
   ScrollViewReader { proxy in
      DummyContent()
         .onTapGesture {
            proxy.scroll(to: item...)
         }
   }
}

滚动到 ScrollView 内的特定子项。

我正在使用 ScrollView 的“从头开始”实现而不使用 AppKit(为了学习和扩展认 ScrollView 的自定义实现)

我设法在我的 ScrollViewer 实现中实现了滚动和剪切内容,我想通过 ScrollViewerProxy 实现滚动(到 :)、缩放(到 :) 功能,就像 Apple 用 ScrollViewProxy 做的那样。 我不知道 Apple 的 ScrollViewProxy 是如何操纵父视图偏移的?

这是我的 ScrollViewerProxy 和 ScrollViewerReader 的示例实现:

struct ScrollViewerProxy {
   @State var offset: CGSize = .zero
   
   func scroll(to origin: CGPoint) {
      let newOrigin = CGPoint(x: origin.x,y: origin.y)
      offset = CGSize(width: newOrigin.x,height: newOrigin.y)
   }
}

struct ScrollViewerReader<Content: View>: View {
   let content: (ScrollViewerProxy) -> Content
   
   @State private var offset: CGSize = .zero
   private var scrollViewerProxy = ScrollViewerProxy()
   
   init(@viewbuilder _ content: @escaping (ScrollViewerProxy) -> Content) {
      self.content = content
   }
   
   var body: some View {
      content(scrollViewerProxy)
         .offset( ??? ) // Can't do scrollViewerProxy.offset since it won't trigger ScrollViewerReader update
   }
}

// Bellow 是自定义 ScrollView 实现的代码,不是很重要,为了完整起见,把它放在这里

struct ScrollViewer<Content: View>: View {
   let content: Content

   var body: some View {
      ZStack {
         GeometryReader { geometry
            content 
               .offset(offset)
               .onPreferenceChange(ContentPreferenceKey.self) { preferences in
                  guard let p = preferences.first else { fatalError() }
                  contentRect = p.frame
                  ....
               // I monitor content frame changes via PreferenceKey
            }
         }
      }
   }
}

// Usage:
ScrollViewer {
   ScrollViewerReader { proxy in
      DummyContent()
         .onTapGesture {
            let random = CGPoint(x: -Int.random(in: 0...400),y: 0)
            proxy.scroll(to: random)
         }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)