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,
};
对于没有设置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;
图片透明度
官方文档:
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。
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.
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 *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最慢。
YYKit、YYImage、YYWebImage、SDWebImage、FLAnimatedImage,
使用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占用的内存最少。
未完待续。