Вызов scrollTo ScrollView из Observer или внешнего представления

#swiftui

#swiftui

Вопрос:

Я пытаюсь сбросить свой ScrollView, когда пользователь выбирает вкладку. Проблема в том, что все учебные пособия предназначены для кнопок, вложенных внутри ScrollView. Мой ScrollView полностью отделен от того места, где мне нужно нажать, чтобы сбросить ScrollView.

Я нашел этот учебник — https://www.hackingwithswift.com/forums/swiftui/have-a-button-outside-of-scrollviewreader-be-able-to-scroll-the-scrollview-to-a-position/2741

Тем не менее, я получаю сообщение об ошибке «Не удается найти прокси в области видимости».

    @EnvironmentObject var global: GlobalObserver    
   return ScrollView {
          ScrollViewReader { (proxy: ScrollViewProxy) in
             EmptyView()
          }.onChange(of: self.global.resetScroll){ resetScroll in
                if (resetScroll){
                    proxy.scrollTo(0)
                    self.global.resetScroll = false
                }
            }
 

Если кто-нибудь знает более простую реализацию для установки положения ScrollView вне представления, я был бы рад это услышать.

Ответ №1:

Адаптируя пример из ссылки в вопросе, ваш код может выглядеть следующим образом:

 struct ContentView: View {
    @State private var scrollTarget: Int?

    var body: some View {
        Button("Reset") {
            scrollTarget = 0
        }
        ScrollViewReader { proxy in
            ScrollView {
                VStack {
                    ForEach(0...50, id: .self) {
                        Text("($0)")
                    }
                }
            }
            .onChange(of: scrollTarget) { target in
                if let target = target {
                    scrollTarget = nil
                    withAnimation {
                        proxy.scrollTo(target)
                    }
                }
            }
        }
    }
}
 

При необходимости вы можете перейти scrollTarget к ObservableObject и вызвать его из-за пределов представления:

 class GlobalObserver: ObservableObject {
    @Published var scrollTarget: Int?
}

struct ContentView: View {
    @EnvironmentObject var global: GlobalObserver

    var body: some View {
        ScrollViewReader { proxy in
            ScrollView {
                VStack {
                    ForEach(0...50, id: .self) {
                        Text("($0)")
                    }
                }
            }
            .onChange(of: global.scrollTarget) { target in
                if let target = target {
                    global.scrollTarget = nil
                    withAnimation {
                        proxy.scrollTo(target)
                    }
                }
            }
        }
    }
}
 

Комментарии:

1. В конечном счете мне нужно было поменять местами ScollView и ScrollViewReader, что вызывало мою первоначальную проблему, но это идеальная реализация. Я отмечу это правильно, чтобы кто-то другой мог решить эту проблему намного быстрее, чем я. Очень признателен