概述:我目前有一个实现自定义动画逻辑的自定义UIView子类,并且我不确定该视图类是否是放置该代码的最佳位置。

我正在Swift中制作一个iOS应用程序,该应用程序使用称为DoorView的UIView子类。 DoorView表示滑动门,该滑动门响应于滑动手势执行滑动动画以打开。

这是我现在拥有的完整动画:

ios - 自定义可重复使用的动画代码应该放在哪里?-LMLPHP

为了使View Controller保持明亮,我将处理这些动画的实际核心动画代码放入DoorView类。 My View Controller通过检查手势是否匹配打开给定门所需的手势来处理该手势,如果是,则在DoorView上调用open()方法。

因此在ViewController中:

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

这是我的DoorView类中的open()方法:
注意:这只是滑动动画,将来会使用对滑动类型的检查来区别于其他类型的门(例如,铰链门)。
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")
    }
}

那么可以将动画逻辑放在视图类中吗?这是我的第一个直觉,因为a)这些动画特定于我的DoorView,并且b)因为animateWithDuration是UIView的类方法,因此似乎有一些先例可以由视图/视图类自己处理动画。

但是我将继续开发我的应用程序,我将在自己的动画中添加更多的门类型,并且我担心DoorView会因动画代码而变得过胖。那时候我应该简单地开始制作DoorView子类(即SlidingDoorView,HingedDoorView等)吗?

还是应该由视图控制器处理视图动画?我的问题是,除了VC膨胀之外,如果我想在其他视图控制器中使用DoorViews,则需要复制代码。这样,我的DoorView便打包了自己的动画,而我所有的VC都需要调用open()。

最佳答案

我认为您可以选择两种方法,两种方法都可以接受。

1.使用扩展名将动画代码与门视图代码分开

在您的主要DoorView类中为门类型添加一个新的枚举,以便您知道门的类型。

然后创建一个新的swift文件,并将其命名为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。

10-01 01:20