Pergunta

I'm trying to create a button that switches from its normal state to a selected state upon simply touching it, and the other way around. However, I didn't manage to make it work. Here is my code:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIButton *button = [UIButton new];
    [button setImage:[UIImage imageNamed:@"touch_normal.png"] forState:UIControlStateNormal];
    [button setImage:[UIImage imageNamed:@"touch_selected.png"] forState:UIControlStateSelected];

    button.frame = CGRectMake(138.5, 208.5, 63, 63);
    [button addTarget:self action:@selector(touch:) forControlEvents:UIControlEventTouchDown];
    button.adjustsImageWhenHighlighted = NO;

    [self.view addSubview:button];
}

- (void)touch:(id)sender
{
    NSLog(@"Touch");

    UIButton *button = sender;

    if (button.selected)
        button.selected = NO;
    else
        button.selected = YES;
}

@end

When I tap and hold, the touch method is triggered, as expected. However, the image of the button only changes to touch_selected.png after I release my finger. Any idea what could be the issue?

Edit: I know what UIControlStateHighlighted is and it's not what I'm looking for, because I want my button to change to the selected state after I touched it (but while I'm still holding my finger on it), and it should stay in the selected state after I removed my finger from the screen.

Foi útil?

Solução

You probably want to change the image for the highlighted state.

You shouldn't need to do anything in the touch: method.

Just change the line:

[button setImage:[UIImage imageNamed:@"touch_selected.png"] forState:UIControlStateSelected];

for:

[button setImage:[UIImage imageNamed:@"touch_selected.png"] forState:UIControlStateHighlighted];

Then the image should change when the button is touched.

EDIT:

To have the button keep the image once the touch has been released, you essentially want to invert the selected state each time a touch is released on the button. I suggest adding a target to the button:

[myButton addTarget:self action:@selector(buttonPushed) forControlEvent:UIControlEventTouchUpInside];

Then in that method, invert the selected state:

- (void)buttonPushed
{
    [myButton setSelected:!myButton.selected];
}

That should hopefully do the trick!

Outras dicas

For what you are trying to achieve, you should be using: UIControlStateHighlighted not UIControlStateSelected

Selected is when the user is finished interacting with it, while highlighted is for when the user is currently interacting with it. I think you've mis interpreted the Ui control state flow.

EDIT: You seem to be confused about the underlying logic thats playing here. Let me try to explain.

There are 3 states:

  • A - UnSelected
  • B - Highlighted
  • C - Selected

What you have done is told your control to use specific images for states A and C, then told it not to react as it normally would in state B. Then you have told it, while in state B transition to state C.

This is all conflicting with the underlying logic inside the button. you can't do this.

You need to specify images for state A and B, and if you need it to be selected after this you need to do so after you release your finger. The internal logic will switch its states after you release your finger as its no longer in the state it was in and it needs to remove the state of highlighted. Its ignoring the fact that you have set it to selected.

If this doesn't suit you, you will need to create your own button

Because you ask to do so. You are changing image when button is selected. If you want to change image when user touch then set an image for UIControlStateHighlighted it will change image when button will be in highlighted state.

The UIControlStateSelected does not mean what you think it means. A control is selected when it is tapped on. When you tap and hold the control, then drag away from that control, it isn't selected. You are looking for UIControlStateHighlighted. Setting the selected property yourself is unnecessary, too. UIButton will take care of that.

The button also has a highlighted state which (visually) overrides the selected state. The highlighted state is maintained internally to show touches.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top