UIImageView

UIImageView 文档,https://developer.apple.com/reference/uikit/uiimageview?language=objc

An object that displays a single image or a sequence of animated images in your interface.

ContentMode影响图片的缩放

scale表示会缩放图片,aspect表示按图片比例缩放,fill表示填满imageView,fit表示不大于imageView。

typedef NS_ENUM(NSInteger, UIViewContentMode) {
    UIViewContentModeScaleToFill,
    UIViewContentModeScaleAspectFit,      // contents scaled to fit with fixed aspect. remainder is transparent
    UIViewContentModeScaleAspectFill,     // contents scaled to fill with fixed aspect. some portion of content may be clipped.
   
    UIViewContentModeRedraw,              // redraw on bounds change (calls -setNeedsDisplay)
    UIViewContentModeCenter,              // contents remain same size. positioned adjusted.
    UIViewContentModeTop,
    UIViewContentModeBottom,
    UIViewContentModeLeft,
    UIViewContentModeRight,
    UIViewContentModeTopLeft,
    UIViewContentModeTopRight,
    UIViewContentModeBottomLeft,
    UIViewContentModeBottomRight,
};
ImageView_ContentMode.png

对于没有设置capInsets的图片,缩放完全由contentMode决定。capInsets可以决定图片缩放的区域和方向。伸缩图片用resizableImageWithCapInsets:resizingMode: 方法创建。
使用伸缩图片的话,一般把imageView的contentMode设置为UIViewContentModeScaleToFill。

图片拉伸

UIImageView *iv1 = [self.view viewWithTag:11];
UIImageView *iv2 = [self.view viewWithTag:12];
UIImageView *iv3 = [self.view viewWithTag:13];

// 设置保护区域,上左下右。这里是距离底部58之间的区域在垂直方向上不被拉伸
UIEdgeInsets capInsets2 = UIEdgeInsetsMake(0, 0, 58, 0);
UIEdgeInsets capInsets3 = UIEdgeInsetsMake(58, 0, 0, 0);

//    UIImage *image = [UIImage imageNamed:@"蓝绿"]; // 44, 116
//    UIImage *image2 = [image resizableImageWithCapInsets:capInsets2]; // 默认平铺,不是拉伸,所以不用这个方法
//    UIImage *image3 = [image resizableImageWithCapInsets:capInsets3];

UIImage *image = iv1.image; // 图片大小:44, 116
UIImage *image2 = [image resizableImageWithCapInsets:capInsets2 resizingMode:UIImageResizingModeStretch];
UIImage *image3 = [image resizableImageWithCapInsets:capInsets3 resizingMode:UIImageResizingModeStretch];

iv2.image = image2;
iv3.image = image3;

图片拉伸.png

<p>

图片透明度

官方文档:
Similarly, any further transparency in the background of the image is dependent on the transparency of the image view and the transparency of the UIImage object it displays. When the image view and its image both have transparency, the image view uses alpha blending to combine the two.

如果image view的opaque属性是YES,the image’s pixels are composited on top of the image view’s background color and the alpha property of the image view is ignored.

如果image view的opaque属性是NO,the alpha value of each pixel is multiplied by the image view’s alpha value, with the resulting value becoming the actual transparency value for that pixel. If the image does not have an alpha channel, the alpha value of each pixel is assumed to be 1.0.

需要注意的是,结合透明图片和透明image view的alpha channel的代价是昂贵的。如果使用Core Animation shadows,性能会进一步受影响,因为需要动态计算。如果不需要透明效果,设置opaque为NO可以提高性能。

Responding to Touch Events

image view 默认忽略用户事件,可以设置userInteractionEnabled = YES接收事件,然后添加手势来处理。更多事件相关信息,查看 Event Handling Guide for UIKit Apps.

Tips for Improving Performance

  • Cache scaled versions of frequently used images. 如果图片很大,视图较小,可以预先创建缩略图并缓存,避免每个image view都要缩放图片。

  • Use images whose size is close to the size of the image view. 创建和视图大小匹配的图片,而不是直接使用大图片。也可以创建resizable image,使用平铺来代替缩放,平铺使用的选项是UIImageResizingModeTile。

  • Make your image view opaque whenever possible. 如果不使用透明图片,可以设置opaque属性为YES使其不透明,默认为YES。

