iOS开发——UIImageView的contentMode、裁剪和layer属性详解

在我们iOS开发过程中,UIImageView是一个非常常见的控件,但是我们未必会用的很溜,因为里面的有些属性不曾注意,或者很难理解。所以会对我们使用该控件带来麻烦,在布局UI过程中可能会造成意想不到的结果。这篇博客主要来讲解UIImageView中的contentMode属性以及和图片裁剪的关系,并且不得不提到就是所有UIView的重要属性:layer(CALayer)。文中提到的所有·示例代码上传至 https://github.com/chenyufeng1991/ImageWithModeCutLayer  。欢迎下载使用。

【contentMode】

该属性是UIView所共有的属性,表示的是内容的填充模式。由于我们是在UIIMageView中该属性用的最频繁,所以我这里使用UIImageView来讲解该属性。首先演示一下我实现的效果,大家就会明白各个属性是什么作用了。

我这里使用CollectionView把contentMode共13种填充模式都显示了出来,cell的背景颜色是黄色,也就是说图片没有覆盖的区域显示的是cell默认的黄色背景。这样显示应该比较直观。下面对13种模式描述一下:

(1)ScaleToFill:这是图片显示的默认模式。图片进行非等比例缩放,直到填铺满整个View区域。所以往往造成图片的变形。也就是图片的长度上缩放一定的比例填满显示区域,在宽度上缩放一定的比例填满显示区域。

(2)ScaleAspectFit:这是等比例缩放,所以使用这种缩放模式的图片永远不会变形。图片按一定比例缩放,直到在长度上或者宽度上达到View的边界就停止。没有填满区域就显示View的背景。

(3)ScaleAspectFill:这也是等比例缩放,图片也不会变形。这种缩放和上面的ScaleAspectFit正好相反,图片按一定比例缩放,直到最短的边达到View的边界。所以这种缩放一定会铺满View,超出View的图片你可以选择截掉或者不截掉。

(4)Redraw:重绘。说实话也不清楚这种模式的特点,仅仅实现效果和下面要讲的Left是一样的。

(5)Center:等比缩放,居中显示。

(6)Top:等比缩放,顶部对齐显示。

(7)Bottom:等比缩放,底部对齐显示。

(8)Left:等比缩放,左侧对齐显示。

(9)Right:等比缩放,右侧对齐显示。

(10)TopLeft:等比缩放,左上角对齐显示。

(11)TopRight:等比缩放,右上角对齐显示。

(12)BottomLeft:等比缩放,左下角对齐显示。

(13)BottomRight:等比缩放,右下角对齐显示。

我这里原始图片的大小为:380*140.  UIImageView的大小为180*180.   还有非常重要的一点就是我设置了UIImageView的属性ImageView.layer.masksToBounds = YES.  这个属性

是可以把超过View区域部分截掉,默认是NO。我们来看看在上面的案例如果masksToBounds = NO会怎样:

也许,当我们把masksToBounds 设置为NO,这样contentMode才更加容易理解。这个属性的作用也就是是否把超过区域部分截掉。所以在这里我们可以知道,并不是我们设置View多大,内容就一定显示在该区域内,还和它的显示模式有关。

【contentMode和图片裁剪】

通过我上面的案例,其实可以发现contentMode也有图片裁剪的功能,那么和普通的图片裁剪方法有什么差异呢,我们简单来比较一下:

(1)正常的图片显示:

    // 原始的显示图片,默认的contentMode为ContentModeScaleToFill
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    [self.imageView setImage:[UIImage imageNamed:@"ford"]];
    self.imageView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:self.imageView];
    [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.equalTo(@100);
        make.height.equalTo(@100);
    }];

效果如下:

(2)经过裁剪:

    // 经过裁剪
    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    UIImage *cutImage = [self cutImage:[UIImage imageNamed:@"ford"]];
    [self.imageView setImage:cutImage];
    self.imageView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:self.imageView];
    [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.equalTo(@100);
        make.height.equalTo(@100);
    }];

//裁剪图片
/**
 *
 *
 */
