如何在Objective-C中播放Lottie动画

3

我已经安装了Lottie的pod文件,并从lottiefiles.com下载了hello.json文件。

 LOTAnimationView *Hello_loader;
 Hello_loader = [LOTAnimationView animationNamed:@"hello"];
 [self.view addSubview:Hello_loader];

我在viewDidLoad()viewDidAppear()中都试过了,但仍然未能出现。

我是iOS编程的新手,请有经验的人帮我解决一下吧。谢谢!

4个回答

7
在 Lottie 3 中,Animation 类是Codable类型,并且在Objective-C中不能直接使用。因此,我创建了一个包装器,允许在Objective-C中使用类似的api(灵感来自于这里):
import Foundation
import UIKit
import Lottie

@objc(AnimationView) class Z_OBJC_Wrapper_AnimationView: UIView {

    @objc var loop:Bool {
        get {
            return animationView.loopMode == .loop
        }
        set {
            animationView.loopMode = newValue ? .loop : .playOnce
        }
    }

    @objc var speed:CGFloat {
        get {
            return animationView.animationSpeed
        }
        set {
            animationView.animationSpeed = newValue
        }
    }

    @objc var progress:AnimationProgressTime {
        get {
            return animationView.currentProgress
        }
        set {
            animationView.currentProgress = newValue
        }
    }

    private let animationView: AnimationView

    @objc override init(frame: CGRect) {
        animationView = AnimationView()

        super.init(frame: frame)
        commonInit()
    }

    required init?(coder aDecoder: NSCoder) {
        animationView = AnimationView()

        super.init(coder: aDecoder)
        commonInit()
    }

    // MARK: - Public Functions

    @objc func loadAnimation(name animationName:String) {
        if let path = Bundle.main.path(forResource: animationName, ofType: "json") {
            do {
                let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
                let animation:Animation = try JSONDecoder().decode(Animation.self, from: data)
                animationView.animation = animation
            } catch {
                assertionFailure("Could not read Lottie json file")
            }
        }
    }

    /**
     Plays the animation from its current state to the end.

     - Parameter completion: An optional completion closure to be called when the animation completes playing.
     */
    @objc func play(completion: LottieCompletionBlock? = nil) {
        animationView.play(completion: completion)
    }

    /**
     Pauses the animation in its current state.

     The completion closure will be called with `false`
     */
    public func pause() {
        animationView.pause()
    }

    /**
     Stops the animation and resets the view to its start frame.

     The completion closure will be called with `false`
     */
    @objc func stop() {
        animationView.stop()
    }

    // MARK: Play with progress

