P9ViewAnimator 1.1.2

P9ViewAnimator 1.1.2

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布上次发布2020年1月

Tae Hyun Na 维护。



  • 作者:
  • Tae Hyun Na

P9ViewAnimator

您可以使用P9ViewAnimator轻松实现基于关键帧的视图动画。

安装

您可以从我们的发布页面下载最新的框架文件。
P9ViewAnimator也通过CocoaPods提供。要安装它,只需将以下行添加到Podfile中。
pod ‘P9ViewAnimator’

概念

P9ViewAnimator通过处理关键帧来实现动画。使用关键帧集合制作动画场景,然后根据给定的场景播放活动(视图)。

场景

场景是关键帧的集合。
因此,创建一个带有名称的场景,并添加关键帧。

// pick a name for scenario.
let scenarioJump = "jump"

// create scenario by given name.
P9ViewAnimator.default().createScenario(scenarioJump)

// add key frame type translate decrease Y value after 1 second.
P9ViewAnimator.default().addKeyframeTranslate(toScenario: scenarioJump, after: 1.0, x: 0.0, y: -2.0, itprType: .easeIn)

// add key frame type translate increase Y value after 1 second.
P9ViewAnimator.default().addKeyframeTranslate(toScenario: scenarioJump, after: 1.0, x: 0.0, y: 2.0, itprType: .easeOut)

现在我们创建了一个场景,一些活动在1秒内向上移动,在1秒内向下移动。
如果您想在同一时间添加多个变换,请通过指定零值添加关键帧。

// make scenario
let scenarioSpinSizeUpDown = "spinSizeUpDown"
P9ViewAnimator.default().createScenario(scenarioSpinSizeUpDown)

// add key frame type scale up twice after 1 second.
P9ViewAnimator.default().addKeyframeScale(toScenario: scenarioSpinSizeUpDown, after: 1.0, x: 2.0, y: 2.0, itprType: .linear)
// add key frame type rotate with same time of previous key frame.
P9ViewAnimator.default().addKeyframeRotateZ(toScenario: scenarioSpinSizeUpDown, after: 0.0, angle: 180.0, itprType: .linear)
// add key frame type scale down half after 1 second.
P9ViewAnimator.default().addKeyframeScale(toScenario: scenarioSpinSizeUpDown, after: 1.0, x: 0.5, y: 0.5, itprType: .linear)
// add key frame type rotate with same time of previous key frame.
P9ViewAnimator.default().addKeyframeRotateZ(toScenario: scenarioSpinSizeUpDown, after: 0.0, angle: 180.0, itprType: .linear)

演员

要播放动画,向视图提供场景,如向演员提供场景。

// any view type object can be a actor
let actorView = UIImageView(named: "avatar")

// play actor with given scenario
P9ViewAnimator.default().action(actorView, withScenario: scenarioJump, delay: 0.0, targetObject: nil, beginning: nil, completion: nil) 

// scenario is reusable, so you can give scenario to another actors to play same animation.
P9ViewAnimator.default().action(anotherActorView, withScenario: scenarioJump, delay: 0.0, targetObject: nil, beginning: nil, completion: nil) 

您可以通过传递块代码,在动画开始或完成时放置自己的业务代码。

P9ViewAnimator.default().action(actorView, withScenario: scenarioJump, delay: 0.0, targetObject: nil, beginning: { (actorView:UIView?) in
    // do something you want when animation begining
}) { (actorView:UIView?) in
    // do something you want when animation completed
}

变换动画关键帧

通过处理锚点和插值类型进行变换动画。

// example keyframes for transform animation
P9ViewAnimator.default().addKeyframeTranslate(toScenario: scenario, after: 1.0, x: 1.0, y: 1.0, itprType: .linear)
P9ViewAnimator.default().addKeyframeRotateX(toScenario: scenario, after: 1.0, angle: 30.0, itprType: .linear)
P9ViewAnimator.default().addKeyframeRotateX(toScenario: scenario, after: 1.0, angle: 30.0, anchorX: 0.5, anchorY: 0.5, itprType: .linear)
P9ViewAnimator.default().addKeyframeRotateY(toScenario: scenario, after: 1.0, angle: 30.0, itprType: .linear)
P9ViewAnimator.default().addKeyframeRotateY(toScenario: scenario, after: 1.0, angle: 30.0, anchorX: 0.5, anchorY: 0.5, itprType: .linear)
P9ViewAnimator.default().addKeyframeRotateZ(toScenario: scenario, after: 1.0, angle: 30.0, itprType: .linear)
P9ViewAnimator.default().addKeyframeRotateZ(toScenario: scenario, after: 1.0, angle: 30.0, anchorX: 0.5, anchorY: 0.5, itprType: .linear)
P9ViewAnimator.default().addKeyframeScale(toScenario: scenario, after: 1.0, x: 2.0, y: 2.0, itprType: .linear)
P9ViewAnimator.default().addKeyframeScale(toScenario: scenario, after: 1.0, x: 2.0, y: 2.0, anchorX: 0.5, anchorY: 0.5, itprType: .linear)

