0

When creating a Draggable UIButton, the dragging events work as they should, however, I am unable to figure out why the UIControlEvents do not respond when the button is simply pressed and not dragged.

Creating the Button

DraggableButton * camera = [DraggableButton buttonWithType:UIButtonTypeCustom];
[camera setFrame:CGRectMake(160,5,149,40)];
[camera setImage: [UIImage imageWithContentsOfFile:cameraMode] forState:UIControlStateNormal];
[camera setTitle: @"Camera" forState:UIControlStateNormal];  // never gets called.
[camera addTarget:self action:@selector(openCamera) forControlEvents:UIControlEventTouchUpInside];
[buttonView addSubview: camera];

Draggable Button

@interface DraggableButon : UIButton
{
@private float deltaX;
@private float deltaY;
    CGPoint startLocation;
    BOOL    dragging;
}
@end
@implementation DraggableButon
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesMoved:touches withEvent:event];

    if ( ! draggable ) return;

    dragging = YES;
    camera.enabled = NO;
    flash.enabled = NO;

    // Calculate offset
    CGPoint pt = [[[event allTouches] anyObject] locationInView:buttonView];
    deltaX = pt.x - startLocation.x;
    deltaY = pt.y - startLocation.y;

    float xx;
    if ( IPAD ) { xx = buttonView.center.x + deltaX; } else { xx = 160; }
    CGPoint newcenter = CGPointMake(xx, buttonView.center.y + deltaY);

    // Set new location
    buttonView.center = newcenter;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesBegan:touches withEvent:event];

    if ( ! draggable ) return;

    // Calculate and store offset, and pop view into front if needed
    CGPoint pt = [[[event allTouches] anyObject] locationInView:buttonView];
    startLocation = pt;
    [[self superview] bringSubviewToFront:buttonView];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{        
    [super touchesEnded:touches withEvent:event];

    dragging = YES;
    if ( dragging )
    {
        camera.enabled = YES;
        flash.enabled = YES;

        //NSLog(@"touchesEnded: buttonView.frame.origin.x: %3.2f, buttonView.frame.origin.y: %3.2f",buttonView.frame.origin.x,buttonView.frame.origin.y);
        rectFromString = [NSString stringWithFormat:@"{{%3.2f,%3.2f},{320,50}}",buttonView.frame.origin.x,buttonView.frame.origin.y]; 
        NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithContentsOfFile: SETTINGS_FILE];
        [dict setObject:rectFromString forKey:@"kCGRectFromString"];
        [dict writeToFile: SETTINGS_FILE atomically:YES];
    }else{
        [self sendActionsForControlEvents:UIControlEventTouchUpInside];
    }
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
{    
    [super touchesCancelled:touches withEvent:event];
}
@end
WrightsCS
  • 50,551
  • 22
  • 134
  • 186

2 Answers2

1

the action is not called because you overwrite the touch events and you're not sending them further to super. You can add a new variable (let's call it dragged). Set this to NO at touchesBegan:, to YES at touchesMoved: and at touchesEnded:, if it's set to NO call [self sendActionsForControlEvents:UIControlEventTouchUpInside];

@interface DraggableButon : UIButton
{
@private float deltaX;
@private float deltaY;
    CGPoint startLocation;
    BOOL    dragging;
}
@end
@implementation DraggableButon
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    dragging=NO;

    if ( ! draggable ) return;

    // Calculate and store offset, and pop view into front if needed
    CGPoint pt = [[[event allTouches] anyObject] locationInView:buttonView];
    startLocation = pt;
    [[self superview] bringSubviewToFront:buttonView];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    dragging=YES;

    if ( ! draggable ) return;

    camera.enabled = NO;
    flash.enabled = NO;

    // Calculate offset
    CGPoint pt = [[[event allTouches] anyObject] locationInView:buttonView];
    deltaX = pt.x - startLocation.x;
    deltaY = pt.y - startLocation.y;

    float xx;
    if ( IPAD ) { xx = buttonView.center.x + deltaX; } else { xx = 160; }
    CGPoint newcenter = CGPointMake(xx, buttonView.center.y + deltaY);

    // Set new location
    buttonView.center = newcenter;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{        
    if(!dragging){  // or if(!dragging||!draggable)
        [self sendActionsForControlEvents:UIControlEventTouchUpInside];
        return;
    }

    camera.enabled = YES;
    flash.enabled = YES;

    //NSLog(@"touchesEnded: buttonView.frame.origin.x: %3.2f, buttonView.frame.origin.y: %3.2f",buttonView.frame.origin.x,buttonView.frame.origin.y);
    rectFromString = [NSString stringWithFormat:@"{{%3.2f,%3.2f},{320,50}}",buttonView.frame.origin.x,buttonView.frame.origin.y]; 
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] initWithContentsOfFile: SETTINGS_FILE];
    [dict setObject:rectFromString forKey:@"kCGRectFromString"];
    [dict writeToFile: SETTINGS_FILE atomically:YES];
}
@end
alex-i
  • 5,406
  • 2
  • 36
  • 56
  • same results. when dragged then let go, the action fires. – WrightsCS Sep 18 '11 at 19:09
  • can you post your updated implementation? In case the button was dragged then `dragged` value should be `YES` in `touchesEnded`, and `sendActionsForControlEvents` should not be sent (so the action should not get fired) – alex-i Sep 19 '11 at 06:03
  • I've updated the answer - removed `super` calls (since we're caling `sendActionsForControlEvents`) and set the `dragging` value – alex-i Sep 19 '11 at 07:28
  • perfect, that got it working. Any idea why the tap wouldn't change the state of the button? When tapping it works as it should (thank you), but it doesn't highlight the button. This isn't too big of a deal, but wonder if that can be remedied as well. – WrightsCS Sep 19 '11 at 07:35
  • 1
    I believe you have to set `self.highlighted` to YES at `touchesBegan` and to NO at `touchesEnded` and `touchesCanceled`. I haven't tested this, so I'm not sure how well it will work. – alex-i Sep 19 '11 at 07:50
0

Have you debug and whether the touch event functions are invoked? And Simple pressed action should be implemented in touchesEnded: withEvent:

Since it is inherited from UIButton,have you tried to add action event directly likeaddTarget: action: forControlEvents:?

scorpiozj
  • 2,687
  • 5
  • 34
  • 60
  • Problem is, I need the buttons to drag when dragged, and when simple press, I need it to execute the method its connected to. So if I put that method in `touchesEnded`, it would fire every time the button is dragged. – WrightsCS Sep 18 '11 at 08:23
  • yes, there is an `addTarget:action:forControlEvents:` as listed in the original question. – WrightsCS Sep 19 '11 at 02:51