HowTo —— SwiftUI2.0 使用 ScrollViewReader 定位滚动位置

SwiftUI2.0 增加了滚动定位功能,已经可以较轻松的适应大多数场景的应用。实现手段完全不同于之前民间的各种解决方案,并不是通过设置具体的 offset 来进行定位,而是使用 id 来进行位置标记。

健康笔记是我开发的一个iOS app,主要服务于有长期健康管理需求的人士。可为全家不同成员创建各自的笔记,允许使用者自定义数据类型以记录各种健康数据。

推广

基本用法——实现从右向左滚动

struct ScrollReaderTest: View {
    var body: some View {
        ScrollView(.horizontal) {
            //类似 GeometryReader 的使用方式,设定滚动定位区域
            ScrollViewReader{ proxy in
                Rectangle()
                    .fill(LinearGradient(
                      gradient: Gradient(colors: [.blue,.red]),
                      startPoint: .leading,
                      endPoint: .trailing))
                    .frame(width: 1000, height: 300, alignment: .center)
                    .id("rec") //为 ScrollView 中需要定位的 View 设置 id
                    .onAppear {
                        //滚动到指定 id 的位置,按照 anchor 的设置来对齐
                        proxy.scrollTo("rec",anchor:.trailing)
                  }
            }
        }
    }
}

通过按钮来滚动到指定位置

import SwiftUI

struct ScrollReadeTest: View {
    private var list = ScrollItem.items(300)
    @State private var position:Int = 0
    var body: some View {
      NavigationView{
        ScrollView{
            ScrollViewReader{ proxy in
                LazyVStack{
                    ForEach(list,id:\.id){ item in
                        Text(item.title).id(item.id)
                    }
                }
                .onChange(of: position) { positon in
                    switch position{
                    case 1: 
                        let id = list.first!.id
                        withAnimation(Animation.easeInOut){
                            proxy.scrollTo(id,anchor:.top)
                        }
                    case 2:
                        
                        let id = list[Int(list.count / 2)].id
                        withAnimation(Animation.easeInOut){
                            proxy.scrollTo(id,anchor:.center)
                        }
                    case 3:
                        let id = list.last!.id
                        withAnimation(Animation.easeInOut){
                            proxy.scrollTo(id,anchor:.bottom)
                        }
                    default:
                        break
                    }
                }
            }
        }
        .navigationTitle("滚动定位")
        
        .toolbar {
            ToolbarItem(placement:.automatic) {
                HStack{
                    Button("top"){
                        position = 1
                    }
                    Button("mid"){
                        position = 2
                    }
                    Button("end"){
                        position = 3
                    }
                }
            }
         }
      }
   }
}

struct ScrollItem:Identifiable{
    var id = UUID()
    var title:String
    
    static func items(_ count:Int) -> [ScrollItem]{
        var result:[ScrollItem] = []
        for i in 0..<count{
            result.append(ScrollItem(title:String("index:\(i) title:\(Int.random(in: 1000...5000))")))
        }
        return result
    }
}

遗憾

没有简单的手段记录当前的滚动位置。

本博客所有文章除特别声明外,均采用CC 4.0许可协议。转载请注明出处和作者。

关注微信公共号肘子的Swift记事本或在推特上关注@fatbobman,永远不会错过新内容! 您的支持和鼓励将为我的博客写作增添更多的动力! 如果您或身边的朋友有健康数据管理的需求,请使用我开发的app【健康笔记】,正是因为它我才创建了这个博客。

关注