保持在触摸后选择的UIButton

时间:2023-01-19 10:17:46

After my user clicks a button, I'd like that button to stay pushed during the time that I perform a network operation. When the network operation is complete, I want the button to return to its default state.

在我的用户点击一个按钮之后,我希望这个按钮在我执行网络操作的时候保持被推。当网络操作完成时,我希望按钮返回到默认状态。

I've tried calling -[UIButton setSelected:YES] right after the button push (with a corresponding call to -[UIButton setSelected:NO] after my network op finishes) but it doesn't seem to do anything. Same thing if I call setHighlighted:.

我试过在按下按钮之后调用-[UIButton setSelected:YES](在我的网络op结束后,我对-[UIButton setSelected:NO]进行了相应的调用),但它似乎什么也没做。同样的事情如果我叫se大灯:。

I suppose I could try swapping out the background image to denote a selected state for the duration of the network op, but that seems like a hack. Any better suggestions?

我想我可以尝试将背景图像替换为在网络op的持续时间内表示一个选定的状态,但这看起来像是一个hack。什么更好的建议吗?

Here's what my code looks like:

我的代码是这样的:

- (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;
}

9 个解决方案

#1


73  

How are you setting the images for the different UIControlStates on the button? Are you setting a background image for UIControlStateHighlighted as well as UIControlStateSelected?

如何设置按钮上不同UIControlStates的图像?您是否为uicontrolstate高亮显示以及uicontrstatesselected设置背景图像?

UIImage *someImage = [UIImage imageNamed:@"SomeResource.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
[button setBackgroundImage:someImage forState:UIControlStateSelected];

If you're setting the selected state on the button touch down event rather than touch up inside, your button will actually be in a highlighted+selected state, so you'll want to set that too.

如果您正在设置按钮touch down事件上的选定状态,而不是在内部进行触摸,那么您的按钮实际上将处于突出显示+选择状态,因此您也需要设置它。

[button setBackgroundImage:someImage forState:(UIControlStateHighlighted|UIControlStateSelected)];

Edit:

To sum up my remarks in the comments and to address the code you posted...you need to set your background images for the full UIControl state that you're in. According to your code snippet, this control state would be disabled + selected + highlighted for the duration of the network operation. This means that you would need to do this:

在评论中总结我的评论,并指出你发布的代码……您需要为您所在的UIControl状态设置背景图像。根据您的代码片段,在网络操作期间,此控制状态将被禁用+ selected +高亮显示。这意味着你需要这样做:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateHighlighted|UIControlStateSelected)];

If you remove the highlighted = YES, then you would need this:

如果删除突出显示的= YES,则需要以下内容:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateSelected)];

Get the picture?

把这幅画吗?

#2


29  

I have an easier way. Just use "performSelector" with 0 delay to perform [button setHighlighted:YES] . This will perform re-highlighting after the current runloop ends.

我有一个更简单的方法。只需要使用“performSelector”和0延迟来执行[按钮selighted:YES]。这将在当前运行循环结束后执行重新突出显示。

- (IBAction)buttonSelected:(UIButton*)sender {
    NSLog(@"selected %@",sender.titleLabel.text);
    [self performSelector:@selector(doHighlight:) withObject:sender afterDelay:0];
}

- (void)doHighlight:(UIButton*)b {
    [b setHighlighted:YES];
}

#3


27  

"Everything gets better when you turn power on"

"当你打开电源,一切都会变得更好"

    button.selected = !button.selected;

works perfectly... after I connected the outlet to the button in the Interface Builder.

作品完美……在我将outlet连接到接口构建器中的按钮之后。

You do not need to setBackgroundImage:forState:, the builder allows you to specify the background (gets resized if necessary) or/and foreground (not resizing) images.

您不需要setBackgroundImage:forState:,构建器允许您指定背景(如果需要,可以调整大小)或/和前景(不调整大小)图像。

#4


27  

Try using NSOperationQueue to achieve this. Try out code as follows:

尝试使用NSOperationQueue来实现这一点。试用代码如下:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    theButton.highlighted = YES;
}];

Hope this helps.

希望这个有帮助。

#5


8  

Use a block so you don't have to build a whole separate method:

使用一个区块,这样你就不需要建立一个完全独立的方法:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
    theButton.highlighted = YES;
});

Update

