# UIUserInterfaceLevel in SwiftUI

iOS 13 introduced a new interface environment trait called `UIUserInterfaceLevel`. It describes the visual level of the content indicating if the interface is `base` (equivalent to your window's main content) or `elevated`. Elevated describes content visually above your window's main content.

> Levels create a visual separation between different parts of your UI. Window content typically appears at the UIUserInterfaceLevel.base level. When you want parts of your UI to stand out from the underlying background, assign the UIUserInterfaceLevel.elevated level to them. For example, the system assigns the UIUserInterfaceLevel.elevated level to alerts and popovers.

In UIKit the level can be obtained through `UITraitCollection` and its instance property `userInterfaceLevel`.

```Swift
UITraitCollection.current.userInterfaceLevel
```

But where to look in SwiftUI to get this information?

A good start is looking in the environment (using the property wrapper `@Environment`). Certain traits can be read using an appropriate `EnvironmentValues` key path. For example, you can read the color scheme of the current view using the key path of the `colorScheme` property.

```Swift
@Environment(\.colorScheme) var colorScheme: ColorScheme
```

And then you can access the property in your view's body.

```Swift
if colorScheme == .dark { // Checks the wrapped value.
    DarkContent()
} else {
    LightContent()
}
```

The following key paths are available related to display characteristics.

- colorScheme
- colorSchemeContrast
- displayScale
- horizontalSizeClass
- imageScale
- pixelLength
- verticalSizeClass
- widgetFamily

Hmmn, nothing related to `UIUserInterfaceLevel`. Wait a minute. I see `isPresented` in a different section of the [documentation](https://developer.apple.com/documentation/swiftui/environmentvalues). `isPresented` is a boolean value that indicates whether the view associated with this environment is currently presented. 

Can `isPresented` be used instead? I guess so. The property returns true for views presented as modals or for alerts.

As a safe alternative, it is possible to provide a custom environment key/value to read and return the current `UIUserInterfaceLevel`. Let's define the custom `EnvironmentKey` and its `defaultValue` is a computed property reading from the current `UITraitCollection`.

```Swift
import UIKit

struct UserInterfaceLevel: EnvironmentKey {
    static var defaultValue: UIUserInterfaceLevel {
        return UITraitCollection.current.userInterfaceLevel
    }
}
```

A custom, computed property on `EnvironmentValues` is needed to return the `UIUserInterfaceLevel`.

```Swift
extension EnvironmentValues {
    var userInterfaceLevel: UIUserInterfaceLevel {
        get { self[UserInterfaceLevel.self] }
    }
}
```

Let's put it into a SwiftUI View

```Swift
struct LevelInfoText: View {
    @Environment(\.isPresented) private var isPresented
    @Environment(\.userInterfaceLevel) private var userInterfaceLevel

    var body: some View {
        VStack {
            Text(isPresented ? "Presented" : "Not presented")
            Text(userInterfaceLevel == .base ? "Base" : "Elevated")
        }
    }
}
```

And embed this view in another view with the capability to present itself as modal.

```
struct ContentView: View {

    @State private var showModal = false

    var body: some View {
        VStack {
            LevelInfoText()

            Button("Show modal") {
                self.showModal = true
            }
        }.sheet(isPresented: $showModal, onDismiss: {
            print(self.showModal)
        }) {
            ContentView()
        }
    }
}
```

![Example](https://cdn.hashnode.com/res/hashnode/image/upload/v1645145782689/7nyrbYVel.gif)

Either with the built-in `isPresented` or with a custom environment value you can now detect the user interface level.