- (UIImage *)cutImage:(UIImage*)originImage
{
    CGSize newImageSize;
    CGImageRef imageRef = nil;

    CGSize imageViewSize = self.imageView.frame.size;
    CGSize originImageSize = originImage.size;

    if ((originImageSize.width / originImageSize.height) < (imageViewSize.width / imageViewSize.height))
    {
        // imageView的宽高比 > image的宽高比
        newImageSize.width = originImageSize.width;
        newImageSize.height = imageViewSize.height * (originImageSize.width / imageViewSize.width);

        imageRef = CGImageCreateWithImageInRect([originImage CGImage], CGRectMake(0, fabs(originImageSize.height - newImageSize.height) / 2, newImageSize.width, newImageSize.height));
    }
    else
    {
        // image的宽高比 > imageView的宽高比   : 也就是说原始图片比较狭长
        newImageSize.height = originImageSize.height;
        newImageSize.width = imageViewSize.width * (originImageSize.height / imageViewSize.height);

        imageRef = CGImageCreateWithImageInRect([originImage CGImage], CGRectMake(fabs(originImageSize.width - newImageSize.width) / 2, 0, newImageSize.width, newImageSize.height));
    }

    return [UIImage imageWithCGImage:imageRef];
}

效果如下:

(3)使用masksToBounds和ScaleAspectFill设置裁剪效果:

 self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
    [self.imageView setImage:[UIImage imageNamed:@"ford"]];
    self.imageView.backgroundColor = [UIColor yellowColor];
    self.imageView.contentMode = UIViewContentModeScaleAspectFill;
    self.imageView.layer.masksToBounds = YES;
    [self.view addSubview:self.imageView];
    [self.imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.equalTo(@100);
        make.height.equalTo(@100);
    }];

效果如下:

显示效果和使用裁剪算法一样。所以,好好利用contentMode和其他属性,可以简化我们的代码。

【layer属性的简单介绍】

任何一个UIView都有一个layer属性,是属于CALayer类型。这个东西一般初学者很少去注意,但是却能发挥大作用。这里还是通过UIImageView来进行演示,图片还是我上面用到的380*140的“福特”图片。

(1)声明属性:

@property (nonatomic, strong) UIImageView *redView;
@property (nonatomic, strong) UIImage *fordImage;

(2)初始化UIView

 self.redView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 50, 200, 200)];
    self.redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.redView];
    [self.redView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.center.equalTo(self.view);
        make.width.equalTo(@100);
        make.height.equalTo(@100);
    }];

(3)使用layer设置圆角

// 使用layer属性设置圆角
    self.redView.layer.cornerRadius = 10;

.

(4)使用layer添加边框

 // 使用layer添加边框
    self.redView.layer.borderColor = [[UIColor blackColor] CGColor];
    self.redView.layer.borderWidth = 5;

(5)修改UIView的背景颜色

 // 可以通过修改layer的背景颜色从而修改UIView的背景颜色
    self.redView.layer.backgroundColor = [[UIColor yellowColor] CGColor];

(6)修改背景透明度

// 修改透明度
    self.redView.layer.opacity = 0.5;

(7)设置View的阴影

// 设置View的阴影
    self.redView.layer.shadowColor = [[UIColor blueColor] CGColor];
    self.redView.layer.shadowOffset = CGSizeMake(10, 10);
    self.redView.layer.shadowOpacity = 1.0; // 一定要设置阴影的透明度,因为默认为0
    self.redView.layer.shadowRadius = 10;

(8)masksToBounds与截取

 // 设置超过layer区域部分是否截掉
    self.redView.layer.masksToBounds = NO;

    /**
     *  在ImageView中加入一张图片
     self.redView.layer.masksToBounds = YES;时可以把超出layer部分截掉。
     */
    self.fordImage = [UIImage imageNamed:@"ford"];
    self.redView.contentMode = UIViewContentModeScaleAspectFill;
    self.redView.image = self.fordImage;

(9)隐藏layer,同时也隐藏View

 // hidden设置为YES会隐藏Layer,视图不可见
    self.redView.layer.hidden = YES;

