UIKit自定义Button中获取AttributedString属性失败的问题求助
用户创建了如下UIButton子类:
import UIKit class Button: UIButton { override func updateConfiguration() { var config = configuration ?? UIButton.Configuration.plain() let color = config.attributedTitle?.foregroundColor switch state { case .normal: config.attributedTitle?.foregroundColor = color.withAlphaComponent(1) case .highlighted: config.attributedTitle?.foregroundColor = color.withAlphaComponent(0.5) default: break } configuration = config } }
需求是从attributedTitle(AttributedString类型)获取前景色,为按钮不同状态设置带透明度的颜色,但遇到两个问题:
updateConfiguration方法中无法获取AttributedString的任何属性,示例中color始终为nil,返回类型为AttributeScopes.SwiftUIAttributes.ForegroundColorAttribute.Value?- 尝试赋值时出现错误:
Value of type 'AttributeScopes.SwiftUIAttributes.ForegroundColorAttribute.Value?' (aka 'Optional<Color>') has no member 'withAlphaComponent'
核心原因解析
1. 属性获取为nil的原因
UIButton.Configuration中的attributedTitle是SwiftUI的AttributedString,而非UIKit的NSAttributedString。直接访问foregroundColor时,会默认使用SwiftUI的属性作用域(AttributeScopes.SwiftUIAttributes),但如果按钮标题属性是通过UIKit API设置的(比如传统的setAttributedTitle(_:for:)),这些属性会存储在UIKit的属性作用域(AttributeScopes.UIKitAttributes)中,SwiftUI作用域下自然读取不到。
另外,updateConfiguration方法被调用时,configuration中的attributedTitle可能还未被正确初始化或同步,也会导致读取不到已设置的属性。
2. 类型不匹配导致的方法调用错误
你拿到的color是SwiftUI的Color?类型,而withAlphaComponent是UIKit中UIColor的方法,两者不属于同一框架的类型,自然无法调用。
解决方案
方案一:使用Configuration的状态变体(推荐)
利用UIButton.Configuration自带的状态属性直接处理,更符合现代UIKit的设计逻辑:
import UIKit class Button: UIButton { override func updateConfiguration() { var config = configuration ?? .plain() // 读取或设置基础前景色 let baseColor = config.baseForegroundColor ?? .black switch state { case .normal: config.baseForegroundColor = baseColor.withAlphaComponent(1) case .highlighted: config.baseForegroundColor = baseColor.withAlphaComponent(0.5) default: break } configuration = config } }
方案二:正确读取UIKit作用域的AttributedString属性
如果必须操作attributedTitle,需要指定UIKit的属性作用域来读取和修改:
import UIKit class Button: UIButton { override func updateConfiguration() { var config = configuration ?? .plain() guard var attributedTitle = config.attributedTitle else { return } // 读取UIKit作用域下的前景色 let baseColor = attributedTitle[UIKitAttributes.ForegroundColorAttribute.self] ?? .black switch state { case .normal: attributedTitle[UIKitAttributes.ForegroundColorAttribute.self] = baseColor.withAlphaComponent(1) case .highlighted: attributedTitle[UIKitAttributes.ForegroundColorAttribute.self] = baseColor.withAlphaComponent(0.5) default: break } config.attributedTitle = attributedTitle configuration = config } }
内容的提问来源于stack exchange,提问作者Petr Bones

