Переопределить метод setText UILabel?
-
12-09-2019 - |
Вопрос
Я хотел бы переопределить 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)
}
}