iOS集成Weex图片加载最全面(包括加载Gif)

关于weex集成到Xcode的过程,可以参考官方文档iOS集成步骤。我在这里记录一下,官方文档没有明确说明但在实际开发过程中需要用到的问题。

解决问题后的代码

描述

在weex集成到Xcode中,运行官方文档提供的we文件,在terminal中通过weex xx.we -o xx.js后,记载该js文件,发现图片不显示。我去weex的中文聊天室问了一下,然后weex团队成员告诉我要从新写图片加载器,让我参考weex的playground代码。

过程

在playground中,我发现一段代码(之所以发现这段代码,是因为在集成weex中最基本的代码不包含他们)

[WXSDKEngine registerHandler:[WXImgLoaderDefaultImpl new] withProtocol:@protocol(WXImgLoaderProtocol)];
[WXSDKEngine registerHandler:[WXEventModule new] withProtocol:@protocol(WXEventModuleProtocol)];
    
[WXSDKEngine registerComponent:@"select" withClass:NSClassFromString(@"WXSelectComponent")];
[WXSDKEngine registerModule:@"event" withClass:[WXEventModule class]];
[self atAddPlugin];

这里有4个注册,根据协议名称,可以判断WXImgLoaderProtocol就应该是图片加载协议,然后我去找了WXImgLoaderDefaultImpl这个类的实现。

WXImgLoaderDefaultImpl.h文件

/**
 * Created by Weex.
 * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
 *
 * This source code is licensed under the Apache Licence 2.0.
 * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
 */

#import <Foundation/Foundation.h>
#import "WXImgLoaderProtocol.h"

@interface WXImgLoaderDefaultImpl : NSObject<WXImgLoaderProtocol, WXModuleProtocol>
@end

WXImgLoaderDefaultImpl.m文件

/**
 * Created by Weex.
 * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
 *
 * This source code is licensed under the Apache Licence 2.0.
 * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
 */

#import "WXImgLoaderDefaultImpl.h"
#import <SDWebImage/UIImageView+WebCache.h>

#define MIN_IMAGE_WIDTH 36
#define MIN_IMAGE_HEIGHT 36

#if OS_OBJECT_USE_OBJC
#undef  WXDispatchQueueRelease
#undef  WXDispatchQueueSetterSementics
#define WXDispatchQueueRelease(q)
#define WXDispatchQueueSetterSementics strong
#else
#undef  WXDispatchQueueRelease
#undef  WXDispatchQueueSetterSementics
#define WXDispatchQueueRelease(q) (dispatch_release(q))
#define WXDispatchQueueSetterSementics assign
#endif

@interface WXImgLoaderDefaultImpl()

@property (WXDispatchQueueSetterSementics, nonatomic) dispatch_queue_t ioQueue;

@end

@implementation WXImgLoaderDefaultImpl

#pragma mark -
#pragma mark WXImgLoaderProtocol

- (id<WXImageOperationProtocol>)downloadImageWithURL:(NSString *)url imageFrame:(CGRect)imageFrame userInfo:(NSDictionary *)userInfo completed:(void(^)(UIImage *image,  NSError *error, BOOL finished))completedBlock
{
    if ([url hasPrefix:@"//"]) {
        url = [@"http:" stringByAppendingString:url];
    }
    return (id<WXImageOperationProtocol>)[[SDWebImageManager sharedManager] downloadImageWithURL:[NSURL URLWithString:url] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize) {
        
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
        if (completedBlock) {
            completedBlock(image, error, finished);
        }
    }];
}

@end

集成过程中遇见Gif的加载,你成功了么?

由于SDWebImageManager中并没有实现加载Gif的方法,虽然实现图片加载,但加载出来的永远是动态图的第一帧!!!不过遇见我了让我来告诉你!上“码”!!!

completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
        if (completedBlock) {
            
            if([WPImgLoaderDefaultTool isGIFWithImage:image])
            {
                image = [WPImgLoaderDefaultTool createGifImageWithData:data duration:image.duration];
            }
                completedBlock(image, error, finished);
        }
    }];
}

在实现方法中提供了一个加载回调方法,我们所获取的数据就是要去渲染的数据,这里说的就是image。针对这个数据我写了一个判断工具类来判定我所要加载的图片究竟属于动态的还是静态的,继续走代码!!!

/**
 判断是否是GIF格式
 */
+(BOOL)isGIFWithImage:(UIImage*)image{
      return (image.images != nil);
}

这里返回的是BOOL值,如果是的话那就来调用处理动态图的方法,也就是 image = [WPImgLoaderDefaultTool createGifImageWithData:data duration:image.duration];
这里的data就是我们回到方法中的data,方法中的duration就是动画持续时间这个我们会按照自己的需求来设定!详细代码如下:

