Environment — одна из уникальных функций SwiftU (которой раньше не было в UIKit): набор environment values и environment objects, распространяемые через иерархию представлений.
Многое из того, что мы делаем в SwiftUI, влияет на среду. Несколько примеров environment values/environment objects:
- View-specific values: для стилей представлений (Button styles, Customize TextFields, Custom SwiftUI view styles);
- Actions: OpenURLAction, TriggerSubmitAction, DismissAction, DismissAction, RefreshAction, ResetFocusAction;
- AppDelegate и SceneDelegate
- Generic component values: controlSize, isEnabled, isFocused, redactionReasons
- Display values: calendar, dynamicTypeSize, displayScale, horizontalSizeClass, layoutDirection, locale, pixelLength, timeZone, verticalSizeClass;
- SF Symbols: imageScale, symbolVariants, symbolRenderingMode;
- Search: isSearching,dismissSearch;
- Keyboard shortcuts: keyboardShortcut;
- Text: lineLimit, minimumScaleFactor, textCase, disableAutocorrection, font, legibilityWeight, multilineTextAlignment, truncationMode, lineSpacing, allowsTightening;
- Accessibility: accessibilityEnabled, accessibilityDifferentiateWithoutColor, accessibilityReduceTransparency, accessibilityReduceMotion, accessibilityInvertColors, accessibilityShowButtonShapes, accessibilityVoiceOverEnabled, accessibilitySwitchControlEnabled;
- Presentation: dismiss, isPresented, scenePhase;
- Colors/Themes: colorScheme, colorSchemeContrast, backgroundMaterial;
- Not associated with any view: managedObjectContext, undoManager;
Рассмотрим, как можно использовать систему окружения SwiftUI для передачи различных частей состояния между двумя представлениями, которые не связаны друг с другом напрямую.
struct RootView: View {
@ObservedObject var theme: Theme
var body: some View {
ArticleListView(articles: articles)
.environmentObject(theme)
}
}
Хотя создать привязки между родительским представлением и одним из его дочерних представлений легко, но проблемно передавать определенный объект или значение в пределах всей иерархии представлений — и та проблема, которую решает environment среда:
struct ArticleView: View {
@EnvironmentObject var themeEnvironmentObject: Theme
var article: Article
var body: some View {
VStack(alignment: .leading) {
Text(article.title)
.foregroundColor(themeEnvironmentObject.titleTextColor)
Text(article.body)
.foregroundColor(themeEnvironmentObject.bodyTextColor)
}
}
}
Теперь все view внутри могут обращаться к theme по @EnvironmentObject:
RootView
└── ArticleListView
└── ArticleView
Второй способ использования системы окружения SwiftUI — определение пользовательского типа EnvironmentKey
struct ThemeEnvironmentKey: EnvironmentKey {
static var defaultValue = Theme.default
}
extension EnvironmentValues {
var theme: Theme {
get { self[ThemeEnvironmentKey.self] }
set { self[ThemeEnvironmentKey.self] = newValue }
}
}
После выполнения вышеизложенного мы теперь можем пометить themeсвойство нашего представления, используя Environment
обертку свойства (а не EnvironmentObject
), и передать key path к ключу среды, для которого мы хотим получить значение:
struct ArticleView: View {
@EnvironmentObject var themeEnvironmentObject: Theme
@Environment(\.theme) var themeEnvironmentValue
var article: Article
var body: some View {
VStack(alignment: .leading) {
Text(article.title)
.foregroundColor(themeEnvironmentObject.titleTextColor)
.foregroundColor(themeEnvironmentValue.titleTextColor)
Text(article.body)
.foregroundColor(themeEnvironmentObject.bodyTextColor)
.foregroundColor(themeEnvironmentValue.bodyTextColor)
}
}
}
Заметное различие между двумя вышеописанными подходами:
- EnvironmentValue подход на основе key path требует от нас определения значения по умолчанию во время компиляции;
- EnvironmentObject подход предполагает, что такое значение будет предоставлено во время выполнения (и неспособность сделать это приведет к сбою);
Это ограничивает от повторного использования Subview без раздумий в любом контексте, на любом экране. EnvironmentObject инжектируется в место, которое получит этот объект окружения
Значительным преимуществом использования Environment и отказа от передачи ObservableObject через метод init представления является внутреннее хранилище SwiftUI. SwiftUI хранит Environment в специальной памяти фреймворка за пределами представления. Это дает неявный доступ к Environment , специфичному для представления , для всех дочерних представлений.
!Прочитать про keyPath: https://www.swiftbysundell.com/articles/the-power-of-key-paths-in-swift/
!Прочитать про что выбрать Observed/Environment: https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views
!The SwiftUI Environment: https://www.fivestars.blog/articles/swiftui-environment-propagation/
!Добавить пункты когда про Environments буду писать: https://useyourloaf.com/blog/swiftui-custom-environment-values/
+++ https://www.fivestars.blog/articles/custom-environment-values-cheatsheet/ ::
The power of Environment in SwiftUI