UISlider change value smoothly

13,739

Solution 1

Why animating the value doesn't work

You obviously found the value property. Check the documentation and you will see this sentence

To render an animated transition from the current value to the new value, you should use the setValue:animated: method instead.

So, just as the documentation says use

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

Why you only get events when you release your finger

The reason you only get events when you release the finger is that your slider is not continuous. From the documentation of the continuous property:

If YES, the slider sends update events continuously to the associated target’s action method. If NO, the slider only sends an action event when the user releases the slider’s thumb control to set the final value.

NSTimer is not the best way

No, using a NSTimer to animate a change like this is definitely not the best way, I would say it's very bad practice to use a timer. Not only is it ineffective and possibly imprecise but you also lose the built in support for easing the animation.

If you really can't do it without a timer, then you should at least use a CADisplayLink instead of a NSTimer. It is made to work with UI updates (as opposed to NSTimer which isn't).

Solution 2

You should probably use these:

  1. Set slider property continuous to YES when your create the slider ,

    in your case aSlider.continuous = YES;

  2. Use setValue:animated method,

    in your case [aSlider setValue:player.currentTime animated:YES];

Solution 3

I was looking for a solution where I add a target to my UISlider which will just be triggered once when the user stops moving the slider.

I wanted to save the value selected once and not on every single update, thats why I deseleceted continous with NO. I just realised, setting continous to NO won't animate the slider anymore. So after some tryings, I found out, the UISlider will be animated if you use self.slider setValue:animated: in combination with [UIView animateWithDuration:animations:] like this:

Add the target

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

Target method

- (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];
        }
    }];
}

Maybe somebody can use this!

Share:
13,739
Alessandro
Author by

Alessandro

Updated on July 31, 2022

Comments

  • Alessandro
    Alessandro almost 2 years

    I have a UIslider setting the position for a 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];
    }
    

    There are three questions i would like to ask.

    1) Why does the animation for the value change not work? 2) Why does the slider position move only when I release my finger from the button and does not follow it? 3) Is using an NSTimer the best way to do it? I have heard that NSTimer is a lot memory consuming...

  • Alessandro
    Alessandro over 10 years
    so what do you suggest me to use instead of a timer?
  • David Rönnqvist
    David Rönnqvist over 10 years
    @Alessandro First option: any implicit or explicit animation. Only if that doesn't work do you use something else. In this case you don't want a NSTimer to do anything related to updating the user interface. Use CADisplayLink instead. First sentence from the documentation: "A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display."
  • Luke Irvin
    Luke Irvin over 10 years
    I'm having a similar issue. For me, if my recording time is low, say 10 seconds, the UISlider is very glitchy. It moves rapidly back and forth. If the time is longer, say 1 minute, it's fairly smooth. Any thoughts?
  • Alex Cio
    Alex Cio almost 9 years
    Check out my solution, works fine for me, its just weird you have to add it to a animationBlock to make it work like it should with setValue:animated:.