1

Übersicht: Ich habe derzeit eine benutzerdefinierte UIView-Unterklasse, die benutzerdefinierte Animationslogik implementiert, und ich bin mir nicht sicher, ob die Ansichtsklasse der beste Ort ist, um diesen Code zu platzieren.Wohin soll benutzerdefinierter, wiederverwendbarer Animationscode gehen?

Ich mache eine iOS-App in Swift, die eine UIView-Unterklasse namens DoorView verwendet. Ein DoorView stellt eine Schiebetür dar, die als Antwort auf eine Wischgeste eine Schiebeanimation zum Öffnen ausführt.

ist die komplette Animation, wie ich es habe jetzt:

enter image description here

Bei dem Versuch, meinen View Controller Licht zu halten, habe ich den eigentlichen Kern Animation Code zu setzen, die diese Animationen in meine DoorView Klasse behandelt. Der View-Controller behandelt die Geste, indem er überprüft, ob sie mit der zum Öffnen einer bestimmten Tür erforderlichen Geste übereinstimmt, und ruft in diesem Fall eine open() -Methode für die Türansicht auf.

So in Viewcontroller:

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

Und hier ist die Methode open() in meinem DoorView Klasse: Hinweis: Dies ist nur die gleitende Animation, und die Prüfung für einen Sliding-Typ wird in die verwendet werden, Zukunft von anderen Arten von Türen zu unterscheiden (zB klappbar).

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

Also ist es in Ordnung, Animationslogik in einer Ansichtsklasse zu setzen? Es war mein erster Instinkt, weil a) diese Animationen spezifisch für mein DoorView sind, und b) weil animateWithDuration eine Klassenmethode von UIView ist, also scheint es einen Präzedenzfall für Animationen zu geben, die von Views/View-Klassen selbst gehandhabt werden.

Aber ich entwickle weiterhin meine App, ich werde mehr Türtypen mit ihren eigenen Animationen hinzufügen, und ich fürchte, DoorView wird mit Animationscode zu dick werden. Soll ich zu diesem Zeitpunkt DoorView-Unterklassen erstellen (d. H. SlidingDoorView, HingedDoorView usw.)?

Oder sollten Animationen vom View-Controller behandelt werden? Mein Problem damit, neben VC Bloat, ist, dass, wenn ich DoorViews in anderen View-Controllern verwenden möchte, ich Code duplizieren muss. Auf diese Weise werden meine DoorViews mit eigenen Animationen ausgeliefert und alle meine VCs müssen open() aufrufen.

+1

Schöne Animation. Klingt wie jede Animation sollte eine eigene Klasse sein. Was Sie davon ableiten, hängt davon ab, welcher Code wiederverwendet werden muss. – dbugger

+0

Ah, interessant! Vielen Dank für Ihre Antwort. In welchem ​​Fall würden die Animationen aufgerufen? Würde ich immer noch diese Aufrufe der Animationsmethode in meiner DoorView-Klasse behandeln, oder würde es mehr Sinn machen, sie in einem View-Controller zu behandeln? –

+1

Wenn Sie sie in der View-Klasse kapseln können, wären sie einfacher in anderen Controllern zu verwenden. – dbugger

Antwort

1

Es gibt zwei Möglichkeiten, ich denke, Sie können es tun und beide gleichermaßen akzeptabel.

Put in einem neuen Enum für die Türtyp in der Haupt DoorView Klasse

1. Erweiterung verwenden, um Ihre Animation Code aus der Tür Ansicht Code zu trennen, so dass Sie wissen, welche Art von Tür ist.

Dann eine neue swift-Datei erstellen und es DoorAnimation.swift rufen und nach innen setzen:

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. Subclass DoorView

Innerhalb DoorView eine Funktion erstellen:

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

Dann überschreiben Sie open() in jeder Ihrer Unterklassen.

Beide Strukturen haben ihre Vor- und Nachteile. Ich würde sagen, wenn die Türen nicht zu viel tun, ist Option 1 großartig. Wenn sie viel Funktionalität haben, wäre es besser, Option 2 zu tun.

+0

Danke für die Antwort! Also nur um klar zu sein, passend zu dem gesamten Designmuster/SoC: Es ist akzeptabel für Views, diese Art von Logik zu enthalten? Beide Vorschläge sind großartig, was die Code-Organisation betrifft, aber beide involvieren immer noch die Views, die letztendlich ihre eigenen Animationen implementieren. Ich möchte nur sicherstellen, dass das koscher ist. EDIT: Dies würde dem Kommentator auf dem ursprünglichen Beitrag, der von einer separaten Animationsklasse vorgeschlagen, nein? –

+1

Es ist akzeptabel, Animationen innerhalb der View-Klasse selbst zu platzieren. Die meiste Zeit (es gibt jedoch Ausnahmen) Ansichten haben ihre eigenen Animationstypen. Wenn Sie jedoch so etwas wie eine Gruppenanimation machen, wie zum Beispiel eine Reihe von Ansichten zum Ausblenden mit einem [View] -Array, sollten Sie eine Erweiterung für die View-Klasse verwenden und ein statisches funcadeOut erstellen (views: [View]) {} Typ Funktion. Es gibt also einige unscharfe Linien. –

Verwandte Themen