项目中使用动画,开始采用Gif动画,发现Gif动画文件1.5M 在线加载慢,改为json动画使用Lottie 第三方库加载对比分析,优缺点分析主要两点:
1.json文件只有400k 对比gif文件包少了三分之二 ;
2.UI效果对比gif显示放大有齿轮和镂空的失真,json动画UI还原度高,但是json动画设计转出json文件更麻烦些;
场景分析:
1.gif动画适合小图标动画效果
2.json动画适合大图动画效果
Gif demo代码片段
/// 显示本地 GIF 图片
func showLocalGIF(name: String?) {
guard let name = name else { return }
self.gifImage=GIFImage(named: name)
}
json 动画代码实例,采用pod 'lottie-ios', '3.2.3'版本 ,本地json文件显示动画:
let animationView = AnimationView(name: "inviteData")
animationView.frame = CGRect(x: 0, y: 0, width: (kScreenWidth - 80)*kWidthScale, height:((kScreenWidth - 80)*1225/879)*kWidthScale)
imageBackVIew.addSubview(animationView)
animationView.contentMode = .scaleToFill
animationView.loopMode = .loop
animationView.play()
animationView.play { (isFinished) in
}
在线加载json文件采用两种方式:
一、在线加载json文件,采用pod 'lottie-ios', '3.2.3'版本 网页可直接打卡json文件:
if let url = URL(string: "https://yangtuo.oss-cn-hangzhou.aliyuncs.com/mall2c/happy_gift.json") {
giftAnimaView = AnimationView(url: url, imageProvider: self, closure: { [weak self] (error) in
guard let `self` = self else { return }
if let _ = error {
print("网络动画加载失败~~")
} else {
/// 获取是异步的,所以需要等待动画获取完成
self.giftAnimaView.play { (finished) in
}
}
}, animationCache: self)
giftAnimaView.frame = CGRect(x: 0, y: 0, width: (kScreenWidth - 80)*kWidthScale, height:((kScreenWidth - 80)*1225/879)*kWidthScale)
giftAnimaView.contentMode = .scaleToFill
giftAnimaView.loopMode = .loop
imageBackVIew.addSubview(giftAnimaView)
}
二、在线加载json文件,采用pod 'lottie-ios', '3.2.3'版本 需下载json文件:
LPLottieResourceManager.shared.loadBundleProvider(123412,"\(BackGround)") {[weakself] (jsonpath, provider)in
guard let`self` =self else{return}
guard let jsonfile = json path else{return}
DeLog("jsonFile:\(jsonfile)")
self.giftAnimaView=AnimationView.init(filePath:jsonfile)
iflet prov = provider {
self.giftAnimaView.imageProvider= prov
}
self.giftAnimaView.frame = CGRect(x: 0, y: 0, width: (kScreenWidth - 80)*kWidthScale, height:((kScreenWidth - 80)*1225/879)*kWidthScale)
self.giftAnimaView.contentMode = .scaleToFill
self.giftAnimaView.loopMode = .loop
self.giftAnimaView.play()
self.imageBackVIew.addSubview(self.giftAnimaView)
}
LPLottieResourceManager 类继承NSObject,实现思路先通过Moya下载本地资源包,通过资源包打卡在线加载:
importUIKit
importFoundation
//import ZipArchive
import Moya
importLottie
typealiaslottieResultBlock= (_ jsonfullpath:String?,_ provider:BundleImageProvider?) ->Void
class LPLottieResourceManager:NSObject {
let filepath =NSHomeDirectory() + "/Documents/LiveKit/GiftFile"
static let shared = LPLottieResourceManager()
override init() {
super.init()
ifFileManager.default.fileExists(atPath:filepath) {
print("礼物 目录存在")
}
else{
try! FileManager.default.createDirectory(atPath: filepath,
withIntermediateDirectories:true,attributes:nil)
}
}
/// 加载lottie特效
/// - Parameters:
/// - giftId: 特效id
/// - downloadurl: 特效下载地址
/// - animationresult: 特效 images目录
func loadBundleProvider(_giftId:Int,_downloadurl:String,_animationresult:@escapinglottieResultBlock) {
letfullpath =filepath+"/\(giftId)/data.json"
letimgprovider =filepath+"/\(giftId)/images"
varjsonpath:String?=nil
ifFileManager.default.fileExists(atPath: fullpath) {
jsonpath = fullpath
if FileManager.default.fileExists(atPath: imgprovider)
{
let provider =BundleImageProvider.init(bundle:Bundle.main,searchPath: imgprovider)
animationresult(jsonpath,provider)
}else{
animationresult(jsonpath,nil)
}
}
//网络下载 并解压
else{
let giftpath =filepath+"/\(giftId)"
letassetName = "\(giftId)"
jsonpath = giftpath +"/data.json"
let urladdress = downloadurl
//通过Moya进行下载
MyServiceProvider.request(.downloadGiftLottie(downloadurl:urladdress,giftDirectoryName: assetName)) { result in
switchresult {
case.success:
letlocalLocation:URL= DefaultDownloadDir.appendingPathComponent(assetName)
print("下载完毕!保存地址:\(localLocation)")
if urladdress.contains(".zip") {
let urlpath =URL.init(fileURLWithPath:self.filepath+"/\(giftId).zip")
do{
try FileManager.default.createDirectory(atPath:self.filepath+"/\(giftId)",withIntermediateDirectories:true,attributes:nil)
//得到正确的资源包 12312/ data images
if FileManager.default.fileExists(atPath: imgprovider)
{
let provider =BundleImageProvider.init(bundle:Bundle.main,searchPath: imgprovider)
animationresult(jsonpath,provider)
}else{
animationresult(jsonpath,nil)
}
// print(zipurl)
}catch(leterr) {
print("解压失败")
animationresult(nil,nil)
}
}
elseifurladdress.contains(".json") {
do{
try FileManager.default.createDirectory(atPath:self.filepath+"/\(giftId)",withIntermediateDirectories:true,attributes:nil)
try FileManager.default.moveItem(atPath:self.filepath+"/data.json",toPath: giftpath +"/data.json")
animationresult(jsonpath,nil)
}catch(leterr) {
debugPrint("文件出错\(err)")
animationresult(nil,nil)
}
}
caselet.failure(error):
print(error)
animationresult(nil,nil)
}
}
}
}
}
//MARK:单独组件处理下载
//初始化请求的provider
let MyServiceProvider = MoyaProvider<DownLoadService>()
//请求分类
public enum DownLoadService {
casedownloadGiftLottie(downloadurl:String,giftDirectoryName:String)//下载文件
}
//请求配置
extension DownLoadService: TargetType {
publicvarpath:String{
return""
}
//服务器地址
publicvarbaseURL:URL{
switchself{
case.downloadGiftLottie(let url , _ ):
returnURL.init(string: url)!
default:
return URL(string: "http://www.baidu.com")!
}
}
//请求类型
publicvarmethod: Moya.Method{
return.get
}
//请求任务事件(这里附带上参数)
publicvartask:Task{
switchself{
case.downloadGiftLottie(let downloadurl ,letsaveName):
varlocalLocation:URL!
ifdownloadurl.contains(".zip") {
localLocation = DefaultDownloadDir.appendingPathComponent(saveName+".zip")
}elseifdownloadurl.contains(".json") {
localLocation = DefaultDownloadDir.appendingPathComponent("data.json")
}
//
letdownloadDestination:DownloadDestination= { _, _in
return(localLocation, .removePreviousFile) }
return.downloadDestination(downloadDestination)
}
}
//是否执行Alamofire验证
public var validate:Bool{
return false
}
//这个就是做单元测试模拟的数据,只会在单元测试文件中有作用
public var sampleData:Data{
return"{}".data(using:String.Encoding.utf8)!
}
//请求头
publicvarheaders: [String:String]? {
returnnil
}
}
//定义下载的DownloadDestination(不改变文件名,同名文件不会覆盖)
privateletDefaultDownloadDestination:DownloadDestination= { temporaryURL, responsein
return(DefaultDownloadDir.appendingPathComponent(response.suggestedFilename!), [.removePreviousFile])
}
//默认下载保存地址(用户文档目录)
let DefaultDownloadDir: URL = {
return URL(fileURLWithPath: LPLottieResourceManager.shared.filepath)
}()