views:

796

answers:

2

I have a sound effect that I want to only play when the slider is moving.

Currently I have the playSound method fire when the UISlider is sending Value Changed events.

I need a way to detect when the slider is not being moved, yet hasn't been released.

I think I can use the Control Events of it's super class to work out the timing but I don't see how to detect them.

Any ideas?

A: 

If I understand you correctly, you want to keep playing the sound as long as the slider is touched, whether it's moving or not. To do this, register one method as the target for UIControlEventTouchDown (and perhaps UIControlEventTouchDragInside) events and another for some combination of UIControlEventTouchDragExit/TouchUpOutside/TouchUpInside/TouchCancel (depending on what you need). The first method starts playing the sound and the second one stops it.

If you want to play another sound when the slider is still touched but not moving, I would recommend starting a timer each time you receive a TouchDown/ValueCahanged/etc event:

self.touchTimer = [NSTimer scheduledTimerWithTimeInterval: kDelay
                                                target:self
                                              selector:@selector(noMovement:)
                                              userInfo:nil
                                               repeats:NO];

Then, whenever you receive another ValueChanged even, you cancel the timer and trigger another (or, better, reschedule the original one). When the timer triggers, it means the user hasn't moved the slider since kDelay, and you can change the sound being played. (You need to cancel the timer when you get a TouchUpInside/Outside event too.)

Felixyz
As I mentioned in the question, if the slider is still down but not moving, I want the sound to stop. If the user thereafter resumes moving the slider, I want the sound to start up again. The thing is, there is almost always a tiny amount of jitter. This leads to stuttering as the sound is cut off even when there is no (apparent to the user) motion.
willc2
You can use the same technique: when you receive a TouchDown or TouchDragInside event, you start a timer that will fire after 0.5 sec (or whatever). When the timer fires, it stops the sound that is currently playing. Whenever you receive new drag events, you cancel the current timer if there is one and start a new one (or reschedule the original one), and, of course, resume playing the sound if it has been stopped.
Felixyz
A: 

Hi willc2,

I'm doing something similar to this, and I just created my own subclass of UISlider. I implemented the standard UIResponder touch functions and performed my own code before calling through to the superclass. Using this approach will provide you with fine grained access to the touch phase information, and you could put the timer within the slider object (seems the best OO way to do it?)

Here's a bit of code that would allow you to add your own behaviors to touchesBegan. Depending on your need, you could also override touchesMoved and touchesEnded. As long as you call through to the superclass, there shouldn't be any change in the slider's behavior.

In my case, I want the gray track of the UISlider to be clickable, so I manually set the slider's value based on the touch location.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // set our value, if necessary
    CGRect t = [self trackRectForBounds: [self bounds]];
    float v = [self minimumValue] + ([[touches anyObject] locationInView: self].x - t.origin.x - 4.0) * (([self maximumValue]-[self minimumValue]) / (t.size.width - 8.0));
    [self setValue: v];

    [super touchesBegan: touches withEvent: event];

}

Hope that helps,

Ben Gotow