当前位置:网站首页>Uibutton status exploration and customization
Uibutton status exploration and customization
2022-07-06 14:20:00 【Code&Ocean】
original text :UIButton New state solution – Netease cloud music big front end
Control state
As iOS developer , When it comes to controls , I have to mention UIButton, It serves as a iOS The most commonly used control in the system to respond to user click operations , It provides us with quite rich functions and customizability . And our daily work 80% ~ 90% Doing is with UI Dealing with , Handle different states of controls under different operations of users , The simplest , For example, when the user is not logged in , The button is grayed out and cannot be clicked , When the user clicks, a reverse color effect will appear and be fed back to the user, and so on . Definition of common States , The system gave it very early :
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 API_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 Enumeration type
We usually preset UIButton Styles in different states , Then directly change the corresponding state bool value , Easy to use .
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
// The normal state
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
// Click to highlight
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
[button setBackgroundImage:[UIImage imageNamed:@"btn_highlighted"] forState:UIControlStateHighlighted];
// Unavailable
[button setTitleColor:[UIColor grayColor] forState:UIControlStateDisabled];
// When the user login status changes , Modify attribute values
if (/* The user is not logged in */) {
button.enabled = NO;
} else {
button.enabled = YES;
}
that UIButton Are there only four states available ? In real development , The state of the control may be many , Four kinds must not be enough .
State combination
First of all, we noticed ,UIControlState The definition of is a NS_OPTIONS, instead of NS_ENUM, Three effective bit The pairwise combination should have 8 States . It's just that we can write Demo Test it :
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setTitle:@"Normal" forState:UIControlStateNormal];
[btn setTitle:@"Selected" forState:UIControlStateSelected];
[btn setTitle:@"Highlighted" forState:UIControlStateHighlighted];
[btn setTitle:@"Highlighted & Disabled" forState:UIControlStateHighlighted | UIControlStateDisabled];
[btn setTitle:@"Disabled" forState:UIControlStateDisabled];
[btn setTitle:@"Selected & Disabled" forState:UIControlStateSelected | UIControlStateDisabled];
[btn setTitle:@"Selected & Highlighted & Disabled" forState:UIControlStateSelected | UIControlStateHighlighted | UIControlStateDisabled];
[btn setTitle:@"Selected & Highlighted" forState:UIControlStateSelected | UIControlStateHighlighted];
Practice has proved ,
UIControlStateHighlightedFollowUIControlStateHighlighted | UIControlStateDisabledUIControlStateSelected | UIControlStateHighlightedFollowUIControlStateSelected | UIControlStateHighlighted | UIControlStateDisabled
The effect is the same , Cover each other .
In fact, it's easy to understand , because UIControlStateDisabled And UIControlStateHighlighted Semantically, they should not coexist , So there are six available state combinations . in addition , It is found in practice that , When a state is not styled , It will be to Normal The style of the state covers the bottom , So in daily development , We'd better set the corresponding style for all the States used .
Custom state
With the above combination , We can basically cover 90% Daily development of , But what if you need to use more States ?
We are developing Yinjie I encountered the problem of insufficient status when I was on my personal homepage , For a follow button , It has the following different states ( Here's the picture ):
- The currently logged in user is not following this user
- The currently logged in user is following this user
- The currently logged in user has paid attention to this user
- The current login user and this user pay attention to each other

In this way, there are three states that users can operate , And each operable state has a corresponding highlight style , So we can't just use selected Status to indicate whether you have paid attention . For this need , An easy way to think of is under different data , Modify the style in the same state :
[button setTitle:@" Focus on " forState:UIControlStateNormal];
[button setTitle:@" Followed " forState:UIControlStateSelected];
// Pay attention to state changes
button.selected = YES;
if (/* The other party also paid attention to me */) {
[button setTitle:@" Pay attention to each other " forState:UIControlStateSelected];
}
The demand is realized , But the use of controls is no longer simple , We can't set all the States during initialization , Then in a data-driven state , State driven style , And add other logic , And this increase is easy to produce Bug.
Is there a better way to define the state , In order to realize the The style is set only once ?
Look back UIControlState The definition of , There is one UIControlStateApplication It seems that it has never been used , Can it be customized ?
We reuse selected Status as our concern followed state , And add loading Attention status , and mutual Pay attention to each other's state .
enum {
NKControlStateFollowed = UIControlStateSelected,
NKControlStateMutual = 1 << 16 | UIControlStateSelected,
NKControlStateLoading = 1 << 17 | UIControlStateDisabled,
};
@interface NKLoadingButton : UIButton
@property (nonatomic, getter=isLoading) BOOL loading;
@property (nonatomic) UIActivityIndicatorView *spinnerView;
@end
@interface NKFollowButton : NKLoadingButton
@property (nonatomic, getter=isMutual) BOOL mutual;
@end
The definition here needs to be explained as follows :
First , Why shift 16 The operation of ?
because UIControlStateApplication The value of is 0x00FF0000, displacement 16 (16 To 23 All are legal values ) Just let the state bit fall within its range .
So customization should start from 16 Start .
secondly ,loading Users should not click to operate , So it's going to or On disabled state ,mutual It must have been followed Of course. ( namely selected), So it's going to or On selected.
Last ,loading State should be reusable elsewhere , Therefore, there is a separate layer in the inheritance relationship NKLoadingButton.NKLoadingButton The implementation of is relatively simple , It should be noted that , We're going to rewrite -setEnabled: Method let it in loading At the same time, it is in a non clickable state .
@implementation NKLoadingButton
- (UIControlState)state
{
UIControlState state = [super state];
if (self.isLoading) {
state |= NKControlStateLoading;
}
return state;
}
- (void)setEnabled:(BOOL)enabled
{
super.enabled = !_loading && enabled;
}
- (void)setLoading:(BOOL)loading
{
if (_loading != loading) {
_loading = loading;
super.enabled = !loading;
if (loading) {
[self.spinnerView startAnimating];
} else {
[self.spinnerView stopAnimating];
}
[self setNeedsLayout];
[self invalidateIntrinsicContentSize];
}
}
@end
NKFollowButton The implementation is as follows :
@implementation NKFollowButton
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setTitle:@" Focus on " forState:UIControlStateNormal];
[self setTitle:@" Followed " forState:UIControlStateSelected];
[self setTitle:@" Followed " forState:UIControlStateSelected | UIControlStateHighlighted];
[self setTitle:@" Pay attention to each other " forState:NKControlStateMutual];
[self setTitle:@" Pay attention to each other " forState:NKControlStateMutual | UIControlStateHighlighted];
[self setTitle:@"" forState:NKControlStateLoading];
[self setTitle:@"" forState:NKControlStateLoading | UIControlStateSelected];
[self setTitle:@"" forState:NKControlStateMutual | NKControlStateLoading];
// Color related settings are omitted below
}
return self;
}
- (UIControlState)state
{
UIControlState state = [super state];
if (self.isMutual) {
state |= NKControlStateMutual;
}
return state;
}
- (void)setSelected:(BOOL)selected
{
super.selected = selected;
if (!selected) {
self.mutual = NO;
}
}
- (void)setMutual:(BOOL)mutual
{
if (_mutual != mutual) {
_mutual = mutual;
if (mutual) {
self.selected = YES;
}
[self setNeedsLayout];
[self invalidateIntrinsicContentSize];
}
}
@end
We need to rewrite -state Methods let the outside world get complete 、 The right value , rewrite -setSelected: Methods and -setMutual: Method , Let them be mutually exclusive under certain conditions , Unified under certain conditions .
such , We achieved only in -init Set a style in , The subsequent modification is only based on the data returned by the server .selected``.loading.mutual The value of the can !
summary
This article starts from a single state , To the combined state , To customize the status of layers of in-depth introduction UIButton The application of the state of in daily development , Only state drives UI It has always been a good idea in programmer development , This article gives the implementation reference from a basic control . in addition , We are looking at some systems that provide API when , Be sure to think more about what Apple's intention is ? How they want us to use , And how to use it correctly ?
边栏推荐
- 【Numpy和Pytorch的数据处理】
- Ucos-iii learning records (11) - task management
- Hackmyvm target series (1) -webmaster
- 【头歌educoder数据表中数据的插入、修改和删除】
- This article explains in detail how mockmvc is used in practical work
- Library management system
- captcha-killer验证码识别插件
- 强化学习基础记录
- Middleware vulnerability recurrence Apache
- [experiment index of educator database]
猜你喜欢