To be clear you still need to set the background (or normal image) for the combination states as well as the regular ones like sbrocket says in the accepted answer. At some point your button will be both selected and highlighted, and you won't have an image for that unless you do something like this:

很明显,你仍然需要为组合状态设置背景(或正常图像),以及像sbrocket这样的常规图像。在某一时刻,你的按钮将被选中并突出显示,除非你这样做:

[button setBackgroundImage:someImage forState (UIControlStateHighlighted|UIControlStateSelected)];

Otherwise your button can fall back to the UIControlStateNormal image for the brief selected+highlighted state and you'll see a flash.

否则,您的按钮可以返回到uicontrolstat诺曼图像的简短选择+突出显示状态,您将看到一个闪光。

#6


1  

I had a similar problem where I wanted a button to keep it's highlight after click. The problem is if you try to use setHighlighted:YES inside of you click action it will reset right after you click action, - (IBAction)checkInButtonPushed

我有一个类似的问题,我想要一个按钮在点击后保持它的高光。问题是,如果你尝试使用se大腿灯:是的,在你点击动作的时候,它会在你点击动作之后重置——(IBAction) checkinbuttonpush

I solved this by using a NSTimer like this

我用这样的解算器解出来了

NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.01
                                         target: self
                                       selector: @selector(selectCurrentIndex)
                                       userInfo: nil
                                        repeats: NO];

and then call setHighlighted:YES from my selectCurrentIndex method. I use regular UIButtonTypeRoundedRect buttons.

然后调用se大腿灯:YES来自我的selectCurrentIndex方法。我使用普通的UIButtonTypeRoundedRect按钮。

#7


1  

In swift I'm doing it like the following.

在swift中,我是这样做的。

I create a Subclass of UIButton and implemented a custom property state

我创建了UIButton的子类并实现了一个自定义属性状态。

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
        }
    }

}

Works perfectly for me.

完全适合我。

#8


0  

I have another way ...if you don't want to use images, and you want the effect of a pressed button, You can subclass the Button and here's my code:

我有另一种方法……如果你不想使用图像,你想要按下按钮的效果,你可以对按钮进行子类化,这是我的代码:

in the .h File:

. h文件中:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

In the .m File:

在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;

     }


 } `

#9


0  

Here is a C# / MonoTouch (Xamarin.iOS) implementation using approaches presented above. It assumes you have set the Highlighted image state already, and configures the selected and selected|highlighted states to use the same image.

下面是使用上述方法实现的c# / MonoTouch (Xamarin.iOS)实现。它假定您已经设置了高亮显示的图像状态,并配置选中的和选中的|,并突出显示了使用相同图像的状态。

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;
        });
    });
};

#1


73  

How are you setting the images for the different UIControlStates on the button? Are you setting a background image for UIControlStateHighlighted as well as UIControlStateSelected?

如何设置按钮上不同UIControlStates的图像?您是否为uicontrolstate高亮显示以及uicontrstatesselected设置背景图像?

UIImage *someImage = [UIImage imageNamed:@"SomeResource.png"];
[button setBackgroundImage:someImage forState:UIControlStateHighlighted];
[button setBackgroundImage:someImage forState:UIControlStateSelected];

If you're setting the selected state on the button touch down event rather than touch up inside, your button will actually be in a highlighted+selected state, so you'll want to set that too.

如果您正在设置按钮touch down事件上的选定状态,而不是在内部进行触摸,那么您的按钮实际上将处于突出显示+选择状态,因此您也需要设置它。

[button setBackgroundImage:someImage forState:(UIControlStateHighlighted|UIControlStateSelected)];

Edit:

To sum up my remarks in the comments and to address the code you posted...you need to set your background images for the full UIControl state that you're in. According to your code snippet, this control state would be disabled + selected + highlighted for the duration of the network operation. This means that you would need to do this:

在评论中总结我的评论,并指出你发布的代码……您需要为您所在的UIControl状态设置背景图像。根据您的代码片段,在网络操作期间,此控制状态将被禁用+ selected +高亮显示。这意味着你需要这样做:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateHighlighted|UIControlStateSelected)];

If you remove the highlighted = YES, then you would need this:

如果删除突出显示的= YES,则需要以下内容:

[button setBackgroundImage:someImage forState:(UIControlStateDisabled|UIControlStateSelected)];

Get the picture?

把这幅画吗?

#2


29  

I have an easier way. Just use "performSelector" with 0 delay to perform [button setHighlighted:YES] . This will perform re-highlighting after the current runloop ends.

我有一个更简单的方法。只需要使用“performSelector”和0延迟来执行[按钮selighted:YES]。这将在当前运行循环结束后执行重新突出显示。

- (IBAction)buttonSelected:(UIButton*)sender {
    NSLog(@"selected %@",sender.titleLabel.text);
    [self performSelector:@selector(doHighlight:) withObject:sender afterDelay:0];
}

- (void)doHighlight:(UIButton*)b {
    [b setHighlighted:YES];
}

#3


27  

"Everything gets better when you turn power on"

"当你打开电源,一切都会变得更好"

    button.selected = !button.selected;

works perfectly... after I connected the outlet to the button in the Interface Builder.

作品完美……在我将outlet连接到接口构建器中的按钮之后。

You do not need to setBackgroundImage:forState:, the builder allows you to specify the background (gets resized if necessary) or/and foreground (not resizing) images.

您不需要setBackgroundImage:forState:,构建器允许您指定背景(如果需要,可以调整大小)或/和前景(不调整大小)图像。

#4


27  

Try using NSOperationQueue to achieve this. Try out code as follows:

尝试使用NSOperationQueue来实现这一点。试用代码如下:

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
    theButton.highlighted = YES;
}];

Hope this helps.

希望这个有帮助。

#5


8  

Use a block so you don't have to build a whole separate method:

使用一个区块,这样你就不需要建立一个完全独立的方法:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{
    theButton.highlighted = YES;
});

Update

To be clear you still need to set the background (or normal image) for the combination states as well as the regular ones like sbrocket says in the accepted answer. At some point your button will be both selected and highlighted, and you won't have an image for that unless you do something like this:

很明显,你仍然需要为组合状态设置背景(或正常图像),以及像sbrocket这样的常规图像。在某一时刻,你的按钮将被选中并突出显示,除非你这样做:

[button setBackgroundImage:someImage forState (UIControlStateHighlighted|UIControlStateSelected)];

Otherwise your button can fall back to the UIControlStateNormal image for the brief selected+highlighted state and you'll see a flash.

否则,您的按钮可以返回到uicontrolstat诺曼图像的简短选择+突出显示状态,您将看到一个闪光。

#6


1  

I had a similar problem where I wanted a button to keep it's highlight after click. The problem is if you try to use setHighlighted:YES inside of you click action it will reset right after you click action, - (IBAction)checkInButtonPushed

我有一个类似的问题,我想要一个按钮在点击后保持它的高光。问题是,如果你尝试使用se大腿灯:是的,在你点击动作的时候,它会在你点击动作之后重置——(IBAction) checkinbuttonpush

I solved this by using a NSTimer like this

我用这样的解算器解出来了

NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.01
                                         target: self
                                       selector: @selector(selectCurrentIndex)
                                       userInfo: nil
                                        repeats: NO];

and then call setHighlighted:YES from my selectCurrentIndex method. I use regular UIButtonTypeRoundedRect buttons.

然后调用se大腿灯:YES来自我的selectCurrentIndex方法。我使用普通的UIButtonTypeRoundedRect按钮。

#7


1  

In swift I'm doing it like the following.

在swift中,我是这样做的。

I create a Subclass of UIButton and implemented a custom property state

我创建了UIButton的子类并实现了一个自定义属性状态。

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
        }
    }

}

Works perfectly for me.

完全适合我。

#8


0  

I have another way ...if you don't want to use images, and you want the effect of a pressed button, You can subclass the Button and here's my code:

我有另一种方法……如果你不想使用图像,你想要按下按钮的效果,你可以对按钮进行子类化,这是我的代码:

in the .h File:

. h文件中:

@interface reservasButton : UIButton {

BOOL isPressed;
}
 @end

In the .m File:

在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;

     }


 } `

#9


0  

Here is a C# / MonoTouch (Xamarin.iOS) implementation using approaches presented above. It assumes you have set the Highlighted image state already, and configures the selected and selected|highlighted states to use the same image.

下面是使用上述方法实现的c# / MonoTouch (Xamarin.iOS)实现。它假定您已经设置了高亮显示的图像状态,并配置选中的和选中的|,并突出显示了使用相同图像的状态。

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;
        });
    });
};