iOS开发基础5-UIButton:高阶用法与封装工具类

深度解析 UIButton:高阶用法与封装工具类

UIButton 是 iOS 开发中最常用的交互控件之一,继承自 UIControl,用于响应用户触摸操作。它支持多种状态样式、图文混排和事件处理。本文从基础用法出发,逐步深入高阶技巧、工具类封装与底层实现。


一、基础使用

1.1 按钮类型

UIButton 通过 buttonWithType: 类方法创建,支持以下类型:

类型 说明
UIButtonTypeCustom 自定义样式,无默认外观,标题颜色默认为白色
UIButtonTypeSystem 系统按钮,默认蓝色文字,按下时有透明度变化(iOS 7+)
UIButtonTypeDetailDisclosure 详情披露按钮,显示蓝色 "i" 图标
UIButtonTypeInfoLight 浅色背景的信息按钮
UIButtonTypeInfoDark 深色背景的信息按钮
UIButtonTypeContactAdd 添加联系人按钮,显示蓝色 "+" 图标
UIButtonTypeClose 关闭按钮,显示灰色 "x" 图标(iOS 13+)

1.2 创建按钮

Objective-C

UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(50, 100, 200, 50);
[button setTitle:@"Click Me" forState:UIControlStateNormal];
[self.view addSubview:button];

Swift

let button = UIButton(type: .system)
button.frame = CGRect(x: 50, y: 100, width: 200, height: 50)
button.setTitle("Click Me", for: .normal)
view.addSubview(button)

1.3 状态与样式设置

UIButton 支持四种核心状态,可分别设置标题、标题颜色、图片和背景图片:

状态 说明
UIControlStateNormal 正常状态(默认)
UIControlStateHighlighted 按下高亮状态
UIControlStateDisabled 禁用状态(enabled = NO)
UIControlStateSelected 选中状态(selected = YES)

Objective-C

// 标题
[button setTitle:@"Normal" forState:UIControlStateNormal];
[button setTitle:@"Highlighted" forState:UIControlStateHighlighted];

// 标题颜色
[button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];

// 图片(按钮内部图标,与标题并列显示)
[button setImage:[UIImage imageNamed:@"icon_normal"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"icon_highlighted"] forState:UIControlStateHighlighted];

// 背景图片(铺满整个按钮,标题显示在其上)
[button setBackgroundImage:[UIImage imageNamed:@"bg_normal"] forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:@"bg_highlighted"] forState:UIControlStateHighlighted];

Swift

button.setTitle("Normal", for: .normal)
button.setTitle("Highlighted", for: .highlighted)

button.setTitleColor(.blue, for: .normal)
button.setTitleColor(.red, for: .highlighted)

button.setImage(UIImage(named: "icon_normal"), for: .normal)
button.setImage(UIImage(named: "icon_highlighted"), for: .highlighted)

button.setBackgroundImage(UIImage(named: "bg_normal"), for: .normal)
button.setBackgroundImage(UIImage(named: "bg_highlighted"), for: .highlighted)

image 与 backgroundImage 的区别:image 是按钮内部图标,与 titleLabel 并列排布;backgroundImage 是背景图,铺满整个按钮,标题和图标显示在其上方。


二、高阶用法

2.1 自定义样式(圆角与边框)

通过 layer 属性可以实现圆角、边框等自定义外观。

Objective-C

