Elephant-Parade 1.0.0

Elephant-Parade 1.0.0

Anton DoudarevElephant TechSohel Siddique 维护。



  • Elephant Engineering

Parade

Build Status codecov.io Carthage compatible Cocoapods Compatible Platform License

简介

向 UICollectionView、UITableView 或 UIScrollViews 内的单元格通信,一直是一个挑战。它几乎总是依赖于一个混乱的过程,尝试将滚动进度传递到触发特殊滚动效果的单元格中。我们设计了这个框架,以最大限度地减少动画视图所需的努力。通过一个简单的基于块构建器,我们使定义视图状态变得简单——从它们出现的地方到它们消失的地方。

功能

  • 支持 UICollectionView、UITableView、UIScrollview
  • 简单基于块的语法
  • 最小化集成需求
  • 支持链式动画视图
  • 可调整的进度范围
  • 46 种不同的参数曲线

交互式演示

项目包含一个示例应用程序,其中包含了以下已实现的示例,用于下面的动画gif中的滚动效果。

包含示例
alt tag 演示包含一个根视图 ParallaxImageViewController,并且以下顺序显示了这些单元格作为示例

- ParallaxIntroCollectionViewCell : 缩放 / 变换 / 透明度

- ParallaxScaleCollectionViewCell : 缩放 / 居中

- ParallaxDoubleImageCollectionViewCell : 居中 / 变换

- ParallaxImageAppearCollectionViewCell : 动画链式偏移

- ParallaxImageCollectionViewCell : 缩放 / 透明度 / 变换

- ParallaxTheEndCollectionViewCell : 3D 变换

注意:示例中也包含将在文档后面讨论的自定义范围。

安装

通信

  • 如果您发现了 错误,或有 特性请求,请提交一个 issue。
  • 如果您想 贡献,请查阅 贡献指南 并提交一个 pull request。
  • 如果您 贡献,请确保代码覆盖率有 100%

基本用法

从核心来看,这个框架为您的可动画视图定义了 起始结束 状态,滚动视图将在这些状态之间进行插值。起始状态定义了视图在滚动进入屏幕时的出现位置——而结束状态定义了视图消失的位置。

除了定义状态之外,还需要实现 PDAnimatableType 在要动画的视图中,其他的都是无缝的。每个动画由开发者定义的 起始结束 状态组成——再加上首次视图开始滚动时自动配置的 快照 状态。

在进行创建之前,请参考下面的图来了解进度计算的坐标空间。进度是相对于scrollview自身的边界而言的。在水平滚动时,X值差异到视口中心点的值等于scrollview自身的宽度。正如垂直滚动时Y值的变化,如以下所示。

alt tag

注意:可以对这些范围进行调整,具体说明可在下方的界限进度范围部分找到。

初始化

在应用程序启动时通过 application(:didFinishLaunchingWithOptions:) 方法初始化Parade。一旦初始化完成,基本的UIScrollView将开始将滚动进度传递给其内部包含的动画视图。

UIScrollView.initializeParade()

创建可动画视图

第一步,通过实现 PDAnimatableType 协议使得视图可动画化,scrollview则会开始向其子视图传递进度。

public protocol PDAnimatableType {

    // The progress animator definition that
    // interpolates over animatable properties
    func configuredAnimator() -> PDAnimator;
}

以下任一视图及其子视图都可以实现 PDAnimatableType 并进行动画处理:

  • UICollectionViewCell
  • UITableViewCell
  • UIScrollView 的子视图

然而,在scrollview可以传递进度之前,需要定义一个与scrollview将要跟踪的相对滚动方向相匹配的动画器。框架附带基于递归块构建器的工具,它可以简化创建复杂的动画,以便在滚动中进行插值。

垂直方向滚动动画器

以下是一个创建垂直滚动动画器的示例。该闭包返回一个动画器,可以用它为层次结构中的任何特定视图创建状态。

func configuredAnimator() -> PDAnimator {

   /* Create a vertical tracking animator call this class method */
   return PDAnimator.newVerticalAnimator { (animator) in

   }
}

