LostMoa – Adding an @EnvironmentBinding PropertyWrapper

Related Articles

Sometimes we have to go through a Binding As an environmental value. A common example of this is binding Used to control navigation, many nested controls and actions within your app will need to read and write to this mode to change what is displayed.

Right now, we can move on Bindings Into the environment however when we read them through @Environment(.keyPath) We end up with the value wrapped in Binding<Value> Type. It has some problems: First if this value binding Indicates changes The display may not be reworked, again to read / write to the value we need to use the exception pattern myValue.wrappedValue = ...

I would like to offer an alternative solution that allows us to create views using the same syntax as we were used to @Binding attribute.

Here’s an example of how you can use the offer @EnvironmentBinding(ToggleValueKey.self) Property cover.

struct ToggleView: View 
  var enabled
  var body: some View 
      Toggle(isOn: $enabled) 
      Button("Tap me") 
        enabled = true

Note that we can pass this on to other controls using the expected $ Prefix, and we can both read and write the value directly within the body.

Declaring an environmental value, exposing its BoundValue type.

To begin with, we are announcing a new protocol that expands the usual EnvironmentKey, We do this so we can extract the BoundValue Type included in Binding<BoundValue>.

protocol EnvironmentBindingKey: EnvironmentKey where Value == Binding<BoundValue> 
  associatedtype BoundValue
  static var path: KeyPath<EnvironmentValues, Value>  get 
  static var defaultBoundValue: BoundValue  get 

For information we can also announce an extension that provides the defaultValue Application required by EnvironmentKey.

extension EnvironmentBindingKey 
  static var defaultValue: Value 

Matching it is similar to EnvironmentKey.

struct ToggleValueKey: EnvironmentBindingKey 
  static var path: KeyPath<EnvironmentValues, Binding<Bool>> 
  static var defaultBoundValue: Bool 

extension EnvironmentValues 
  var toggle: Binding<Bool> 
      return self[ToggleValueKey.self]
      self[ToggleValueKey.self] = newValue

We define the ToggleValueKey Providing a defaultBoundValue And KeyPath For this use b EnvironmentValues. We also add the appropriate extension to EnvironmentValues To it KeyPath.

Creating the @EnvironmentBinding Property cover

This property wrap is a little more involved than part. But at its core, he extracts the Environment Value what @Environment And associates it not @Binding.

struct EnvironmentBinding<Key: EnvironmentBindingKey>: DynamicProperty 

  init(_ key: Key.Type) 
    self._value = Environment(key.path)
    self._wrappedValue = Key.defaultValue
  private var value: Binding<Key.BoundValue>
  var wrappedValue: Key.BoundValue
  var projectedValue: Binding<Key.BoundValue> 
  mutating func update() 
    self._wrappedValue = value

Important here is DynamicProperty A match that satisfies the update() method. It is called by SwiftUI before the display body is evaluated, at this point we can take the opportunity to update the @Binding An instance of the current value in environment.



Please enter your comment!
Please enter your name here

Popular Articles