SwiftUI: ScrollView offset

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SwiftUI: ScrollView offset相关的知识,希望对你有一定的参考价值。

参考技术A 在线搜索“SwiftUI ScrollView offset”会得到很多关于如何控制 ScrollView 滚动位置的讨论:随着ios 14的发布,SwiftUI新增了 ScrollViewReader .

这是否意味着我们不再需要 ScrollView 偏移量offset?
在本文中,我们将探讨如何获得 offset 偏移量以及它的一些用途.

类似 UIScrollView , ScrollView 由两个 layer 组成:

如果我们查看一个垂直滚动视图(本文将使用这个视图),则偏移量表示 frame layer 层的y坐标的最小值与 content layer 内容层的y坐标的最小值之间的差值。

SwiftUI的 ScrollView 初始化方法:

除了 content 视图构建器之外,我们没有什么可以使用的.
让我们创建一个简单的 ScrollView 的例子,用一些 Text 文本填充:

偏移量将与内容中第一个元素 Text("A") 的偏移量相同,我们如何得到这个元素的偏移量?
再一次,我们需要用到SwiftUI的 GeometryReader ,以及一个新的 PreferenceKey 。

首先,让我们定义preference key:

其次,我们为视图的 .background 修饰器添加 GeometryReader :

geometry reader就像我们在 SwiftUI:GeometryReader 中看到的一样,是用来分享视图层次结构中元素的信息:我们使用它来提取视图的y坐标的最小值,计算出偏移量。

然而它并不能正常执行:
我们正在为局部坐标空间中的框架查询 GeometryProxy ,该空间是我们的 .background 背景视图中建议的空间。
简而言之,就是 Color.clear 的 minY 在 .local 局部坐标一直是0.
修改为 .global 全局坐标,从设备屏幕的坐标系来看是有问题的, Scrollview 可以放在视图层次结构的任何地方, .global 全局坐标系并没有什么帮助。

如果我们把 GeometryReader 放在 Text("A") 上面会发生什么?

这可能看起来更有希望,但它仍然不会工作:
在这种情况下, .local 的坐标系是 ScrollView 的 content layer ,但是我们需要把它显示在 ScrollView 的 frame layer 。

根据我们的 ScrollView 的 frame layer 获得到 GeometryProxy ,我们需要在 ScrollView 上定义一个新的坐标空间,并在 GeometryReader 中引用它:

这是可行的,因为 ScrollView 把 frame layer 暴露在的外层。现在正确的 ScrollView 的 offset 偏移量在视图层次结构中可用。

简单修改下,在控制台看下结果!!

我们在开发中需要抽取封装,可以在需要时轻松地获得偏移量。
ScrollView 接受 content 内容视图构建器,这使得我们无法获得该内容的第一个元素(如果你知道方法,请联系我).

我们可以申请 .background 修饰器作用于整个 content 上,但是这并没有考虑到 content 内容本身可能是一个 Group 组的可能性,在这种情况下,修饰符将应用于组的每个元素,这不是我们想要的。

一种解决方案是将 geometry reader 移动到 ScrollView 内容的上方,然后在实际内容上用负的 padding 来隐藏它:

类似于 readSize 修饰器,我们也可以让 ScrollViewOffset 在每次偏移量改变时触发回调方法:

然后我们就可以这样使用:

现在我们有了这个强大的组件,就可以做我们要做的了。
最常见的用法可能是在滚动时改变顶部安全区域的颜色:

这是一个基于滚动位置改变背景颜色的视图:

浮点数取余:商取整数,余数还是浮点数
类似整型的 % ,

我们在ios14上看到的一切都很好,但是在ios13上,最初的偏移量是不同的。

在iOS13中,偏移量考虑了顶部安全区域:例如,嵌入大标题的 NavigationView 中的 ScrollViewOffset 的初始偏移量为 140 ,iOS14中的相同视图的初始(正确)偏移量值为 0 。
这点是需要特别注意的!!!

有了 ScrollViewReader ,在大多数用例中,我们不再需要访问 ScrollView 偏移量:对于其余的用例, GeometryReader 都是可以做到的.

Swiftui Scrollview Viewmodifier 适用于所有 Scrollview

【中文标题】Swiftui Scrollview Viewmodifier 适用于所有 Scrollview【英文标题】:Swiftui Scrollview Viewmodifier Applies to All Scrollviews 【发布时间】:2020-12-23 22:58:40 【问题描述】:

我已经为 Swiftui 的滚动视图实现了一个视图修改器,以禁用内置滚动,以允许应用自定义拖动手势。修饰符效果很好。

问题是 viewmodifier 被应用于应用程序中的其他滚动视图,而不仅仅是那些以 .modifier 为目标的滚动视图!我尝试了简单的可能解决方案,例如滚动视图的唯一 ID,但无济于事。

有谁知道这种行为是否可以修复?

ScrollViewReader  (proxy: ScrollViewProxy) in
     ScrollView(.horizontal) 
         LazyHGrid(rows: rows, alignment: .center, spacing: cellSpacing) 
              ForEach(Assets, id: \.self)  asset in
                   AssetView(asset)
              
          .transition(.asymmetric(insertion: .identity, removal: .identity))
                    .offset(x: initialOffset.width + x.width)
      
      .id("AssetDetail")
      .modifier(DetailScrollViewModifier())
      .gesture(DragGesture(minimumDistance: 30, coordinateSpace: .local)......


struct DetailScrollViewModifier: ViewModifier 
    init() 
        UIScrollView.appearance().isUserInteractionEnabled = false
        UIScrollView.appearance().isScrollEnabled = false
        
    

    func body(content: Content) -> some View 
        return content
       

非常感谢

【问题讨论】:

正如你所提到的, UIScrollView.appearance() 总是会影响应用中所有滚动视图的外观。如果您使用手势“滚动”网格,那么您不妨完全移除 ScrollView。 developer.apple.com/documentation/uikit/uiappearance 非常感谢您的回复。我正在使用滚动视图,因为在没有滚动视图的情况下通过偏移移动时,lazyhstack 似乎不会延迟加载 - 我正在使用延迟将昂贵的加载推迟到需要时。 【参考方案1】:

试试这个

ScrollView(.vertical, showsIndicators: false) 
   VStack 
      // Your Code
   

.onAppear 
    // set
    UIScrollView.appearance().isUserInteractionEnabled = false
    UIScrollView.appearance().isScrollEnabled = false

.onDisappear 
    // reset
    UIScrollView.appearance().isUserInteractionEnabled = true
    UIScrollView.appearance().isScrollEnabled = true   

【讨论】:

不工作...回到上一个视图 ScrollView 保持禁用状态 :(

以上是关于SwiftUI: ScrollView offset的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI - 淡出 ScrollView

SwiftUI:调整 ScrollView 的边界

SwiftUI:为啥这个 ScrollView 的内容错位了?

SwiftUI:在 ScrollView 中居中内容

SwiftUI - 如何获取 ScrollView 内容的大小(高度)

SwiftUI:奇怪的行为 ScrollView