2015-10-20 3 views
12

У меня есть два UILabels, встроенных в UIStackView. Верхняя метка остается видимой постоянно, но нижняя метка включается и выключается через свойство hidden. Я хотел, чтобы этот эффект будет анимационный, так что я воткнул его в анимации блока:Скрытое свойство нельзя изменить в блоке анимации

private func toggleResultLabel(value:Double) { 
    if value == 0 { 
     UIView.animateWithDuration(0.25) {() -> Void in 
      self.resultLabel.hidden = true 
     } 
    } else { 
     UIView.animateWithDuration(0.25) {() -> Void in 
      // Something weird is happening. I had to add 3 of the same statements to get 
      // the hidden flag to be false 
      self.resultLabel.hidden = false 
      self.resultLabel.hidden = false 
      self.resultLabel.hidden = false 
     } 
    } 
} 

Проблема заключается в том, что скрытые свойства не изменится, если я не повторить заявление снова и снова (3 раза в данном случае). Я нашел это, когда вломился в закрытие анимации и увидел, что свойство не изменится на его назначение. Теперь я замечаю ту же проблему, которая кажется случайно случайной. Значение по умолчанию для второй метки - true, если это необходимо.

Есть ли что-то, что мне здесь не хватает, или это ошибка?

Update: Для чего это стоит, я получил это работает, добавив removeArrangedSubview() и addArrangedSubview():

if value == 0 { 
    UIView.animateWithDuration(0.25) {() -> Void in 
     self.resultLabel.hidden = true 
     self.heroStackView.removeArrangedSubview(self.resultLabel) 
    } 
} else { 
    UIView.animateWithDuration(0.25) {() -> Void in 
     self.heroStackView.addArrangedSubview(self.resultLabel) 
     self.resultLabel.hidden = false 
    } 
} 
+1

Значение, которое не меняется, является странным, но в любом случае для анимации вашей метки вы должны изменить значение 'alpha', а не' hidden'. AFAIK, 'hidden' не анимативна. –

+0

Спасибо @GuillaumeAlgis! Я мог бы попробовать изменить альфа, но я не думаю, что он изменит StackView, поскольку он будет невидимым и удаленным. Скрытое свойство анимативно и работает в 95% случаев. Для справки я использовал раздел в нижней части страницы: [https://developer.apple.com/library/prerelease/tvos/documentation/UIKit/Reference/UIStackView_Class_Reference/index.html](https://developer.apple .com/library/prerelease/tvos/documentation/UIKit/Reference/UIStackView_Class_Reference/index.html) – Alex

+0

Хм, если я правильно понимаю документ, это конкретное поведение 'UIStackView'. Вне этого специального случая «скрытый» не будет анимироваться. Используете ли вы 'UIStackView'? –

ответ

15

КСН 11 и ранее, скрывая arrangedSubview из UIStackView с использованием API анимации UIView несколько раз, значения скрытых свойств «стекают», и для его изменения требуется установить значение false несколько раз до того, как значение действительно изменится.

На работе мы решили использовать расширение UIView с обходным методом, который устанавливает только скрытые данные для заданного значения.

extension UIView { 

    // Workaround for the UIStackView bug where setting hidden to true with animation 
    // mulptiple times requires setting hidden to false multiple times to show the view. 
    public func workaround_nonRepeatingSetHidden(hidden: Bool) { 
     if self.hidden != hidden { 
      self.hidden = hidden 
     } 
    } 
} 

Это, безусловно, ошибка в UIKit, проверить sample project, воспроизводящий это ясно.

enter image description here

+1

Ничего себе, спасибо, что заметили это! Решил его –

+1

Июль 2017 года, ошибка все еще там, только что воспроизведена. спасибо за исчерпывающий ответ. – Kappe

+0

Это происходит и в IOS 11. –

7

Там, кажется, корреляция на сколько раз скрытый флаг установлен в том же состоянии и сколько раз он должен быть установлен в другое состояние, прежде чем он будет фактически изменен. В моем случае у меня был скрытый флаг, уже установленный в YES, прежде чем он снова будет установлен в YES снова в блоке анимации, и это вызвало проблему, когда мне пришлось дважды вызвать скрытый = НЕТ в моем другом блоке анимации, чтобы снова увидеть его. Если бы я добавил несколько скрытых строк = YES в первый блок анимации для одного и того же представления, мне пришлось бы иметь более скрытые строки = НЕТ во втором блоке анимации. Это может быть ошибкой в ​​наблюдении KVO UIStackView для скрытого флага, который не проверяет, действительно ли значение было изменено или нет, прежде чем изменять какое-то внутреннее состояние, которое приводит к этой проблеме.

Чтобы устранить проблему (пока Apple не установит ее), я создал категорию для UIView и swizzled setHidden: метод для версии, которая сначала проверяет исходное значение и устанавливает новое значение, только если оно отличается от оригинала. Кажется, что это работает без каких-либо негативных последствий.

@implementation UIView (MethodSwizzling) 

+ (void)load 
{ 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     Class class = [self class]; 

     SEL originalSelector = @selector(setHidden:); 
     SEL swizzledSelector = @selector(UIStackViewFix_setHidden:); 

     Method originalMethod = class_getInstanceMethod(class, originalSelector); 
     Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); 

     BOOL didAddMethod = 
     class_addMethod(class, 
         originalSelector, 
         method_getImplementation(swizzledMethod), 
         method_getTypeEncoding(swizzledMethod)); 

     if (didAddMethod) { 
      class_replaceMethod(class, 
           swizzledSelector, 
           method_getImplementation(originalMethod), 
           method_getTypeEncoding(originalMethod)); 
     } else { 
      method_exchangeImplementations(originalMethod, swizzledMethod); 
     } 
    }); 
} 

- (void)UIStackViewFix_setHidden:(BOOL)hidden 
{ 
    if (hidden != self.hidden) { 
     [self UIStackViewFix_setHidden:hidden]; 
    } 
} 

@end 
4

Появляется ошибка Apple с UIStackView. Смотрите следующий ...

UIStackView: toggleing скрытый с анимацией застревает в скрытом режиме http://www.openradar.me/22819594

мое решение, хотя и не идеально, было скрыть UIStackView без анимации.

5

При рассмотрении ошибки UIStackView я решил проверить скрытое свойство.

if myView.hidden != hidden { 
    myView.hidden = hidden 
} 

Это не самое элегантное решение, но оно работает для меня.

1

В ответ на вопрос Raz0, который выяснил, что только установка isHidden при необходимости решает проблему, вот быстрое решение, которое заставило его работать на меня.Я избегаю метод swizzling, потому что это по сути небезопасна, в пользу show/hide подхода, который должен не испортить с оригинальными методами:

extension UIView { 
    func show() { 
     guard isHidden else { 
      return 
     } 
     isHidden = false 
    } 

    func hide() { 
     guard !isHidden else { 
      return 
     } 
     isHidden = true 
    } 
} 

Используйте это так:

view.show() 
view.hide() 
0

То, что сработало для меня, чтобы установить скрытое свойство за пределы анимации, а затем анимировать layoutIfNeeded(), так же, как вы бы с оживляющими ограничениями:

label.isHidden = true 
UIView.animate(withDuration: 3) { 
    self.view.layoutIfNeeded() 
} 

, где этикетка устроенный subview UIStackView.

Смежные вопросы