SwiftUI,如何滚动到顶部?

mrphzbgm  于 2022-12-22  发布在  Swift
关注(0)|答案(6)|浏览(456)

我正在使用ScrollView,当我执行任何操作(如单击按钮等)时,是否可以将视图滚动到顶部?

vwhgwdsa

vwhgwdsa1#

我认为目前最好的方法是使用View的id函数
1.声明一个具有唯一ID的状态变量

@State private var scrollViewID = UUID()

1.然后将id函数添加到ScrollView

ScrollView(.horizontal, showsIndicators: true) {
// ...
}.id(self.scrollViewID)

无论何时更改该id(例如在按钮事件中),滚动视图都将从头重新构建,这就像滚动到顶部一样

kfgdxczn

kfgdxczn2#

在刚刚发布的ScrollViewProxy中。
一个代理值,允许以编程方式滚动视图层次结构中的可滚动视图。-https://developer.apple.com/documentation/swiftui/scrollviewproxy
Xcode 12.0 beta (12A6159)

mdfafbf1

mdfafbf13#

从iOS 14开始,也许更早。

struct Example: View {

    private static let topId = "topIdHere"

    /*
      Use only for toggling, binding for external access or @State for internal access
    */
    @Binding var shouldScrollToTop: Bool = false 

    var body: some View {

        ScrollViewReader { reader in  // read scroll position and scroll to
            ScrollView { 
                VStack {
                   TopView() // << first view on top
                    .id(Self.topId) // << assigned id (use for scroll)
                }
                .onChange(shouldScrollToTop) { _ in 
                    withAnimation {  // add animation for scroll to top
                       reader.scrollTo(Self.topId, anchor: .top) // scroll
                    }
                }
            }
        }
    }
}

是这样吗?)

ix0qys7i

ix0qys7i4#

有一个变通方案可以通过在显示新内容之前隐藏所有内容来实现ScrollToTop()效果。

@State var hideEverything = false

var body: some View {
  ScrollView {
    if hideEverything {
      EmptyView()
    } else {
      // your content view
    }
  }
}

func ScrollToTop() {
  self.hideEverything = true
  DispatchQueue.main.asyncAfter(deadline: .now() + 0.01)  
  {  
    self.data = ... // update data source
    self.hideEverything = false
  }
}
avkwfej4

avkwfej45#

滚动到顶部的简单方法:

struct ScrollerToTop: View {
    let reader: ScrollViewProxy
    @Binding var scrollOnChange: Bool
    
    var body: some View {
        EmptyView()
            .id("topScrollPoint")
            .onChange(of: scrollOnChange) { _ in
                withAnimation {
                    reader.scrollTo("topScrollPoint", anchor: .bottom)
                }
            }
    }
}

用法:

ScrollViewReader { reader in
   ScrollView { 
       ScrollerToTop(reader: reader, scrollOnChange: $model.scrollToTopVar)

       VStack {
            //Some Views
       }
    }
}

更改发布的布尔值"model. scrollToTopVar"时,ScrollView将滚动到顶部:)

zdwk9cvp

zdwk9cvp6#

使用this解决方案(之前简化),我做了一个例子,当按下按钮时,将ScrollView.content.offset严格移动到顶部:

struct ScrollToTheTop: View {

    @State private var verticalOffset: CGFloat = 0.0
    @State private var gestureOffset: CGFloat = 0.0
    @State private var itemCount: Int = 200

    var body: some View {

        NavigationView {
            VStack {

                ScrollView(.vertical, showsIndicators: false) {

                    VStack {

                        ForEach(1...itemCount, id: \.self) { item in
                            Text("--- \(item) ---") // height 17.5
                        }

                    }

                }
                .content.offset(y: (self.verticalOffset + self.gestureOffset)
                    // all the content divided by 2 for zero position of scroll view
                    + CGFloat(17.5 * Double(self.itemCount/2)))
                    .gesture(DragGesture().onChanged( { value in
                        self.gestureOffset = value.translation.height
                    }).onEnded( { value in
                        withAnimation {
                            // here should calculate end position with value.predictedEndLocation.y
                            self.verticalOffset += value.translation.height
                            self.gestureOffset = 0.0
                        }
                    }))

            }.navigationBarItems(trailing: Button("To top!") {
                withAnimation {
                    self.verticalOffset = 0.0
                }
            })
        }

    }

}

如果这个例子合适,您必须改进DragGesture

相关问题