2015-10-20 8 views
12

Ich habe zwei UILabels in einem UIStackView eingebettet. Das obere Etikett bleibt ständig sichtbar, aber das untere Etikett wird über die Eigenschaft hidden ein- und ausgeschaltet. Ich wollte diesen Effekt werden animiert, so dass ich steckte es in einem Animationsblock:Versteckte Eigenschaft kann nicht innerhalb eines Animationsblocks geändert werden

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

Das Problem ist, dass die verborgene Eigenschaft wird sich nicht ändern, es sei denn ich die Aussage über und über (3-mal in diesem Fall) zu wiederholen. Ich fand dies, während ich in den Animationsabschluss einbrach und sah, dass sich die Eigenschaft nicht zu ihrer Zuweisung änderte. Jetzt stelle ich fest, dass das gleiche Problem scheinbar zufällig wieder auftritt. Der Standardwert des zweiten Labels ist true, wenn das relevant ist.

Gibt es etwas, das mir hier fehlt, oder ist das ein Fehler?

aktualisieren: Für das, was es wert ist, habe ich es von removeArrangedSubview() und addArrangedSubview() Arbeits Zugabe:

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

Der Wert, der sich nicht ändert, ist seltsam, aber um Ihr Label zu animieren, sollten Sie den Alpha-Wert der Ansicht ändern und nicht "versteckt". AFAIK, "versteckt" ist nicht animierbar. –

+0

Danke @GuillaumeAlgis! Ich könnte versuchen, das Alpha zu ändern, aber ich denke nicht, dass es das StackView neu arrangieren wird, da es nur unsichtbar ist und entfernt wird. Die versteckte Eigenschaft ist animierbar und funktioniert in 95% der Fälle. Als Referenz habe ich den Abschnitt unten auf der Seite verwendet: [https://developer.apple.com/library/prerelease/tvos/documentation/UIKit/Reference/UIStackView_Class_Reference/index.html](https://developer.apple UMSatz/Referenz/UIStackView_Class_Reference/index.html) – Alex

+0

Hmm, wenn ich das Dokument richtig verstehe, ist dies ein bestimmtes Verhalten von 'UIStackView'. Außerhalb dieses speziellen Falls wird "versteckt" nicht animiert. Verwenden Sie ein 'UIStackView'? –

Antwort

15

Auf iOS 11 Wenn Sie zuvor eine arrangedSubview einer UIStackView mithilfe der UIView-Animations-API mehrere Male ausblenden, werden die ausgeblendeten Eigenschaftswerte "stack" und die Einstellung muss false mehrmals ausgeblendet werden, bevor sich der Wert tatsächlich ändert.

Bei der Arbeit haben wir uns entschieden, eine UIView-Erweiterung mit einer Workaround-Methode zu verwenden, die nur einmal für den angegebenen Wert ausgeblendet setzt. Diese

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

ist definitiv ein Fehler in UIKit, überprüfen Sie die sample project heraus, dass es eindeutig wiedergibt.

enter image description here

+1

Wow, danke, dass du das bemerkt hast! Gelöst es –

+1

Juli 2017, der Fehler ist immer noch da, nur reproduziert. Danke für die ausführliche Antwort. – Kappe

+0

Es passiert auch in iOS 11. –

7

Es Korrelation auf, wie oft versteckt Flagge zu sein scheint, wird auf denselben Zustand und wie viele Mal muss es in einen anderen Zustand versetzt werden, bevor es tatsächlich zurück geändert wird. In meinem Fall hatte ich das ausgeblendete Flag bereits auf YES gesetzt, bevor es im Animationsblock wieder auf YES gesetzt wurde, und das verursachte das Problem, dass ich hidden = NO zweimal in meinem anderen Animationsblock aufrufen musste, um es wieder sichtbar zu machen. Wenn ich mehr Hidden = YES-Zeilen im ersten Animationsblock für dieselbe Ansicht hinzugefügt habe, musste ich auch mehr versteckte = NO-Zeilen im zweiten Animationsblock haben. Dies könnte ein Fehler in der KVO-Beobachtung von UIStackView für das ausgeblendete Flag sein, das nicht prüft, ob der Wert tatsächlich geändert wird oder nicht, bevor ein interner Zustand geändert wird, der zu diesem Problem führt.

Um das Problem vorübergehend zu beheben (bis Apple es behebt), habe ich eine Kategorie für UIView und swizzled setHidden: method zu einer Version gemacht, die zuerst den ursprünglichen Wert überprüft und den neuen Wert nur dann einstellt, wenn er vom Original abweicht. Dies scheint ohne negative Auswirkungen zu funktionieren.

@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

Scheint, ein Apple-Bug mit UIStackView zu sein. Sehen Sie im folgenden ...

UIStackView: toggleing mit Animationen versteckt wird in versteckten Modus http://www.openradar.me/22819594

Meine Lösung, wenn auch nicht ideal, stecken war die UIStackView ohne Animation zu verstecken.

5

In Anbetracht UIStackView Bug entscheide ich mich, versteckte Eigenschaft zu überprüfen.

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

Es ist nicht die eleganteste Lösung, aber es funktioniert für mich.

1

Wie die Raz0 Antwort, die herausgefunden, dass nur die Einstellung isHidden bei Bedarf löst das Problem, hier ist ein schneller Workaround, der es für mich funktioniert.Ich bin zu vermeiden Methode Swizzling weil es von Natur aus unsicher ist, zugunsten eines show/hide Ansatz, die mit dem ursprünglichen Verfahren nicht vermasseln sollte: es so

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

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

Verwendung:

view.show() 
view.hide() 
0

Was für mich gearbeitet ist die verborgene Eigenschaft außerhalb der Animation zu setzen und dann layoutIfNeeded() Animieren, so wie du mit animiere Einschränkungen würde:

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

wo Markierung ein angeordnet ist Unteransicht eines UIStackView.

Verwandte Themen