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感兴趣的同胞们!!跟着我脚步!大不向前迈!!!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容