UIButton *customButton = [UIButton buttonWithType:UIButtonTypeCustom];
customButton.frame = CGRectMake(50, 200, 200, 50);
[customButton setTitle:@"Custom Button" forState:UIControlStateNormal];
[customButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
customButton.backgroundColor = [UIColor purpleColor];

// 圆角:纯背景色 + 圆角不需要 masksToBounds,避免离屏渲染
customButton.layer.cornerRadius = 10;

// 边框
customButton.layer.borderColor = [UIColor whiteColor].CGColor;
customButton.layer.borderWidth = 2.0;

// 仅当有子视图/图片需要裁剪到圆角内时才开启
// customButton.layer.masksToBounds = YES;

[self.view addSubview:customButton];

Swift

let customButton = UIButton(type: .custom)
customButton.frame = CGRect(x: 50, y: 200, width: 200, height: 50)
customButton.setTitle("Custom Button", for: .normal)
customButton.setTitleColor(.white, for: .normal)
customButton.backgroundColor = .purple

customButton.layer.cornerRadius = 10
customButton.layer.borderColor = UIColor.white.cgColor
customButton.layer.borderWidth = 2.0

// 仅在需要裁剪溢出内容时开启
// customButton.layer.masksToBounds = true

view.addSubview(customButton)

性能提示:cornerRadius 配合 backgroundColor 可以直接显示圆角,无需设置 masksToBounds = YES。masksToBounds 会触发离屏渲染(Off-screen Rendering),在列表中大量使用时会造成卡顿。只有当按钮内部有图片或子视图需要被圆角裁剪时,才需要开启。

2.2 富文本标题

通过 NSAttributedString 可以在按钮标题中混合不同字体、颜色和样式。

Objective-C

NSString *text = @"Rich Text Button";
NSMutableAttributedString *attributedTitle = [[NSMutableAttributedString alloc] initWithString:text];

// "Rich" 部分:黑色 + 粗体
[attributedTitle addAttribute:NSForegroundColorAttributeName
                       value:[UIColor blackColor]
                       range:NSMakeRange(0, 4)];
[attributedTitle addAttribute:NSFontAttributeName
                       value:[UIFont boldSystemFontOfSize:18]
                       range:NSMakeRange(0, 4)];

// "Text" 部分:红色 + 斜体
[attributedTitle addAttribute:NSForegroundColorAttributeName
                       value:[UIColor redColor]
                       range:NSMakeRange(5, 4)];
[attributedTitle addAttribute:NSFontAttributeName
                       value:[UIFont italicSystemFontOfSize:18]
                       range:NSMakeRange(5, 4)];

[customButton setAttributedTitle:attributedTitle forState:UIControlStateNormal];

Swift

let text = "Rich Text Button"
let attributedTitle = NSMutableAttributedString(string: text)

attributedTitle.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(location: 0, length: 4))
attributedTitle.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 18), range: NSRange(location: 0, length: 4))

attributedTitle.addAttribute(.foregroundColor, value: UIColor.red, range: NSRange(location: 5, length: 4))
attributedTitle.addAttribute(.font, value: UIFont.italicSystemFont(ofSize: 18), range: NSRange(location: 5, length: 4))

customButton.setAttributedTitle(attributedTitle, for: .normal)

2.3 图文混排按钮

按钮可以同时显示图标和文字,通过 imageEdgeInsets 和 titleEdgeInsets 调整相对位置。常见有四种布局:左图右文(默认)、右图左文、上图下文、下图上文。

左图右文(默认)

Objective-C

UIButton *imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
imageButton.frame = CGRectMake(50, 300, 200, 50);
[imageButton setTitle:@"Icon Button" forState:UIControlStateNormal];
[imageButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[imageButton setImage:[UIImage imageNamed:@"icon"] forState:UIControlStateNormal];

// 图标左移 10pt,标题右移 10pt,增大间距
imageButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0);
imageButton.titleEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);

[self.view addSubview:imageButton];

Swift

let imageButton = UIButton(type: .custom)
imageButton.frame = CGRect(x: 50, y: 300, width: 200, height: 50)
imageButton.setTitle("Icon Button", for: .normal)
imageButton.setTitleColor(.black, for: .normal)
imageButton.setImage(UIImage(named: "icon"), for: .normal)

imageButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: -10, bottom: 0, right: 0)
imageButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)

view.addSubview(imageButton)

四种布局通用方法

通过封装一个方法,根据图片位置自动计算 imageEdgeInsets 和 titleEdgeInsets:

Objective-C(UIButton 分类)

// UIButton+ImagePosition.h
typedef NS_ENUM(NSInteger, ButtonImagePosition) {
    ButtonImagePositionLeft,   // 图片在左,文字在右(默认)
    ButtonImagePositionRight,  // 图片在右,文字在左
    ButtonImagePositionTop,    // 图片在上,文字在下
    ButtonImagePositionBottom  // 图片在下,文字在上
};