/**
 根据二进制数据转换成Gif图片
 */
+(UIImage*)createGifImageWithData:(NSData*)dataImage duration:(NSTimeInterval)duration{

        if (!dataImage) {
            return nil;
        }
        CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)dataImage, NULL);
        
        size_t count = CGImageSourceGetCount(source);
    
        UIImage *staticImage;
        
        if (count <= 1) {
            staticImage = [[UIImage alloc] initWithData:dataImage];
        } else {
 
#if SD_WATCH
            CGFloat scale = 1;
            scale = [WKInterfaceDevice currentDevice].screenScale;
#elif SD_UIKIT
            CGFloat scale = 1;
            scale = [UIScreen mainScreen].scale;
#endif
            NSMutableArray *arrFrameImages = [NSMutableArray array];

            for (int i = 0; i < count; i++)
            {
                CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, i, NULL);
                
#if SD_UIKIT || SD_WATCH
                
                UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp];
                [arrFrameImages addObject:frameImage];
                
#endif
                CGImageRelease(CGImage);
            }
            
            staticImage = [UIImage animatedImageWithImages:arrFrameImages duration:duration*count*2];
            

        }
        
        CFRelease(source);
        
        return staticImage;

    
}

返回的image放到 completedBlock(image, error, finished);
中就可以实现你的动图啦!!!
就问你清不清晰!!!实现了不要感谢我!!哈哈哈,留名点赞!双击!!!

重点来了!!!

虽然可以加载出网络图片,一提到网络我们不得不考虑到无网络或弱网状态下渲染出的效果是怎样,因此我们要在图片渲染出之前像Native实现一样添加图片的Placeholder,不扯了!直接上代码!!!

 return (id<WXImageOperationProtocol>)[[SDWebImageManager sharedManager] loadImageWithURL:[NSURL URLWithString:url] options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
        
        if (completedBlock) {
            completedBlock([UIImage imageNamed:@"wpimageutils_error"], nil, NO);
        }
        
    } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
        if (completedBlock) {

completedBlock([UIImage imageNamed:@"wpimageutils_error"], nil, NO);这个block回调包括三个参数,UIImage,Error,BOOL,也就是图片、加载错误信息、是否渲染完成状态,图片对应的名字一定是我们本地准备好的占位图,由于正在渲染错位信息为空,加载完成状态为No,加载过程中占位图搞定!!!

加载错误图片处理方法

在渲染过程中我们考虑了无网络和弱网状态,但作为一名资深的开发者我们也绝对不可以忽略错误!这是绝对不可以忍受的!并不是所有的图片路径都是我们想要的,万一有错呢?来来来!我来给你解决!!!上代码!!!

 completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
        if (completedBlock) {
            
            if([WPImgLoaderDefaultTool isGIFWithImage:image])
            {
                image = [WPImgLoaderDefaultTool createGifImageWithData:data duration:image.duration];
            }
            if (error) {
                image = [UIImage imageNamed:@"wpimageutils_error"];
                completedBlock([UIImage imageNamed:@"wpimageutils_error"], nil, finished);
            }else {
                completedBlock(image, error, finished);
            }
        }

针对error做一个判断如果有错误就直接加载本地准备好的错误图片,没有的话不做任何处理直接通过block方法回调image进行渲染。

分析

从该类的代码中,可以发现:这个本地的图片加载类是遵守了WXImgLoaderProtocol协议,并实现了- (id<WXImageOperationProtocol>)downloadImageWithURL:(NSString *)url imageFrame:(CGRect)imageFrame userInfo:(NSDictionary *)options completed:(void(^)(UIImage *image, NSError *error, BOOL finished))completedBlock;方法。在WXImgLoaderDefaultImpl.m中,官方使用的是SDWebImage去加载网络图片的。这个地方采用其他加载图片的方法也是可以的。

结论

如果想要Xcode中能够显示出,网络图片,需要从新写一个图片加载器,该加载器需要遵守WXImgLoaderProtocol协议,并实现加载方法。不过在我的这个加载器的时候,发现如果只写上述方法,会出现警告,因为该协议还有一个- (void)cancel;方法,也需要实现。当加载器写好之后需要在入口类中注册一下[WXSDKEngine registerHandler:[YHImageLoader new] withProtocol:@protocol(WXImgLoaderProtocol)];。到此,再去运行项目,就能够显示出网络图片了。

喜欢的话动动小手,给博主一个小❤️,关注一下!对iOS集成Weex感兴趣的同胞们!!跟着我脚步!大不向前迈!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容