定制的、可重复使用的动画代码应该放在哪里?

Where should custom, reusable animation code go?

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

我正在 Swift 中制作一个 iOS 应用程序,它使用 UIView 子class 我调用 DoorView。 DoorView 代表一扇滑动门,它响应滑动手势,执行滑动动画以打开。

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

为了让我的 View Controller 保持轻便,我将处理这些动画的实际核心动画代码放入了我的 DoorView class。我的视图控制器通过检查它是否与打开给定门所需的手势匹配来处理手势,如果匹配,则调用 DoorView 上的 open() 方法。

所以在 ViewController:

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

这是我的 DoorView class 中的 open() 方法: 注意:这只是滑动动画,以后会用到Sliding-type的检查来区别于其他类型的门(例如铰链)。

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

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

但我会继续开发我的应用程序,我会添加更多带有自己动画的门类型,我担心 DoorView 会因动画代码而变得过于臃肿。那时我是否应该简单地开始制作 DoorView subclasses(即 SlidingDoorView、HingedDoorView 等)?

或者视图动画应该由视图控制器处理?我的问题是,除了 VC 膨胀之外,如果我想在其他视图控制器中使用 DoorViews,我将需要复制代码。这样,我的 DoorViews 就打包了自己的动画,我的 VCs 需要做的就是调用 open()。

有两个选项我认为你可以做到并且都同样可以接受。

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

在您的主 DoorView class 中为门类型输入一个新的枚举,这样您就知道它是什么类型的门。

然后新建一个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。 Subclass DoorView

在 DoorView 中创建一个函数:

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

然后只需在每个子classes 中覆盖 open()。

两种结构各有优缺点。我会说如果门不做太多选择 1 很棒。如果他们有很多功能,最好做选项2。