水平方向滚动动画器

以下是一个创建水平动画器的示例,该动画器可以水平滚动。闭包返回一个可以使用它来创建和指定视图任何特定状态的动画器。

func configuredAnimator() -> PDAnimator {

   /* Create a horizontal tracking animator with this class method */
   return PDAnimator.newHorizontalAnimator { (animator) in

   }
}

闭包返回一个可以根据需要为特定视图创建和到状态的动画器。

配置动画状态

配置结束状态

为了使一个视图相对于滚动进度淡入,可以通过如下方式调用startState(for:)方法定义一个起始状态。每次添加状态时,都会返回一个状态制造器,可以用来遍历多个属性。

func configuredAnimator() -> PDAnimator {

    let offScreenAlpha : CGFloat = 0.0

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startState(for: animatedImageView, { (s) in
          s.alpha(offScreenAlpha)
        })
     }
}

配置结束状态

在上一个例子基础上,为了使一个视图相对于滚动进度隐去,通过调用endState(for:)方法定义一个结束状态。

func configuredAnimator() -> PDAnimator {

    let offScreenAlpha : CGFloat = 0.0

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startState(for: animatedImageView, { (s) in
          s.alpha(offScreenAlpha)
        }).endState(for: animatedImageView, { (s) in
          s.alpha(offScreenAlpha)
        })
     }
}

配置起始和结束状态

在上一个例子基础上,出现的透明度消失似乎是相同的。如果起始和结束状态值相同,可以通过使用startEndState(for:)方法来同时设置两个状态。

func configuredAnimator() -> PDAnimator {

    let offScreenAlpha : CGFloat = 0.0

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startEndState(for: animatedImageView, { (s) in
          s.alpha(offScreenAlpha)
        })
     }
}

为多个视图设置起始和结束状态

如果需要多个视图执行相同的动画,已经定义了辅助方法来为视图数组创建动画。以下是如何使用它们的示例。

func configuredAnimator() -> PDAnimator {

    var animatedViews = [view1, view2, view3, view4]

    let offScreenAlpha : CGFloat = 0.0

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startEndState(forViews: animatedViews, { (s) in
          s.alpha(offScreenAlpha)
        })
     }
}

这也可以用于多个视图。

func startState(forViews views:  [UIView], _ callback : ... )    -> PDAnimationMaker
func endState(forViews views:  [UIView], _ callback : ... )      -> PDAnimationMaker
func startEndState(forViews views:  [UIView], _ callback : ... ) -> PDAnimationMaker

状态属性

该框架提供了许多辅助方法,可以轻松地定义视图及其支持层的状态属性。

/* View Property Setters */

public func alpha(_ value : CGFloat)               -> PDAnimatablePropertyMaker
public func backgroundColor(_ value : UIColor)     -> PDAnimatablePropertyMaker
public func bounds(_ value : CGSize)               -> PDAnimatablePropertyMaker
public func center(_ value : CGPoint)              -> PDAnimatablePropertyMaker
public func size(_ value : CGSize)                 -> PDAnimatablePropertyMaker
public func transform(_ value : CGAffineTransform) -> PDAnimatablePropertyMaker

/* Layer Property Setters */

public func borderColor(_ value : UIColor)         -> PDAnimatablePropertyMaker
public func borderWidth(_ value : CGFloat)         -> PDAnimatablePropertyMaker
public func contentsRect(_ value : CGRect)         -> PDAnimatablePropertyMaker
public func cornerRadius(_ value : CGFloat)        -> PDAnimatablePropertyMaker
public func shadowColor(_ value : UIColor)         -> PDAnimatablePropertyMaker
public func shadowOffset(_ value : CGSize)         -> PDAnimatablePropertyMaker
public func shadowOpacity(_ value : CGFloat)       -> PDAnimatablePropertyMaker
public func shadowRadius(_ value : CGFloat)        -> PDAnimatablePropertyMaker
public func transform3D(_ value : CATransform3D)   -> PDAnimatablePropertyMaker
public func zPosition(_ value : CGFloat)           -> PDAnimatablePropertyMaker

