如何为 UISlider 实现 shouldChangeValue(to: Int)?
How to implement shouldChangeValue(to: Int) for UISlider?
我只有 UISlider
和 minValue 0
和 maxValue 100
。我的 currentValue 是 40
.
- 我有 6 个滑块,每个滑块都有自定义的最小值和最大值。
- 我也有某种验证(总和不应大于200)。
有没有办法检查@IBAction
中的currentValue
@objc private func didValueChanged(slider: UISlider) {
// check if it is not over 200,
// if not then set previous value.
// How do I get previous value of slider?
}
没有超过我的限制并且do nothing then
否则将以前的值设置为滑块?
不清楚当滑块的总和超过 200 个限制时你想要做什么,但总体思路...
您需要跟踪每个滑块的最后有效 值。当用户停止拖动时:
- 获取“活动”滑块的值
- 获取其他 5 个滑块的总和
- 将“有效”值添加到总和
- 如果总和为out-of-range(总和 > 200)
- 重置为活动滑块的保存值
- 其他
- 更新活动滑块的保存值
所以,给你的滑块这个动作:
slider.addTarget(self, action: #selector(didStopSliding(slider:)), for: [.touchUpInside, .touchUpOutside, .touchCancel])
当用户停止滑动时调用(抬起触摸或滑动 off-screen 或取消操作)。
您可以保留当前的:
slider.addTarget(self, action: #selector(didValueChanged(slider:)), for: .valueChanged)
如果您还想在拖动时做一些事情(例如更新值标签)。
这是一个简单的例子:
// struct to associate values and display labels with the UISlider
struct MySliderStruct {
var minValue: Float = 0
var maxValue: Float = 0
var curValue: Float = 0
var minLabel: UILabel = UILabel()
var curLabel: UILabel = UILabel()
var maxLabel: UILabel = UILabel()
var theSlider: UISlider = UISlider()
}
class SliderCheckVC: UIViewController {
var theSliders: [MySliderStruct] = []
let runningTotalLabel: UILabel = {
let v = UILabel()
v.textAlignment = .center
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
let minMax: [[Float]] = [
[10, 40],
[20, 50],
[0, 10],
[0, 50],
[10, 60],
[0, 100],
]
let colors: [UIColor] = [
.init(red: 1.0, green: 0.8, blue: 0.8, alpha: 1.0),
.init(red: 0.5, green: 1.0, blue: 0.5, alpha: 1.0),
.init(red: 0.8, green: 0.8, blue: 1.0, alpha: 1.0),
.init(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0),
.init(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0),
.init(red: 0.0, green: 1.0, blue: 1.0, alpha: 1.0),
]
let outerStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 16
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
for (pair, clr) in zip(minMax, colors) {
// vertical stack view for labels + slider
let vStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 4
return v
}()
// horizontal stack view for the labels
let hStack: UIStackView = {
let v = UIStackView()
v.distribution = .fillEqually
return v
}()
let vMin: UILabel = {
let v = UILabel()
v.textAlignment = .left
v.font = .systemFont(ofSize: 13.0)
v.text = formatVal(pair[0])
return v
}()
let vCur: UILabel = {
let v = UILabel()
v.textAlignment = .center
v.font = .systemFont(ofSize: 13.0)
v.text = formatVal(pair[0])
return v
}()
let vMax: UILabel = {
let v = UILabel()
v.textAlignment = .right
v.font = .systemFont(ofSize: 13.0)
v.text = formatVal(pair[1])
return v
}()
hStack.addArrangedSubview(vMin)
hStack.addArrangedSubview(vCur)
hStack.addArrangedSubview(vMax)
let slider = UISlider()
slider.minimumValue = pair[0]
slider.maximumValue = pair[1]
slider.setValue(pair[0], animated: false)
slider.addTarget(self, action: #selector(didValueChanged(slider:)), for: .valueChanged)
slider.addTarget(self, action: #selector(didStopSliding(slider:)), for: [.touchUpInside, .touchUpOutside, .touchCancel])
vStack.backgroundColor = clr
vStack.addArrangedSubview(hStack)
vStack.addArrangedSubview(slider)
outerStack.addArrangedSubview(vStack)
let thisSlider: MySliderStruct = MySliderStruct(minValue: pair[0],
maxValue: pair[1],
curValue: pair[0],
minLabel: vMin,
curLabel: vCur,
maxLabel: vMax,
theSlider: slider
)
theSliders.append(thisSlider)
}
// running total line
let hStack: UIStackView = {
let v = UIStackView()
v.distribution = .fillEqually
return v
}()
let v1 = UILabel()
v1.text = "Current Total"
v1.textAlignment = .center
runningTotalLabel.textAlignment = .center
hStack.addArrangedSubview(v1)
hStack.addArrangedSubview(runningTotalLabel)
outerStack.addArrangedSubview(hStack)
view.addSubview(outerStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
outerStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 12.0),
outerStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
outerStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
updateTotalLabel()
}
@objc private func didStopSliding(slider: UISlider) {
guard let thisSliderIDX = theSliders.firstIndex(where: { [=12=].theSlider == slider})
else {
print("Invalide slider setup")
return
}
// get the value of "active" slider
let thisValue: Float = slider.value.rounded()
// get sum of all other sliders, plus
// this slider value
var total: Float = 0
for i in 0..<theSliders.count {
if i == thisSliderIDX {
total += thisValue
} else {
total += theSliders[i].curValue
}
}
// if sum is less-than max allowed
if total < 200.0 {
// update array with new value
theSliders[thisSliderIDX].curValue = thisValue
// move slider to rounded Int value
slider.setValue(thisValue, animated: true)
} else {
// reset to last value
slider.setValue(theSliders[thisSliderIDX].curValue, animated: true)
// update this slider's current value label
theSliders[thisSliderIDX].curLabel.text = formatVal(theSliders[thisSliderIDX].curValue)
}
updateTotalLabel()
}
@objc private func didValueChanged(slider: UISlider) {
// do something as the slider is dragged
guard let thisSliderIDX = theSliders.firstIndex(where: { [=12=].theSlider == slider})
else {
print("Invalide slider setup")
return
}
// get the value of "active" slider
let thisValue: Float = slider.value.rounded()
// update this slider's current value label
theSliders[thisSliderIDX].curLabel.text = formatVal(thisValue)
// get sum of all other sliders, plus
// this slider value
var total: Float = 0
for i in 0..<theSliders.count {
if i == thisSliderIDX {
total += thisValue
} else {
total += theSliders[i].curValue
}
}
// update the running total label here, because
// we might throw out this value
runningTotalLabel.text = formatVal(total)
}
func updateTotalLabel() {
let sumOfValues = theSliders.reduce(0) { [=12=] + (.curValue ) }
runningTotalLabel.text = formatVal(sumOfValues)
}
func formatVal(_ val: Float) -> String {
return "\(Int(val))"
}
}
看起来像这样:
在“完成滑动”时,如果将滑块拖动到一个值,导致总和超过 200,则该滑块将重置为其上一个“有效”值。
我只有 UISlider
和 minValue 0
和 maxValue 100
。我的 currentValue 是 40
.
- 我有 6 个滑块,每个滑块都有自定义的最小值和最大值。
- 我也有某种验证(总和不应大于200)。
有没有办法检查@IBAction
中的currentValue@objc private func didValueChanged(slider: UISlider) {
// check if it is not over 200,
// if not then set previous value.
// How do I get previous value of slider?
}
没有超过我的限制并且do nothing then
否则将以前的值设置为滑块?
不清楚当滑块的总和超过 200 个限制时你想要做什么,但总体思路...
您需要跟踪每个滑块的最后有效 值。当用户停止拖动时:
- 获取“活动”滑块的值
- 获取其他 5 个滑块的总和
- 将“有效”值添加到总和
- 如果总和为out-of-range(总和 > 200)
- 重置为活动滑块的保存值
- 其他
- 更新活动滑块的保存值
所以,给你的滑块这个动作:
slider.addTarget(self, action: #selector(didStopSliding(slider:)), for: [.touchUpInside, .touchUpOutside, .touchCancel])
当用户停止滑动时调用(抬起触摸或滑动 off-screen 或取消操作)。
您可以保留当前的:
slider.addTarget(self, action: #selector(didValueChanged(slider:)), for: .valueChanged)
如果您还想在拖动时做一些事情(例如更新值标签)。
这是一个简单的例子:
// struct to associate values and display labels with the UISlider
struct MySliderStruct {
var minValue: Float = 0
var maxValue: Float = 0
var curValue: Float = 0
var minLabel: UILabel = UILabel()
var curLabel: UILabel = UILabel()
var maxLabel: UILabel = UILabel()
var theSlider: UISlider = UISlider()
}
class SliderCheckVC: UIViewController {
var theSliders: [MySliderStruct] = []
let runningTotalLabel: UILabel = {
let v = UILabel()
v.textAlignment = .center
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
let minMax: [[Float]] = [
[10, 40],
[20, 50],
[0, 10],
[0, 50],
[10, 60],
[0, 100],
]
let colors: [UIColor] = [
.init(red: 1.0, green: 0.8, blue: 0.8, alpha: 1.0),
.init(red: 0.5, green: 1.0, blue: 0.5, alpha: 1.0),
.init(red: 0.8, green: 0.8, blue: 1.0, alpha: 1.0),
.init(red: 1.0, green: 1.0, blue: 0.0, alpha: 1.0),
.init(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0),
.init(red: 0.0, green: 1.0, blue: 1.0, alpha: 1.0),
]
let outerStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 16
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
for (pair, clr) in zip(minMax, colors) {
// vertical stack view for labels + slider
let vStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 4
return v
}()
// horizontal stack view for the labels
let hStack: UIStackView = {
let v = UIStackView()
v.distribution = .fillEqually
return v
}()
let vMin: UILabel = {
let v = UILabel()
v.textAlignment = .left
v.font = .systemFont(ofSize: 13.0)
v.text = formatVal(pair[0])
return v
}()
let vCur: UILabel = {
let v = UILabel()
v.textAlignment = .center
v.font = .systemFont(ofSize: 13.0)
v.text = formatVal(pair[0])
return v
}()
let vMax: UILabel = {
let v = UILabel()
v.textAlignment = .right
v.font = .systemFont(ofSize: 13.0)
v.text = formatVal(pair[1])
return v
}()
hStack.addArrangedSubview(vMin)
hStack.addArrangedSubview(vCur)
hStack.addArrangedSubview(vMax)
let slider = UISlider()
slider.minimumValue = pair[0]
slider.maximumValue = pair[1]
slider.setValue(pair[0], animated: false)
slider.addTarget(self, action: #selector(didValueChanged(slider:)), for: .valueChanged)
slider.addTarget(self, action: #selector(didStopSliding(slider:)), for: [.touchUpInside, .touchUpOutside, .touchCancel])
vStack.backgroundColor = clr
vStack.addArrangedSubview(hStack)
vStack.addArrangedSubview(slider)
outerStack.addArrangedSubview(vStack)
let thisSlider: MySliderStruct = MySliderStruct(minValue: pair[0],
maxValue: pair[1],
curValue: pair[0],
minLabel: vMin,
curLabel: vCur,
maxLabel: vMax,
theSlider: slider
)
theSliders.append(thisSlider)
}
// running total line
let hStack: UIStackView = {
let v = UIStackView()
v.distribution = .fillEqually
return v
}()
let v1 = UILabel()
v1.text = "Current Total"
v1.textAlignment = .center
runningTotalLabel.textAlignment = .center
hStack.addArrangedSubview(v1)
hStack.addArrangedSubview(runningTotalLabel)
outerStack.addArrangedSubview(hStack)
view.addSubview(outerStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
outerStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 12.0),
outerStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
outerStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])
updateTotalLabel()
}
@objc private func didStopSliding(slider: UISlider) {
guard let thisSliderIDX = theSliders.firstIndex(where: { [=12=].theSlider == slider})
else {
print("Invalide slider setup")
return
}
// get the value of "active" slider
let thisValue: Float = slider.value.rounded()
// get sum of all other sliders, plus
// this slider value
var total: Float = 0
for i in 0..<theSliders.count {
if i == thisSliderIDX {
total += thisValue
} else {
total += theSliders[i].curValue
}
}
// if sum is less-than max allowed
if total < 200.0 {
// update array with new value
theSliders[thisSliderIDX].curValue = thisValue
// move slider to rounded Int value
slider.setValue(thisValue, animated: true)
} else {
// reset to last value
slider.setValue(theSliders[thisSliderIDX].curValue, animated: true)
// update this slider's current value label
theSliders[thisSliderIDX].curLabel.text = formatVal(theSliders[thisSliderIDX].curValue)
}
updateTotalLabel()
}
@objc private func didValueChanged(slider: UISlider) {
// do something as the slider is dragged
guard let thisSliderIDX = theSliders.firstIndex(where: { [=12=].theSlider == slider})
else {
print("Invalide slider setup")
return
}
// get the value of "active" slider
let thisValue: Float = slider.value.rounded()
// update this slider's current value label
theSliders[thisSliderIDX].curLabel.text = formatVal(thisValue)
// get sum of all other sliders, plus
// this slider value
var total: Float = 0
for i in 0..<theSliders.count {
if i == thisSliderIDX {
total += thisValue
} else {
total += theSliders[i].curValue
}
}
// update the running total label here, because
// we might throw out this value
runningTotalLabel.text = formatVal(total)
}
func updateTotalLabel() {
let sumOfValues = theSliders.reduce(0) { [=12=] + (.curValue ) }
runningTotalLabel.text = formatVal(sumOfValues)
}
func formatVal(_ val: Float) -> String {
return "\(Int(val))"
}
}
看起来像这样:
在“完成滑动”时,如果将滑块拖动到一个值,导致总和超过 200,则该滑块将重置为其上一个“有效”值。