(10)子Layer,父Layer

// 由于self.view是redView的父视图,所以self.view.layer同样也是redView.layer的父图层
    CALayer *superLayer = self.redView.layer.superlayer;
    CALayer *selfViewLayer = self.view.layer;
    NSLog(@"superLayer = %@,selfViewLayer = %@",superLayer,selfViewLayer);

父子View的层级结构同样适用于父子Layer的层级结构。

(11)打印Layer的各项参数

 CALayer *redLayer = self.redView.layer;

    NSLog(@"redView.bounds = %@,redLayer.bounds = %@",NSStringFromCGRect(self.redView.bounds),NSStringFromCGRect(redLayer.bounds));
    NSLog(@"redView.center = %@,redLayer.position = %@",NSStringFromCGPoint(self.redView.center),NSStringFromCGPoint(redLayer.position));
    NSLog(@"redLayer.zPosition = %f",redLayer.zPosition);
    NSLog(@"redLayer.anchorPoint = %@",NSStringFromCGPoint(redLayer.anchorPoint));
    NSLog(@"redView.frame = %@,redLayer.frame = %@",NSStringFromCGRect(self.redView.frame),NSStringFromCGRect(redLayer.frame));

    NSLog(@"fordImage.size = %@",NSStringFromCGSize(self.fordImage.size)); // 图片的原始大小

view中的很多属性基本是和layer中吻合的。View中的bounds等同于Layer中的bounds;View中的center等同于layer中的center;View中的frame等同于layer中的frame。

(12)对View和Layer的总结

-- 每个UIView都有CALayer,即UIView.layer;

-- CALayer能够对UIView做许多的设置,如阴影,边框,圆角,和透明效果;

-- CALayer重要属性

shadowPath:设置CALayer阴影(shadow)的位置;

shadowOffset:shadow在X,Y轴上的偏移;

shadowOpacity:shadow的透明效果;

shadowRadius:shadow的圆角;

masksToBounds:防止子元素大小溢出父元素,如果要防止溢出,设置为YES;

borderWidth和borderColor:边框颜色和宽度;

bounds:设置UIView大小;

opacity:UIView的透明效果;

cornerRadius:UIView的圆角;

-- UIView可以响应事件,CALayer不可以

UIView继承自UIResponder,在UIResponder中定义了处理各种事件和事件传递的接口。而CALayer直接继承NSObject,并没有相应的处理事件的接口。

-- 一个CALayer的frame是由它的anchorPoint,position,bounds和transform共同决定,而一个View的frame只是简单的返回Layer的frame,同样View的center和bounds也是返回layer的一些属性。

-- UIView主要是对显示内容的管理,而CALayer主要侧重显示内容的绘制。UIView是CALayer的CALayerDelegate。

-- 每个UIView内部都有一个CALayer在背后提供内容的绘制和显示,并且UIView的尺寸样式都由内部的Layer提供。两者都有树状层级结构,layer内部有SubLayers,  View内部有SubViews。

-- 两者最明显的区别是View可以接受并处理事件,而Layer不可以。View是Layer的代理Delegate。

时间: 2024-12-17 14:03:18

iOS开发——UIImageView的contentMode、裁剪和layer属性详解的相关文章

iOS开发——使用Charles进行https网络抓包详解

我在前面两篇博客中<网络抓包工具Charles的介绍与使用><iOS开发--使用Charles进行http网络抓包详解>对Charles的http抓包进行了详细的讲解.今天我们来实现一下进行https的抓包,比http抓包稍微麻烦一点. (1)https初级的配置请参考<网络抓包工具Charles的介绍与使用>中的https配置部分. (2)由于目前iOS9更改了对于https网络的安全机制,所以还需要在iPhone上安装一个证书,安装方式如下: 在iPhone的Saf

IOS 开发环境,证书和授权文件等详解

