Swift 2 RAC4 合并 UITextField 信号和 UISwitch 信号
Swift 2 RAC4 Merge UITextField Signal and UISwitch Signal
我已经编写了代码的反应命令式版本:
widthTextField.rac_textSignal().subscribeNext { (val) in
let multiplier = 0.2
if var v = Double(val as! String){
if(self.viewModel.proportionalBool.value){
v *= multiplier
self.heightTextField.text = String(v)
}
}
}
我的 ViewModel 中有三个 MutableProperties:Bool 类型的 proportionalBool、heightString 和 String 类型的 widthString。
我的 ViewController.
中也有对应的 UISwitch 和两个 UITextField
我想学习的是以下场景:
1. 如果 bool/switch 为 false,则 heightString 应该保持不变
2. 如果 bool 为真,则 heightString 的值应为: widthString * multiplier
我知道我写的代码很糟糕。我想我应该使用 combineLatest 但我不知道如何将两个信号:UITextField 和 UISwitch 合并为一个生成信号。
谁能给我任何提示或简单的代码示例?
let boolSignal = proportionalSwitch.rac_newOnChannel()
let widthSignal = widthTextField.rac_textSignal()
let heightSignal = heightTextField.rac_textSignal()
...?
我假设您总是希望 ViewModel 中的 MutableProperties 始终具有正确的值。
此外,我将使用 REX (which will soon be a part of RAC anyway) 来实现更简单的 UI 绑定。
假设这是您的 viewModel:
final class ViewModel {
let on = MutableProperty<Bool>(false)
let width = MutableProperty<Double>(0.0)
let height = MutableProperty<Double>(0.0)
}
第一部分是将开关和文本字段绑定到 viewModel 的 MutableProperties。
前两个比较简单:
viewModel.on <~ onSwitch.rex_on
viewModel.width <~ widthTextField.rex_textSignal
.map { Double([=11=]) ?? 0 }
注意:如果宽度文本字段的输入不是有效数字,我选择发送 0 作为宽度。根据您的需要,您可能希望以不同方式处理这种情况,例如通过让 width
和 height
属性具有可选值...
现在高度几乎相同,但我们必须确保它仅在开关处于 on 时处理。这是通过使用 combineLatest
和 filter
实现的:
viewModel.height <~ combineLatest(viewModel.on.producer, viewModel.width.producer) // SignalProducer<(Bool, Double), NoError>
.filter { on, text in return on } // Only send values when the switch is `on`
.map { on, width in return width } // Now we dont care about the switch value anymore, extract just the width
.map { width in return 0.5 * width }// Transform the width as you wish
现在,剩下的就是将高度值绑定到 UI。除非我遗漏了什么,否则 REX 对此没有任何帮助(至少 UITextField
没有),所以我们将不得不使用 DynamicProperty
:
override func viewDidLoad() {
super.viewDidLoad()
// Previously mentioned binding to the viewModel
DynamicProperty(object: heightTextField, keyPath: "text") <~ viewModel.height.producer.map { String([=13=]) }
}
我已经编写了代码的反应命令式版本:
widthTextField.rac_textSignal().subscribeNext { (val) in
let multiplier = 0.2
if var v = Double(val as! String){
if(self.viewModel.proportionalBool.value){
v *= multiplier
self.heightTextField.text = String(v)
}
}
}
我的 ViewModel 中有三个 MutableProperties:Bool 类型的 proportionalBool、heightString 和 String 类型的 widthString。
我的 ViewController.
中也有对应的 UISwitch 和两个 UITextField我想学习的是以下场景: 1. 如果 bool/switch 为 false,则 heightString 应该保持不变 2. 如果 bool 为真,则 heightString 的值应为: widthString * multiplier
我知道我写的代码很糟糕。我想我应该使用 combineLatest 但我不知道如何将两个信号:UITextField 和 UISwitch 合并为一个生成信号。
谁能给我任何提示或简单的代码示例?
let boolSignal = proportionalSwitch.rac_newOnChannel()
let widthSignal = widthTextField.rac_textSignal()
let heightSignal = heightTextField.rac_textSignal()
...?
我假设您总是希望 ViewModel 中的 MutableProperties 始终具有正确的值。
此外,我将使用 REX (which will soon be a part of RAC anyway) 来实现更简单的 UI 绑定。
假设这是您的 viewModel:
final class ViewModel {
let on = MutableProperty<Bool>(false)
let width = MutableProperty<Double>(0.0)
let height = MutableProperty<Double>(0.0)
}
第一部分是将开关和文本字段绑定到 viewModel 的 MutableProperties。
前两个比较简单:
viewModel.on <~ onSwitch.rex_on
viewModel.width <~ widthTextField.rex_textSignal
.map { Double([=11=]) ?? 0 }
注意:如果宽度文本字段的输入不是有效数字,我选择发送 0 作为宽度。根据您的需要,您可能希望以不同方式处理这种情况,例如通过让 width
和 height
属性具有可选值...
现在高度几乎相同,但我们必须确保它仅在开关处于 on 时处理。这是通过使用 combineLatest
和 filter
实现的:
viewModel.height <~ combineLatest(viewModel.on.producer, viewModel.width.producer) // SignalProducer<(Bool, Double), NoError>
.filter { on, text in return on } // Only send values when the switch is `on`
.map { on, width in return width } // Now we dont care about the switch value anymore, extract just the width
.map { width in return 0.5 * width }// Transform the width as you wish
现在,剩下的就是将高度值绑定到 UI。除非我遗漏了什么,否则 REX 对此没有任何帮助(至少 UITextField
没有),所以我们将不得不使用 DynamicProperty
:
override func viewDidLoad() {
super.viewDidLoad()
// Previously mentioned binding to the viewModel
DynamicProperty(object: heightTextField, keyPath: "text") <~ viewModel.height.producer.map { String([=13=]) }
}