Question

Je crée une classe Split View adaptée à l'autolayout pour l'une de mes applications. Parmi ses différentes caractéristiques, il peut s'effondrer les volets et peut animer leur effondrement, tout comme vous auriez pu voir NSSPlitview faire.

Puisque j'utilise des contraintes, je le réalise en plaçant une contrainte Largeur = (largeur actuelle) sur le volet, puis en fixant la constante constante à 0 de manière animée:

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

Cela fonctionne magnifiquement. Malheureusement, l'expansion du volet plus tard ne s'en va pas si 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 j'insère un code de synchronisation, je peux voir que le gestionnaire d'achèvement se déclenche presque instantanément, en supprimant la contrainte avant d'avoir le temps d'animation. Définir une durée sur le nsanimationcontext n'a aucun effet.

Une idée de ce que je pourrais faire de mal ici?

Était-ce utile?

La solution

Vous devez d'abord définir le gestionnaire d'achèvement et seulement envoyer le message au proxy animateur. Sinon, il semble que la définition du gestionnaire d'achèvement après que l'animation ait commencé à le déclencher immédiatement et que la constante est supprimée avant que l'animation ait le temps de terminer. Je viens de vérifier cela avec un morceau de code simple:

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

NsanimationContext Endgrouping]; Cela fonctionne parfaitement, mais si vous définissez le gestionnaire d'achèvement après -setConstant:, L'animation n'a pas la chance de courir.

Autres conseils

Je suis d'accord, c'est assez étrange et pourrait bien être un bug. Je le signalerais certainement en tant que tel parce que, au mieux de ma connaissance, ceci devrait travailler.

J'ai pu le faire fonctionner en utilisant le NSAnimationContext Méthode de classe +runAnimationGroup:completionHandler: à la place du beginGrouping et endGrouping déclarations:

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

Le gestionnaire d'achèvement tire immédiatement parce qu'il pense qu'il n'y a pas d'animations qui doivent être exécutées. Je vérifierais et confirmerais que l'animation que vous avez créée est toujours attachée à la vue. Par défaut, la cabasicanimation est définie pour se retirer à la fin de la propriété supprimée en objet, il hérite de la caanimation (qui est par défaut sur oui).

Tu voudras

anim.removedOnCompletion = NO;

J'arrive juste à saisir ce truc moi-même donc c'est peut-être une analyse naïve mais:

Il me semble que vous spécifiez qu'une animation sur les propriétés des contraintes (dans votre bloc d'autre), mais, puis, définissant immédiatement la référence à la contrainte à NIL (la libérer potentiellement) avant que l'animation ait une chance de s'exécuter.

Je m'attendrais à ce que vous souhaitiez définir HiddenConstraint à Nil de l'intérieur, ou déclenché par le bloc d'achèvement de l'animation.

Notez que si, comme c'est probable, je me trompe, j'apprécierais un mot ou deux sur les raisons pour lesquelles vous m'aider à mieux comprendre :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top