JHChainableAnimations 3.0.1

JHChainableAnimations 3.0.1

测试已测试
语言 Obj-CObjective C
许可证 MIT
发布最新版本2017年10月

Jeff HurrayJeff Hurray 维护。



  • 作者
  • Jeff Hurray







3.x 版本新增内容是什么?

  • 更简洁的语法
  • 支持 Swift 4
  • 错误修复和改进

2.x 版本新增内容是什么?

  • 从头重新设计,不再需要直接操作 UIView🛠
  • 为每个动画步骤添加了预动画和后动画钩子
  • 添加了暂停和继续功能
  • 添加了重复动画功能🔂
  • 在单独的框架中添加了友好的 Swift 接口🔥🕊

动画有什么问题?

CAAnimations 和 UIView 动画非常强大,但将多个动画链接在一起困难,尤其是在更改锚点时。

此外,复杂的动画难以阅读。

比如说我想将 myView 向右移动 50 像素并使用弹簧,然后在移动完成后将背景颜色改为向内减速

旧方法

    [UIView animateWithDuration:1.0
                          delay:0.0
         usingSpringWithDamping:0.8
          initialSpringVelocity:1.0
                        options:0 animations:^{
                            CGPoint newPosition = self.myView.frame.origin;
                            newPosition.x += 50;
                            self.myView.frame.origin = newPosition;
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.5
                              delay:0.0
                            options:UIViewAnimationOptionCurveEaseIn
                         animations:^{
            self.myView.backgroundColor = [UIColor purpleColor];
        } completion:nil];
    }];

这相当糟糕……使用 JHChainableAnimations 只需一行代码。

使用 JHChainableAnimations

JHChainableAnimator *animator = [[JHChainableAnimator alloc] initWithView:self.myView];
animator.moveX(50).spring.thenAfter(1.0).makeBackground([UIColor purpleColor]).easeIn.animate(0.5);

还有一些非常好的动画库,例如RBBAnimationDCAnimationKitPMTween,但它们仍然缺乏强大且易于阅读/编写的链式动画语法。

安装

您可以将此框架添加到项目的几种方式。Objective-C 框架名为 JHChainableAnimations,Swift 框架名为 ChainableAnimations。有关 Swift 使用的更多说明,请参阅此处

Objective-C
pod 'JHChainableAnimations', '~> 3.0.1'

然后添加以下内容

#import <JHChainableAnimations/JHChainableAnimations.h>
Swift
pod 'ChainableAnimations', '~> 3.0.1'

然后添加以下内容

import ChainableAnimations
Objective-C

JHChainableAnimations 框架添加到您的项目中。

Swift

ChainableAnimations 框架添加到您的项目中。

手动添加到项目

要么克隆代码库,然后手动将 JHChainableAnimations 中的文件添加到项目中。

用法

创建一个动画器

要创建一个 JHChainableAnimator 实例,您必须调用 initWithView: 方法。

JHChainableAnimator *animator = [[JHChainableAnimator alloc] initWithView:self.myView];

动画

链式属性如 moveX(x) 必须位于视图和 animate(t) 函数之间

下面是如何在 1 秒内将对象的大小加倍的一个示例。

animator.makeScale(2.0).animate(1.0);

组合动画

如果您想在缩放视图的同时移动视图,请添加另一个链式属性。顺序不重要

animator.makeScale(2.0).moveXY(100, 50).animate(1.0);
// the same as animator.moveXY(100, 50).makeScale(2.0).animate(1.0);

链式属性的完整列表可以在此处找到

链式动画

要链式连接动画,请使用 thenAfter(t) 函数分隔链式。

以下是一个例子,展示了如何在0.5秒内缩放一个对象,然后在完成缩放后移动它1秒。

animator.makeScale(2.0).thenAfter(0.5).moveXY(100, 50).animate(1.0);

动画效果

要添加动画效果,请在要应用动画的链式属性之后调用效果方法。

以下是一个使用弹簧效果缩放视图的例子。

animator.makeScale(2.0).spring.animate(1.0);

如果将2个相同的链式属性添加到同样的链式属性,第二个将取消第一个的效果。

animator.makeScale(2.0).bounce.spring.animate(1.0);
// The same as animator.makeScale(2.0).spring.animate(1.0);

这里可以找到完整的动画效果属性列表。

锚定

为了锚定视图,在动画链中的某个时刻调用锚定方法。就像效果一样,在同一个链中依次调用将会取消第一个的效果。

以下是一个围绕不同锚定点旋转视图的例子。

animator.rotateZ(180).anchorTopLeft.thenAfter(1.0).rotateZ(90).anchorCenter.animate(1.0);

// animator.rotateZ(90).anchorTopLeft.anchorCenter == animator.rotateZ(90).anchorCenter