循环队列(C语言)
![[dark horse morning post] Shanghai Municipal Bureau of supervision responded that Zhong Xue had a high fever and did not melt; Michael admitted that two batches of pure milk were unqualified; Wechat i](/img/d7/4671b5a74317a8f87ffd36be2b34e1.jpg)
[dark horse morning post] Shanghai Municipal Bureau of supervision responded that Zhong Xue had a high fever and did not melt; Michael admitted that two batches of pure milk were unqualified; Wechat i

Canvas foundation 1 - draw a straight line (easy to understand)

HackMyvm靶机系列(4)-vulny

攻防世界MISC练习区(gif 掀桌子 ext3 )

List and data frame of R language experiment III

Windows platform mongodb database installation

How to understand the difference between technical thinking and business thinking in Bi?

Package bedding of components

记一次edu,SQL注入实战
随机推荐
2022华中杯数学建模思路
记一次,修改密码逻辑漏洞实战
XSS之冷门事件
WEB漏洞-文件操作之文件包含漏洞
Record a penetration of the cat shed from outside to inside. Library operation extraction flag
强化学习基础记录
外网打点(信息收集)
Simply understand the promise of ES6
HackMyvm靶机系列(3)-visions
What language should I learn from zero foundation. Suggestions
7-14 error ticket (PTA program design)
内网渗透之内网信息收集(一)
Windows platform mongodb database installation
Wei Shen of Peking University revealed the current situation: his class is not very good, and there are only 5 or 6 middle-term students left after leaving class
7-4 散列表查找(PTA程序设计)
Hackmyvm Target Series (3) - vues
Experiment 7 use of common classes (correction post)
内网渗透之内网信息收集(四)
Data mining - a discussion on sample imbalance in classification problems
浅谈漏洞发现思路