透明度动画关键帧

// example keyframe for alpha animation
P9ViewAnimator.default().addKeyframeAlpha(toScenario: scenario, after: 1.0, alpha: 0.5, itprType: .linear)

帧形变动画关键帧

您可以使用 P9ViewAnimatorTargetObjectProtocol 在一个演员视图到另一个帧、某个视图的帧或建议帧之间执行缩放动画。

使用目标帧很简单。只需将帧矩形值传递给缩放。

let targetFrame = CGRect(x: 0, y: 0, width: 100, height: 100)
P9ViewAnimator.default().addKeyframeMorph(toScenario: scenario, after: 1.0, targetFrame: targetFrame, itprType: .linear)

使用目标视图也很简单。只需将视图对象传递给缩放。
P9ViewAnimator 使用给定视图的帧矩形并自动进行动画。

let targetView = UIView(frame: CGRect(x:100, y:100, width: 100, height: 100))
P9ViewAnimator.default().addKeyframeMorph(toScenario: scenario, after: 1.0, targetView: targetView, itprType: .linear)

如果您需要在运行时获取帧矩形,则需要确认并实现 P9ViewAnimatorTargetObjectProtocol。
以下是 P9ViewAnimatorTargetObjectProtocol。

@protocol P9ViewAnimatorTargetObjectProtocol <NSObject>

- (void)P9ViewAnimatorScenarioStarted:(NSString * _Nonnull)scenarioName;
- (void)P9ViewAnimatorScenarioEnded:(NSString * _Nonnull)scenarioName;
- (BOOL)P9ViewAnimatorReadyForTargetName:(NSString * _Nonnull)targetName;

@optional
- (UIView * _Nullable)P9ViewAnimatorViewForTargetName:(NSString * _Nonnull)targetName;
- (CGRect)P9ViewAnimatorFrameForTargetName:(NSString * _Nonnull)targetName;
- (void)P9ViewAnimatorSetVelocity:(CGFloat)relativeVelocity forTargetName:(NSString * _Nonnull)targetName;
- (void)P9ViewAnimatorSetLoop:(BOOL)loop forTargetName:(NSString * _Nonnull)targetName;
- (void)P9ViewAnimatorPlayTargetName:(NSString * _Nonnull)targetName;

@end

P9ViewAnimator 在使用目标对象激活关键帧的动画时调用这些协议函数。
确认 P9ViewAnimatorTargetObjectProtocol 到您的控制区域。
对于此示例,我们已确认并在视控制器中实现它。

extension SampleViewController: P9ViewAnimatorTargetOjectProtocol {

    // called when animation start and give the name of scenario.
    func p9ViewAnimatorScenarioStarted(_ scenarioName: String) {
        print("scenario \(scenarioName) started.")
    }
    
    // called when animation complete and give the name of scenario.
    func p9ViewAnimatorScenarioEnded(_ scenarioName: String) {
        print("scenario \(scenarioName) ended.")
    }
    
    // called when key frame using target object is need to play.
    // if you ready to handling target object then return true.
    // otherwise, return false, then P9ViewAnimator delay the animation until you ready.
    func p9ViewAnimatorReady(forTargetName targetName: String) -> Bool {
        guard let targetView = targetView else {
            return false
        }
        return true
    }
    
    // called when p9ViewAnimatorReady(fortargetName:) confirm ready and key frame using target object want target view object.
    func p9ViewAnimatorView(forTargetName targetName: String) -> UIView? {
        guard let targetView = targetView else {
            return nil
        }
        return targetView
    }
    
    // called when p9ViewAnimatorReady(fortargetName:) confirm ready and key frame using target object want target frame.
    func p9ViewAnimatorFrame(forTargetName targetName: String) -> CGRect {
        guard let targetView = targetView else {
            return .zero
        }
        return targetView.frame
    }
}

准备好后,通过传递确认了 P9ViewAnimatorTargetObjectProtocol 的目标对象调用操作,在这种情况下是视控制器。

P9ViewAnimator.default().action(anotherActorView, withScenario: scenario, delay: 0.0, targetObject: self, beginning: nil, completion: nil) 

如果您使用独立舞台视图和欺骗视图,则可以使动画效果像某些演员视图在视图控制器上到另一个视图控制器。

帧动画关键帧

P9ViewAnimator基于关键帧进行动画,但您也可以自己制作帧动画对象并通过确认和实现P9ViewAnimatorTargetObjectProtocol来处理。
使用目标名称、速度和循环为帧动画创建关键帧。

let targetAvatar = "avatar"

P9ViewAnimator.default().addKeyframeFrameAni(toScenario: scenario, after: 1.0, targetName: targetAvatar, velopcity: 1.0, loop: false, itprType: .linear)

extension SampleViewController: P9ViewAnimatorTargetOjectProtocol {

    // called when key frame using frame animation is ready
    func p9ViewAnimatorSetVelocity(_ relativeVelocity: CGFloat, forTargetName targetName: String) {
        if targetName == targetAvatar {
            playView.velocity = relativeVelocity
        }
    }

    // called when key frame using frame animation is ready
    func p9ViewAnimatorSetLoop(_ loop: Bool, forTargetName targetName: String) {
        if targetName == targetAvatar {
            playView.loop = loop
        }
    }

    // called when key frame using frame animation is ready
    func p9ViewAnimatorPlayTargetName(_ targetName: String) {
        if targetName == targetAvatar {
            playView.play()
        }
    }
}

动作关键帧

您可以通过使用动作关键帧在动画过程中执行一些自定义操作。

P9ViewAnimator.default().addKeyframeAction(toScenario: scenario, after: 0.0) { (actorView:UIView) in
    playSound()
}

诱饵动画

P9ViewAnimator直接对给定演员视图进行动画。
但是,您可以使用诱饵机制来实现更多的动画效果。

P9ViewAnimator.default().actionDecoy(actorView, onStageView: stageView, withScenario: scenario, delay: 0.0, targetObject: self, beginning: { (actorView:UIView?) in
    self.actorView.alpha = 0.0
}) { (actorView:UIView?) in
    self.actorView.alpha = 1.0
}

如果调用的是'function actionDecoy'而不是'function action',P9ViewAnimator将捕捉给定演员视图的快照并从它创建一个诱饵视图。
然后,使用诱饵视图在场景视图中进行动画。
因此,您可以使用这种技巧:在动画开始时隐藏原始演员视图,用诱饵视图进行动画,然后在动画完成后显示原始演员视图。
如果您在顶层任何其他视图控制器上有一个场景视图,您可以使动画看起来像将演员视图从视图控制器移动到另一个视图控制器。

在调用'function actionDecoy'时,您可以传递场景视图,但也您可以将默认场景视图设置为P9ViewAnimator。以下是一个简单示例,展示如何设置场景视图。

var window: UIWindow?
var stageView: UIView = UIView(frame: .zero)

stageView.backgroundColor = .clear
stageView.layer.zPosition = .greatestFiniteMagnitude
stageView.frame = self.windows?.bounds ?? .zero
window.addSubview(stageView)

P9ViewAnimator.default().defaultStageView = stageView

// pass the nil for stage view then P9ViewAnimator use default stage view.
P9ViewAnimator.default().actionDecoy(actorView, onStageView: nil, withScenario: scenario, delay: 0.0, targetObject: self, beginning: { (actorView:UIView?) in
    self.actorView.alpha = 0.0
}) { (actorView:UIView?) in
    self.actorView.alpha = 1.0
}

处理动画

如果您需要停止某些视图的动画,调用所有'function stopAction'。通过调用'function stopAllActions'函数停止P9ViewAnimation控制的动画。

P9ViewAnimator.default().stopAction(actorView)
P9ViewAnimator.default().stopAllActions()

从文件加载场景

P9ViewAnimator支持json文件格式来加载场景。

{
   "<scenario name>" : [
        {
            "type": "frameAnimation" | "morph" | "alpha" | "translate" | "rotateX" | "rotateY" | "rotateZ" | "scale",
            "after": <time interval>,
            "target": "<target name>",
            "velocity": <velocity>,
            "loop": <bool flag>,
            "alpha": <alpha value>,
            "x": <x value>,
            "y": <y value>,
            "z": <z value>,
            "angle": <eulur angle>,
            "anchorX": <anchor x value>,
            "anchorY": <anchor y value>,
            "interpolation": "linear" | "easeIn" | "easeOut" | "easeInOut",
        },
        ...
   ],
   ...
}
if let resourcePath = Bundle.main.resourcePath {
    P9ViewAnimator.default().loadScenarios(fromFile: resourcePath+"/senarios.json", overwrite: true)
}

许可

适用于的情况,MIT 许可证。 http://en.wikipedia.org/wiki/MIT_License