【问题标题】:Where should custom, reusable animation code go?自定义的、可重用的动画代码应该放在哪里?
【发布时间】:2016-03-22 22:40:53
【问题描述】:

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

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

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

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

所以在 ViewController 中:

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

这是我的 DoorView 类中的 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")
    }
}

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

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

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

【问题讨论】:

  • 不错的动画。听起来每个动画都应该是它自己的类。你从什么子类化它取决于需要重用什么代码。
  • 啊,有趣!感谢您的答复。在那种情况下,动画会在哪里调用?我是否仍然在我的 DoorView 类中处理这些动画方法调用,还是在 View Controller 中处理它更有意义?
  • 如果您可以将它们封装在 View 类中,它们将更容易在其他控制器中使用。
  • 太好了,这也是我的直觉。

标签: ios animation design-patterns core-animation cocoa-design-patterns


【解决方案1】:

我认为有两种选择可以做到,而且都可以接受。

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。

【讨论】:

  • 感谢您的回复!所以为了清楚起见,建议整体设计模式/SoC:视图包含这种逻辑是否可以接受?就代码组织而言,您的两个建议都很棒,但都涉及最终实现自己的动画的视图。我只是想确保那是洁净的。编辑:这会与建议单独动画课程的原始帖子的评论者相矛盾,不是吗?
  • 将动画放入视图类本身是可以接受的。大多数时候(但也有例外)视图有自己的动画类型。但是,如果您正在执行类似组动画之类的操作,例如使用 [View] 数组让一堆视图淡出,您应该在基本 View 类上使用扩展并创建一个静态函数 fadeOut(views: [View] ) {} 类型函数。所以有一些模糊的线条。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-24
  • 1970-01-01
  • 2014-03-04
  • 1970-01-01
  • 2016-01-21
  • 1970-01-01
相关资源
最近更新 更多