UIButton 禁用状态不会立即改变

Posted

技术标签:

【中文标题】UIButton 禁用状态不会立即改变【英文标题】:UIButton disabled state not changing immediately 【发布时间】:2015-01-18 16:04:59 【问题描述】:

我有一个UIButton 设置,我想用它来告诉用户正在发生的事情,而不是只为这个实例使用加载器。

例如UIControlStateNormal 有: 背景绿色 标题文字白色 标题 - 点击发送

那么UIControlStateDisabled 有: 背景白色 标题文字绿色 标题 - 发送中

然后当点击按钮时,我们将按钮更新为enabled = NO;

问题 我注意到的问题是,当按钮更改为禁用(启用否)时,标题文本、颜色、背景的更改直到所有方法调用等都完成后才完成,所以为时已晚。

我阅读了一些其他线程以使用btn layoutIfNeeded 和/或btn setNeedsLayout。这些实际上是强制更新按钮的原因,但在所有其他调用/方法完成之前似乎不会发生。因此更新按钮文本等为时已晚。

关于如何使按钮立即更新其状态和属性然后完成其他任务的任何想法?我已经检查以确保它在主线程上并且所有更新/调用都不是问题。

编辑 基本上,当点击按钮时,我们会更新状态:

- (IBAction)sendFeedbackButtonPressed:(id)sender 
    DebugLog(@"selected: %@",self.sendFeedbackButton.selected ? @"Yes" : @"No");
    DebugLog(@"highlighted: %@",self.sendFeedbackButton.highlighted ? @"Yes" : @"No");

    dispatch_async(dispatch_get_main_queue(), ^
        [self shouldFeedbackButtonBeEnabled:NO];
        DebugLog(@"enabled: %@",self.sendFeedbackButton.enabled ? @"Yes" : @"No");
    );

    dispatch_async(dispatch_get_main_queue(), ^
        NSString *errorMessage = [self validateForm];

        if (errorMessage) 
            [[[UIAlertView alloc] initWithTitle:nil message:errorMessage delegate:nil cancelButtonTitle:nil otherButtonTitles:NSLocalizedString(@"Feedback Form Validation Error Ok Button", nil), nil] show];
            [self shouldFeedbackButtonBeEnabled:YES];
            return;
        

        //TODO: send it
        // Send the form values to the server here.
        [self sendFeedbackToParse];
    );


-(void)setupSendFeedbackButton 
    UIColor *mainColor = [UIColor colorWithRed:41/255.0f green:128/255.0f blue:185/255.0f alpha:1];

    self.sendFeedbackButton.clipsToBounds = YES;
    self.sendFeedbackButton.layer.cornerRadius = 5.0f;
    self.sendFeedbackButton.layer.borderWidth = 2;
    self.sendFeedbackButton.layer.borderColor = mainColor.CGColor;

    // Disabled State
    [self.sendFeedbackButton setBackgroundImage:[WTNUtility imageFromColor:[UIColor whiteColor]] forState:UIControlStateDisabled | UIControlStateHighlighted];
    [self.sendFeedbackButton setTitle:NSLocalizedString(@"Feedback Form Send Feedback Button - Sending feedback disabled state", nil) forState:UIControlStateDisabled | UIControlStateHighlighted];
    [self.sendFeedbackButton setTitleColor:mainColor forState:UIControlStateDisabled | UIControlStateHighlighted];

    // Normal State
    [self.sendFeedbackButton setBackgroundImage:[WTNUtility imageFromColor:mainColor] forState:UIControlStateNormal];
    [self.sendFeedbackButton setTitle:NSLocalizedString(@"Feedback Form Send Feedback Button Title", nil) forState:UIControlStateNormal];
    [self.sendFeedbackButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];


-(void)shouldFeedbackButtonBeEnabled:(BOOL)decision 
    BOOL currentState = self.sendFeedbackButton.enabled;

    if (currentState == decision) 
        return;
     else 
        self.sendFeedbackButton.enabled = decision;
        [self.sendFeedbackButton layoutIfNeeded];
    


-(void)sendFeedbackToParse 
    DebugLog(@"%s",__PRETTY_FUNCTION__);
    DebugLog(@"button is enabled: %@",self.sendFeedbackButton.enabled ? @"Yes" : @"No");
    DebugLog(@"highlighted: %@",self.sendFeedbackButton.highlighted ? @"Yes" : @"No");
//    sleep(10);

//    self.sendFeedbackButton.enabled = YES;

【问题讨论】:

@Varosion 它是第一个运行的 【参考方案1】:

您在检查主队列方面处于正确的轨道上,但您的额外处理必须在 UI 有机会更新之前完成。

如果您的代码对这种方法友好,请使用两个调度块返回主队列。第一个是您的 UI 状态设置,第二个是您的剩余处理。这让 UI 状态在您的附加处理完成之前实际更新。

伪代码:

- (IBAction) handlePress:(id)sender 
  dispatch_async(dispatch_get_main_queue(), ^
// Do your state update (button disabled, etc)
                        );

  dispatch_async(dispatch_get_main_queue(), ^
// Do your further processing - AFTER the ui has been updated
                        );

【讨论】:

谢谢,您是什么意思?我们运行的过程不是太密集和不够友好。基本上我们会做一些验证/错误来显示它是否通过了我们将数据发送到某个地方。您将如何在主节点上有两个调度块?我可以用一些示例代码来更新问题 看起来我们正在同时编辑。看看修改后的答案;这是更清楚还是更需要? 谢谢,我是否需要做任何回调来确保 UI 更新,或者仅使用两个块意味着一个在主线程上的第二个任务开始之前在主线程上完成?> 除非你有更复杂的事情发生,否则你不需要做任何额外的事情。通过使用这两个块,您可以在进入额外处理之前让状态更改有机会实际处理 UI。 不幸的是它没有区别。即使我在第二个主队列调用开始时中断,按钮状态的更新仍然没有完成。即使它只是将启用更改为 NO 并应用相关的状态控制项,如 titleLabel、backgroundColor 等……就像它们在排队并且直到最后才完成。

以上是关于UIButton 禁用状态不会立即改变的主要内容,如果未能解决你的问题,请参考以下文章

UIButton的界面状态

如何禁用 UIButton 的高亮控制状态?

如何删除禁用的 UIButton 的灰色外观

UIButton在HighLighted时不会改变图片,只会将图片设置为灰色

禁用 UIButton 的突出显示 UIControl 状态

如何在nib文件中按下时禁用UIButton高亮显示?