web-dev-qa-db-fra.com

UIView.animateWithDuration N'animant pas Swift (encore)

Remarque: j'ai déjà vérifié les problèmes de débordement de pile suivants:

27907570 , 32229252 , 26118141 , 31604300

Tout ce que j'essaie de faire, c'est de fondre animé dans une vue (par alpha) lorsqu'il est appelé par un IBAction associé à un bouton. Puis inversez lorsqu'un bouton de la vue est touché.

Mon problème est peut-être que j'utilise une vue secondaire qui se trouve sur ViewDock dans la vue Storyboard. La vue est ajoutée à la sous-vue au moment de viewDidLoad, où le cadre/les limites sont identiques à la vue d'ensemble (pour une mise en veille complète).

Cela s’explique par le fait qu’il s’agit d’un indicateur de didacticiel.

Le résultat (comme beaucoup d'autres qui ont énuméré ce problème) est que la vue (et les contrôles contenus) apparaissent tout simplement instantanément et disparaissent instantanément. Aucun fondu.

J'ai essayé animationWithDuration avec délai, avec ou sans achèvement, avec transition et j'ai même commencé avec l'ancien UIView.beginAnimations.

Rien ne fonctionne. Suggestions chaleureusement accueillies.

Le code est aussi simple que je peux le faire:
Edit: A étendu le code à tout ce qui est pertinent
Edit2: TL; DR Tout fonctionne à l'exception de UIViewAnimateWithDuration qui semble ignorer le bloc et la durée et n'exécute que le code en ligne en tant que modification immédiate de l'interface utilisateur. _ {Résoudre ceci obtient la prime} _

@IBOutlet var infoDetailView: UIView! // Connected to the view in the SceneDock

override func viewDidLoad() {
    super.viewDidLoad()

    // Cut other vDL code that isn't relevant

    setupInfoView()
}

func setupInfoView() {
    infoDetailView.alpha = 0.0
    view.addSubview(infoDetailView)
    updateInfoViewRect(infoDetailView.superview!.bounds.size)
}

func updateInfoViewRect(size:CGSize) {
    let viewRect = CGRect(Origin: CGPointZero, size: size)

    infoDetailView.frame = viewRect
    infoDetailView.bounds = viewRect

    infoDetailView.layoutIfNeeded()
    infoDetailView.setNeedsDisplay()
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    updateInfoViewRect(size)
}

func hideInfoView() {
    AFLog.enter(thisClass)
    UIView.animateWithDuration(
        2.0,
        animations:
        {
            self.infoDetailView.alpha = 0.0
        },
        completion:
        { (finished) in
            return true
        }
    )
    AFLog.exit(thisClass)
}

func showInfoView() {
    AFLog.enter(thisClass)
    UIView.animateWithDuration(
        2.0,
        animations:
        {
            self.infoDetailView.alpha = 0.75
        },
        completion:
        { (finished) in
            return true
        }
    )
    AFLog.exit(thisClass)
}

// MARK: - IBActions

@IBAction func openInfoView(sender: UIButton) {
    showInfoView()
}

@IBAction func closeInfoView(sender: UIButton) {
    hideInfoView()
}

S'il vous plaît noter, j'ai commencé avec ce qui suit:

func showInfoView() {
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.75
    })
}

func hideInfoView() {
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.00
    })
}
18
Lord Andrei

Si infoDetailView est soumis à des contraintes de mise en page automatiques, vous devez appeler layoutIfNeeded sur le parent view inside animateWithDuration:

func showInfoView() {
    self.view.layoutIfNeeded() // call it also here to finish pending layout operations
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.75
        self.view.layoutIfNeeded()
    })
}

Théoriquement, cela ne devrait pas être nécessaire si vous modifiez simplement la valeur .alpha, mais peut-être cela pourrait être le problème dans ce cas. 

36
Darko

Il y a plusieurs choses étranges que je peux voir,

d'abord, supprimez:

infoDetailView.layoutIfNeeded()
infoDetailView.setNeedsDisplay()

Généralement, vous n'avez pas besoin d'appeler ces méthodes manuellement à moins de savoir exactement ce que vous faites.

En outre, lorsque vous modifiez la taille:

infoDetailView.frame = viewRect
infoDetailView.bounds = viewRect

Il n'est jamais nécessaire de définir bounds et frame. Il suffit de définir frame.

En outre, vous devriez probablement vous assurer que la vue n'ignore pas le cadre en définissant: 

infoDetailView.translatesAutoresizingMaskIntoConstraints = true

Au lieu de réinitialiser le cadre, définissez simplement le masque de redimensionnement automatique:

infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

Résultant en:

override func viewDidLoad() {
    super.viewDidLoad()

    // Cut other vDL code that isn't relevant

    setupInfoView()
}

