Как получить горизонтальный ScrollView в SwiftUI для автоматической прокрутки до конца при обновлении заключенного текста

Я пишу приложение SwiftUI для iOS, где мне нужен view для автоматической прокрутки до конца содержимого при его обновлении. Обновление происходит с модели. Чтобы не усложнять этот вопрос деталями моего приложения, я создал простой сценарий, в котором у меня есть два текстовых поля и текстовая метка. Любой текст, введенный в текстовые поля, объединяется и отображается в текстовой метке. Текстовая метка заключена по горизонтали и может быть прокручена вручную, если текст длиннее ширины экрана. Я хочу добиться автоматической прокрутки текста до конца при каждом обновлении метки.

Вот простой код модели:

      class Model: ObservableObject {
    var firstString = "" {
        didSet { combinedString = "\(firstString). \(secondString)." }
    }
    
    var secondString = "" {
        didSet { combinedString = "\(firstString). \(secondString)." }
    }
    
    @Published var combinedString = ""
}

Это ContentView:

      struct ContentView: View {
    @ObservedObject var model: Model
    
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            TextField("First string: ", text: $model.firstString)
            TextField("Second string: ", text: $model.secondString)
            Spacer().frame(height: 20)
            Text("Combined string:")
            ScrollView(.horizontal) {
                Text(model.combinedString)
            }
        }
    }
}

Из проведенного мною исследования единственный способ, который я нашел для прокрутки до конца текста, без необходимости делать это вручную, - это добавить кнопку в представление, в результате чего текст в метке прокручивается до конца. .

Вот выше встроен в , с кнопкой для выполнения действия прокрутки.

      ScrollViewReader { scrollView in
    VStack {
        ScrollView(.horizontal) {
            Text(model.combinedString)
                .id("combinedText")
        }
        Button("Scroll to end") {
            withAnimation {
                scrollView.scrollTo("combinedText", anchor: .trailing)
            }
        }
        .padding()
        .foregroundColor(.white)
        .background(Color.black)
    }
}

Это работает при условии, что намерение состоит в том, чтобы использовать кнопку для выполнения действия прокрутки.

Мой вопрос: может ли описанное выше действие прокрутки запускаться всякий раз, когда модель обновляется, без необходимости нажимать кнопку.

Мы будем очень благодарны за любую помощь или указатели.

Спасибо.

2 ответа

Я предполагаю, что вы хотели этого:

      ScrollViewReader { scrollView in
    VStack {
        ScrollView(.horizontal) {
            Text(model.combinedString)
                .id("combinedText")
        }
        .onChange(of: model.combinedString) {     // << here !!
            withAnimation {
                scrollView.scrollTo("combinedText", anchor: .trailing)
            }
        }
    }
}

ScrollViewReader — это решение, которое вы ищете. Возможно, вам придется поиграть со значением. Также вам нужно будет добавить .id(0)модификатор для вашего textview.

      ScrollView {
    ScrollViewReader { reader in 
        Button("Go to first then anchor trailing.") {
                    value.scrollTo(0, anchor: .trailing)
                }
      // The rest of your code .......
Другие вопросы по тегам