TGViewer
Мобильный трудоголик Мобильный трудоголик @hardworkerit · 1.65K subscribers
Post #444 1.03K
🔢 От ScrollViewReader до ScrollPosition - как изменилась программная прокрутка в SwiftUI.

До iOS 17 программный скролл в SwiftUI требовал использования ScrollViewReader. Этот контейнер давал доступ к ScrollViewProxy с единственным методом scrollTo(_:anchor:). API было односторонним: можно было задать позицию, но нельзя было прочитать, где находится пользователь. Скролл к краю или к конкретному оффсету тоже был проблемой - приходилось ставить якорные вью на границах контента.

Начиная с iOS 17, SwiftUI начал менять подход. scrollPosition(id:anchor:) заменил прокси-подход на привязку к состоянию. А iOS 18 добавил еще больше возможностей.


Как задать начальную позицию:

По умолчанию ScrollView показывает верхнюю часть контента. defaultScrollAnchor(_:), появившийся в iOS 17, позволяет изменить это поведение. Типичный пример - чат, где контент должен начинаться снизу.


ScrollView {
LazyVStack {
ForEach(messages) { message in
MessageView(message: message)
}
}
}
.defaultScrollAnchor(.bottom)


В iOS 18 появилась более точная перегрузка defaultScrollAnchor(_:for:), которая принимает ScrollAnchorRole. Например, роль alignment позволяет центрировать небольшой контент, сохраняя нижнюю привязку для длинных списков.


Программный скролл через scrollPosition:

iOS 17 добавил scrollPosition(id:anchor:) для управления скроллом через привязку к состоянию. iOS 18 расширил API: появился scrollPosition(_:anchor:) с привязкой к ScrollPosition. Это структура, которая может хранить позицию как идентификатор, край или сырой оффсет.

Пример: кнопка для перехода к последнему сообщению в чате. Объявляем ScrollPosition, передаем в модификатор и вызываем scrollTo(id:) при нажатии.


struct ChatView: View {
let messages: [Message]
@State private var position = ScrollPosition()

var body: some View {
ScrollView {
LazyVStack {
ForEach(messages) { message in
MessageView(message: message)
.id(message.id)
}
}
}
.defaultScrollAnchor(.bottom)
.scrollPosition($position)
.onAppear {
position = ScrollPosition(id: messages.last?.id)
}
.safeAreaBar(edge: .bottom) {
Button {
withAnimation {
position.scrollTo(id: messages.last?.id)
}
} label: {
Text("Перейти к последнему")
}
}
}
}



🔗 Читать подробнее


💡 Вывод:

SwiftUI прошел путь от ScrollViewReader с односторонним управлением до гибкого API с двусторонней связью. Теперь можно не только двигать скролл, но и читать его состояние.

Ключевые инструменты: defaultScrollAnchor для начальной позиции, scrollPosition для управления и чтения, onScrollGeometryChange для отслеживания геометрии.

API мощные, но с нюансами. viewID - единственный способ читать позицию при ручной прокрутке. edge, point, x и y работают только для программно установленных значений. Понимание этих различий помогает строить интерфейсы, которые естественно реагируют на действия пользователя.


Подписаться на канал:
➡️ Telegram | Max
  • 👍 13
  • 🔥 7
  • ❤ 2
  • 👀 1
  • 🤝 1
More from @hardworkerit
  1. Sep 29, 2026🔢 Управление тулбарами на iPhone Duo. На iPhone Duo элементы управления навигацией, дейст…
  2. Sep 27, 2026🔢 Новые возможности Hashable в Swift 6.4 В Swift 6.4 добавили Hashable для нескольких тип…
  3. Sep 25, 2026🔢 Приватные свойства больше не ломают memberwise инициализатор в Swift 6.4 Swift автомати…
  4. Sep 24, 2026👨‍💻 Почему разработчики ненавидят своих менеджеров. Всем привет! Сегодня хочу разобрать…
  5. Sep 22, 2026🔢 Релиз Swift 6.4: главные изменения для разработчиков. Swift 6.4 вышел. Это обновление п…
  6. Sep 20, 2026📱 Официальный симулятор iPhone Duo уже доступен в Xcode 27.1 В бета-версии Xcode 27.1 поя…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →