关于 UIControlState 一次神奇的发现

最近发现关于 UIButton 状态的一个挺有意思的问题,大概就是:

当一个按钮处于选中状态,也就是 selectedYES 时,如果这时候再点击它时,按钮会变成 normal 状态时候的样子!

问题效果大概这样:

因为只是个 Demo ,所以代码写的比较随意,就是设置按钮不同状态下的呈现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#import "ViewController.h"
@interface ViewController ()
@property (strong, nonatomic) UIButton *btn1;
@property (strong, nonatomic) UIButton *btn2;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
btn1.frame = CGRectMake(100, 100, 60, 30);
[btn1 setTitle:@"按钮一" forState:UIControlStateNormal];
[btn1 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btn1 setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
[self.view addSubview:_btn1 = btn1];
[btn1 addTarget:self action:@selector(btn1Click) forControlEvents:UIControlEventTouchUpInside];
UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
btn2.frame = CGRectMake(170, 100, 60, 30);
[btn2 setTitle:@"按钮二" forState:UIControlStateNormal];
[btn2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[btn2 setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
[self.view addSubview:_btn2 = btn2];
[btn2 addTarget:self action:@selector(btn2Click) forControlEvents:UIControlEventTouchUpInside];
}
- (void)btn1Click {
if(_btn2.isSelected) {_btn2.selected = NO;}
_btn1.selected = YES;
}
- (void)btn2Click {
if(_btn1.isSelected) {_btn1.selected = NO;}
_btn2.selected = YES;
}
@end

我们可以发现,这里分别设置了按钮 UIControlStateNormalUIControlStateSelected 状态的标题颜色,那么该如何解决呢?

分别加上这两句就可以了:

1
2
3
[btn1 setTitleColor:[UIColor redColor] forState:UIControlStateSelected|UIControlStateHighlighted];
[btn2 setTitleColor:[UIColor redColor] forState:UIControlStateSelected|UIControlStateHighlighted];

至于为什么,我们可以看看 UIControlState 枚举的定义:

1
2
3
4
5
6
7
8
9
typedef NS_OPTIONS(NSUInteger, UIControlState) {
UIControlStateNormal = 0,
UIControlStateHighlighted = 1 << 0, // used when UIControl isHighlighted is set
UIControlStateDisabled = 1 << 1,
UIControlStateSelected = 1 << 2, // flag usable by app (see below)
UIControlStateFocused NS_ENUM_AVAILABLE_IOS(9_0) = 1 << 3, // Applicable only when the screen supports focus
UIControlStateApplication = 0x00FF0000, // additional flags available for application use
UIControlStateReserved = 0xFF000000 // flags reserved for internal framework use
};

我们可以发现,这是个 NS_OPTIONS 类型的枚举。既然是 NS_OPTIONS 类型,就表示按钮的状态可以是多个状态的:比如上面选中状态下再点击,可以理解为 选中|高亮 状态,也就是 UIControlStateSelected|UIControlStateHighlighted。当我们处于某个状态(selected)下,再想触发另外一个状态(highlighted),如果不做处理,就会导致一开始说的那种情况。