func setupInfoView() {
    infoDetailView.alpha = 0.0
    infoDetailView.translatesAutoresizingMaskIntoConstraints = true
    infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
    infoDetailView.frame = view.bounds
    view.addSubview(infoDetailView)
}

func hideInfoView() {
  ...
}

Je pense que cela devrait réellement aider car les animations immédiates sont souvent liées à des problèmes de taille.

Si le problème persiste, vous devez vérifier si la infoDetailView de votre animation est le même objet que la infoDetailView que vous ajoutez au contrôleur.

12
Sulthan

Si l'animation ne semble pas s'exécuter, envisagez d'examiner l'état de chacune de vos vues avant d'entrer dans le bloc d'animation. Par exemple, si l'alpha est déjà défini sur 0,4, l'animation qui ajuste l'affichage de la vue s'achève presque instantanément, sans effet apparent.

Pensez plutôt à utiliser une animation par images clés. Voici à quoi ressemble une animation d'agitation dans Objective C.

+(CAKeyframeAnimation*)shakeAnimation {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-10.0, 0.0, 0.0)],
                         [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(10.0, 0.0, 0.0)]];
    animation.autoreverses = YES;
    animation.repeatCount = 2;
    animation.duration = 0.07;
    return animation;
}

Voici un article qui vous montre comment régler l'alpha à l'aide d'images clés https://stackoverflow.com/a/18658081/1951992

4
user1951992

Assurez-vous que infoDetailView 's opaque est faux.

https://developer.Apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//Apple_ref/occ/instp/UIView/opaque

Cette propriété indique au système de dessin comment traiter la vue. Si défini sur true, le système de dessin traite la vue comme totalement opaque, ce qui lui permet d'optimiser certaines opérations de dessin et d'améliorer les performances. Si la valeur est false, le système de dessin compose la vue normalement avec un autre contenu. La valeur par défaut de cette propriété est true.

3
Jeff

J'ai répliqué votre code et cela fonctionne bien, tout va bien ... Vous devez probablement contrôler les contraintes, les connexions IBOutlet et IBActions. Essayez d’isoler ce code dans un nouveau projet si cela est nécessaire.

Update: mon code Et mon storyboard et la photo du dossier de projet:

 my storyboard and project folder photo

Tous les objets (vue et boutons) ont des paramètres par défaut.

 enter image description here

J'ai commenté toutes les lignes AFLog (ce n'est probablement plus du "mode verbeux" pour vous aider), le reste de votre code est ok et il fait ce que vous aspectez à partir de cela, si vous appuyez sur le bouton open, lorsque vous appuyez sur le bouton de fermeture, la vue disparaît progressivement.

Post-scriptum Non pertinent, mais j'utilise xCode 7.3, un nouveau projet Swift 2.2.

1

Essayez ci-dessous le code. Il suffit de jouer avec alpha et la durée pour le perfectionner.

Masquer func

func hideInfoView() {
AFLog.enter(thisClass)
UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.8
    },
    completion:
    { (finished) in
        UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.4
    },
    completion:
    { (finished) in
        self.infoDetailView.alpha = 0.0
    }
)
    }
)
AFLog.exit(thisClass)
}

Montrer func

func showInfoView() {
AFLog.enter(thisClass)
UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.3
    },
    completion:
    { (finished) in
        UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.7
    },
    completion:
    { (finished) in
        self.infoDetailView.alpha = 1.0
    }
)
    }
)
AFLog.exit(thisClass)
}
1
Arun Gupta

Utilisez ce code:

UIView.animateWithDuration(0.3, animations: { () -> Void in
    self.infoDetailView.alpha = 0.0 
})
1
shikha kochar

Pour le composant UILabel, essayez plutôt de modifier la couleur d’arrière-plan du calque.

Essayez ceci (testé sur Swift 4):

UIView.animate(withDuration: 0.2, animations: { 
    self.dateLabel.layer.backgroundColor = UIColor.red.cgColor;
})
0
Wanpaya

Avez-vous essayé de changer votre showInfoView() en quelque chose de plus semblable à toggleInfoView?

func toggleInfoView() {
    let alpha = CGFloat(infoDetailView.alpha == 0 ? 1 : 0)
    infoDetailView.alpha = alpha       //this is where the toggle happens
}

Il indique que si l'alpha de votre vue est 0, changez-le en 1. Sinon, rendez-le 0.

Si vous avez besoin que cela se produise dans une animation, essayez

@IBAction func openInfoView(sender: UIButton) {
    UIView.animate(withDuration: 2.0, animations: {
        self.toggleInfoView()           //fade in/out infoDetailView when animating
    })   
}
  • Vous voudrez toujours conserver ce infoDetailView.alpha = 0.0 où vous l'avez, en venant de la viewDidLoad.
0
Rudi Wever