    /**
     Plays the animation from a progress (0-1) to a progress (0-1).

     - Parameter fromProgress: The start progress of the animation.
     - Parameter toProgress: The end progress of the animation.
     - Parameter loopMode: The loop behavior of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(fromProgress from: AnimationProgressTime,
                    toProgress to: AnimationProgressTime,
                    loop loopBool: Bool,
                    completion: LottieCompletionBlock? = nil) {
        let loopMode:LottieLoopMode = loopBool ? .loop : .playOnce
        animationView.play(fromProgress: from, toProgress: to, loopMode: loopMode, completion: completion)
    }

    /**
     Plays the animation from a progress (0-1) to a progress (0-1). The view's `loopMode` property will be used.

     - Parameter fromProgress: The start progress of the animation.
     - Parameter toProgress: The end progress of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(fromProgress from: AnimationProgressTime,
                    toProgress to: AnimationProgressTime,
                    completion: LottieCompletionBlock? = nil) {
        animationView.play(fromProgress: from, toProgress: to, loopMode: nil, completion: completion)
    }

    /**
     Plays the animation from the current progress to a progress (0-1).

     - Parameter toProgress: The end progress of the animation.
     - Parameter loopMode: The loop behavior of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(toProgress to: AnimationProgressTime,
                    loop loopBool: Bool,
                    completion: LottieCompletionBlock? = nil) {
        let loopMode:LottieLoopMode = loopBool ? .loop : .playOnce
        animationView.play(fromProgress: nil, toProgress: to, loopMode: loopMode, completion: completion)
    }

    /**
     Plays the animation from the current progress to a progress (0-1). The view's `loopMode` property will be used

     - Parameter toProgress: The end progress of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(toProgress to: AnimationProgressTime,
                    completion: LottieCompletionBlock? = nil) {
        animationView.play(fromProgress: nil, toProgress: to, loopMode: nil, completion: completion)
    }

    // MARK: Play with frame

    /**
     Plays the animation from a start frame to an end frame in the animation's framerate.

     - Parameter fromFrame: The start frame of the animation.
     - Parameter toFrame: The end frame of the animation.
     - Parameter loopMode: The loop behavior of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(fromFrame from: AnimationFrameTime,
                    toFrame to: AnimationFrameTime,
                    loop loopBool: Bool,
                    completion: LottieCompletionBlock? = nil) {
        let loopMode:LottieLoopMode = loopBool ? .loop : .playOnce
        animationView.play(fromFrame: from, toFrame: to, loopMode: loopMode, completion: completion)
    }

    /**
     Plays the animation from a start frame to an end frame in the animation's framerate. The view's `loopMode` property will be used.

     - Parameter fromFrame: The start frame of the animation.
     - Parameter toFrame: The end frame of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(fromFrame from: AnimationFrameTime,
                    toFrame to: AnimationFrameTime,
                    completion: LottieCompletionBlock? = nil) {
        animationView.play(fromFrame: from, toFrame: to, loopMode: nil, completion: completion)

    }

    /**
     Plays the animation from the current frame to an end frame in the animation's framerate.

     - Parameter toFrame: The end frame of the animation.
     - Parameter loopMode: The loop behavior of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(toFrame to: AnimationFrameTime,
                    loop loopBool: Bool,
                    completion: LottieCompletionBlock? = nil) {
        let loopMode:LottieLoopMode = loopBool ? .loop : .playOnce
        animationView.play(fromFrame: nil, toFrame: to, loopMode: loopMode, completion: completion)

    }

    /**
     Plays the animation from the current frame to an end frame in the animation's framerate. The view's `loopMode` property will be used.

     - Parameter toFrame: The end frame of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(toFrame to: AnimationFrameTime,
                    completion: LottieCompletionBlock? = nil) {
        animationView.play(fromFrame: nil, toFrame: to, loopMode: nil, completion: completion)
    }

    // MARK: Play with marker

    /**
     Plays the animation from a named marker to another marker.

     Markers are point in time that are encoded into the Animation data and assigned
     a name.

     NOTE: If markers are not found the play command will exit.

     - Parameter fromMarker: The start marker for the animation playback.
     - Parameter toMarker: The end marker for the animation playback.
     - Parameter loopMode: The loop behavior of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(fromMarker from: String,
                    toMarker to: String,
                    loop loopBool: Bool,
                    completion: LottieCompletionBlock? = nil) {
        let loopMode:LottieLoopMode = loopBool ? .loop : .playOnce
        animationView.play(fromMarker: from, toMarker: to, loopMode: loopMode, completion: completion)
    }

    /**
     Plays the animation from a named marker to another marker. The view's `loopMode` property will be used.

     Markers are point in time that are encoded into the Animation data and assigned
     a name.

     NOTE: If markers are not found the play command will exit.

     - Parameter fromMarker: The start marker for the animation playback.
     - Parameter toMarker: The end marker for the animation playback.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(fromMarker from: String,
                    toMarker to: String,
                    completion: LottieCompletionBlock? = nil) {
        animationView.play(fromMarker: from, toMarker: to, loopMode: nil, completion: completion)
    }

    /**
     Plays the animation the current progress to a named marker.

     Markers are point in time that are encoded into the Animation data and assigned
     a name.

     NOTE: If markers are not found the play command will exit.

     - Parameter toMarker: The end marker for the animation playback.
     - Parameter loopMode: The loop behavior of the animation.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(toMarker to: String,
                    loop loopBool: Bool,
                    completion: LottieCompletionBlock? = nil) {
        let loopMode:LottieLoopMode = loopBool ? .loop : .playOnce
        animationView.play(fromMarker: nil, toMarker: to, loopMode: loopMode, completion: completion)
    }

    /**
     Plays the animation from the current progress to named marker. The view's `loopMode` property will be used.

     Markers are point in time that are encoded into the Animation data and assigned
     a name.

     NOTE: If markers are not found the play command will exit.

     - Parameter toMarker: The end marker for the animation playback.
     - Parameter completion: An optional completion closure to be called when the animation stops.
     */
    @objc func play(toMarker to: String,
                    completion: LottieCompletionBlock? = nil) {
        animationView.play(fromMarker: nil, toMarker: to, loopMode: nil, completion: completion)
    }

