You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决UIButton开启showsActivityIndicator时高度不一致问题

问题描述

在默认大动态字体尺寸下,以下代码创建的UIButton初始高度为28.33;点击按钮开启showsActivityIndicator后,高度意外增至34.33。字体越小、动态字体尺寸越大,高度差异越明显。

let button = UIButton(configuration: {
    var config = UIButton.Configuration.filled()
    config.title = "Button"
    config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
        var container = $0
        container.uiKit.font = .preferredFont(forTextStyle: .caption1)
        return container
    }
    return config
}())
button.addAction(UIAction() { _ in
    button.configuration?.showsActivityIndicator = true
}, for: .touchUpInside)

问题核心:按钮高度由内容内边距决定,内边距是基于当前最大内容计算的。初始仅显示标题时高度较小,添加更高的活动指示器后,按钮为满足内边距要求自动增高。需求是不设置固定高度约束,让按钮在加载和非加载状态下高度保持一致。


解决方案

方法1:预计算活动指示器高度,调整非加载状态内边距

先获取系统活动指示器的默认高度,再计算它和标题文本的高度差,把这个差值平均分配到上下内边距里,让非加载状态的按钮高度和加载状态对齐。

示例代码:

let button = UIButton(configuration: {
    var config = UIButton.Configuration.filled()
    config.title = "Button"
    config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
        var container = $0
        container.uiKit.font = .preferredFont(forTextStyle: .caption1)
        return container
    }
    
    // 获取系统默认活动指示器的高度
    let indicator = UIActivityIndicatorView(style: .medium)
    indicator.sizeToFit()
    let indicatorHeight = indicator.frame.height
    
    // 计算当前标题文本的高度
    let titleFont = UIFont.preferredFont(forTextStyle: .caption1)
    let titleHeight = "Button".size(withAttributes: [.font: titleFont]).height
    
    // 计算需要补充的内边距,让按钮高度匹配指示器
    let paddingDelta = max(0, indicatorHeight - titleHeight)
    config.contentInsets = NSDirectionalEdgeInsets(
        top: config.contentInsets.top + paddingDelta/2,
        leading: config.contentInsets.leading,
        bottom: config.contentInsets.bottom + paddingDelta/2,
        trailing: config.contentInsets.trailing
    )
    
    return config
}())
button.addAction(UIAction() { _ in
    button.configuration?.showsActivityIndicator = true
}, for: .touchUpInside)

方法2:复用加载状态的内边距配置

先创建一个临时的加载状态配置,提取它的内容内边距,把这个内边距直接应用到默认状态的按钮上,确保两种状态下的内边距基准一致。

示例代码:

let button = UIButton(configuration: {
    var config = UIButton.Configuration.filled()
    config.title = "Button"
    config.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer {
        var container = $0
        container.uiKit.font = .preferredFont(forTextStyle: .caption1)
        return container
    }
    
    // 生成加载状态的临时配置,提取其内容内边距
    let tempLoadingConfig = UIButton.Configuration.filled()
    tempLoadingConfig.showsActivityIndicator = true
    tempLoadingConfig.title = ""
    if let resolvedInsets = tempLoadingConfig.resolvedConfiguration(for: .normal)?.contentInsets {
        config.contentInsets = resolvedInsets
    }
    
    return config
}())
button.addAction(UIAction() { _ in
    button.configuration?.showsActivityIndicator = true
}, for: .touchUpInside)

内容的提问来源于stack exchange,提问作者Jordan H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 09:57:30