0

Dans un projet iOS, je dois implémenter un contrôleur de vue qui permet de choisir une valeur flottante en utilisant un curseur et un champ de texte en même temps . il doit avoir le comportement suivant:Liaisons cycliques avec ReactiveCocoa, Comment lier une valeur à deux éléments d'interface utilisateur

  • chaque fois qu'un nombre est saisi dans le champ de texte, le curseur devrait mettre à jour sa valeur au numéro de flotteur tapé
  • chaque fois que le curseur est déplacé, il doit mettre à jour le champ de texte avec le curseur valeur

idées actuelles est la suivante:

J'ai deux propertys dans le modèle de vue, la valeur réelle et le texte de valeur. Chaque fois que la valeur est mise à jour, je mets à jour le texte dans le modèle de vue. Le champ de texte et le curseur modifient uniquement la valeur. Mais j'ai alors une sorte de dépendance 'cyclique': le champ de texte met à jour la valeur des modèles de vue, qui met à jour le texte des modèles de vue, lié au champ de texte où nous tapons simplement la valeur. Cela conduit à un comportement buggé du champ de texte. J'ai essayé de contourner la propriété isFirstResponder, cela fonctionne mieux, mais ne semble pas être la meilleure pratique, et ce n'est pas comme prévu. Est-il possible de lier la propriété enabledProperty du curseur à isFirstResponder du champ de texte? Cela fonctionne également

Manchettes en VC:

 layout.valueTextField.reactive.text <~ viewModel.valueText.map({ text in 
     if !self.layout.valueTextField.isFirstResponder { 
      return text 
     } 
     return self.layout.valueTextField.text ?? "" 
     } 
    ) 
    viewModel.value <~ layout.valueSlider.reactive.values 
    layout.valueSlider.reactive.value <~ viewModel.value 
    viewModel.value <~ layout.valueTextField.reactive.continuousTextValues.map({ textValue in 
     if let t = textValue { 
      if let parsed = Float(t) { 
       return parsed 
      } 
     } 
     return viewModel.value.value 
    }) 

Mon point de vue Modèle:

import ReactiveSwift 

class ValuePickerViewModel { 

var valueText: MutableProperty<String> 
var value: MutableProperty<Float> 
let minValue: Float 
let maxValue: Float 
let unit: String 

init(initialValue: Float, formatter: FloatFormatter, minValue: Float, maxValue: Float, unit: String) { 
    self.value = MutableProperty(initialValue) 
    self.valueText = MutableProperty(formatter.format(value: initialValue)) 
    self.valueText <~ self.value.map({value in 
     formatter.format(value: value) 
     } 
    ) 
    self.minValue = minValue 
    self.maxValue = maxValue 
    self.unit = unit 
} 

} 

Répondre

1

La solution est simple: La valeur TextFields se lie aux modèles de vue valeur flotter. La valeur des diapositives est liée à la valeur du texte des modèles de vue. Ainsi chaque composant met à jour l'autre, et il n'y a pas de cycle!

Code de travail:

Bindings:

viewModel.value <~ layout.valueTextField.reactive.continuousTextValues.map({ textValue in 
     if let t = textValue { 
      if let parsed = Float(t) { 
       return parsed 
      } 
     } 
    return viewModel.value.value 
    }) 
    viewModel.valueText <~ layout.valueSlider.reactive.values.map({ value in 
     return viewModel.formatter.format(value: value) 
    }) 
    layout.valueSlider.reactive.value <~ viewModel.value 
    layout.valueTextField.reactive.text <~ viewModel.valueText 

ViewModel:

import ReactiveSwift 

class ValuePickerViewModel { 

var valueText: MutableProperty<String> 
var value: MutableProperty<Float> 
let minValue: Float 
let maxValue: Float 
let unit: String 
let formatter: FloatFormatter 

init(initialValue: Float, formatter: FloatFormatter, minValue: Float, maxValue: Float, unit: String) { 
    self.formatter = formatter 
    self.value = MutableProperty(initialValue) 
    self.valueText = MutableProperty(formatter.format(value: initialValue)) 
    self.minValue = minValue 
    self.maxValue = maxValue 
    self.unit = unit 
} 

}