现状:app首页标题只支持展示文字
app首页标题支持展示图片,json 动画
如图
实现思路:将需要展示的资源包下载到沙盒中,在创建频道标题视图的时候,根据该频道在沙盒中是否有对应的图片、json资源来确定是否展示图片和动画,这里需要用到的技术点有,下载
解压资源包,展示沙盒中的json 动画文件,比较复杂的逻辑是
下载资源的展示,删除,更新逻辑,下面分别介绍
下载使用的是该下载功能组件
链接: link
资源包的展示逻辑
需求要保证的是,频道标题视图创建过之后,就不会在变化,
由于首页有编辑频道顺序功能,调整频道顺序的时候,是将原有的频道是图更新标题内容,这个过程中会重新从沙盒中获取资源,所以,我们就要保证,频道标题视图创建之后,沙盒中的内容就不再变化, 我这里创建了一个管理下载和使用资源逻辑的单例
代码如下
@implementation TPChannelHeadSourceManager
+ (instancetype)shareManager
{
static TPChannelHeadSourceManager *manager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[TPChannelHeadSourceManager alloc] init];
[manager inittialHeadSource];
});
return manager;
}
- (void)inittialHeadSource
{
if ([[TPUserDefault instance].channelHeadSourceFlag isEqualToString:@"1"]) {
//上次标记要删除资源包
[self deleteChannelSource];
} else if ([[TPUserDefault instance].channelHeadSourceFlag isEqualToString:@"2"]) {
///上次是在进入首页之后请求到资源的,需要更新资源路径
[self updateChannelSource];
}
[TPUserDefault instance].channelHeadSourceFlag = @"";
}
- (BOOL)isHaveChannelSource
{
//资源包下载好,暂时不更新资源包。(下次更新)
if (isBlankString([TPUserDefault instance].channelHeadSourcePath)) {
/*这里没有像皮肤的判断一样添加 ||[[TPUserDefault instance].channelHeadSourceFlag isEqualToString:@"2"]
因为这个场景:我们创建频道名item的时候(肯定进入首页了) ,资源包下载还没有完成,这时候 [TPUserDefault instance].channelHeadSourceFlag = @"",
我们是可以获取到资源包的,然后下载完成,这时候 [TPUserDefault instance].channelHeadSourceFlag = @"2" ,
如果我们加了 [TPUserDefault instance].channelHeadSourceFlag = @"2" 这个判断条件,就会造成,我们调整频道顺序的时候, 判断为没有资源包,从而导致
原来有资源包的item判断为没有资源包,从而导致有图片的item变为没有图片的
*/
return NO;
}else{
return YES;
}
}
- (void)updateChannelHeadSourceWithUrl:(NSString *)downloadUrl minVersion:(NSString *)minVersion
{
if (isBlankString(downloadUrl) || [self isLessThanChannelHeaderSourceMinVersion:minVersion]) {
//服务端无首页标题图片资源包,或者服务端控制的最低版本号比当前版本号大
//如果已经进入了首页,则做个标记,下次启动的时候删除
if (self.isComeMainPage) {
[TPUserDefault instance].channelHeadSourceFlag = @"1";
} else {
//如果还没有进入首页,则直接删除
[self deleteChannelSource];
}
return;
}
NSString *localfileName = downloadUrl.lastPathComponent;
localfileName = [localfileName stringByReplacingOccurrencesOfString:@".zip" withString:@""];
//判断是否更新标题资源包
if ([[TPUserDefault instance].channelHeadSourceRemoteURL isEqualToString:downloadUrl]) {
return;
}
FDownLoaderManager *manger = [[FDownLoaderManager alloc]init];
[manger downLoader:[NSURL URLWithString:downloadUrl] downloadPath:kChannelHeadSourceCachePath tempPath:kChannelHeaderSourceTmpPath downLoadInfo:^(long long totalSize, NSHTTPURLResponse *response) {
NSLog(@"下载信息:%lld",totalSize);
} progress:^(float progress) {
NSLog(@"下载进度:%f",progress);
} success:^(NSString *cachePath) {
NSLog(@"下载成功路径:%@",cachePath);
//1.文件的存放
NSString *fileName = cachePath;
/// 临时文件路径
ZipArchive *zipArch = [ZipArchive new];
if ([zipArch UnzipOpenFile:fileName]) {
NSString *path = [fileName stringByReplacingOccurrencesOfString:@".zip" withString:@""];
BOOL unzipSuccess = [zipArch UnzipFileTo:path overWrite:YES];
//删掉zip
[FFileTool removeFile:fileName];
if (!unzipSuccess) {
[zipArch UnzipCloseFile];
}else{
//更新新的标题图片资源地址
if (self.isComeMainPage) {
//走到这里说明是进入到首页之后才下载成功的,则标记为2
[TPUserDefault instance].channelHeadSourceFlag = @"2";
/*
这里之所以不更新channelHeadSourcePath ,而更新 toBeUsedHeadSourcePath,
是因为下面这个场景:
1 之前没有资源包 (本来就没有资源包,或者执行开始下载的时候,还没有进入到首页,资源包被删除了),2 有资源包,执行开始下载的时候,已经进入了首页,所以没有删除资源包),
但是下载还没有完成,在以上两种情况的时候创建了频道名item,这时候如果更新 channelHeadSourcePath,我们在调整频道顺序的时候,就会使用新的资源包,造成调整频道顺序前后展示的图片资源不同,
所以这里使用 toBeUsedHeadSourcePath 记录 资源包,在下次启动的时候使用
*/
[TPUserDefault instance].toBeUsedHeadSourcePath = localfileName;
} else {
/*
下载成功之后再删除资源包
如果已经进入首页,则不再删除
*/
/*
我们调整频道顺序的时候,是需要重新用到资源包的
场景: 之前有资源包,执行到这里的时候,已经进入到首页了,频道名视图已经创建好了, 如果 不添加 !self.isComeMainPage 的判断
条件,将资源包删除了,我们调整频道顺序的时候,就会获取包不到资源包,造成有图片的item 在调整顺序之后,没有图片了,
所以这里添加了一个没有进入首页的判断
*/
[self deleteChanelSourceWhenDoloadSuccess];
/*
如果下载结束的时候,还没有进入到首页,则直接 将路径赋值给 channelHeadSourcePath
使用新资源包
*/
[TPUserDefault instance].channelHeadSourcePath = localfileName;
}
[TPUserDefault instance].channelHeadSourceRemoteURL = downloadUrl;
}
}else{
//删掉zip
[FFileTool removeFile:fileName];
}
} failed:^{
NSLog(@"下载失败");
}];
}
- (void)deleteChanelSourceWhenDoloadSuccess
{
NSString *path = [NSString stringWithFormat:@"%@/%@",kChannelHeadSourceCachePath, [TPUserDefault instance].channelHeadSourcePath];
if ([FFileTool fileExists:path]) {
[FFileTool removeFile:path];
}
}
-(void)deleteChannelSource{
[FFileTool removeFile:kChannelHeadSourceCachePath];
[TPUserDefault instance].channelHeadSourcePath = @"";
[TPUserDefault instance].channelHeadSourceRemoteURL = @"";
}
- (void)updateChannelSource {
///这里一定要添加一个不为空的判断,否则如果为空,会导致 toBeUsedHeadSourcePath 目录下的资源也被删除,
if (!isBlankString([TPUserDefault instance].channelHeadSourcePath) && ![[TPUserDefault instance].channelHeadSourcePath isEqualToString:[TPUserDefault instance].toBeUsedHeadSourcePath]) {
/*
这里删除要拼接上 [TPUserDefault instance].channelHeadSourcePath,
如果不拼接,会将 toBeUsedHeadSourcePath目录下的资源文件删除
*/
NSString *path = [NSString stringWithFormat:@"%@/%@",kChannelHeadSourceCachePath, [TPUserDefault instance].channelHeadSourcePath];
if ([FFileTool fileExists:path]) {
[FFileTool removeFile:path];
}
}
[TPUserDefault instance].channelHeadSourcePath = [TPUserDefault instance].toBeUsedHeadSourcePath;
[TPUserDefault instance].toBeUsedHeadSourcePath = @"";
}
@end
下载好的资源如下图
将下载好的资源包解压缩,并删除压缩包
解压缩使用的工具 ZipArchive
使用如下代码展示沙盒中的json 文件(支持json文件使用图片资源)
[LOTAnimationView animationWithFilePath:jsonPath]
NSString *jsonPath = [NSString stringWithFormat:@"%@/%@/%@_animation/animation.json",kChannelHeadSourceCachePath,[TPUserDefault instance].channelHeadSourcePath , self.itemDic[@"nodeId"]];
if ([FFileTool fileExists:jsonPath]) {
self.hasJsonAnimation = YES;
self.animationView = [LOTAnimationView animationWithFilePath:jsonPath];
[self addSubview:self.animationView];
self.animationView.frame = CGRectMake(0, 0, width, 44 * rectScale());
} else {
self.hasImgSource = YES;
[self addSubview:self.imgView];
self.imgView.frame = CGRectMake(0, 0, width, 44 * rectScale());
self.imgView.image = self.normalImg;
}
这里要注意的一点,点击按钮(选中)的时候开始json 动画
调用 下面代码 [self.animationView playWithCompletion:^(BOOL animationFinished) {
}];即可,动画结束的时候,
会自动停留在最后一帧动画
if (self.animationView.animationProgress == 0) {
//这里的 self.animationView.animationProgress == 0表示json 动画还没有开始,防止重复动画
[self.animationView playWithCompletion:^(BOOL animationFinished) {
}];
}
滑走未选中的时候,要展示json动画的第一帧动画
调用 [self.animationView stop];
即可
[self.animationView stop];