选择一个时取消选择所有 UIButton

Posted

技术标签:

【中文标题】选择一个时取消选择所有 UIButton【英文标题】:Deselect all UIButtons when one is selected 【发布时间】:2013-09-02 13:16:37 【问题描述】:

我的游戏中有八 (8) 个 UIButtons 设置。当一个被选中时,它显示它已被选中,如果再次单击它,它将显示为未选中。但是,我想这样做,以便当您选择一个按钮并且选择其他七 (7) 个按钮中的任何一个时,它们将变为未选中状态。

我知道如何通过使用[buttonName setSelected:NO] 来做到这一点,但问题是如果buttonTwo 已经传递给buttonOne,我无法将buttonOne 传递给buttonTwo,因为我已经在buttonOne 中导入了buttonTwo 的头文件。如果我有两个标题相互导入,它会引发解析错误。我已经被困了一段时间了,希望有人能解决我的问题。

感谢您的帮助。

【问题讨论】:

哇,等一下,你们到底为什么要相互导入自定义按钮的头文件?不要告诉我你已经为 each 和你拥有的每一个 UIButton 创建了一个自定义类。 在选择任何按钮之前,重新创建所有按钮 如果其中任何一个对您有帮助,请选择一个答案,或者提供更多详细信息以查看我们是否可以帮助您。谢谢! 【参考方案1】:

获取当前按钮的父视图并遍历其中的所有按钮,取消选择所有按钮。然后,选择当前的。

// Unselect all the buttons in the parent view
for (UIView *button in currentButton.superview.subviews) 
    if ([button isKindOfClass:[UIButton class]]) 
        [(UIButton *)button setSelected:NO];
    


// Set the current button as the only selected one
[currentButton setSelected:YES];

注意:按照 cmets 的建议,您可以保留一组按钮并按照上述代码处理父视图的子视图的方式遍历它。如果包含按钮的视图内部有许多其他子视图,这将提高代码的性能。

【讨论】:

您可以通过更改操作顺序来跳过使用每个按钮检查 currentButton。首先 - 取消全选,而不是选择当前。并且最好为遵循此行为的按钮创建单独的数组,而不是遍历所有子视图。 @ArtFeel 你是对的。我们可以先取消选择所有按钮,然后再选择当前按钮。我将编辑答案。谢谢!!【参考方案2】:

我知道回答这个问题为时已晚,但我只用了几行代码就完成了。这是我所做的:

NSArray *arrView = self.view.subviews;
    for (UIButton *button in arrView) 
        if ([button isKindOfClass:[UIButton class]]) 
            [((UIButton *) button) setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        
    
[button1 setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal];

【讨论】:

【参考方案3】:

简单的方法。

-(void)buttonSelected:(id)sender
    UIButton *currentButton = (UIButton *)sender;
    for(UIView *view in self.view.subviews)

        if([view isKindOfClass:[UIButton class]])

            UIButton *btn = (UIButton *)view;
            [btn setSelected:NO];
        
    

    [currentButton setSelected:YES];


【讨论】:

【参考方案4】:

我实际上是通过阅读你们所有的意见来创建答案的,我非常感谢你们。在这篇文章之前,我不知道 UIButton 类的 tag 属性。

我创建了自己的 UIButton 子类,我们称之为CustomUIButton.m。我创建了一个NSMutableArray 属性以在存储按钮时使用,我将其称为customButtonArray

创建按钮时,我设置了tag 属性,并将按钮添加到父视图控制器上的本地数组中。在创建了我想要的所有按钮后,我设置了customButtonArray,如下所示:

// Initialize buttonHolderArray
NSMutableArray *buttonHolderArray = [[NSMutableArray alloc] init];

// Create a button
CustomUIButton *newButton = [[CustomUIButton alloc] initWithFrame:CGRectMake(10, 10, 50, 30)];
newButton.tag = 1;
[newButton setImage:[UIImage imageNamed:@"newButtonUnselected" forControlState:UIControlStateNormal]];
[buttonHolderArray addObject:newButton];

// Create additional buttons and add to buttonHolderArray...
// using different numbers for their tags (i.e. 2, 3, 4, etc)

// Set customButtonArray property by iterating through buttonHolderArray
NSInteger buttonCount = [buttonHolderArray count];

for (int i = 0; i < buttonCount; i++)

   [[buttonHolderArray objectAtIndex:i] setCustomButtonArray:buttonHolderArray];

要取消选择在调用不同按钮 handleTap: 时选择的任何其他按钮,我遍历子类主文件中的customButtonArray 并将selected 属性设置为NO。我还从另一个用图像手动填充的数组属性设置了正确的图像,这样做是为了不必在每次按下按钮时都填充数组。最后,取消选择所有其他按钮,如下所示:

// Populate two arrays: one with selected button images and the other with
// unselected button images that correspond to the buttons index in the 
// customButtonArray
NSMutableArray *tempSelectedArray = [[NSMutableArray alloc] init];
[tempSelectedArray addObject:[UIImage imageNamed:@"newButtonSelected"]];
// Add the other selected button images...
// Set the property array with this array
[self setSelectedImagesArray:tempSelectedArray];

NSMutableArray *tempUnselectedArray = [[NSMutableArray alloc] init];
[tempUnselectedArray addObject:[UIImage imageNamed:@"newButtonUnselected"]];
// Add the other unselected button images...
// Set the property array with this array
[self setUnselectedImagesArray:tempUnselectedArray];

- (void)handleTap:(UIGestureRecognizer *)selector

    // Get the count of buttons stored in the customButtonArray, use an if-elseif
    // statement to check if the button is already selected or not, and iterate through
    // the customButtonArray to find the button and set its properties
    NSInteger buttonCount = [[self customButtonArray] count];

    if (self.selected == YES)
    
        for (int i = 0; i < buttonCount; i++)
        
            if (self.tag == i)
            
                [self setSelected:NO];
                [self setImage:[[self unselectedImagesArray] objectAtIndex:i] forControlState:UIControlStateNormal];
            
        
    
    else if (self.selected == NO)
    
        for (int i = 0; i < buttonCount; i++)
        
            if (self.tag == i)
            
                [self setSelected:NO];
                [self setImage:[[self selectedImagesArray] objectAtIndex:i] forControlState:UIControlStateNormal];
            
        
    

    for (int i = 0; i < buttonCount; i++)
    
        if (self.tag != i)
        
            [self setSelected:NO];
            [self setImage:[[self unselectedImagesArray] objectAtIndex:i] forControlState:UIControlStateNormal];
        
    

感谢所有有用的信息,我想我应该详细分享我想出的最终答案,以帮助遇到此问题的其他人。

【讨论】:

【参考方案5】:

我想出了一个非常简单的方法来解决这个问题。我的示例是 2 个按钮,但您可以轻松地为其他按钮添加更多 if 语句。将所有按钮作为属性连接到 .h 文件并命名它们(我做了 button1 和 button2)。将以下代码放在您的 .m 文件中并将其(通过情节提要)连接到您的所有按钮。确保在设置按钮时为正常的 UIControlStateNormal 和 UIControlStateSelected 设置图像,否则这将不起作用。

- (IBAction)selectedButton1:(id)sender 

if ([sender isSelected]) 
    [sender setSelected:NO];

    if (sender == self.button1) 
        [self.button2 setSelected:YES];
    
    if (sender == self.button2) 
        [self.button1 setSelected:YES];
    


else

    [sender setSelected:YES];

    if (sender == self.button1) 
        [self.button2 setSelected:NO];
    
    if (sender == self.button2) 
        [self.button1 setSelected:NO];
    


【讨论】:

【参考方案6】:

回答“如果我有两个标题相互导入,则会引发解析错误”...

您应该尽可能避免在 .h 文件中使用 #import,而是将您想要使用的任何内容声明为前向类声明:

@class MyCustomClass

@interface SomethingThatUsesMyCustomClass : UIViewController

@property (nonatomic, strong) MyCustomClass *mcc;

@end

然后#import .m 文件中的标头:

#import "MyCustomClass.h"

@implementation SomethingThatUsesMyCustomClass

-(MyCustomClass *)mcc

   // whatever


@end

这种方法将防止由#import 循环引起的错误。

虽然我必须说我同意 SergiusGee 关于这个设置感觉有点奇怪的问题的评论。

【讨论】:

【参考方案7】:

这里最简单的方法是让父 UIView 按钮处于打开状态并遍历它。这是我的代码中的一个简单示例:

for (UIView *tmpButton in bottomBar.subviews)

  if ([tmpButton isKindOfClass:[UIButton class]])
  
       if (tmpButton.tag == 100800)
       
           tmpButton.selected = YES;
           [tmpButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal];
           [tmpButton setTitleColor:[UIColor greenColor] forState:UIControlStateHighlighted];

       else

          tmpButton.selected = NO;
          [tmpButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
          [tmpButton setTitleColor:[UIColor redColor]  forState:UIControlStateHighlighted];
        
    

【讨论】:

仅在UIButtons 实例化中使用“UIControlStateSelected”不是更简单吗?将 UIControlStateNormal 设置为 redColor,将 UIControlStateSelected 设置为 greenColor ?这样,您不必在每次用户触摸 UI 时更改按钮颜色。 如果bottomBar 有不是 UIButtons 的子视图,这段代码会发生什么? @Vinzzz 我在这里所做的是让用户看不到按钮的触摸。发生什么了?我猜它不会被执行。如果您愿意,我们可以将 for 语句中的 UIButton 更改为简单的 UIView 我认为你猜错了,你会得到一个运行时错误。恕我直言,将UIButton 更改为UIView,然后检查[view isKindOf:[UIButton class]] 可能更容易出错。 @Vinzzz 同意。以防万一。【参考方案8】:

您是否尝试过使用 ReactiveCocoa 框架并为您的代码添加一些块,这不是最简单的方法,但我会说当您有多个依赖项并且非常适合扩展时它是最有效的

我使用我建议的方法创建了一个小项目来解决您的问题(我尝试将其调整为良好的旧 MVC 模式,而不是我喜欢的 MVVM)

你可以在这里找到它

https://github.com/MWaly/MWButtonExamples

确保安装 cocoa pods 文件,因为此示例需要“ReactiveCocoa”和“BlocksKit”

我们将使用两个主要的类

ViewController => 显示按钮的 viewController 对象 MWCustomButton => 处理事件的自定义 UIButton

在创建按钮时,还会使用属性创建对 viewController 的弱引用

@property (weak) ViewController *ownerViewController ;

事件将在 blocksKit bk_addEventHandler 方法的帮助下处理,并将其传递给 ViewController (selectedButtonCallBackBlock) 的块

 [button bk_addEventHandler:^(id sender)
    
        self.selectedButtonCallBackBlock(button);

     forControlEvents:UIControlEventTouchUpInside];

现在在 ViewController 中,每个被触摸的按钮都会触发 callBackButtonBlock ,如果适用,它将更改其当前选择的按钮

__weak __typeof__(self) weakSelf = self;

self.selectedButtonCallBackBlock=^(MWCustomButton* button)
     __typeof__(self) strongSelf = weakSelf;
    strongSelf.currentSelectedButton=button;
      ;

在 MWCustomButton 类中,它会监听其 ownerViewController 的“currentSelectedButton”属性的任何变化,并使用我们良好的 Reactive Cocoa 来根据它更改其选择属性

 ///Observing changes to the selected button
    [[RACObserve(self, ownerViewController.currentSelectedButton) distinctUntilChanged] subscribeNext:^(MWCustomButton *x) 
            self.selected=(self==x);
    ];

我认为这会解决您的问题,同样您的问题可能会以更简单的方式解决,但是我相信使用这种方法会更具可扩展性和更简洁。

【讨论】:

【参考方案9】:

遍历父视图中的所有视图。检查它是否是 UIButton(或您的自定义按钮类)而不是发件人。将所有视图 isSelected 设置为 false。循环完成后,将发送者按钮 isSelected 设置为 true。

Swift 3 方式:

func buttonPressed(sender: UIButton) 
    for view in view.subviews 
        if view is UIButton && view != sender 
            (view as! UIButton).isSelected = false
        
    
    sender.isSelected = true

【讨论】:

【参考方案10】:

斯威夫特 4

  //Deselect all tip buttons via IBOutlets

  button1.isSelected = false
  button2.isSelected = false
  button3.isSelected = false

  //Make the button that triggered the IBAction selected.
  sender.isSelected = true

  //Get the current title of the button that was pressed.
    let buttonTitle = sender.currentTitle!

【讨论】:

以上是关于选择一个时取消选择所有 UIButton的主要内容,如果未能解决你的问题,请参考以下文章

选择/取消选择所有复选框 WIN32

在alertview中选择取消按钮时如何从数组中关闭所有alertview?

选择所有垫子选项并取消选择全部

如何使用一个 UIButton 从 UITableView 中选择和取消选择所有复选标记?

如何取消选择 DataGridView 控件中的所有选定行?

复制所有文本后隐藏复制和取消选择 UITextView 选项