我想覆盖UILabel
的setText
方法,但我不确定:
A)有可能,
B)如果有更好的方法来实现我想要实现的目标。
我有一个子类,UIView
它有一个UILabel
属性作为其子视图之一。我想知道UILabel
' 的“文本”属性何时发生变化,以便我可以调整它后面的圆角矩形的大小。如果我拥有UILabel
,我会覆盖setText
......但UILabel
它是 Apple 的,并且它的实现是隐藏的。
那么,我该怎么做呢?
我想覆盖UILabel
的setText
方法,但我不确定:
A)有可能,
B)如果有更好的方法来实现我想要实现的目标。
我有一个子类,UIView
它有一个UILabel
属性作为其子视图之一。我想知道UILabel
' 的“文本”属性何时发生变化,以便我可以调整它后面的圆角矩形的大小。如果我拥有UILabel
,我会覆盖setText
......但UILabel
它是 Apple 的,并且它的实现是隐藏的。
那么,我该怎么做呢?
UILabel 的子类可以很容易地覆盖 setText 方法。我不太确定为什么这还没有作为这个 4 岁问题的合法答案。
- (void) setText:(NSString *)text
{
[super setText:text];
[self sizeToFit];
}
您可以使用Key-Value Observing
来跟踪对UILabel.text
属性的更改。该方法包括三个步骤:
1)注册观察属性,当你加载视图
[label addObserver:inspector
forKeyPath:@"text"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
2) 收到有关任何更改的通知:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([keyPath isEqual:@"text"]) {
// put your logic here
}
// be sure to call the super implementation
// if the superclass implements it
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
3)当您不再感兴趣时,取消注册观察:
[label removeObserver:inspector forKeyPath:@"text"];
马特的答案对Objective-C有好处,但在Swift中不起作用(正常,当他回答时它不存在),notnoop接受的答案确实可以在swift中起作用,即使它更复杂,只是为了给另一个快速的想法你可以使用didSet:
class MyLabel: UILabel {
override var text: String? {
didSet {
if let text = text {
println("the new text is: \(text)")
} else {
println("the text has been set to nil")
}
}
}
基于 Drix 的回答,我认为这是一种更正确的方法(使用set
代替didSet
):
class UnreadCountLabel: UILabel {
override var text: String? {
set {
if let newValue = newValue where !newValue.isEmpty {
super.text = " \(newValue) "
self.hidden = false
} else {
super.text = newValue
self.hidden = true
}
}
get {
return super.text
}
}
}
您只是使用圆角矩形作为标签的背景吗?如果是这种情况,您可以考虑使用 UIIMage stretchableImageWithLeftCapWidth:topCapHeight。这将获取您创建的图像,该图像具有您指定的宽度的左侧和顶部重复部分,并自动将其拉伸到您的宽度。
如果没有,键值观察是要走的路。只是为了涵盖另一种选择——这就像 Apple 程序员 Evan Doll 在他的斯坦福讲座中所说的“玩火”——您可以使用方法调配来将一种方法实现交换为另一种。
void method_exchangeImplementations(Method m1, Method m2);
在这种情况下,您想调整 setText 的实现,但您还想调用 UILabel 中的原始 setText。因此,您可以将 setText 与 setTextAndUpdateSize 交换,并在 setTextAndUpdateSize 内部执行 setText 最初所做的操作,并添加更多内容。如果您感到困惑或认为这是一个坏主意,那可能是。您可以通过调用 class_getInstanceMethod([NSSTring class], @selector (methodName).
一旦您的方法 swizzle 被调用一次,在您的新方法中,您就可以使用 setTextAndUpdateSize 从新方法中调用旧的 setText 实现。这很令人困惑,不推荐,但它确实有效。在开发人员示例代码中可以找到一个很好的示例。
我在 Swift 2.0 中取消了 Method Swizzling。通过交换标签的 setText 方法的实现来改变整个应用程序的字体。
复制应用程序委托中的代码并使用 customSetText 进行应用程序级别的更改
// MARK: - Method Swizzling
extension UILabel {
public override class func initialize() {
struct Static {
static var token: dispatch_once_t = 0
}
// make sure this isn't a subclass
if self !== UILabel.self {
return
}
dispatch_once(&Static.token) {
let originalSelector = Selector("setText:")
let swizzledSelector = Selector("customSetText:")
let originalMethod = class_getInstanceMethod(self, originalSelector)
let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)
let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
}
}
// MARK: - Custom set text method for UI Label
func customSetText(text: String) {
self.customSetText(text)
//set custom font to all the labels maintaining the size UILabel
self.font = UIFont(name: "Lato-LightItalic", size: self.font.pointSize)
}
}