Date:

Share:

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 
  @EnvironmentBinding(ToggleValueKey.self)
  var enabled
   
  var body: some View 
    HStack 
      Toggle(isOn: $enabled) 
        Text("Toggle")
      
       
      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 
    .constant(self.defaultBoundValue)
  

Matching it is similar to EnvironmentKey.

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


extension EnvironmentValues 
  var toggle: Binding<Bool> 
    get 
      return self[ToggleValueKey.self]
    
    set 
      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.

@propertyWrapper
struct EnvironmentBinding<Key: EnvironmentBindingKey>: DynamicProperty 

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

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.

Source

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Popular Articles