Manter um UIBUBUTTON selecionado após um toque
Pergunta
Depois que meu usuário clica em um botão, eu gostaria que esse botão fique pressionado durante o tempo em que eu execute uma operação de rede. Quando a operação da rede estiver concluída, quero que o botão retorne ao seu estado padrão.
Eu tentei ligar -[UIButton setSelected:YES]
logo após o botão empurrar (com uma chamada correspondente para -[UIButton setSelected:NO]
Após o meu término da minha rede), mas parece não fazer nada. A mesma coisa se eu ligar setHighlighted:
.
Suponho que poderia tentar trocar a imagem em segundo plano para denotar um estado selecionado durante a duração do Network Op, mas isso parece um hack. Alguma sugestão melhor?
Aqui está como é o meu código:
- (IBAction)checkInButtonPushed
{
self.checkInButton.enabled = NO;
self.checkInButton.selected = YES;
self.checkInButton.highlighted = YES;
[self.checkInActivityIndicatorView startAnimating];
[CheckInOperation startWithPlace:self.place delegate:self];
}
- (void)checkInCompletedWithNewFeedItem:(FeedItem*)newFeedItem wasNewPlace:(BOOL)newPlace possibleError:(NSError*)error;
{
[self.checkInActivityIndicatorView stopAnimating];
self.checkInButton.enabled = YES;
self.checkInButton.selected = NO;
self.checkInButton.highlighted = NO;
}
Solução
Como você está definindo as imagens para os diferentes UIControlStates
no botão? Você está definindo uma imagem de fundo para UIControlStateHighlighted
assim como UIControlStateSelected
?
UIImage *someImage = [UIImage imageNamed:@"SomeResource.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
[button setBackgroundImage:someImage forState:UIControlStateSelected];
Se você estiver definindo o estado selecionado no evento Button Touch, em vez de encerrar, seu botão estará realmente em um estado destacado+selecionado, então você também deve definir isso.
[button setBackgroundImage:someImage forState:(UIControlStateHighlighted|UIControlStateSelected)];
Editar:
Para resumir minhas observações nos comentários e abordar o código que você postou ... você precisa definir suas imagens de fundo para o completo UIControl
Declare que você está. De acordo com o seu snippet de código, esse estado de controle seria desativado + selecionado + destacado para a duração da operação de rede. Isso significa que você precisaria fazer isso:
[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateHighlighted|UIControlStateSelected)];
Se você remover o highlighted = YES
, então você precisaria disso:
[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateSelected)];
Obter a foto?
Outras dicas
Eu tenho uma maneira mais fácil. Basta usar o "PerformSelector" com 0 atraso para executar [button setHighlighted:YES]
. Isso executará a luz de destaque após o final do Runloop atual.
- (IBAction)buttonSelected:(UIButton*)sender {
NSLog(@"selected %@",sender.titleLabel.text);
[self performSelector:@selector(doHighlight:) withObject:sender afterDelay:0];
}
- (void)doHighlight:(UIButton*)b {
[b setHighlighted:YES];
}
"Tudo fica melhor quando você liga"
button.selected = !button.selected;
Funciona perfeitamente ... depois de conectar a tomada ao botão no construtor de interface.
Você não precisa ser contratante: forstate:, o construtor permite especificar o plano de fundo (é redimensionado, se necessário) ou/e em primeiro plano (não redimensionando).
Tente usar o NsoperationQueue para conseguir isso. Experimente o código da seguinte maneira:
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
theButton.highlighted = YES;
}];
Espero que isto ajude.
Use um bloco para que você não precise construir um método totalmente separado:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
theButton.highlighted = YES;
});
Atualizar
Para ficar claro, você ainda precisa definir o plano de fundo (ou imagem normal) para os estados combinados, bem como os regulares como Sbrocket diz na resposta aceita. Em algum momento, seu botão será selecionado e destacado, e você não terá uma imagem para isso, a menos que faça algo assim:
[button setBackgroundImage:someImage forState (UIControlStateHighlighted|UIControlStateSelected)];
Caso contrário, seu botão poderá voltar à imagem UiControlStatEnormal para o breve estado selecionado+destacado e você verá um flash.
Em Swift, estou fazendo isso como o seguinte.
Eu crio uma subclasse de UIButton
e implementou uma propriedade personalizada state
class ActiveButton: UIButton {
private var _active = false
var active:Bool {
set{
_active = newValue
updateState()
}
get{
return _active
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addTarget(self, action: #selector(ActiveButton.touchUpInside(_:)), forControlEvents: .TouchUpInside)
}
func touchUpInside(sender:UIButton) {
active = !active
}
private func updateState() {
NSOperationQueue.mainQueue().addOperationWithBlock {
self.highlighted = self.active
}
}
}
Funciona perfeitamente para mim.
Eu tive um problema semelhante em que queria um botão para manter o destaque após o clique. O problema é se você tentar usar setHighlighted:YES
Dentro de você, clique em Ação, ele será redefinido logo após você clicar em Ação, - (IBAction)checkInButtonPushed
Eu resolvi isso usando um nstimer como este
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.01
target: self
selector: @selector(selectCurrentIndex)
userInfo: nil
repeats: NO];
e então ligue setHighlighted:YES
do meu selectCurrentIndex
método. Eu uso regular UIButtonTypeRoundedRect
botões.
Eu tenho outra maneira ... se você não quiser usar imagens e deseja o efeito de um botão pressionado, você pode subclasse o botão e aqui está o meu código:
No arquivo .h:
@interface reservasButton : UIButton {
BOOL isPressed;
}
@end
No arquivo .m:
#import <QuartzCore/QuartzCore.h>
@implementation reservasButton
-(void)setupView { //This is for Shadow
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 0.5;
self.layer.shadowRadius = 1;
self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f); //comment
// self.layer.borderWidth = 1;
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
// [self setBackgroundColor:[UIColor whiteColor]];
// self.opaque = YES;
}
-(id)initWithFrame:(CGRect)frame{
if((self = [super initWithFrame:frame])){
[self setupView];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder{
if((self = [super initWithCoder:aDecoder])){
[self setupView];
}
return self;
}
//Here is the important code
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (isPressed == FALSE) {
self.contentEdgeInsets = UIEdgeInsetsMake(1.0,1.0,-1.0,-1.0);
self.layer.shadowOffset = CGSizeMake(1.0f, 1.0f);
self.layer.shadowOpacity = 0.8;
[super touchesBegan:touches withEvent:event];
isPressed = TRUE;
}
else {
self.contentEdgeInsets = UIEdgeInsetsMake(0.0,0.0,0.0,0.0);
self.layer.shadowOffset = CGSizeMake(2.0f, 2.0f);
self.layer.shadowOpacity = 0.5;
[super touchesEnded:touches withEvent:event];
isPressed = FALSE;
}
} `
Aqui está uma implementação C# / Monotouch (xamarin.ios) usando abordagens apresentadas acima. Ele assume que você já definiu o estado de imagem destacado e configura os estados selecionados e selecionados | destacados para usar a mesma imagem.
var selected = button.BackgroundImageForState(UIControlState.Highlighted);
button.SetBackgroundImage(selected, UIControlState.Selected);
button.SetBackgroundImage(selected, UIControlState.Selected | UIControlState.Highlighted);
button.TouchUpInside += delegate
{
NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(0), delegate
{
button.Highlighted = true;
NSTimer.CreateScheduledTimer(TimeSpan.FromMilliseconds(200), delegate
{
button.Highlighted = false;
});
});
};