<p>

Debugging Issues with Your Image View

如果图片不能正常显示:

  • **Load images using the correct method. ** 使用 imageNamed:imageNamed:inBundle:compatibleWithTraitCollection: 方法加载 asset catalogs 或者 app’s bundle 的图片。app’s bundle 之外的图片,使用 imageWithContentsOfFile: 方法。

  • Do not use image views for custom drawing. TheUIImageView class does not draw its content using the drawRect: method. Use image views only to present images. To do custom drawing involving images, subclass UIView directly and draw your image there.

<p>

State Preservation

给 image view的 restorationIdentifier 赋值,它会尝试保存 frame、bounds、center、transform和 layer属性的 anchorPoint。
For more information about how state preservation and restoration works, see App Programming Guide for iOS.

Animating a Sequence of Images

创建一个图片数组,然后赋值给imageView的animationImages属性。或者通过animatedImageWithImages:duration:方法创建一个image对象,然后赋值给imageView的image属性。两个要求:

  • All images in the sequence should have the same size.
  • All images in the sequence should use the same content scale factor.

虽然UIImageView显示gif是静止的,但是可以播放一组图片作为动画效果。先讲一下如何获取动态图。静态图片用imageName:方法创建。动态图不能直接加载gif生成,而是用animatedImageNamed: duration:方法创建,该方法会加载基本名字相同的图片(比如imageName0,imageName1,imageName1024,等等),然后返回一个UIImage的对象image,image有个数组属性images表示所有的图片。

// 加载基本名字相同的图片:name0,name1,… 数字要连续,如果少了name4,那么name5和之后的图片不会加载。名字可以是中文。
// duration表示播放周期,不是时间间隔哦!
// read sequence of files with suffix starting at 0 or 1. 
+ (nullable UIImage *)animatedImageNamed:(NSString *)name duration:(NSTimeInterval)duration NS_AVAILABLE_IOS(5_0);  

有两种方法可以播放动画。第一种是设置image属性,第二种是设置animationImages属性。第一种会自动播放动画,不能设置循环次数、循环周期,不能结束动画,第二种则相反。也可以设置高亮状态的动画 highlightedAnimationImages。

// The array must contain UIImages. Setting hides the single image. default is nil
@property (nullable, nonatomic, copy) NSArray<UIImage *> *animationImages; 
// 获取UIImageView
UIImageView *iv = [self.view viewWithTag:100];

// 加载图片Gundam0,Gundam1.png,… 循环周期2秒。可以是中文。数字要连续,从0或1开始。貌似不能加载tiff图片。
UIImage *animatedImage = [UIImage animatedImageNamed:@"Gundam" duration:2];

// 第一种,直接设置image。动画自动开始,不能通过stopAnimating方法暂停动画,设置动画时间和重复次数无效。
iv.image = animatedImage;

// 第二种,设置animationImages属性
iv.image = animatedImage.images.firstObject; // 动画开始前和结束后显示的图片
iv.animationImages = animatedImage.images; // 设置图片数组
iv.animationRepeatCount = -1; // 设置次数小于等于0依然会动
iv.animationDuration = 5; // 设置动画周期
[iv startAnimating]; // 这句要在最后调用

注意了,修改动画周期和次数会停止动画。可以通过animating属性判断动画状态。

// 两秒后执行代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    UIImageView *iv = [self.view viewWithTag:100];
    NSLog(@"%d", iv.animating); // 输出1
    iv.animationRepeatCount = 600;
    NSLog(@"%d", iv.animating); // 输出0

    [iv stopAnimating]; // 停止动画
});

显示GIF图片

UIImageView的image属性只能显示gif的第一帧图片,想使用animationImages属性但是获取gif的所有图片又很麻烦。

UIImage *animatedImage = [UIImage imageNamed:@"demo.gif"];
UIImage *animatedImage = [UIImage animatedImageNamed:@"demo.gif" duration:2]; // 加载失败,animatedImage为nil
UIImageView *iv = [self.view viewWithTag:100];
iv.image = animatedImage; // 显示的图片静止
iv.animationImages = animatedImage.images; // 尝试获取gif的所有图片,但是animatedImage.images是nil

