views:

68

answers:

2

I'm implementing touchesMoved, touchesBegan, and touchesEnded on a few UIButtons, so that I can slide my fingers over them and have them call the appropriate actions.

It seems to be working almost as intended, however, if I press two fingers outside of the two buttons' frames, and then slide them into the buttons' frames at the same time, the function within touchesMoved gets called multiple times. Instead, it should only call each button's function once while in the button's frame.

Below is my code.

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

for(UITouch *t in touches) {

CGPoint location = [t locationInView:t.view];

if(CGRectContainsPoint(Button1.frame, location)) 
{
    if (!Button1.isHighlighted){
        if(!button1Highlighted) {
            [self doAction1];
        }
        [Button1 setHighlighted:YES];
        button1Highlighted = YES;
    }
}
else {
    [Button1 setHighlighted:NO];
    button1Highlighted = NO;
}
if(CGRectContainsPoint(Button2.frame, location)) 
{
    if (!Button2.isHighlighted){
        if(!button2Highlighted) {
            [self doAction2];
        }
        [Button2 setHighlighted:YES];
        button2Highlighted = YES;
    }
}
else {
    [Button2 setHighlighted:NO];
    button2Highlighted = NO;
}

}

}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

for(UITouch *t in touches) {

    CGPoint location = [t locationInView:t.view];

    if(CGRectContainsPoint(Button1.frame, location)) 
    {
        [Button1 setHighlighted:YES];
        button1Highlighted = YES;
        [self doAction1];
    }
    if(CGRectContainsPoint(Button2.frame, location)) 
    {
        [Button2 setHighlighted:YES];
        button2Highlighted = YES;
        [self doAction2];
    }
}

}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

for(UITouch *t in touches) {

    CGPoint location = [t locationInView:t.view];

    if(CGRectContainsPoint(Button1.frame, location)) 
    {
        [Button1 setHighlighted:NO];
        button1Highlighted = NO;
    }
    if(CGRectContainsPoint(Button2.frame, location)) 
    {
        [Button2 setHighlighted:NO];
        Button2Highlighted = NO;
            }
}

}

Any help is greatly appeciated. Thanks!

A: 

If -touchesMoved: is getting called with multiple touches such that there's one touch on Button1 and another on Button2 and both buttons are not highlighted, then the touch over Button1 will highlight Button1 and unhighlight Button2. Meanwhile, in the same loop in the same call to -touchesMoved:, the touch over Button2 will essentially reset Button1's highlight state back to unhighlighted.

-touchesMoved: will be called as long as there are touches, and each call will cycle the two buttons again.

Maybe you need to add a 'hasBeenHighlighted' property to your buttons. I am not sure how best to initialize this property to NO for all your buttons. But it would need to be set to YES inside -setHighlighted: and it would need to be checked before calling -doActionX.

I am not sure that I understand exactly what you are trying to achieve, but I hope this is of some help.

westsider
That makes sense. I created a BOOL button1hasbeenHighlighted, and did as you said, but it still has the same problem when two fingers are moving inside the buttons at the same time. Any other suggestions?
c0dec0de
Well, -touchesMoved: *should* be called many times. The problem is that doAction1 and doAction2 are being called repeatedly, right? You might want to add some NSLog() lines at entry of -touchesBegan:, -touchesMoved: and -touchedEnded:. Also, inside the doActionX methods. If you see calls to doActionX in each call to touchesMoved, then that's the problem. Without seeing code, it's hard to know if I am understanding problem.
westsider
Hey westsider, the calls to doActionX are definitely the problem. I'm just not sure how to fix it. I've updated the code above. I really appreciate you looking into this for me. Thank you.
c0dec0de
Try removing button1Highlighted = NO; and button2Highlighted = NO; from -touchesMoved:. Does that make any difference?
westsider
That seemed to have fixed the problem with two fingers causing the doActionX to be fired so much. However, now it only lets me slide my finger over the two buttons one way, but it doesnt fire the actions again if I slide back over the two buttons without lifting my finger.
c0dec0de
Yes. Well, I think that what you are attempting is a bit non-standard, so it will probably take a bit more work. You can keep references to the UITouch objects. They will maintain their identity for the lifetimes. You could then create some sort of tracking object that references one UITouch but which also maintains some state information. These wrappers would be instantiated in touchesBegan and released in touchesEnded. In touchesBegan and touchesMoved check their states and react accordingly. You would need to keep an NSMutableArray of these wrapper objects and be mindful of lifetime issues.
westsider
Thanks for your help westsider. I didnt think it was going to be this hard just to slide between two buttons and trigger sounds. Seems like there's a lot of glitches.
c0dec0de
Maybe there's a much easier way. I'll be watching this question with interest. Good luck.
westsider
Forgot to mention that my code is largely based on this question: http://stackoverflow.com/questions/2218613/touchesmoved-with-button
c0dec0de
If a UITouch could only ever be over a single button at a time, then you could have your buttons track which UITouches are over them - and they could essentially ignore ones that were already 'inside', provided they tracked when they left.
westsider
Do you think maybe I could detect when there are two simultaneous touches on the screen and then set a flag so that the actions within the touchesMoved are only triggered once until one of the touches is finished?
c0dec0de
You could but the multiple simultaneous touches is a nice effect. And ignore user input can become problematic.
westsider
I would only check for the multiple touches on touchesMoved, so touchesBegan would still call the button's actions for simultaneous touches. I'll give it a try later and let you know how I make out.
droidy
A: 

I ended up getting it to work by storing the number of touches on the screen in a variable called touchesCount. I then increment it in touchesBegan, and decrease it in touchesEnded. Then in the touchesMoved before calling doActionX, I checked to make sure touchesCount < 2.

c0dec0de