一.成员介绍 1.    Certification(证书) 证书是对电脑开发资格的认证,每个开发者帐号有一套,分为两种: 1)    Developer Certification(开发证书) 安装在电脑上提供权限:开发人员通过设备进行真机测试. 可以生成副本供多台电脑安装: 2)      Distribution Certification(发布证书) 安装在电脑上提供发布iOS程序的权限:开发人员可以制做测试版和发布版的程序. 不可生成副本,仅有配置该证书的电脑才可使用:(副本制做介绍在

iOS开发——实战篇&amp;Xcode 7真机测试详解

Xcode 7真机测试详解 1.准备 注意:一定要让你的真机设备的系统版本和app的系统版本想对应,如果不对应就会出现一个很常见的问题:could not find developer disk image 首先,准备好下面的设备机相关软件 MAC版本:OSX10.10.4 Xcode版本:Xcode7 beta5(点击下载) 真机设备:iPad Air(iOS 8.1.3)/iphone 6 2.首先先安装Xcode7,并且运行Xcode,点击左上角菜单Xcode -> Preferences

iOS开发之---block的使用(详解)

一.基本概念 block (代码块)类似C语言函数指针. 定义一个block的格式:返回值类型 (^变量名)(参数列表)--->void (^blcok)(void). 一般使用typedef重命名block,上面的block定义可以这样写--->typedef void(^MyBlock)(void),MyBlock block. 二.简单使用 block在iOS的开发中,主要用来对象之间的通信,包括值的传递(反向传递)和方法的传递.

iOS开发 多线程-转自MJ的GCD详解

一.简介 在iOS所有实现多线程的方案中,GCD应该是最有魅力的,因为GCD本身是苹果公司为多核的并行运算提出的解决方案.GCD在工作时会自动利用更多的处理器核心,以充分利用更强大的机器.GCD是Grand Central Dispatch的简称,它是基于C语言的.如果使用GCD,完全由系统管理线程,我们不需要编写线程代码.只需定义想要执行的任务,然后添加到适当的调度队列(dispatch queue).GCD会负责创建线程和调度你的任务,系统直接提供线程管理 二.调度队列(dispath qu

IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解

copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象没有变化.copy减少对象对上下文的依赖 retain属性表示两个对象地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1也就是说,retain 是指针拷贝,copy 是内容拷贝. 当然在ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying

iOS开发——加载、滑动翻阅大量图片解决方案详解

加载.滑动翻阅大量图片解决方案详解 今天分享一下私人相册中,读取加载.滑动翻阅大量图片解决方案,我想强调的是,编程思想无关乎平台限制. 我要详细说一下,在缩略图界面点击任意小缩略图后,进入高清大图全屏浏览界面的这短暂的1秒内(和后续的几秒),都发生了什么. 常规思路流程 点击任意小图后, 1.首先制作scrollview框架:大小2个scrollview,小的用于手势缩放单一图片,大的横向依次加载全部照片 2.制作好scrollview框架后,加载照片 3.一切准备就绪跳转页面呈现给用户选择的大

iOS开发UI篇—CAlayer(自定义layer)

iOS开发UI篇—CAlayer(自定义layer) 一.第一种方式 1.简单说明 以前想要在view中画东西,需要自定义view,创建一个类与之关联,让这个类继承自UIView,然后重写它的DrawRect:方法,然后在该方法中画图. 绘制图形的步骤: (1)获取上下文 (2)绘制图形 (3)渲染图形 如果在layer上画东西,与上面的过程类似. 代码示例: 新建一个类,让该类继承自CALayer YYMylayer.m文件 1 // 2 // YYMylayer.m 3 // 05-自定义l

html5开发手机打电话发短信功能,html5的高级开发,html5开发大全,html手机电话短信功能详解

在很多的手机网站上,有打电话和发短信的功能,对于这些功能是如何实现的呢.其实不难,今天我们就用html5来实现他们.简单的让你大开眼界. HTML5 很容易写,但创建网页时,您经常需要重复做同样的任务,如创建表单.在这...有 HTML5 启动模板.空白图片.打电话和发短信.自动完成等等,帮助你提高开发效率的同时,还带来了更炫的功能.好了,我们今天就来做一做看看效果吧!! 看代码: <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitio