この記事では、@Environmentの使い方について徹底解説していきたいと思います。
Contents
@Environmentとは
@Environmentとは、簡単いうと、その端末の状態や、Viewの状態を読み取れるカスタム属性です。
例えば、その端末がダークモードなのかライトモードなのか、その端末のピクセル数はどのくらいなのか、その端末の文字の大きさの設定はどのくらいなのか、その端末はモーダルを開いている状態なのかどうかなど、その端末やViewの状態が取得できます。
この@Environmentは自作することもできます。
使い方
では、使い方について解説していきたいと思います。@Environmentは色々な使い方があるので、よく使うものや重要なものを紹介していきたいと思います。
ダークモードかライトモードか判定
以下のように、@Environmentで\.colorScheme
と記載することで、ダークモードかライトモードかの判定が取得できます。
@Environment(\.colorScheme) var colorScheme: ColorScheme
struct ContentView: View { @Environment(\.colorScheme) var colorScheme: ColorScheme var body: some View { if colorScheme == .dark { Text("dark mode") } else if colorScheme == .light { Text("light mode") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() // .preferredColorScheme(.dark) } }
ちなみに、プレビュー部分の.preferredColorScheme(.dark)
をコメントアウト解除すると端末がダークモードになります。
モーダルを閉じる
これはよく使うと思います。
struct ContentView: View { @State var isShowNextView = false var body: some View { VStack { Text("Hello, world!") .padding() Button("NextViewへ") { isShowNextView = true } .sheet(isPresented: $isShowNextView) { NextView() } } } } struct NextView: View { @Environment(\.dismiss) var dismiss var body: some View { VStack { Text("BView") .padding() Button("閉じる") { dismiss() } } } }
iOS14以前では、@Environment(\.dismiss) var dismiss
という@Environmentはなく以下のような書き方をしていました。こちらの書き方は、iOS15以降、非推奨になっていますので、上記の書き方で書くようにしてください。
struct NextView: View { @Environment(\.presentationMode) var presentationMode var body: some View { VStack { Text("BView") .padding() Button("閉じる") { presentationMode.wrappedValue.dismiss() } } } }
モーダルを開いているかどうかの判定
struct ContentView: View { @Environment(\.isPresented) var isPresented @Environment(\.dismiss) var dismiss @State var isShowModalView = false var body: some View { if !isPresented { VStack { Button("モーダル遷移") { isShowModalView = true } .sheet(isPresented: $isShowModalView) { ContentView() } } } else { VStack { Button("閉じる") { dismiss() } } } } }
こちらもdismiss
と同じように、iOS14以前では、@Environment(\.presentationMode) var presentationMode
という@Environmentで、presentationMode.wrappedValue.isPresented
という書き方をしていました。この書き方は、iOS15以降、非推奨になっているので上記の書き方で書いてください。
@Environmentで使える値一覧
上記で紹介した@Environment以外にもたくさんあります。紹介しきれないほどあるので、詳しくはAppleの公式サイトをご確認ください。
- accessibilityDifferentiateWithoutColor: Bool
- accessibilityEnabled: Bool
- accessibilityInvertColors: Bool
- accessibilityReduceMotion: Bool
- accessibilityReduceTransparency: Bool
- accessibilityShowButtonShapes: Bool
- legibilityWeight: LegibilityWeight?
- colorScheme:ColorScheme
- colorSchemeContrast:ColorSchemeContrast
- controlSize:ControlSize
- controlProminence: Prominence
- controlActiveState: ControlActiveState
- defaultWheelPickerItemHeight: CGFloat
- headerProminence: Prominence
- isEnabled: Bool
- menuIndicatorVisibility: Visibility
- managedObjectContext: NSManagedObjectContext
- calendar: Calendar
- locale: Locale
- timeZone: TimeZone
- displayScale: CGFloat
- imageScale: Image.Scale
- pixelLength: CGFloat
- isLuminanceReduced: Bool
- editMode: Binding?
- isFocused: Bool
- resetFocus: ResetFocusAction
- keyboardShortcut: KeyboardShortcut?
- defaultMinListHeaderHeight: CGFloat?
- defaultMinListRowHeight: CGFloat
- backgroundMaterial: Material?
- isPresented: Bool
- dismiss: DismissAction
- redactionReasons: RedactionReasons
- refresh: RefreshAction?
- scenePhase: ScenePhase
- isSearching: Bool
- dismissSearch: DismissSearchAction
- horizontalSizeClass: UserInterfaceSizeClass?
- verticalSizeClass: UserInterfaceSizeClass?
- symbolRenderingMode: SymbolRenderingMode?
- symbolVariants: SymbolVariants
- allowsTightening: Bool
- disableAutocorrection: Bool?
- dynamicTypeSize: DynamicTypeSize
- font: Font?
- layoutDirection: LayoutDirection
- lineLimit: Int?
- lineSpacing: CGFloat
- minimumScaleFactor: CGFloat
- multilineTextAlignment: TextAlignment
- textCase: Text.Case?
- truncationMode: Text.TruncationMode
- undoManager: UndoManager?
- openURL: OpenURLAction
- widgetFamily: WidgetFamily
- description: String
@Environmentを自作する方法
@Environmentは自作することができます。
あまり自作をしてまで使う機会はないと思いますが、意外と簡単なので紹介しておきます。
struct ContentView: View { @Environment(\.mainColor) var mainColor var body: some View { Text("Hello, world!") .padding() .background(mainColor) } } struct MainColorKey: EnvironmentKey { static let defaultValue: Color = .orange } extension EnvironmentValues { var mainColor: Color { get { self[MainColorKey.self] } set { self[MainColorKey.self] = newValue } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() // .environment(\.mainColor, .red) } }
まずは、structでKeyを作ります。
struct MainColorKey: EnvironmentKey { static let defaultValue: Color = .orange }
このdefaultValue
に入れる値がデフォルト値になります。
次に、extensionでEnvironmentValuesに値を追加します。
extension EnvironmentValues { var mainColor: Color { get { self[MainColorKey.self] } set { self[MainColorKey.self] = newValue } } }
たったこれで、@Environmentの自作ができましたので、あとは通常通り上記の@Environmentと同じように使えます。
まとめ
まとめると、@Environmentというのは、その端末の状態や、Viewの状態を読み取れるカスタム属性です。たくさんの環境変数があるので何が読み取れるのかを一度全て確認しておいた方が良いかと思います。
参考文献