Это сложнее, чем должно быть
Выпуск iOS 15 принес некоторые столь необходимые улучшения в SwiftUI. Теперь у нас есть встроенные панели поиска и даже поддержка уценки для текстовых представлений.
Но каким-то образом SwiftUI ScrollView
все еще немного глючит. Этот парень из Reddit выразился очень красиво:
Что-то вроде изменения цвета фона SwiftUI ScrollView
по-прежнему представляет собой довольно сложную задачу. Интуитивно понятно, что нужно использовать модификатор .background
непосредственно на ScrollView
, например:
ScrollView { Text(“Hello, World”) } .background(Color.purple)
Я обнаружил, что это работает в определенных обстоятельствах, с некоторыми оговорками.
- Ваш
ScrollView
должен находиться непосредственно внутриNavigationView
(без навигации) - Ваш
ScrollViews
контент должен масштабироваться по горизонтали, используяHStack
сSpacers
, чтобы заставитьScrollView
заполнить всю ширину экрана (или установить его рамку вручную).
Если какое-либо из этих предостережений не будет выполнено, вы получите нежелательное поведение.
Либо ваш ScrollView
отображается посередине с цветом, отличным от фона фактического вида (менее проблематично), либо если вы не поместите свой ScrollView
напрямуюв NavigationView
, ScrollView
не будет автоматически сворачивать панель навигации. — она идет под ним — как будто панель навигации прозрачная.
Определенно не идеальное решение!
В моем собственном примере использования я обнаружил, что использую ScrollView
внутри экрана сведений (переход к нему осуществляется с другого экрана).
Это означает, что у меня не было возможности использовать другой NavigationView
вокруг ScrollView
(см. предостережение 2). И обертывание моего ScrollView
двумя слоями NavigationViews
(и, может быть, скрытие одного?) просто не кричит мне о стабильности.
Если вы гуглили эти проблемы так же долго, как и я, вы, вероятно, сталкивались с решениями, использующими модификатор appearance()
.
Обычно что-то вроде ниже, когда я хотел, чтобы мой фон ScrollViews
был изменен на розовый:
UIScrollView.appearance().backgroundColor = UIColor.systemPink
При первом осмотре все работает отлично. Вы получаете именно то поведение, которое ожидаете от UIKit ScrollView
. Панель навигации схлопывается и все хорошо…
Пока вы не попытаетесь использовать TextField
. При редактировании TextField
цвет фона вашего TextField
меняется на цвет вашего ScrollView
. Вы можете увидеть пример того, как это происходит ниже (справа):
Почему, черт возьми, это происходит? Не имею представления. Использование модификатора appearance()
вызывает неодобрение, но это единственный способ заставить некоторые вещи работать в SwiftUI.
Несмотря на это, нет никакого смысла в том, что он также должен менять цвет совершенно не связанных между собой компонентов.
Использование модификатора appearance()
изменяет оба цвета фона TextFields
(при их редактировании), а также (каким-то образом) область автозамены клавиатуры. Я предполагаю, что это как-то связано с каким-то волшебным вуду SwiftUI.
Мы приближаемся, но на самом деле это не решение, если вам нужно сломать каждое текстовое поле в вашем приложении, чтобы оно заработало.
После целой кучи возни и испытаний я нашел модификатор appearance()
, который, кажется, содержит урон.
Фактически вы можете указать условия для модификаторов appearance
. Это полезно для UIKit, потому что вы можете указать контроллеры представления, где вы хотите применить стили. Вы также можете указать UITraitCollection
, чтобы отфильтровать, где стили применяются еще дальше.
Путем проб и ошибок я нашел комбинацию, которая работает очень хорошо:
В этом есть две части:
Во-первых, мы указываем userInterfaceLevel
для применения только к областям, где уровень интерфейса считается base
.
Документы Apple говорят, что это в основном только ваш основной контент Windows. Также есть значение elevated
, которое, как я могу предположить, равно Alerts
или Sheets
.
Затем мы указываем свойство whenContainedInInstancesOf
как:
...whenContainedInInstancesOf: [UINavigationController.self]...
Сочетание этих условий останавливает модификатор ScrollView appearance()
, ломающий наш TextFields
и наши клавиатуры.
Указание свойства whenContainedInInstancesOf
фиксирует цвет автоисправления клавиатуры на серый по умолчанию. Я предполагаю, что это связано с тем, что клавиатура не содержится в навигационном контроллере, поскольку она не является частью нашего приложения (она представлена iOS).
И затем, указание userInterfaceLevel
исправляет фон TextField
. Я не уверен, почему это так. Можно подумать, что любое представление в вашем приложении можно рассматривать как уровень пользовательского интерфейса base
. Возможно, та часть TextField
, которая меняет цвет фона, считается elevated
.
Один неприятный побочный эффект заключается в том, что это изменит цвет каждого ScrollView
везде в вашем приложении. Но если у вас одинаковый стиль в вашем приложении, то это решение может быть именно тем, что вы ищете.
Чтобы использовать его, поместите модификатор внешнего вида в свой корневой вид или, если вы хотите сохранить его отдельно, вы можете использовать вспомогательный вид, подобный тому, который я сделал.
Надеюсь, эта статья помогла вам сориентироваться в хитром и коварном мире SwiftUI. Будем надеяться, что в iOS 16 ситуация улучшится (постучим по дереву).
Спасибо за прочтение.
Want to Connect With the Author? Give me a follow on Twitter to see what I’m working on.