UISlider 平滑地改变值

Posted

技术标签:

【中文标题】UISlider 平滑地改变值【英文标题】:UISlider change value smoothly 【发布时间】:2013-09-15 13:26:47 【问题描述】:

我有一个 UIslider 设置 AVAdioRecording 的位置:

CGRect frame = CGRectMake(50.0, 230.0, 200.0, 10.0);
                     aSlider = [[UISlider alloc] initWithFrame:frame];
                     // Set a timer which keep getting the current music time and update the UISlider in 1 sec interval
                     sliderTimer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self selector:@selector(updateSlider) userInfo:nil repeats:YES];
                     // Set the maximum value of the UISlider
                     aSlider.maximumValue = player.duration;
                     // Set the valueChanged target
                     [aSlider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
                     [self.ViewA addSubview:aSlider];




 - (void)updateSlider 
// Update the slider about the music time

[UIView beginAnimations:@"returnSliderToInitialValue" context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView setAnimationDuration:1.3];

aSlider.value = player.currentTime;

[UIView commitAnimations];


- (IBAction)sliderChanged:(UISlider *)sender 
// Fast skip the music when user scroll the UISlider
[player stop];
[player setCurrentTime:aSlider.value];
[player prepareToPlay];
[player play];

我想问三个问题。

1) 为什么数值变化的动画不起作用? 2) 为什么只有当我的手指从按钮上松开而不跟随它时,滑块位置才会移动? 3) 使用 NSTimer 是最好的方法吗?我听说 NSTimer 非常消耗内存...

【问题讨论】:

【参考方案1】:

为什么动画 value 不起作用

您显然找到了value 属性。查看文档你会看到这句话

要呈现从当前值到新值的动画过渡,您应该改用setValue:animated: 方法。

所以,正如文档所说的那样使用

[aSlider setValue:player.currentTime animated:YES];

为什么只有松开手指才能收到事件

只有在松开手指时才会收到事件的原因是您的滑块不连续。来自continuous 属性的文档:

如果YES,滑块会不断地向关联目标的操作方法发送更新事件。如果为NO,则当用户松开滑块的拇指控件设置最终值时,滑块才会发送一个动作事件。

NSTimer 不是最好的方法

不,使用 NSTimer 为这样的更改设置动画绝对不是最好的方法,我会说使用计时器是非常糟糕的做法。它不仅无效且可能不精确,而且您还会失去对缓动动画的内置支持。

如果你真的不能没有计时器,那么你至少应该使用CADisplayLink 而不是NSTimer。它适用于 UI 更新(与 NSTimer 不同)。

【讨论】:

那么你建议我用什么来代替计时器? @Alessandro 第一个选项:任何隐式或显式动画。只有当这不起作用时,你才会使用其他东西。在这种情况下,您不希望 NSTimer 做任何与更新用户界面相关的事情。请改用CADisplayLink。文档中的第一句话:“CADisplayLink 对象是一个计时器对象,它允许您的应用程序将其绘图与显示器的刷新率同步。” 我遇到了类似的问题。对我来说,如果我的录制时间很短,比如 10 秒,那么 UISlider 就会出现故障。它来回快速移动。如果时间较长,比如 1 分钟,则相当顺利。有什么想法吗? 查看我的解决方案,对我来说效果很好,只是很奇怪你必须将它添加到一个动画块中才能让它像 setValue:animated: 一样工作。【参考方案2】:

你应该使用这些:

    在创建滑块时将滑块属性continuous 设置为YES

    在你的情况下 aSlider.continuous = YES;

    使用setValue:animated方法,

    你的情况 [aSlider setValue:player.currentTime animated:YES];

【讨论】:

【参考方案3】:

我正在寻找一种解决方案,将目标添加到我的 UISlider 中,当用户停止移动滑块时只会触发一次。

我想保存一次选择的值,而不是每次更新,这就是为什么我用NO 取消选择continous。我刚刚意识到,将 continous 设置为 NO 将不再为滑块设置动画。所以经过一些尝试,我发现,如果您将self.slider setValue:animated:[UIView animateWithDuration:animations:] 结合使用,UISlider 将被动画化,如下所示:

添加目标

[self.sliderSkill addTarget:self 
                     action:@selector(skillChange) 
           forControlEvents:UIControlEventValueChanged];

目标方法

- (void)skillChange

    CGFloat fValue = self.sliderSkill.value;

    [UIView animateWithDuration:0.5f animations:^
        if( fValue < 1.5f )
            [self.slider setValue:1 animated:YES];
         else if( fValue > 1.5f && fValue < 2.5f )
            [self.slider setValue:2 animated:YES];
         else 
            [self.slider setValue:3 animated:YES];
        
    ];

也许有人可以使用它!

【讨论】:

以上是关于UISlider 平滑地改变值的主要内容,如果未能解决你的问题,请参考以下文章

当 UISlider 值改变时会调用啥?

UISLider 以正确的方式改变 UILabel 的值

UISlider 进展不顺利

UIProgressView和UISlider

如何获取给定值沿 UISlider 的位置?

在 Swift 中:如何使用 uislider 值作为变量来设置旋转速度