我想覆盖UILabel
的{{1}}方法,但我不确定:
A)这是可能的,和 B)如果可能有更好的方法来实现我想要实现的目标。
我有一个setText
的子类,它有一个UIView
属性作为其子视图之一。我想知道UILabel
的“text”属性何时更改,以便我可以调整其后面的圆角矩形的大小。如果我拥有UILabel
,我只是覆盖UILabel
...但setText
是Apple的,其实现是隐藏的。
那么,我该怎么做呢?
答案 0 :(得分:10)
您可以使用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"];
答案 1 :(得分:10)
UILabel的子类可以很容易地覆盖setText方法。我不确定为什么在这个4岁的问题上还没有把它作为一个合理的答案。
- (void) setText:(NSString *)text
{
[super setText:text];
[self sizeToFit];
}
答案 2 :(得分:6)
Matt的答案对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")
}
}
}
答案 3 :(得分:3)
基于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
}
}
}
答案 4 :(得分:2)
您是否只使用圆角矩形作为标签的背景?如果是这种情况,您可以查看使用UIIMage stretchableImageWithLeftCapWidth:topCapHeight。这将拍摄您创建的图像,其中左侧和顶部重复部分具有您指定的宽度,并自动将其拉伸到您的宽度。
如果没有,Key-Value观察是可行的方法。只是为了涵盖另一种选择 - 这就像“玩火”,正如Apple程序员Evan Doll在他的斯坦福大学讲座中所说的那样 - 你可以使用方法调配来为另一种方法交换一种方法。
void method_exchangeImplementations(Method m1, Method m2);
在这种情况下,您想要调整setText的实现,但您还想在UILabel中调用原始的setText。所以你可以用setTextAndUpdateSize交换setText,并在setTextAndUpdateSize里面做setText最初做的事情再添加一点。如果你感到困惑或认为这是一个坏主意,它可能是。您可以通过调用class_getInstanceMethod([NSSTring class],@ selector(methodName))来获取Method对象以传递给method_exchangeImplementations。
一旦你的方法调用被调用一次,你可以在新方法中使用,yes,setTextAndUpdateSize从新方法中调用setText的旧实现。这是令人困惑的,不推荐,但它的工作原理。在the developer sample code.
中可以找到一个很好的例子答案 5 :(得分:0)
我在Swift 2.0中提取了Method Swizzling。通过交换标签的setText方法的实现来更改整个应用程序的字体。
复制app delegate中的代码并使用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)
}
}