@interface UIButton (ImagePosition)
- (void)setImagePosition:(ButtonImagePosition)position spacing:(CGFloat)spacing;
@end
// UIButton+ImagePosition.m
@implementation UIButton (ImagePosition)

- (void)setImagePosition:(ButtonImagePosition)position spacing:(CGFloat)spacing {
    [self layoutIfNeeded];
    
    CGSize imageSize = self.imageView.frame.size;
    CGSize titleSize = self.titleLabel.frame.size;
    
    CGFloat imageOffsetX = (imageSize.width + titleSize.width / 2) - (imageSize.width + titleSize.width + spacing) / 2;
    CGFloat imageOffsetY = imageSize.height / 2;
    CGFloat titleOffsetX = (titleSize.width + imageSize.width / 2) - (imageSize.width + titleSize.width + spacing) / 2;
    CGFloat titleOffsetY = titleSize.height / 2;
    
    UIEdgeInsets imageEdge = UIEdgeInsetsZero;
    UIEdgeInsets titleEdge = UIEdgeInsetsZero;
    
    switch (position) {
        case ButtonImagePositionLeft:
            imageEdge = UIEdgeInsetsMake(0, -spacing/2, 0, spacing/2);
            titleEdge = UIEdgeInsetsMake(0, spacing/2, 0, -spacing/2);
            break;
        case ButtonImagePositionRight:
            imageEdge = UIEdgeInsetsMake(0, titleSize.width + spacing/2, 0, -(titleSize.width + spacing/2));
            titleEdge = UIEdgeInsetsMake(0, -(imageSize.width + spacing/2), 0, imageSize.width + spacing/2);
            break;
        case ButtonImagePositionTop:
            imageEdge = UIEdgeInsetsMake(-(titleSize.height + spacing/2), titleSize.width/2, titleSize.height + spacing/2, -titleSize.width/2);
            titleEdge = UIEdgeInsetsMake(imageSize.height + spacing/2, -imageSize.width/2, -(imageSize.height + spacing/2), imageSize.width/2);
            break;
        case ButtonImagePositionBottom:
            imageEdge = UIEdgeInsetsMake(titleSize.height + spacing/2, titleSize.width/2, -(titleSize.height + spacing/2), -titleSize.width/2);
            titleEdge = UIEdgeInsetsMake(-(imageSize.height + spacing/2), -imageSize.width/2, imageSize.height + spacing/2, imageSize.width/2);
            break;
    }
    
    self.imageEdgeInsets = imageEdge;
    self.titleEdgeInsets = titleEdge;
}

@end

Swift(UIButton 扩展)

enum ButtonImagePosition {
    case left, right, top, bottom
}

extension UIButton {
    func setImagePosition(_ position: ButtonImagePosition, spacing: CGFloat) {
        layoutIfNeeded()
        
        guard let imageSize = imageView?.frame.size,
              let titleSize = titleLabel?.frame.size else { return }
        
        var imageEdge = UIEdgeInsets.zero
        var titleEdge = UIEdgeInsets.zero
        
        switch position {
        case .left:
            imageEdge = UIEdgeInsets(top: 0, left: -spacing/2, bottom: 0, right: spacing/2)
            titleEdge = UIEdgeInsets(top: 0, left: spacing/2, bottom: 0, right: -spacing/2)
        case .right:
            imageEdge = UIEdgeInsets(top: 0, left: titleSize.width + spacing/2,
                                     bottom: 0, right: -(titleSize.width + spacing/2))
            titleEdge = UIEdgeInsets(top: 0, left: -(imageSize.width + spacing/2),
                                     bottom: 0, right: imageSize.width + spacing/2)
        case .top:
            imageEdge = UIEdgeInsets(top: -(titleSize.height + spacing/2),
                                     left: titleSize.width/2,
                                     bottom: titleSize.height + spacing/2,
                                     right: -titleSize.width/2)
            titleEdge = UIEdgeInsets(top: imageSize.height + spacing/2,
                                     left: -imageSize.width/2,
                                     bottom: -(imageSize.height + spacing/2),
                                     right: imageSize.width/2)
        case .bottom:
            imageEdge = UIEdgeInsets(top: titleSize.height + spacing/2,
                                     left: titleSize.width/2,
                                     bottom: -(titleSize.height + spacing/2),
                                     right: -titleSize.width/2)
            titleEdge = UIEdgeInsets(top: -(imageSize.height + spacing/2),
                                     left: -imageSize.width/2,
                                     bottom: imageSize.height + spacing/2,
                                     right: imageSize.width/2)
        }
        
        imageEdgeInsets = imageEdge
        titleEdgeInsets = titleEdge
    }
}

