Вопрос

Я хотел бы переопределить UILabel's setText метод, но я не уверен, что:

А) это возможно, и
Б) если, возможно, есть лучший способ достичь того, чего я пытаюсь достичь.

У меня есть подкласс UIView у которого есть UILabel собственность как один из ее подвидов.Я хотел бы знать, когда UILabelСвойство text изменяется, поэтому я могу настроить размер закругленного прямоугольника позади него.Если бы я владел UILabel я бы просто переопределил setText...но UILabel принадлежит Apple, и его реализация скрыта.

Итак, как мне поступить в этом случае?

Это было полезно?

Решение

Вы можете использовать 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"];

Другие советы

Подклассы UILabel могут довольно легко переопределить метод setText.Я не совсем понимаю, почему это до сих пор не включено в качестве законного ответа на этот вопрос четырехлетней давности.

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

    [self sizeToFit];
}

Ответ Мэтта хорош для Objective-C, но не работает в Swift (обычно, его не существовало, когда он ответил), принятый ответ от notnoop работает в Swift, хотя он и сложнее, просто чтобы дать другой идея в быстром вы можете использовать сделалSet:

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")
        }
      }
  }

Основываясь на ответе Дрикса, я думаю, что это более правильный подход (использование 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 Эван Долл в одной из своих лекций в Стэнфорде), вы можете использовать метод swizzling для замены одной реализации метода на другую.

void method_exchangeImplementations(Method m1, Method m2);

В этом случае вы хотите настроить реализацию setText, но также хотите вызвать исходный setText в UILabel.Таким образом, вы можете обменять setText на setTextAndUpdateSize, а внутри setTextAndUpdateSize сделать то, что изначально делает setText, плюс добавить еще немного.Если вы запутались или думаете, что это плохая идея, возможно, так оно и есть.Вы можете получить объект метода для передачи в метод_exchangeImplementations, вызвав class_getInstanceMethod([класс NSSTring], @selector (methodName).

После того, как ваш метод swizzle был вызван один раз, внутри нового метода вы можете вызвать старую реализацию setText из новой, используя, да, setTextAndUpdateSize.Это сбивает с толку и не рекомендуется, но это работает.Хороший пример можно найти в пример кода разработчика.

Я использовал метод Swizzling в Swift 2.0.Изменение шрифта всего приложения путем замены реализации метода 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)
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top