1

Vue d'ensemble: J'ai actuellement une sous-classe UIView personnalisée qui implémente la logique d'animation personnalisée, et je ne suis pas sûr que la classe de vue est le meilleur endroit pour mettre ce code.Où devrait aller le code d'animation personnalisé et réutilisable?

Je crée une application iOS dans Swift qui utilise une sous-classe UIView que j'appelle DoorView. Un DoorView représente une porte coulissante qui, en réponse à un geste de balayage, effectue une animation coulissante à ouvrir.

Voici une animation complète que je l'ai maintenant:

enter image description here

En essayant de garder mon point de vue la lumière du contrôleur, je mets le code d'animation de base réelle qui gère ces animations dans ma classe DoorView. My View Controller gère le mouvement en vérifiant s'il correspond au geste requis pour ouvrir une porte donnée, et si c'est le cas, appelle une méthode open() sur DoorView.

Ainsi, dans ViewController:

@IBAction func swipe(sender: UISwipeGestureRecognizer) { 
     if (sender.direction.rawValue == currentDoorView.door.swipeDirection.rawValue) { 
      self.currentDoorView.open() 
     } 
    } 

Et voici la méthode ouverte() dans ma classe DoorView: Note: Ceci est juste l'animation de glissement, et le contrôle d'un type coulissant sera utilisé dans la l'avenir de se différencier des autres types de portes (par exemple à charnière).

func open(withDuration duration: CFTimeInterval = 1.0) { 

    /// We only slideOpen if switch statement below determines self.door is Sliding, 
    /// so we downcast as SlidingDoor so we can switch on door.slideDirection. 
    /// For each slideDirection case, a different translation is created, 
    /// which is then passed into the slideAnimation below. 
    func slideOpen() { 

     let slidingDoor = self.door as! SlidingDoor 
     let translation: CATransform3D 

     switch slidingDoor.slideDirection { 
     case .Down: 
      let height = baseLayer.bounds.height 
      translation = CATransform3DMakeTranslation(0, height, 0) 
     case .Left: 
      let width = openingLayer.bounds.size.width 
      translation = CATransform3DMakeTranslation(-width, 0, 0) 
     case .Right: 
      let width = openingLayer.bounds.size.width 
      translation = CATransform3DMakeTranslation(width, 0, 0) 
     case .Up: 
      let height = baseLayer.bounds.height 
      translation = CATransform3DMakeTranslation(0, -height, 0) 
     } 

     let slideAnimation = { 
      (completion:(() ->())?) in 
      CATransaction.begin() 
      CATransaction.setCompletionBlock(completion) 
      CATransaction.setAnimationDuration(duration) 
      self.openingLayer.transform = translation 
      CATransaction.commit() 
     } 

     /// Actual call to slideAnimation closure. 
     /// Upon completion, notify delegate and call walkThroughDoor() 
     slideAnimation({ 
      self.delegate?.doorDidOpen(self) 
      self.walkThroughDoor() 
     }) 
    } 

    /// Switch to determine door type, and thus appropriate opening animation. 
    switch self.door { 
    case is Sliding: 
     slideOpen() 
    default: 
     print("is not sliding") 
    } 
} 

Alors, est-il correct de mettre la logique d'animation dans une classe de vue? C'était mon premier instinct car a) ces animations sont spécifiques à mon DoorView, et b) parce que animateWithDuration est une méthode de classe de UIView, donc il semble y avoir un précédent pour que les animations soient gérées par les classes vues/vues elles-mêmes.

Mais je continue à développer mon application, je vais ajouter plus de types de portes avec leurs propres animations, et je crains que DoorView devienne trop gros avec le code d'animation. Devrais-je commencer à créer des sous-classes DoorView (c'est-à-dire SlidingDoorView, HingedDoorView, etc.)?

Ou les animations doivent-elles être gérées par le contrôleur de vue? Mon problème avec cela, en plus de VC bloat, est que si je veux utiliser DoorViews dans d'autres contrôleurs de vue, j'ai besoin de dupliquer le code. De cette façon, mes DoorViews sont livrés avec leurs propres animations et tout ce que mes VC doivent faire est d'appeler open().

+1

Belle animation. On dirait que chaque animation devrait être sa propre classe. Ce que vous sous-classez dépend de quel code doit être réutilisé. – dbugger

+0

Ah, intéressant! Merci pour votre réponse. Dans ce cas, où seraient appelées les animations? Serais-je toujours en train de gérer ces appels de méthodes d'animation dans ma classe DoorView, ou cela aurait-il plus de sens de le traiter dans un View Controller? –

+1

Si vous pouvez les encapsuler dans la classe View, ils seront plus faciles à utiliser dans d'autres contrôleurs. – dbugger

Répondre

1

Il y a deux options, je pense que vous pouvez le faire et les deux sont également acceptables.

1. En utilisant l'extension pour séparer votre code d'animation à partir du code de la vue de la porte

Mettre dans une nouvelle ENUM pour le type de porte dans votre classe principale de DoorView, donc vous savez ce type de porte est.

Ensuite, créez un nouveau fichier rapide et l'appeler DoorAnimation.swift et mettre à l'intérieur:

extension DoorView { 
    func open(withDuration duration: CFTimeInterval = 1.0) { 
    switch doorType { 
     case .Hinged: 
     openHingedDoor(duration) 
     case .Sliding: 
     openSlidingDoor(duration) 
    } 
    } 

    func openSlidingDoor(withDuration duration: CFTimeInterval = 1.0) { 
    // Enter the custom code 
    // You can call use self to access the current door view instance 
    } 

    func openHingedDoor(withDuration duration: CFTimeInterval = 1.0) { 
    // Enter hinged door animation code 
    } 
} 

2. Sous DoorView

Dans DoorView créer une fonction:

func open() { 
    print("WARNING: This requires an override.") 
} 

Ensuite, remplacez open() dans chacune de vos sous-classes.

Les deux structures ont leurs avantages et leurs inconvénients. Je dirais que si les portes ne font pas trop, l'option 1 est géniale. Si elles ont beaucoup de fonctionnalités, il serait préférable de faire l'option 2.

+0

Merci pour la réponse! Donc, juste pour être clair, à propos du modèle de conception global/SoC: il est acceptable pour les vues de contenir ce genre de logique? Vos deux suggestions sont excellentes en ce qui concerne l'organisation du code, mais les deux impliquent toujours les Vues qui implémentent leurs propres animations. Je veux juste m'assurer que c'est kasher. EDIT: Cela contredirait l'intervenant sur le post original qui a suggéré une classe d'animation distincte, non? –

+1

Il est acceptable de mettre des animations dans la classe de vue elle-même. La plupart du temps (il y a des exceptions cependant) les vues ont leurs propres types d'animation. Cependant, si vous faites quelque chose comme une animation de groupe, comme faire disparaître un tas de vues avec un tableau [View], vous devez utiliser une extension sur la classe View de base et créer une fonction fadeOut statique (views: [View]) {} type fonction. Il y a donc des lignes floues. –