如果没有定义setter,并且需要将特定属性设置为插值之间,还定义了两个setter,适用于视图及其支持层并使用KVC。

public func viewValue(_ value : Any?, forKey key : String)    -> PDAnimatablePropertyMaker
public func layerValue(_ value : Any?, forKey key : String)   -> PDAnimatablePropertyMaker

参数式缓动

有46种不同的参数曲线可以应用于每个属性的独特插值。框架内置了以下支持的参数曲线,可以单独应用于每个属性。

.inSine
.inOutSine
.outSine
.outInSine
.inQuadratic
.inOutQuadratic
.outQuadratic
.outInQuadratic
.inCubic
.inOutCubic
.outCubic
.outInCubic
.inQuartic
.inOutQuartic
.outQuartic
.outInQuartic
.inQuintic
.inOutQuintic
.outQuintic
.outInQuintic
.inAtan
.inOutAtan
.outAtan
*
.inExponential
.inOutExponential
.outExponential
.outInExponential
.inCircular
.inOutCircular
.outCircular
.outInCircular
.inBack
.inOutBack
.outBack
.outInBack
.inElastic
.inOutElastic
.outElastic
.outInElastic
.inBounce
.inOutBounce
.outBounce
.outInBounce
.linear
.smoothStep
.smootherStep
*

在构建视图状态时附加到状态的属性定义中。有关支持的某些参数曲线的参考信息,请访问此处

func configuredAnimator() -> PDAnimator {

    let offScreenAlpha : CGFloat = 0.0
    let offScreenTransform = CGAffineTransform.identity.scaledBy(x: 0.5, y: 0.5)

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startEndState(for: animatedImageView, { (s) in
          s.alpha(offScreenAlpha).easing.(.inSine)
          s.transform(offScreenTransform).easing(.inOutCubic)
        })
     }
}

高级视图动画

链式动画

动画进度不必仅适用于正在滚动的顶级视图。如果一个子视图实现了 PDAnimatableType,并且是子视图层次结构的一部分,将其附加到动画器可以创建一个链。

然后动画器将进度与子视图的动画器进行通信,子视图可以附加到子视图,或者子视图甚至可以将它们附加到子视图,以创建最终可以遍历多个级别以产生一些有趣效果的链。要附加一个动画视图,请按照如下方式调用 attachAnimatableView(:) 方法。

func configuredAnimator() -> PDAnimator {

    let offScreenAlpha : CGFloat = 0.0
    let offScreenTransform = CGAffineTransform.identity.translatedBy(x: 0.0, y: 100.0)

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startEndState(for: animatedImageView, { (s) in
          s.transform(offScreenTransform).easing(.inOutCubic)
        }).attachAnimatableView(animatedImageView)
     }
}

边界进度范围

有时需要调整进度实际发生的位置。当动画视图的大小小于滚动视图的边界大小时,这特别有用。观察定义的范围示例以及它们如何影响进度。通过定义一个范围,这基本上是在告诉滚动视图从0到100的进度计数从哪里开始。

alt tag

可以像对缓动函数那样,按属性定义不同的范围,从而允许不同的属性在不同的坐标空间内插值。以下示例定义了每个属性的两个不同范围,并且可以在上面直观地参考哪里将发生插值。

func configuredAnimator() -> PDAnimator {

    let offScreenAlpha : CGFloat = 0.0
    let offScreenTransform = CGAffineTransform.identity.translatedBy(x: 0.0, y: 100.0)

    return PDAnimator.newVerticalAnimator { (animator) in

        animator.startState(for: animatedImageView, { (s) in
          s.transform(offScreenTransform).easing(.inOutCubic).range(0.5...1.0)
          s.alpha(offScreenTransform).easing(.inOutCubic).range(0.25...0.75)
        })
     }
}

许可

Parade 在 MIT 许可下发布。有关详细信息,请参阅 许可