2012-02-29 6 views
14

Estoy creando una clase de vista dividida para una de mis aplicaciones. Entre sus diversas características se encuentra el hecho de que puede colapsar paneles y animar su colapso, de la misma forma en que lo ha visto hacer NSSplitView.NSLayoutConstraint.constant que ignora la animación

Desde que estoy usando limitaciones, estoy lograr esto colocando una restricción de anchura requerida = (anchura actual) en el panel, y luego poner la constante a 0 la restricción de una manera animada:

- (NSLayoutConstraint*)newHiddenConstraintAnimated:(BOOL)animated { 
    NSLayoutConstraint * constraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:NSWidth(self.view.frame)]; 
    constraint.priority = NSLayoutPriorityRequired; 

    CABasicAnimation * anim = [CABasicAnimation animation]; 
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; 
    anim.duration = 0.2; 
    constraint.animations = [NSDictionary dictionaryWithObject:anim forKey:@"constant"]; 

    [self.view addConstraint:constraint]; 

    [(animated ? constraint.animator : constraint) setConstant:0.0]; 

    return constraint; 
} 

Esto funciona maravillosamente. Desafortunadamente, expandir el panel más tarde no le va tan bien.

- (void)removeHiddenConstraintAnimated:(BOOL)animated { 
    if(!animated) { 
     [self.view removeConstraint:self.hiddenConstraint]; 
    } 
    else { 
     NSLayoutConstraint * constraint = self.hiddenConstraint; 
     NSView * theView = self.view; 

     [NSAnimationContext beginGrouping]; 

     [constraint.animator setConstant:self.width]; 

     [NSAnimationContext currentContext].completionHandler = ^{ 
      [theView removeConstraint:constraint]; 
     }; 

     [NSAnimationContext endGrouping]; 
    } 

    self.hiddenConstraint = nil; 
} 

Si inserto un código de tiempo, puedo ver que el controlador de finalización dispara casi al instante, la eliminación de la restricción antes de que tenga tiempo para animar. Establecer una duración en NSAnimationContext no tiene ningún efecto.

¿Alguna idea de lo que podría estar haciendo mal aquí?

+0

¿Alguna vez terminaste esta clase de vista dividida? ¿Posibilidad de que sea de código abierto? –

+0

No pienso hacerlo por el momento. Es bastante especializado para esta aplicación, y creo que 'NSSplitView' en [PURRDACTED] se ha rediseñado para que funcione mejor con el autolayout. –

+0

Oh, tengo. Con respecto a [redactado], tiene una buena característica en cuanto a la distribución automática, pero por supuesto no es compatible con objetivos anteriores. Oh, bueno, voy a hacer mi propia, supongo! :) –

Respuesta

15

Tienes que establecer primero el manejador de terminación y sólo entonces enviar el mensaje a la proxy animador. De lo contrario, parece que al configurar el controlador de finalización después de que la animación comenzó, se dispara inmediatamente y la constante se elimina antes de que la animación tenga tiempo para terminar. acabo de comprobar esto con un pedazo de código simple:

[NSAnimationContext beginGrouping]; 
    NSAnimationContext.currentContext.duration = animagionDuration; 
    NSAnimationContext.currentContext.completionHandler = ^{[self removeConstraint:collapseConstraint];}; 
    [collapseConstraint.animator setConstant:expandedHeight]; 
    [NSAnimationContext endGrouping]; 

Esto funciona perfectamente, pero si establece manejador de finalización después de -setConstant:, la animación no tiene la oportunidad de correr.

+0

Guau, eso realmente funcionó. ¡Gracias por el consejo! –

+0

No, en absoluto, hace un tiempo me encontré con el mismo problema, y ​​fue su pregunta la que me llevó a experimentar :) – skh

1

sólo estoy llegar a enfrentarse con estas cosas a mí mismo por lo que este puede ser un análisis ingenua pero:

Me parece que está especificando que una animación sobre las propiedades de las limitaciones (en su bloque else) pero, inmediatamente, estableciendo la referencia a la restricción en nil (potencialmente liberándola) antes de que la animación tenga la oportunidad de ejecutarse.

Espero que quieras establecer hiddenConstraint en cero desde, o activado por, el bloque de finalización de la animación.

Tenga en cuenta que si, como es probable, que estoy equivocado le agradecería una o dos palabras acerca de por qué para ayudar a entender mejor :)

+0

Es razonable suponer que una vista posee cualquier restricción que agregue a ella, por lo que incluso si la restricción no se referencia a través de la propiedad 'hiddenConstraint', todavía debe hacer referencia a la lista de restricciones de la vista. También lo mantiene vivo el bloque en sí, ya que los bloques retienen los valores de cualquier variable de objeto que use en ellos. –

+0

Como dijo Peter, 'constraint' es una referencia fuerte y es capturada por el bloque, e incluso si no fuera así, la vista conserva la restricción. Hay cientos de restricciones en un diseño automático moderadamente complejo, y la gran mayoría solo se referencia por las vistas que son suyas. –

+0

Gracias por las amables respuestas chicos. –

3

El manejador de finalización está disparando inmediatamente porque piensa que no hay ninguno animaciones que necesitan ejecutarse. Verificaría y confirmaría que la animación que creó todavía está adjunta a la vista. De forma predeterminada, CABasicAnimation está configurado para eliminarse al completarse mediante la propiedad removedOnCompletion que hereda de CAAnimation (que de forma predeterminada se establece en YES).

usted querrá

anim.removedOnCompletion = NO; 
+0

Agregar 'anim.removedOnCompletion = NO;' no tiene ningún efecto. Buena sugerencia, sin embargo. –

12

Estoy de acuerdo, esto es bastante extraño, y bien podría ser un error. Definitivamente lo reportaría como tal porque, según mi leal saber y entender, este debería funcionar en.

que era capaz de conseguir que funcione con el método NSAnimationContext clase +runAnimationGroup:completionHandler: en lugar de las declaraciones beginGrouping y endGrouping:

[NSAnimationContext runAnimationGroup:^(NSAnimationContext* context){ 
    [constraint.animator setConstant:self.width]; 
} completionHandler:^(void){ 
    [theView removeConstraint:constraint]; 
    NSLog(@"completed"); 
}]; 
+0

Por desgracia, esto no parece haber tenido un efecto en mi código. Sin embargo, probablemente archivaré un radar; esto ciertamente parece que debería funcionar. –

+0

Eso es extraño. Definitivamente funciona bien aquí. –

+0

Funcionó para mí también. – stevex

Cuestiones relacionadas