6

我想覆盖UILabelsetText方法,但我不确定:

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

我有一个子类,UIView它有一个UILabel属性作为其子视图之一。我想知道UILabel' 的“文本”属性何时发生变化,以便我可以调整它后面的圆角矩形的大小。如果我拥有UILabel,我会覆盖setText......但UILabel它是 Apple 的,并且它的实现是隐藏的。

那么,我该怎么做呢?

4

6 回答 6

11

UILabel 的子类可以很容易地覆盖 setText 方法。我不太确定为什么这还没有作为这个 4 岁问题的合法答案。

- (void) setText:(NSString *)text
{
    [super setText:text];

    [self sizeToFit];
}
于 2013-09-26T06:22:36.057 回答
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"];
于 2009-08-07T23:48:20.683 回答
6

马特的答案对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")
        }
      }
  }
于 2014-11-04T14:17:57.127 回答
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
        }
    }
}
于 2016-01-29T10:24:21.627 回答
2

您只是使用圆角矩形作为标签的背景吗?如果是这种情况,您可以考虑使用 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 实现。这很令人困惑,不推荐,但它确实有效。在开发人员示例代码中可以找到一个很好的示例。

于 2009-08-08T00:10:34.447 回答
0

我在 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)
    }
}
于 2015-12-30T19:47:54.460 回答