iOS 如何使滑块停止在离散点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7083375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS how to make slider stop at discrete points
提问by gonzobrains
I would like to make a slider stop at discrete points that represent integers on a timeline. What's the best way to do this? I don't want any values in between. It would be great if the slider could "snap" to position at each discrete point as well.
我想让滑块停在代表时间线上整数的离散点处。做到这一点的最佳方法是什么?我不想要介于两者之间的任何值。如果滑块也可以“捕捉”到每个离散点的位置,那就太好了。
采纳答案by jrturton
To make the slider "stick" at specific points, your viewcontroller should, in the valueChanged method linked to from the slider, determine the appropriate rounded from the slider's value and then use setValue: animated: to move the slider to the appropriate place. So, if your slider goes from 0 to 2, and the user changes it to 0.75, you assume this should be 1 and set the slider value to that.
要使滑块“粘”在特定点,您的视图控制器应该在从滑块链接到的 valueChanged 方法中,根据滑块的值确定适当的舍入值,然后使用 setValue:animated: 将滑块移动到适当的位置。因此,如果您的滑块从 0 变为 2,并且用户将其更改为 0.75,则您假设这应该是 1 并将滑块值设置为该值。
回答by Nathan Dries
The steps that I took here were pretty much the same as stated in jrturton's answer but I found that the slider would sort of lag behind my movements quite noticeably. Here is how I did this:
我在这里采取的步骤与 jrturton 的回答中所述的步骤几乎相同,但我发现滑块会明显滞后于我的动作。这是我如何做到的:
Put the slider into the view in Interface Builder. Set the min/max values of the slider. (I used 0 and 5)
将滑块放入 Interface Builder 的视图中。设置滑块的最小值/最大值。(我使用了 0 和 5)
In the .h file:
在 .h 文件中:
@property (strong, nonatomic) IBOutlet UISlider *mySlider;
- (IBAction)sliderChanged:(id)sender;
In the .m file:
在 .m 文件中:
- (IBAction)sliderChanged:(id)sender
{
int sliderValue;
sliderValue = lroundf(mySlider.value);
[mySlider setValue:sliderValue animated:YES];
}
After this in Interface Builder I hooked up the 'Touch Up Inside' event for the slider to File's Owner, rather than 'Value Changed'. Now it allows me to smoothly move the slider and snaps to each whole number when my finger is lifted.
在界面生成器中,我将滑块的“Touch Up Inside”事件连接到 File's Owner,而不是“Value Changed”。现在,当我抬起手指时,它允许我平滑地移动滑块并捕捉到每个整数。
Thanks @jrturton!
谢谢@jrturton!
UPDATE- Swift:
更新- 斯威夫特:
@IBOutlet var mySlider: UISlider!
@IBAction func sliderMoved(sender: UISlider) {
sender.setValue(Float(lroundf(mySlider.value)), animated: true)
}
Also if there is any confusion on hooking things up in the storyboard I have uploaded a quick example to github: https://github.com/nathandries/StickySlider
另外,如果在故事板中连接东西有任何混淆,我已经上传了一个简单的例子到 github:https: //github.com/nathandries/StickySlider
回答by ctlockey
What I did for this is first set an "output" variable of the current slider value to an integer (its a float by default). Then set the output number as the current value of the slider:
我为此所做的是首先将当前滑块值的“输出”变量设置为整数(默认情况下为浮点数)。然后将输出编号设置为滑块的当前值:
int output = (int)mySlider.value;
mySlider.value = output;
This will set it to move in increments of 1 integers. To make it move in a specific range of numbers, say for example, in 5s, modify your output value with the following formula. Add this between the first two lines above:
这会将其设置为以 1 个整数为增量移动。要使其在特定的数字范围内移动,例如在 5 秒内移动,请使用以下公式修改输出值。在上面的前两行之间添加:
int output = (int)mySlider.value;
int newValue = 5 * floor((output/5)+0.5);
mySlider.value = newValue;
Now your slider "jumps" to multiples of 5 as you move it.
现在,当您移动滑块时,它会“跳”到 5 的倍数。
回答by Nicolas Miari
I did as Nathan suggested, but I also want to update an associated UILabel
displaying the current value in real time, so here is what I did:
我按照 Nathan 的建议做了,但我也想UILabel
实时更新显示当前值的关联,所以这是我所做的:
- (IBAction) countdownSliderChanged:(id)sender
{
// Action Hooked to 'Value Changed' (continuous)
// Update label (to rounded value)
CGFloat value = [_countdownSlider value];
CGFloat roundValue = roundf(value);
[_countdownLabel setText:[NSString stringWithFormat:@" %2.0f 秒", roundValue]];
}
- (IBAction) countdownSliderFinishedEditing:(id)sender
{
// Action Hooked to 'Touch Up Inside' (when user releases knob)
// Adjust knob (to rounded value)
CGFloat value = [_countdownSlider value];
CGFloat roundValue = roundf(value);
if (value != roundValue) {
// Almost 100% of the time - Adjust:
[_countdownSlider setValue:roundValue];
}
}
The drawback, of course, is that it takes two actions (methods) per slider.
当然,缺点是每个滑块需要两个动作(方法)。
回答by sabiland
Swift version with ValueChangedand TouchUpInside.
带有ValueChanged和TouchUpInside 的Swift 版本。
EDIT: Actually you should hook up 3 events in this case:
编辑:实际上,在这种情况下,您应该连接 3 个事件:
yourSlider.addTarget(self, action: #selector(presetNumberSliderTouchUp), for: [.touchUpInside, .touchUpOutside, .touchCancel])
I've just pasted my code, but you can easily see how it's done.
我刚刚粘贴了我的代码,但您可以很容易地看到它是如何完成的。
private func setSizesSliderValue(pn: Int, slider: UISlider, setSliderValue: Bool)
{
if setSliderValue
{
slider.setValue(Float(pn), animated: true)
}
masterPresetInfoLabel.text = String(
format: TexturingViewController.createAndSendPresetNumberNofiticationTemplate,
self.currentPresetNumber.name.uppercased(),
String(self.currentPresetNumber.currentUserIndexHumanFriendly)
)
}
@objc func presetNumberSliderTouchUp(_ sender: Any)
{
guard let slider = sender as? NormalSlider else{
return
}
setupSliderChangedValuesGeneric(slider: slider, setSliderValue: true)
}
private func setupSliderChangedValuesGeneric(slider: NormalSlider, setSliderValue: Bool)
{
let rounded = roundf((Float(slider.value) / Float(presetNumberStep))) * Float(presetNumberStep)
// Set new preset number value
self.currentPresetNumber.current = Int(rounded)
setSizesSliderValue(pn: Int(rounded), slider: slider, setSliderValue: setSliderValue)
}
@IBAction func presetNumberChanged(_ sender: Any)
{
guard let slider = sender as? NormalSlider else{
return
}
setupSliderChangedValuesGeneric(slider: slider, setSliderValue: false)
}