使用示例:

[button setImagePosition:ButtonImagePositionTop spacing:8]; // 上图下文,间距 8pt
button.setImagePosition(.top, spacing: 8)

注意:基于 imageEdgeInsets / titleEdgeInsets 的图文布局在使用 Auto Layout 时,可能影响 intrinsicContentSize 的计算。iOS 15+ 推荐使用 UIButton.Configuration 的 imagePlacement 属性,原生支持四种布局且与 Auto Layout 完美兼容。

2.4 其他实用属性

属性 说明
adjustsImageWhenHighlighted 高亮时是否自动变暗图片(默认 YES)
adjustsImageWhenDisabled 禁用时是否自动变亮图片(默认 YES)
showsTouchWhenHighlighted 高亮时是否显示发光效果(默认 NO)
tintColor 按钮的渲染颜色,对 system 类型按钮和模板图片生效
contentEdgeInsets 内容(图片+标题整体)的内边距

2.5 iOS 15+:UIButton.Configuration

iOS 15 引入了声明式按钮配置 API,统一管理外观、布局和交互,推荐新项目优先使用。

Objective-C

UIButtonConfiguration *config = [UIButtonConfiguration filledButtonConfiguration];
config.title = @"Filled Button";
config.subtitle = @"Subtitle";                    // 副标题
config.image = [UIImage systemImageNamed:@"star"]; // SF Symbols 图标
config.imagePlacement = NSDirectionalRectEdgeTop;  // 图标在上方
config.imagePadding = 8;                           // 图标与文字间距
config.baseBackgroundColor = [UIColor systemBlueColor];
config.baseForegroundColor = [UIColor whiteColor];
config.cornerStyle = UIButtonConfigurationCornerStyleLarge;

UIButton *button = [UIButton buttonWithConfiguration:config primaryAction:nil];
button.frame = CGRectMake(50, 100, 200, 60);
[self.view addSubview:button];

Swift

var config = UIButton.Configuration.filled()
config.title = "Filled Button"
config.subtitle = "Subtitle"
config.image = UIImage(systemName: "star")
config.imagePlacement = .top
config.imagePadding = 8
config.baseBackgroundColor = .systemBlue
config.baseForegroundColor = .white
config.cornerStyle = .large

let button = UIButton(configuration: config)
button.frame = CGRect(x: 50, y: 100, width: 200, height: 60)
view.addSubview(button)

Configuration 提供三种预设样式:

样式 说明
filled() 填充式按钮,有背景色
tinted() 浅色背景 + 深色文字
gray() 灰色背景按钮
plain() 无背景,仅文字/图标

三、事件处理

3.1 常见事件类型

UIControl 定义了多种触摸事件,最常用的是 UIControlEventTouchUpInside(在按钮范围内松开手指)。

事件 触发时机
touchDown 手指按下
touchDownRepeat 多次按下(双击及以上)
touchUpInside 在控件范围内松开(最常用)
touchUpOutside 在控件范围外松开
touchCancel 触摸被系统中断(如来电)
valueChanged 控件值发生变化(如 UISwitch、UISlider)

3.2 Target-Action 机制

按钮通过 addTarget:action:forControlEvents: 注册事件处理器。一个按钮可以注册多个 target-action,同一事件也可以关联多个方法。

Objective-C

[button addTarget:self
           action:@selector(buttonClicked:)
 forControlEvents:UIControlEventTouchUpInside];

- (void)buttonClicked:(UIButton *)sender {
    NSLog(@"按钮被点击: %@", sender);
}

Swift