这里可以找到锚定属性的完整列表。

延迟

要延迟动画,请调用链式属性 wait(t)delay(t)

以下是一个在0.5秒延迟后移动视图的例子。

animator.moveXY(100, 50).wait(0.5).animate(1.0);
// The same as animator.moveXY(100, 50).delay(0.5).animate(1.0);

完成

要动画结束后执行代码,请设置您的动画器的 completionBlock 属性,或者调用 animateWithCompletion(t, completion) 函数。

animator.makeX(0).animateWithCompletion(1.0, ^{
	NSLog(@"Animation Done");
});

它与以下相同:

animator.completionBlock = ^{
	NSLog(@"Animation Done");
};
animator.makeX(0).animate(1.0);

重复动画

您可以通过用 repeat(time, count) 方法替换 thenAfter(time) 方法来重复动画。这将重复之前定义的动画。

// The animator will double its scale 3 times for 0.5 seconds each before it calls `moveXY` and finishes the animation
animator.makeScale(2.0).repeat(0.5, 3).moveXY(100, 50).animate(1.0);

通过调用 animateWithRepeat(time, count),您可以重复动画的最后一部分。

// The animator will double its scale then rotate by 90 degrees 3 times for 1 second each.
animator.makeScale(2.0).thenAfter(0.5).rotate(90). animateWithRepeat(1.0, 3);

暂停和取消

要暂停动画,请调用动画器上的 pause 方法。调用暂停时,链中的当前动画将完成,但将不会执行任何后续操作。您可以使用 isPausedisAnimating 只读属性来检查状态。如果一个动画被暂停但没有停止,它仍然会被评估为 animating

要从中断的状态重新开始,请调用动画器上的 resume 方法。

要停止动画并清除状态,请调用动画器上的 stop 方法。

// In this case the `moveX` animation will execute but the `moveY` will not
// If `resume` is called `moveY` will be executed
// If `stop` is called, nothing will be executed and the animator will get a fresh state
animator.moveX(10).thenAfter(0.5).moveY(10).animate(0.5);
[animator pause];

回调

您可以通过调用 preAnimationBlock(block)animationBlock(block)postAnimationBlock(block) 方法来勾入动画过程的不同步骤。所有这些方法都接受一个简单的块 void(^)() 参数。在动画链中调用这些方法的顺序不重要。

animator.moveX(10).preAnimationBlock(^{ 
	NSLog(@"before the first animation");
 }).thenAfter(1.0).postAnimationBlock(^{
 	NSLog(@"After the second animation");
 }).moveY(10).animate(1.0);

贝塞尔路径

您还可以让视图沿着 UIBezierPath 动画。创建一个 UIBezierPath * 实例,然后向它添加点、曲线或线条,并在链式属性中使用它。

UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:self.myView.center];
[path addLineToPoint:CGPointMake(25, 400)];
[path addLineToPoint:CGPointMake(300, 500)];
animator.moveOnPath(path).animate(1.0);

动画效果不作用于路径运动。

与 Auto Layout 一起使用

变换

使用 transform 链式属性。这些属性更适合与 AutoLayout 约束的视图一起使用。您不应该将它们与其他链式属性混合使用

animatorForViewWithConstraints.transformX(50).transformScale(2).animate(1.0);

与 Swift 一起使用

现在使用带有 Swift 的 JHChainableAnimations 在版本 2.x 中稍微更易读。我创建了一个独立的 Swift 框架,其中包含一个名为 ChainableAnimator 的类。这是一个 very thin wrapper over JHChainableAnimator,拥有略为易读的语法。

let animator = ChainableAniamtor(view: myView)
animator.moveX(x: 50).thenAfter(t: 1.0).rotate(angle: 360).bounce.animate(t:1.0)

所有 Objective-C 方法都映射到了一个 Swift 方法。

链式属性

