覆盖UILabel的setText方法?

时间:2009-08-07 23:38:12

标签: objective-c cocoa cocoa-touch uilabel

我想覆盖UILabel的{​​{1}}方法,但我不确定:

A)这是可能的,和   B)如果可能有更好的方法来实现我想要实现的目标。

我有一个setText的子类,它有一个UIView属性作为其子视图之一。我想知道UILabel的“text”属性何时更改,以便我可以调整其后面的圆角矩形的大小。如果我拥有UILabel,我只是覆盖UILabel ...但setText是Apple的,其实现是隐藏的。

那么,我该怎么做呢?

6 个答案:

答案 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)
    }
}