1

Обзор: В настоящее время у меня есть пользовательский подкласс UIView, который реализует логику пользовательской анимации, и я не уверен, что класс представления - лучшее место для размещения этого кода.Где должен быть выполнен код, многоразовый код анимации?

Я делаю приложение iOS в Swift, которое использует подкласс UIView. Я вызываю DoorView. Дверь ViewView представляет собой раздвижную дверь, которая в ответ на жест скольжения выполняет скользящую анимацию для открытия.

Вот полный анимации, как я сейчас:

enter image description here

В попытке сохранить мой View Controller свет, я ставлю фактический основной код анимации, который обрабатывает эти анимации в моем классе DoorView. My View Controller обрабатывает жест, проверяя, соответствует ли он жест, необходимый для открытия данной двери, и если это так, вызывает метод open() в DoorView.

Так в ViewController:

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

А вот открытым способом() в моем классе DoorView: Примечание: это только скользящая анимация, и проверка на Sliding-типа будет использоваться в будущее для дифференциации от других типов дверей (например, навесное).

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

Так можно ли положить анимационную логику в класс представления? Это был мой первый инстинкт, потому что: а) эти анимации специфичны для моего DoorView и b) потому что animateWithDuration - это метод класса UIView, поэтому кажется, что некоторые анимации обрабатываются самими видами/представлениями.

Но я продолжаю разрабатывать свое приложение, я буду добавлять больше типов дверей с их собственными анимациями, и я опасаюсь, что DoorView станет слишком толстым с анимационным кодом. Должен ли я в этот момент просто начать создавать подклассы DoorView (т. Е. SlidingDoorView, HingedDoorView и т. Д.)?

Или следует просматривать анимацию с помощью контроллера вида? Моя проблема с этим, помимо VC bloat, заключается в том, что если я хочу использовать DoorViews в других контроллерах представлений, мне нужно будет дублировать код. Таким образом, мои DoorViews поставляются в комплекте с их собственной анимацией, и все мои VC, которые нужно сделать, это вызов open().

+1

Хорошая анимация. Кажется, каждая анимация должна быть ее собственным классом. То, что вы подклассифицируете, зависит от того, какой код нужно повторно использовать. – dbugger

+0

А, интересно! Спасибо за ваш ответ. В этом случае, где будут вызваны анимации? Должен ли я по-прежнему обрабатывать вызовы методов анимации в моем классе DoorView, или было бы разумнее, чтобы это обрабатывалось в контроллере просмотра? –

+1

Если вы можете инкапсулировать их в класс View, они будут проще использовать в других контроллерах. – dbugger

ответ

1

Есть два варианта, я думаю, вы можете это сделать и оба одинаково приемлемы.

1. Используя расширение, чтобы отделить код анимации из кода вида двери

Put в новом перечислении для типа двери в вашем главном классе DoorView, так что вы знаете, какой тип двери она.

Затем создайте новый быстрый файл и назовите его DoorAnimation.swift и положить внутрь:

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. Подкласс DoorView

В DoorView создать функцию:

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

Затем просто переопределите open() внутри каждого из ваших подклассов.

Обе структуры имеют свои преимущества и недостатки. Я бы сказал, если двери не делают слишком много вариантов 1, это здорово. Если у них много функциональности, было бы лучше сделать вариант 2.

+0

Спасибо за ответ! Поэтому, чтобы быть понятным, применительно к общей схеме дизайна/SoC: приемлемо ли для Views придерживаться такой логики? Оба ваших предложения отлично подходят для организации кода, но оба они по-прежнему связаны с представлением, в конечном счете реализующим их собственные анимации. Я просто хочу убедиться, что это кошер. EDIT: Это противоречило бы комментатору на исходном посту, который предложил отдельный класс анимации, нет? –

+1

Его приемлемо размещать анимации внутри самого класса представления. В большинстве случаев (есть исключения) представления имеют свои собственные типы анимации. Однако, если вы делаете что-то вроде групповой анимации, например, чтобы получить кучу представлений, чтобы исчезнуть с помощью массива [View], вы должны использовать расширение в базовом классе View и создать статический func fadeOut (views: [View]) {} функция типа. Таким образом, есть несколько размытых линий. –