iOS之听说你想要一张圆形图片

传统依然是效果展示,请看下图 ↓


带边框的圆形图

这个显示效果的做法有很多:

方法一: 使用两张图片, 作为边框的背景图片和中间的图片,然后使用imageView的cornerRadius来做圆, 具体代码如下:
backImageView.layer.cornerRadius = backImageView.frame.size.width / 2;
backImageView.layer.masksToBounds = YES;
frontImageView.layer.cornerRadius = frontImageView.frame.size.width / 2;
frontImageView.layer.masksToBounds = YES;

但是很显然, 今天的主角并不是上边的方法.上边的做法需要两张图片来完成带边框的圆形图片,而接下来要介绍的方法并不需要两张图片, 只需要一张图片就可以!

方法二: 使用图形上下文, 生成一张带有边框的圆形图片, 话不多说, 代码如下:
// borderWidth 表示边框的宽度
CGFloat imageW = image.size.width + 2 * borderWidth;
CGFloat imageH = imageW;
CGSize imageSize = CGSizeMake(imageW, imageH);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
// borderColor表示边框的颜色
[borderColor set];
CGFloat bigRadius = imageW * 0.5;
CGFloat centerX = bigRadius;
CGFloat centerY = bigRadius;
CGContextAddArc(context, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
CGContextFillPath(context);
CGFloat smallRadius = bigRadius - borderWidth;
CGContextAddArc(context, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
CGContextClip(context);
[image drawInRect:CGRectMake(borderWidth, borderWidth, image.frame.size.width, image.frame.size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
接下来解释一下上边的代码
  1. 首先是原理: 画一个圆环, 宽度为borderWidth,然后将图片放入这个圆环中, 使其只显示圆环中的部分.
  2. 前三行代码: 得到带边框的图片的整体宽度和高度(因为要得到圆形图片, 所以需要宽和高相同), 同时得到一个CGSize对象留着后边用
  3. 代码:
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);

表示开启图形上下文, 我们来看一些头文件中的方法声明:

UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale)

第一个参数需要填入一个CGSize对象, 也就是第三行的imageSize,表示绘制图形的范围
第二个参数的布尔值表示是否透明, 选择NO即可
If the opaque parameter is YES, the alpha channel is ignored and the bitmap is treated as fully opaque
第三个参数的scale是比例因子, 我们填入0.0, 表示是以屏幕的比例来计算
If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen

  1. 代码:
CGContextRef context = UIGraphicsGetCurrentContext();

既然要使用上下文来绘制图片, 当然得获取当前的上下文对象了

  1. 代码:
[borderColor set];

先来看一下这个set的头文件注释

// Sets the fill and stroke colors in the current drawing context

给当前的上下文设置填充和描边的颜色, 说起填充色有没有想到画图软件中的填充 ?使用过PS的朋友应该很清楚.说白了这行代码的意思就是设置好颜色, 待会给上下文上色用...

  1. 代码:
CGFloat bigRadius = imageW * 0.5;
CGFloat centerX = bigRadius;
CGFloat centerY = bigRadius;
CGContextAddArc(context, centerX, centerY, bigRadius, 0, M_PI * 2, 0);

正常来讲画一个圆需要什么 ? 需要半径和圆心对不对
bigRadius 是带边框图片整体的绘制半径, 画圆需要半径, 这个就是!
centerX 和centerY 是圆心坐标的x和y
CGContextAddArc 这个方法表示给当前的上下文画一个圆弧, 我们来看下头文件的方法声明

void CGContextAddArc(CGContextRef cg_nullable c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

参数比较多, 我分别列出来其表示的意义:
@param c 上下文
@param x 圆弧中心点的x
@param y 圆弧中心点的y
@param radius 圆弧的半径(bigRadius)
@param startAngle 起始点的角度
@param endAngle 结束点的角度 M_PI * 2表示一周
@param clockwise 顺时针画圆弧填1 逆时针填0

  1. 代码:
CGContextFillPath(context);

填充当前上下文, 用什么填充 ? 当然是填充色! 到这里我们得到了一个半径为bigRadius, 颜色为填充色的圆形上下文

  1. 代码:
CGFloat smallRadius = bigRadius - borderWidth;
CGContextAddArc(context, centerX, centerY, smallRadius, 0, M_PI * 2, 0);

意义和 -代码6- 一样, 给当前的上下文(一个有颜色的圆)添加一个圆弧, 其中的smallRadius就是中间图片的半径

  1. 代码:
CGContextClip(context);

头文件是这么说的: Intersect the context's path with the current clip path and use the
resulting path as the clip path for subsequent rendering operations.
大意是将当前的上下文以当前的剪辑路径(代码8所画的圆弧)进行剪辑, 然后使用剪辑后的路径(代码8得到的圆弧)来进行后续的着色操作.
简单说就是使用 -代码7- 得到的圆形上下文中间的部分来进行后续的绘制...

  1. 代码:
[image drawInRect:CGRectMake(borderWidth, borderWidth, image.frame.size.width, image.frame.size.height)];

这个方法是将图片以给定的范围绘制到当前的图形上下文中, -代码9- 中已经得到了进行绘制操作的路径, 也就是说, 这张图只保留 -代码9- 中路径内的部分. 注意此时上下文已经变成了带边框的圆形图片了!

  1. 代码:
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

从当前上下文中得到图片并关闭图形上下文

到这里呢就算是结束了, 我们得到了一个带有边框的圆形图片, 从方法复杂性来说方法二比较复杂, 使用了图形上下文. 但是就得到圆形图片来说他们的意义不同.
方法一是用叠加的原理得到视觉上的带边框
方法二则完全生成了一张带边框的圆形图片

在日常开发中完成某项功能需要根据需求去决定如何实现, 同样的, 上边的两种方法也是, 如果想要一张自带边框的圆形图片使用方法二即可.

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

推荐阅读更多精彩内容