Skip to content

Latest commit

 

History

History
143 lines (100 loc) · 8.31 KB

File metadata and controls

143 lines (100 loc) · 8.31 KB

Environments

Environment — одна из уникальных функций SwiftU (которой раньше не было в UIKit): набор environment values и environment objects, распространяемые через иерархию представлений.

Список встроенных environment

Многое из того, что мы делаем в 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;

Использование Environment

Рассмотрим, как можно использовать систему окружения SwiftUI для передачи различных частей состояния между двумя представлениями, которые не связаны друг с другом напрямую.

EnvironmentObject

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

Environment Value

Второй способ использования системы окружения 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)
        }
    }
}

Проблема с EnvironmentObject

Заметное различие между двумя вышеописанными подходами:

  • EnvironmentValue подход на основе key path требует от нас определения значения по умолчанию во время компиляции;
  • EnvironmentObject подход предполагает, что такое значение будет предоставлено во время выполнения (и неспособность сделать это приведет к сбою);

    Это ограничивает от повторного использования Subview без раздумий в любом контексте, на любом экране. EnvironmentObject инжектируется в место, которое получит этот объект окружения

ThemeEnvironmentObject


Значительным преимуществом использования Environment и отказа от передачи ObservableObject через метод init представления является внутреннее хранилище SwiftUI. SwiftUI хранит Environment в специальной памяти фреймворка за пределами представления. Это дает неявный доступ к Environment , специфичному для представления , для всех дочерних представлений.



TBD

!Прочитать про 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/ ::

1, 2, 3, 4, 5.

The power of Environment in SwiftUI