UIWebView可以正确显示gif图片但是效果不好,还是使用第三方库吧。显示本地的gif可以使用YYImage和FLAnimatedImage ,显示网络的gif可以使用YYWebImage和SDWebImage。sd实际用的FLAnimatedImage,只不过给它加了一个category。YYImage比FLAnimatedImage使用的内存更少,使用webView是最占内存的。测试一个5.6MB的gif图片,yy占内存6.4,sd占11.8,webView占33.8MB。播放速度,yy和sd一样,webView最快。webView加载gif最慢。

YYKitYYImageYYWebImageSDWebImageFLAnimatedImage
使用SDWebImage和YYImage下载高分辨率图,导致内存暴增的解决办法

使用SDWebImage播放gif,不管本地还是网络的,都要使用FLAnimatedImage。sd的sd_animatedGIFWithData方法返回的image只包含第一帧。FLAnimatedImage要另外添加到项目中。

使用SDWebImage显示gif:

// 该文件扩展了FLAnimatedImageView的sd_setImageWithURL:方法
#import "FLAnimatedImageView+WebCache.h"

// 测试网络gif
NSString *urlStr = @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1488309254574&di=62e28c0d91d1711546ff9344d4570af6&imgtype=0&src=http%3A%2F%2Fmat1.gtimg.com%2Fcomic%2Fbaba%2Fguzhang.gif";
NSURL *url = [NSURL URLWithString:urlStr];

// 测试本地gif
NSString *urlStr = [[NSBundle mainBundle]pathForResource:@"demo" ofType:@"gif"];
NSURL *url = [NSURL fileURLWithPath:urlStr];

FLAnimatedImageView *iv = [FLAnimatedImageView new]; 
[iv sd_setImageWithURL:url];

使用YYWebImage显示gif:

#import "YYImage.h"
#import "UIImageView+YYWebImage.h"

// 测试网络gif
NSString *urlStr = @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1488309254574&di=62e28c0d91d1711546ff9344d4570af6&imgtype=0&src=http%3A%2F%2Fmat1.gtimg.com%2Fcomic%2Fbaba%2Fguzhang.gif";
NSURL *url = [NSURL URLWithString:urlStr];

// 测试本地gif
NSString *urlStr = [[NSBundle mainBundle]pathForResource:@"demo" ofType:@"gif"];
NSURL *url = [NSURL fileURLWithPath:urlStr];

UIImageView *iv = [YYAnimatedImageView new];

iv.yy_imageURL = url;
// 或者
[iv yy_setImageWithURL:url options:0];

使用YYImage加载本地的gif还可以这样写:

#import "YYImage.h"

UIImage *image = [YYImage imageNamed:@"demo.gif"];
UIImageView *imageView = [[YYAnimatedImageView alloc] initWithImage:image];

使用FLAnimatedImage显示本地的gif:

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"]];
FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:data];
FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init];
imageView.animatedImage = image;

总结一下,显示gif有两种方法。一种是把gif分解成多张png,然后通过UIImageView的animationImages属性显示。另一种是使用第三方或者UIWebView显示gif。通过代码提取gif的所有图片再用UIimageView显示比较复杂,不推荐使用。使用SDWebImage显示gif,记得是调用sd给FLAnimatedImage添加的category方法。使用YYimage显示gif占用的内存最少。

<p>
未完待续。

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,068评论 4 62
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,342评论 7 249
  • UIImageView 用UIImageView来显示图片,其contentMode属性控制图片如何显示,默认值是...
    ilaoke阅读 828评论 1 2
  • 好人是个什么概念?善良,没脾气,爱奉献,讲道德,守信用,乐于助人,等等这些词汇无不和好人挂钩。每个人都想和好人...
    三脚猫WW阅读 1,437评论 0 0
  • 今夜不眠 我在雨后的寂静里读你 黑暗是你的眸光 流淌着热情的呼唤 别忘记那一眼如月的弯 深情处,蓄满力量 大山是你...
    蓝朵世界阅读 593评论 45 47