属性 采取... 用法
- (JHChainableRect) makeFrame; CGRect animator.makeFrame(rect).animate(1.0);
- (JHChainableRect) makeBounds; CGRect animator.makeBounds(rect).animate(1.0);
- (JHChainableSize) makeSize; (CGFloat: width, CGFloat: height) animator.makeSize(10, 20).animate(1.0);
- (JHChainablePoint) makeOrigin; (CGFloat: x, CGFloat: y) animator.makeOrigin(10, 20).animate(1.0);
- (JHChainablePoint) makeCenter; (CGFloat: x, CGFloat: y) animator.makeCenter(10, 20).animate(1.0);
- (JHChainableFloat) makeX; (CGFloat: f) 动画器.makeX(10).animate(1.0);
- (JHChainableFloat) makeY; (CGFloat: f) 动画器.makeY(10).animate(1.0);
- (JHChainableFloat) makeWidth; (CGFloat: f) 动画器.makeWidth(10).animate(1.0);
- (JHChainableFloat) makeHeight; (CGFloat: f) 动画器.makeHeight(10).animate(1.0);
- (JHChainableFloat) makeOpacity; (CGFloat: f) 动画器.makeOpacity(10).animate(1.0);
- (JHChainableColor) makeBackground; (UIColor: 颜色) 动画器.makeBackground(颜色).animate(1.0);
- (JHChainableColor) makeBorderColor; (UIColor: 颜色) 动画器.makeBorderColor(颜色).animate(1.0);
- (JHChainableFloat) makeBorderWidth; (CGFloat: f) 动画器.makeBorderWidth(3.0).animate(1.0);
- (JHChainableFloat) makeCornerRadius; (CGFloat: f) 动画器.makeCornerRadius(3.0).animate(1.0);
- (JHChainableFloat) makeScale; (CGFloat: f) 动画器.makeScale(2.0).animate(1.0);
- (JHChainableFloat) makeScaleX; (CGFloat: f) 动画器.makeScaleX(2.0).animate(1.0);
- (JHChainableFloat) makeScaleY; (CGFloat: f) 动画器.makeScaleY(2.0).animate(1.0);
- (JHChainablePoint) makeAnchor; (CGFloat: x, CGFloat: y) 动画器.makeAnchor(0.5, 0.5).animate(1.0);
- (JHChainableFloat) moveX; (CGFloat: f) 动画器.moveX(50).animate(1.0)
- (JHChainableFloat) moveY; (CGFloat: f) 动画器.moveY(50).animate(1.0)
- (JHChainablePoint) moveXY; (CGFloat: x, CGFloat: y) 动画器.moveXY(100, 50).animate(1.0)
- (JHChainableFloat) moveHeight; (CGFloat: f) 动画器.moveHeight(50).animate(1.0)
- (JHChainableFloat) moveWidth; (CGFloat: f) 动画器.moveWidth(50).animate(1.0)
- (JHChainableDegrees) rotateX; (CGFloat: 角度) #非弧度! 动画器.rotateX(360).animate(1.0);
- (JHChainableDegrees) rotateY; (CGFloat: 角度) #非弧度! 动画器.rotateY(360).animate(1.0);
- (JHChainableDegrees) rotateZ; (CGFloat: 角度) #非弧度! 动画器.rotateZ(360).animate(1.0);
- (JHChainablePolarCoordinate) movePolar; (CGFloat: 半径, CGFloat: 角度) 动画器.movePolar(30, 90).animate(1.0);
- (JHChainableBezierPath) moveOnPath; (UIBezierPath *path) 动画器.moveOnPath(path).animate(1.0);
- (JHChainableBezierPath) moveAndRotateOnPath; (UIBezierPath *path) 动画器.moveAndRotateOnPath(path).animate(1.0);
- (JHChainableBezierPath) moveAndReverseRotateOnPath; (UIBezierPath *path) 动画器.moveAndReverseRotateOnPath(path).animate(1.0);
- (JHChainableFloat) transformX; (CGFloat f) 动画器.transformX(50).animate(1.0);
- (JHChainableFloat) transformX; (CGFloat f) 动画器.transformX(50).animate(1.0);
- (JHChainableFloat) transformY; (CGFloat f) 动画器.transformY(50).animate(1.0);
- (JHChainableFloat) transformZ; (CGFloat f) 动画器.transformZ(50).animate(1.0);
- (JHChainablePoint) transformXY; ( CGFloat x, CGFloat y) 动画器.transformXY(50, 100).animate(1.0);
- (JHChainableFloat) transformScale; (CGFloat f) 动画器.transformScale(50).animate(1.0);
- (JHChainableFloat) transformScaleX; (CGFloat f) 动画器.transformScaleX(50).animate(1.0);
- (JHChainableFloat) transformScaleY; (CGFloat f) 动画器.transformScaleY(50).animate(1.0);
- (JHChainableAnimator *) transformIdentity; 无内容 动画器.transformIdentity.animate(1.0);

动画效果

这些函数的快速查看可以在这里找到

这些动画函数是从一个很酷的关键帧动画库中获取的,可以在这里找到

它们基于可以在这里找到的jQuery缓动函数

锚定

有关锚定的信息可以在这里找到

待办事项

我收到了许多关于下一步做什么的优秀建议。如果您认为这里缺少什么,请告诉我!以下是我打算按顺序开展工作的事务。

  • OSX版本
  • 约束动画器

联系信息及贡献

请随时发邮件给我[email protected]。我很乐意听取您的想法,或看到使用该功能的示例。

MIT许可证