SVGAParsePlayer是一个便捷SVGA播映器,是对SVGAPlayer的二次封装。

SVGAParsePlayer_Demo

Feature:
    ✅ 内置SVGA解析器;
    ✅ 带有播映状况且可操控;
    ✅ 可自界说下载器;
    ✅ 防止重复加载;
    ✅ 兼容 OC & Swift;
    ✅ API简略易用。

【iOS】SVGAParsePlayer - 便捷SVGA播放器

SVGAPlayer是个很老的第三方库了,作者很久没有更新,运用起来挺费事的,本来的运用办法:

let player = SVGAPlayer()
override func viewDidLoad() {
    super.viewDidLoad()
    player.frame = CGRect(x: 100, y: 100, width: 100, height: 100)
    view.addSubview(player)
    // 创建 SVGA 动画解析器
    let parser = SVGAParser()
    // 加载 SVGA 动画文件
    parser.parse(withNamed: "your_animation_file", in: nil) { [weak self] videoItem in
        guard let self, videoItem else { return }
        // 将 SVGA 动画加载到播映器中
        self.player.videoItem = videoItem
        // 开端播映动画
        self.player.startAnimation()
    }
}

老实说,功能没有Lottie好,可是没办法,项目要用。为了运用起来愈加便利,于是乎在此基础上进行二次封装。

根本运用

SVGAParsePlayer本身便是继承自SVGAPlayer,根本设置跟之前相同即可,主要是API的运用不相同(变得愈加易用)。

加载并播映:

player.play("your_animation_path", fromFrame: 0, isAutoPlay: true)
  • fromFrame: 从第几帧开端
  • isAutoPlay: 加载完结后是否主动开端播映

内部会主动调用SVGAParser进行「长途/本地」SVGA资源的加载,所以调用该办法后并不会立马播映,会有加载的过程。

加载后能够挑选是否主动播映,具体的状况能够恪守SVGAParsePlayerDelegate,能够收到状况产生改动的回调:

/// 状况产生改动的回调
func svgaParsePlayer(_ player: SVGAParsePlayer,
                     statusDidChanged status: SVGAParsePlayerStatus,
                     oldStatus: SVGAParsePlayerStatus)

别的加载的失利和完结SVGAParsePlayerDelegate也有对应的回调:

/// SVGA不知道来源
func svgaParsePlayer(_ player: SVGAParsePlayer,
                     unknownSvga source: String)
/// SVGA资源加载失利
func svgaParsePlayer(_ player: SVGAParsePlayer,
                     svga source: String,
                     dataLoadFailed error: Error)
/// 加载的SVGA资源解析失利
func svgaParsePlayer(_ player: SVGAParsePlayer,
                     svga source: String,
                     dataParseFailed error: Error)
/// 本地SVGA资源解析失利
func svgaParsePlayer(_ player: SVGAParsePlayer,
                     svga source: String,
                     assetParseFailed error: Error)
/// SVGA资源解析成功
func svgaParsePlayer(_ player: SVGAParsePlayer,
                     svga source: String,
                     parseDone entity: SVGAVideoEntity)
  • SVGAParsePlayerDelegate的办法都是可选的,还有其他的办法具体能够看看Demo。

假如现已有现成的SVGAVideoEntity目标,就能够直接运用该目标进行播映:

let entity: SVGAVideoEntity = ...
player.play(with: entity, fromFrame: 0, isAutoPlay: true)
  • 运用这种办法播映的话,svgaSource则为SVGAVideoEntity目标的内存地址。

加载优化

加载长途的SVGA资源,内部是运用SVGAParser自带的下载办法,假如需求自己界说下载办法(例如加载缓存的资源),能够自界说下载器:

SVGAParsePlayer.downloader = { svgaSource, success, failure in
    guard let url = URL(string: svgaSource) else {
        failure(NSError(domain: "SVGAParsePlayer", code: -1, userInfo: [NSLocalizedDescriptionKey: "途径过错"]))
        return
    }
    Task {
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            await MainActor.run { success(data) }
        } catch {
            await MainActor.run { failure(error) }
        }
    }
}
  • 完成SVGAParsePlayer.downloader这个闭包即可。

阐明一点,假如播映相同的资源途径,并且该资源正在加载或许现已加载好了,是不会重复去加载的。内部是依据资源途径来判断是否同一个SVGA资源,除非换成新的资源途径,就会清除上一个资源去加载新的资源,这是为了保证同一个资源不会做重复的加载操作

