PDA

View Full Version : Set Continuous Feedback and Duration For UISlider:setValue:animated




Darkroom
Dec 3, 2009, 01:48 PM
i would like to slow down the setValue:animated animation duration from it's default (which i assume is 0.25f) to about 2 seconds. additionally, i need to have continuous feedback of the slider's value while it is animating. how can this be accomplished? i assume i'll have to write my own method to achieve this behavior, but i'm a bit fuzzy on the logic behind this.

any guides or suggestions?

[EDIT] i'm thinking this could be accomplished thru a loop, using setValue:animated:NO thru steps that multiply (speed up) in the loop until the value of the slider becomes the desired value. if anyone has any better ideas please let me know. my idea seems like a big hack.

[EDIT AGAIN] yeah, that totally didn't work. it seems i had forgotten how fast for loops can execute. :rolleyes:



Darkroom
Dec 3, 2009, 03:46 PM
ok so i managed to control the animation curve and duration by simply throwing the setValue method of the slider in an animation block - should have been my first thought, really.


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

[mySlider setValue:0.0];

[UIView commitAnimations];


now all i have to do is figure out how to execute the UIControlEvenValueChanged for each step of the animation... i'm not sure this is even possible. any ideas or confirmation on the possibility of this?

North Bronson
Dec 3, 2009, 05:09 PM
Have you tried using "performSelector:withObject:afterDelay:"?

Darkroom
Dec 3, 2009, 05:25 PM
Have you tried using "performSelector:withObject:afterDelay:"?

the problem with the animation block is that the value of the slider is set immediately as the animation is only starting.

i'm currently trying to work it out using setAnimationDidStopSelector: in the animation block, but i'm having coder's block right now.

here is my current state of mind:

- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
if (([animationID isEqualToString:@"returnSliderToInitialValue"]) && finished)
NSLog(@"done");//send back to returnSliderToInitialValue until value is 0.0f;
}

- (IBAction)returnSliderToInitialValue:(UISlider *)sender
{
float initialValue = 0.0;
float releasedValue = roundf([sender value]);
float distanceFromInitialValue = (fabsf(initialValue - releasedValue));
NSLog(@"%f", distanceFromInitialValue);


[UIView beginAnimations:@"returnSliderToInitialValue" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
[UIView setAnimationDuration:2.0];

[pitchSlider setValue: distanceFromInitialValue - 0.5];

[UIView commitAnimations];
}

North Bronson
Dec 3, 2009, 05:41 PM
Here's what I'm getting at:

Suppose you have a film that you want to display. Your view is currently displaying the first frame of the film. You have a method called "showNextFrame". It could work kind of like this:

- (void)showNextFrame
{
NSInteger nextFrame = ([self currentFrame] + 1);

[self setCurrentFrame: nextFrame];

// Update the currently displayed image with the next image.

// If the film has more frames, show the next after a delay.

if ([self currentFrame] < [self lastFrame])
{
[self performSelector: @selector(showNextFrame) withObject: nil afterDelay: (1.0 / 24)];
}
}

This should give you a way to make a "manual animation" and make whatever method calls you want in-between frames.

Darkroom
Dec 4, 2009, 12:52 AM
i just tried your suggestion. unfortunately the slider is quite slow moving back to it's original position, even if afterDelay is set to zero.

Darkroom
Dec 7, 2009, 04:39 AM
i'm going to submit a feature request / bug to apple about this. i think if a continuous UISlider's value can be set and animated then the animation should also be continuous.

North Bronson
Dec 7, 2009, 05:13 AM
So you need to call a certain method every time your slider changes value? Kind of like how bindings work on the desktop?

Darkroom
Dec 7, 2009, 05:27 AM
So you need to call a certain method every time your slider changes value? Kind of like how bindings work on the desktop?

yes. i'm creating a music app that has a pitch wheel (similar to those found on MIDI keyboards) that returns to it's original, center position when released. the value's output will be controlling an audio unit. currently, since the values don't animate with the slider's thumb while using setValue:animated:, the sound output will not be as fluid as it should be - unless i manage to find a way to do what i want, but that seems pretty unlikely.

i do, however, see this as a non-issue if setValue:animated is used, since the default animation speed is so fast that the value output would hardly be noticed. however, setting the continuous slider's value in it's own slower animation block doesn't work either.

i've submitted a bug report to apple.

North Bronson
Dec 7, 2009, 06:06 AM
Have you tried creating a subclass of UISlider and overriding the "value" method? If you call "setValue:animated:" and the class calls "value" with each tick, that might do the job.

Darkroom
Dec 7, 2009, 06:21 AM
Have you tried creating a subclass of UISlider and overriding the "value" method? If you call "setValue:animated:" and the class calls "value" with each tick, that might do the job.

in case of an oversight i'd be nervous to do that without using the actual code as a guide. you don't happen to have that do you?

or maybe i could just call [super setValue:value] from my custom method?

North Bronson
Dec 7, 2009, 06:44 AM
Yea, I was thinking to try:

- (float)value
{
NSLog(@"Value Changed")

float returnValue = [super value];

return returnValue;
}

and see if your console logs with each value.

Darkroom
Dec 10, 2009, 04:00 AM
i don't think that would work. the problem seems to be that the animation block (either the default one or one i've created myself) which animates the UISlider's thumb uses only one value. i think the only way to make this work is to have the slider post it's value during each step of the animation, which i think would require quite a complex animation block.