    // MARK: - Private

    private func commonInit() {
        translatesAutoresizingMaskIntoConstraints = false
        setUpViews()
    }

    private func setUpViews() {
        animationView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(animationView)
        animationView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        animationView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        animationView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        animationView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }
}

在Objective-C中的使用:

AnimationView *loader = [[AnimationView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[loader loadAnimationWithName:@"loader"];
[loader playWithCompletion:nil];

[self addSubview:loader];

为什么加载器被添加后才作为子视图添加?这对我来说有点奇怪。 - Johan Karlsson

1

最后一个支持 Objective C 的 Lottie 版本是 2.5.3。大多数最新的公共 Lottie 文件都是为版本 3+ 编译的。但是,有些人可能需要仅使用 Objective-C 的解决方案。

在 pod 文件中添加 Lottie 并指定版本号。

pod 'lottie-ios', '2.5.3'

我喜欢将加载和播放代码分别放在不同的方法中。

在.h文件中

#import <Lottie/Lottie.h>
...
LOTAnimationView * animation;

在 .m 文件中。
-(void) loadAnimation {
    NSString * path = [[NSBundle mainBundle] pathForResource:@"public-animation" ofType:@"json"];
    NSData *myData = [NSData dataWithContentsOfFile:path];
    
    NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:myData
                                                            options:kNilOptions
                                                              error:nil];

    animation = [LOTAnimationView animationFromJSON:jsonDict];

}

// animation is an instance of LOTAnimationView which is a subclass of UIView 
// at a base level. Hence it accepts all the related 
// properties (e.g setFrame, setCenter etc).

-(void) playAnimation {

    if ([animation isAnimationPlaying]) {
        [animation stop];
    }        
    [self.view addSubview:animation];  
    [animation play];    
}

现在按照您的需求调用动画即可。
[self playAnimation];

很高兴听到问题已经解决,我认为这对某些人会有帮助。

0

试一下这个

 LOTAnimationView *hello_loader = [LOTAnimationView animationNamed:@"hello"];
 [self.view addSubview:hello_loader];
 [hello_loader play];

尝试这个:[self.Hello_loader play]; - Jigar
以上代码会抛出一个错误 [在类型为 'ViewController *' 的对象上找不到属性 'hello_loader']。 - Minato
我想像上面的描述一样加载“hello”...但它只显示了行数...你能帮我解决一下吗?@IOS - Minato
请检查此链接@IOS。 - Minato
尽管此代码可能回答了问题,但提供有关为什么和/或如何回答问题的附加上下文可以提高其长期价值。 - Donald Duck
显示剩余12条评论

-1

Swift 5(使用最新版本的lottie)

    let animationView = AnimationView(name: "Bubbles") //Replace "Bubbles" with your animation file name.
    animationView.frame = CGRect(x: 0, y: 0, width: 150, height: 150)
    animationView.center = self.view.center
    animationView.loopMode = .loop
    animationView.backgroundBehavior = .pauseAndRestore //to pause in background and restart when it reach foreground
    self.view.addSubview(animationView)
    animationView.play()

在此链接上检查输出


1
感谢您的回答,但问题指定了Objective-C。 - Neo
@Neo 你可以用Objective-C来回答。 - Hardik Thakkar
答案在上面 :) - Neo
现在只有少数开发者像你一样仍在使用Objective-C,其他人都转向了最新的趋势。我认为我的答案并没有错。 - Hardik Thakkar
这没错。只是在履行StackOverflow的“公民责任”。而且我只在旧项目中使用Objective-C。我只写Swift。但没有必要再拖下去了。 - Neo
你开始吧,我只是在帮助别人,不会像你一样发表任何评论。 - Hardik Thakkar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接