注意:内部是经过判定资源途径是否带有http://https://的前缀,才去调用下载器进行下载的,不然就会运用本地资源加载的办法。

假如想完全由自己操控加载办法,能够去完成SVGAParsePlayer.loader这个闭包:

SVGAParsePlayer.loader = { svgaSource, success, failure, forwardDownload, forwardLoadAsset in
    // 判断是不是磁盘的SVGA
    guard FileManager.default.fileExists(atPath: svgaSource) else {
        if svgaSource.hasPrefix("http://") || svgaSource.hasPrefix("https://") {
            // 调用SVGAParsePlayer内部的长途加载办法(假如完成了SVGAParsePlayer.downloader就调用该闭包)
            forwardDownload(svgaSource)
        } else {
            // 调用SVGAParsePlayer内部的本地资源加载办法
            forwardLoadAsset(svgaSource)
        }
        return
    }
    // 加载磁盘的SVGA
    do {
        let data = try Data(contentsOf: URL(fileURLWithPath: svgaSource))
        success(data)
    } catch {
        failure(error)
    }
}
  • forwardDownload:本来SVGAParsePlayer内部的长途加载办法(假如完成了SVGAParsePlayer.downloader就调用该闭包)
  • forwardLoadAsset::本来SVGAParsePlayer内部的本地资源加载办法

其他的API和设置

/// 播映当时SVGA(从当时所在帧开端)
player.play()
/// 播映当时SVGA
/// - Parameters:
///  - fromFrame: 从第几帧开端
player.play(fromFrame: 0)
/// 暂停播映
player.pause()
/// 重置当时SVGA(回到开头)
/// - Parameters:
///   - isAutoPlay: 是否主动开端播映
player.reset(isAutoPlay: false)
/// 中止播映
/// - Parameters:
///  - isClear: 是否清空SVGA资源(清空的话下次播映就需求重新加载资源)
player.stop(isClear: false)
  • 由于调用播映的办法并不会立马就播映,假如在加载的过程中再次调用播映的办法,但fromFrameisAutoPlay不相同,那么fromFrameisAutoPlay会以最新的设置来进行后续的操作。

可定制化的设置:

/// 是否带动画过渡
/// - 为`true`则会在「替换SVGA」和「播映/中止」的场景中带有淡入淡出的效果
var isAnimated = false
/// 是否在空闲/中止状况时隐藏本身
var isHidesWhenStopped = false
/// 是否启用内存缓存(SVGAParser)
var isEnabledMemoryCache = false

互斥的API

由于SVGAParsePlayer本身继承自SVGAPlayer,为了避免产生过错,不要调用SVGAPlayer本来的这些API:

@property (nonatomic, weak) id<SVGAPlayerDelegate> delegate;
- (void)startAnimation;
- (void)startAnimationWithRange:(NSRange)range reverse:(BOOL)reverse;
- (void)pauseAnimation;
- (void)stopAnimation;
- (void)clear;
- (void)stepToFrame:(NSInteger)frame andPlay:(BOOL)andPlay;
- (void)stepToPercentage:(CGFloat)percentage andPlay:(BOOL)andPlay;
  • 本来的delegate给到本身恪守了,假如需求监听曾经的代理办法,那就运用myDelegate,也便是SVGAParsePlayerDelegate,包含了本来delegate的办法还有上面的那几个回调办法。

已然不想运用本来的API,为什么要运用继承SVGAPlayer的办法?

  1. 首先为了让根本设置跟之前相同;
  2. 其次期望跟之前相同当做一个UIView来运用,但不想再套一层UIView,为了尽可能削减图层的数量。

最后

介绍就这么多了,总的来说SVGAPlayer比照Lottie轻量一些,比较适合动画数量少的场景。但假如需求许多且复杂的场景,我个人愈加引荐Lottie,究竟架构和功能要比SVGAPlayer好许多,最重要是Lottie一直都有维护和更新,而SVGAPlayer现已不更新了。

而我的SVGAParsePlayer只是在SVGAPlayer的基础上做了「加载防重」和「API简化」,假如需求运用,能够到SVGAParsePlayer_Demo中直接CV代码(SVGAParsePlayer.swift和SVGAParsePlayer+.swift这两个文件)到自己工程里面就好了。