button.addTarget(self, action: #selector(buttonClicked(_:)), for: .touchUpInside)

@objc func buttonClicked(_ sender: UIButton) {
    print("按钮被点击: \(sender)")
}

Swift 中 action 对应的方法必须标记 @objc,因为 Objective-C 运行时通过消息机制调用。


四、封装工具类

将常用按钮创建逻辑封装为工厂类,减少重复代码。

4.1 Objective-C 版本

ButtonFactory.h

#import <UIKit/UIKit.h>

@interface ButtonFactory : NSObject

/// 创建系统按钮
+ (UIButton *)systemButtonWithTitle:(NSString *)title
                             target:(id)target
                             action:(SEL)action
                              frame:(CGRect)frame;

/// 创建自定义圆角按钮
+ (UIButton *)customButtonWithTitle:(NSString *)title
                        titleColor:(UIColor *)titleColor
                    backgroundColor:(UIColor *)bgColor
                       cornerRadius:(CGFloat)cornerRadius
                             target:(id)target
                             action:(SEL)action
                              frame:(CGRect)frame;

/// 创建富文本按钮
+ (UIButton *)richTextButtonWithAttributedTitle:(NSAttributedString *)title
                                 backgroundColor:(UIColor *)bgColor
                                          target:(id)target
                                          action:(SEL)action
                                           frame:(CGRect)frame;

/// 创建图文按钮
+ (UIButton *)imageButtonWithTitle:(NSString *)title
                        titleColor:(UIColor *)titleColor
                             image:(UIImage *)image
                          position:(ButtonImagePosition)position
                           spacing:(CGFloat)spacing
                            target:(id)target
                            action:(SEL)action
                             frame:(CGRect)frame;

@end

ButtonFactory.m

#import "ButtonFactory.h"
#import "UIButton+ImagePosition.h"

@implementation ButtonFactory

+ (UIButton *)systemButtonWithTitle:(NSString *)title
                             target:(id)target
                             action:(SEL)action
                              frame:(CGRect)frame {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    button.frame = frame;
    [button setTitle:title forState:UIControlStateNormal];
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    return button;
}

+ (UIButton *)customButtonWithTitle:(NSString *)title
                        titleColor:(UIColor *)titleColor
                    backgroundColor:(UIColor *)bgColor
                       cornerRadius:(CGFloat)cornerRadius
                             target:(id)target
                             action:(SEL)action
                              frame:(CGRect)frame {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = frame;
    [button setTitle:title forState:UIControlStateNormal];
    [button setTitleColor:titleColor forState:UIControlStateNormal];
    button.backgroundColor = bgColor;
    button.layer.cornerRadius = cornerRadius;
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    return button;
}

+ (UIButton *)richTextButtonWithAttributedTitle:(NSAttributedString *)title
                                 backgroundColor:(UIColor *)bgColor
                                          target:(id)target
                                          action:(SEL)action
                                           frame:(CGRect)frame {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = frame;
    [button setAttributedTitle:title forState:UIControlStateNormal];
    button.backgroundColor = bgColor;
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    return button;
}

+ (UIButton *)imageButtonWithTitle:(NSString *)title
                        titleColor:(UIColor *)titleColor
                             image:(UIImage *)image
                          position:(ButtonImagePosition)position
                           spacing:(CGFloat)spacing
                            target:(id)target
                            action:(SEL)action
                             frame:(CGRect)frame {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = frame;
    [button setTitle:title forState:UIControlStateNormal];
    [button setTitleColor:titleColor forState:UIControlStateNormal];
    [button setImage:image forState:UIControlStateNormal];
    [button setImagePosition:position spacing:spacing];
    [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside];
    return button;
}

@end

使用示例

UIButton *systemBtn = [ButtonFactory systemButtonWithTitle:@"系统按钮"
                                                    target:self
                                                    action:@selector(buttonAction)
                                                     frame:CGRectMake(50, 400, 200, 50)];
[self.view addSubview:systemBtn];

UIButton *customBtn = [ButtonFactory customButtonWithTitle:@"自定义按钮"
                                                titleColor:[UIColor whiteColor]
                                           backgroundColor:[UIColor purpleColor]
                                              cornerRadius:10
                                                    target:self
                                                    action:@selector(buttonAction)
                                                     frame:CGRectMake(50, 470, 200, 50)];
[self.view addSubview:customBtn];

4.2 Swift 版本

Swift 中更适合使用 extension 扩展 UIButton,配合默认参数实现便捷创建:

extension UIButton {
    static func systemButton(title: String,
                             target: Any?,
                             action: Selector,
                             frame: CGRect = .zero) -> UIButton {
        let btn = UIButton(type: .system)
        btn.frame = frame
        btn.setTitle(title, for: .normal)
        btn.addTarget(target, action: action, for: .touchUpInside)
        return btn
    }
    
    static func customButton(title: String,
                             titleColor: UIColor = .white,
                             backgroundColor: UIColor,
                             cornerRadius: CGFloat = 8,
                             target: Any?,
                             action: Selector,
                             frame: CGRect = .zero) -> UIButton {
        let btn = UIButton(type: .custom)
        btn.frame = frame
        btn.setTitle(title, for: .normal)
        btn.setTitleColor(titleColor, for: .normal)
        btn.backgroundColor = backgroundColor
        btn.layer.cornerRadius = cornerRadius
        btn.addTarget(target, action: action, for: .touchUpInside)
        return btn
    }
}

使用示例

let systemBtn = UIButton.systemButton(title: "系统按钮",
                                      target: self,
                                      action: #selector(buttonAction),
                                      frame: CGRect(x: 50, y: 400, width: 200, height: 50))
view.addSubview(systemBtn)

let customBtn = UIButton.customButton(title: "自定义按钮",
                                      backgroundColor: .purple,
                                      target: self,
                                      action: #selector(buttonAction),
                                      frame: CGRect(x: 50, y: 470, width: 200, height: 50))
view.addSubview(customBtn)

五、底层实现逻辑

5.1 继承关系与事件传递

UIResponder
    └── UIView
          └── UIControl
                └── UIButton
  • UIView 提供基础的渲染、触摸事件接收和层级管理。
  • UIControl 在 UIView 基础上实现了 Target-Action 机制,将原始触摸事件(touchesBegan / touchesMoved / touchesEnded)转换为语义化的控件事件(touchUpInside 等)。
  • UIButton 进一步封装了状态管理和多内容(标题/图片/背景图)切换。

5.2 渲染与布局

UIButton 内部包含两个子视图:

  • titleLabel(UILabel 类型):显示按钮标题。
  • imageView(UIImageView 类型):显示按钮图标。

按钮在 layoutSubviews 中根据 contentEdgeInsets、imageEdgeInsets、titleEdgeInsets 和当前状态,计算并布局这两个子视图的位置。背景图则直接绘制在按钮自身的 layer 上。

5.3 状态管理

按钮维护一个 state 属性(UIControlState 类型的位掩码),在以下时机更新状态:

  • 手指按下 → 进入 Highlighted 状态。
  • 手指抬起 → 回到 Normal 状态(或保持 Selected)。
  • enabled = NO → 进入 Disabled 状态。
  • selected = YES → 叠加 Selected 状态。

状态变化时,按钮调用 setNeedsLayout,从内部存储中取出当前状态对应的标题、图片、背景图和标题颜色,更新 titleLabel 和 imageView。不同状态的内容分别存储,互不干扰。

5.4 性能优化

  • 预渲染与缓存:不同状态的标题和图片在设置时就准备好,状态切换时直接赋值,避免实时计算。
  • 按需重绘:仅在状态变化时更新子视图内容,普通状态下不触发 drawRect:。
  • UIButtonTypeSystem 类型的高亮效果通过改变 alpha 实现,不需要重新渲染图片。

六、总结

  • UIButton 继承自 UIControl,通过 Target-Action 机制处理交互,支持 Normal / Highlighted / Disabled / Selected 四种状态。
  • 自定义样式时注意 masksToBounds 的性能影响,纯背景色圆角不需要开启。
  • 图文混排可通过 imageEdgeInsets / titleEdgeInsets 实现四种布局;iOS 15+ 推荐使用 UIButton.Configuration 的 imagePlacement。
  • 封装工厂类或扩展可以减少重复代码,提升开发效率。
  • 理解内部 titleLabel + imageView 的双子视图结构和状态管理机制,有助于排查布局和样式问题。

posted @ 2015-07-15 02:52  Mr.陳  阅读(517)  评论(0)    收藏  举报