iOS 不规则的ImageView「建议收藏」

iOS 不规则的ImageView

大家好,又见面了,我是全栈君。

我们在做iOS开发的时候,往往须要实现不规则形状的头像,如:

iOS 不规则的ImageView「建议收藏」

那怎样去实现?

通常图片都是矩形的,假设想在client去实现不规则的头像,须要自己去实现。

1.使用layer去实现, 见http://blog.csdn.net/johnzhjfly/article/details/39993345

2.使用CAShapeLayer, CALayer怎样去实现

我们来看看怎样使用CAShapeLayer去实现,

定义一个ShapedImageView。继承于UIView, 代码例如以下:

#import "ShapedImageView.h"

@interface ShapedImageView()
{
    CALayer      *_contentLayer;
    CAShapeLayer *_maskLayer;
}
@end

@implementation ShapedImageView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup
{
    _maskLayer = [CAShapeLayer layer];
    _maskLayer.path = [UIBezierPath bezierPathWithOvalInRect:self.bounds].CGPath;
    _maskLayer.fillColor = [UIColor blackColor].CGColor;
    _maskLayer.strokeColor = [UIColor redColor].CGColor;
    _maskLayer.frame = self.bounds;
    _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
    _maskLayer.contentsScale = [UIScreen mainScreen].scale;
    
    _contentLayer = [CALayer layer];
    _contentLayer.mask = _maskLayer;
    _contentLayer.frame = self.bounds;
    [self.layer addSublayer:_contentLayer];
    
}

- (void)setImage:(UIImage *)image
{
    _contentLayer.contents = (id)image.CGImage;
}

@end

声明了用于maskLayer个CAShapedLayer。 CAShapedLayer有个path的属性。将内容Layer的mask设置为maskLayer, 就能够获取到我们想要的形状。

path我们能够使用CAMutablePath随意的构造,上述的代码执行想过例如以下:

iOS 不规则的ImageView「建议收藏」

假设将代码改成

    _maskLayer = [CAShapeLayer layer];
    _maskLayer.path = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:20].CGPath;
    _maskLayer.fillColor = [UIColor blackColor].CGColor;
    _maskLayer.strokeColor = [UIColor redColor].CGColor;
    _maskLayer.frame = self.bounds;
    _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
    _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //很关键设置自己主动拉伸的效果且不变形
    
    _contentLayer = [CALayer layer];
    _contentLayer.mask = _maskLayer;
    _contentLayer.frame = self.bounds;
    [self.layer addSublayer:_contentLayer];

的效果:

iOS 不规则的ImageView「建议收藏」

假设将代码改成:

    CGMutablePathRef path = CGPathCreateMutable();
    CGPoint origin = self.bounds.origin;
    CGFloat radius = CGRectGetWidth(self.bounds) / 2;
    CGPathMoveToPoint(path, NULL, origin.x, origin.y + 2 *radius);
    CGPathMoveToPoint(path, NULL, origin.x, origin.y + radius);
    
    CGPathAddArcToPoint(path, NULL, origin.x, origin.y, origin.x + radius, origin.y, radius);
    CGPathAddArcToPoint(path, NULL, origin.x + 2 * radius, origin.y, origin.x + 2 * radius, origin.y + radius, radius);
    CGPathAddArcToPoint(path, NULL, origin.x + 2 * radius, origin.y + 2 * radius, origin.x + radius, origin.y + 2  * radius, radius);
    CGPathAddLineToPoint(path, NULL, origin.x, origin.y + 2 * radius);
    
    _maskLayer = [CAShapeLayer layer];
    _maskLayer.path = path;
    _maskLayer.fillColor = [UIColor blackColor].CGColor;
    _maskLayer.strokeColor = [UIColor clearColor].CGColor;
    _maskLayer.frame = self.bounds;
    _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
    _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //很关键设置自己主动拉伸的效果且不变形
    
    _contentLayer = [CALayer layer];
    _contentLayer.mask = _maskLayer;
    _contentLayer.frame = self.bounds;
    [self.layer addSublayer:_contentLayer];

将是这个效果:

iOS 不规则的ImageView「建议收藏」

理论上我们能够构造出随意想要的形状。可是有些形状假设你不熟悉几何知识的话是构造不出正确的

path的,从代码上我们能够看到我们能够通过设置CALayer的contents属性来设置显示的内容,那我们

是不是能够通过设置CAShapedLayer的contents来设置maskLayer呢?答案是肯定的,代码例如以下:

    _maskLayer = [CAShapeLayer layer];
    _maskLayer.fillColor = [UIColor blackColor].CGColor;
    _maskLayer.strokeColor = [UIColor clearColor].CGColor;
    _maskLayer.frame = self.bounds;
    _maskLayer.contentsCenter = CGRectMake(0.5, 0.5, 0.1, 0.1);
    _maskLayer.contentsScale = [UIScreen mainScreen].scale;                 //很关键设置自己主动拉伸的效果且不变形
    _maskLayer.contents = (id)[UIImage imageNamed:@"gray_bubble_right@2x.png"].CGImage;
    
    _contentLayer = [CALayer layer];
    _contentLayer.mask = _maskLayer;
    _contentLayer.frame = self.bounds;
    [self.layer addSublayer:_contentLayer];

gray_bubble_right就是你想要的形状,执行效果例如以下:

iOS 不规则的ImageView「建议收藏」

不停的改变CALayer的一个坏处就是很的损耗性能,假设你有一个cell的列表。每一个列表有个头像的话。高速滑动的时候。你会发现很的卡。

此时理想的解决方式是使用CGPath或者UIBezierPath构建不规则的path,然后clip画出来。这里就不具体解说了。

演示样例代码例如以下:

- (UIImage *)maskImage
{
    // start with an image
    UIImage * fooImage = self;//[UIImage imageNamed:@"foo.png"];
    CGRect imageRect = CGRectMake(0, 0, fooImage.size.width, fooImage.size.height);
    // set the implicit graphics context ("canvas") to a bitmap context for images
    UIGraphicsBeginImageContextWithOptions(imageRect.size, NO, 0.0);
    // create a bezier path defining rounded corners
    UIBezierPath * path = [UIBezierPath bezierPathWithRect:imageRect];
    CGFloat radius = fooImage.size.width / 2.5;
    CGFloat _radius = radius;
    //construct your shaped path
    [path moveToPoint:CGPointMake(0, 0)];
    [path addArcWithCenter:CGPointMake(radius, radius) radius:_radius startAngle:M_PI endAngle:3 * M_PI / 2 clockwise:TRUE];
    [path moveToPoint:CGPointMake(fooImage.size.width, 0)];
    [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, radius) radius:_radius startAngle:3 * M_PI / 2 endAngle:2 * M_PI clockwise:TRUE];
    [path moveToPoint:CGPointMake(fooImage.size.width, fooImage.size.height)];
    [path addArcWithCenter:CGPointMake(fooImage.size.width - radius, fooImage.size.height - radius) radius:_radius startAngle:0 endAngle:M_PI / 2 clockwise:TRUE];
    [path moveToPoint:CGPointMake(0, fooImage.size.height)];
    [path addArcWithCenter:CGPointMake(radius, fooImage.size.height - radius) radius:_radius startAngle:M_PI / 2 endAngle:M_PI clockwise:TRUE];
    path.flatness = 1000;
    path.lineCapStyle = kCGLineCapRound;
    path.lineJoinStyle = kCGLineJoinRound;
    // use this path for clipping in the implicit context
    [path addClip];
    // draw the image into the implicit context
    [fooImage drawInRect:imageRect];
    // save the clipped image from the implicit context into an image
    UIImage *maskedImage = UIGraphicsGetImageFromCurrentImageContext();
    // cleanup
    UIGraphicsEndImageContext();
    return maskedImage;
}

源码

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115792.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • idea 2021.10.3 激活码【2021最新】

    (idea 2021.10.3 激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~1STL5S9V8F-eyJsaWNlbnNlSWQiOi…

    2022年3月27日
    73
  • c语言中break和continue的用法和区别

    c语言中break和continue的用法和区别break与continue的的用法以及区别1.当它们用在循环语句的循环体时,break用于立即退出本层循环,而continue仅仅结束本次循环(本次循环体内不执continue语句后的其它语句,但下一次循环还会继续执行。2.如果有多层循环时,break只会跳出本层循环,不会跳出其他层的循环.3.break可用于switch语句,表示跳出整个switch语句块,而contin…

    2025年10月25日
    6
  • 计算机三级-数据库技术

    计算机三级-数据库技术三级数据库技术知识点总结1数据字典是对系统种各类数据描述的集合,包括数据项,数据结构,数据流,数据存储和处理过程五个部分2数据模型的三要素:数据结构、数据操作和完整性约束3数据库系统:一般由数据库、操作系统、数据库管理系统(及其工具)、应用系统、数据库管理人员和用户构成4数据模型:数据模型是数据库系统的数学形式框架,是数据库系统的核心和基础5数据模型的分类:概念模型,也称信息…

    2022年6月18日
    49
  • Promise用法详解(一)

    Promise用法详解(一)Promise基本概念Promise是一个构造函数,所以可以new出一个Promise的实例在Promise上有两个函数resolve(成功之后的回调函数)和reject(失败后的回调函数)在Promise构造函数的prototype属性上,有一个.then()方法。所以只要是Promise构造函数创建的实例,都可以访问到.then()方法Promise表示一个一…

    2022年6月16日
    40
  • 神思第二代身份证验证系统怎么拍照_神思二代身份证验证器没反应

    神思第二代身份证验证系统怎么拍照_神思二代身份证验证器没反应开发的平台中涉及到读取身份证信息,采用的是神思第二代身份证验证系统。一、下载驱动本设备型号:SS628(100)神思官网下载相应的驱动和演示Demo,下载之前需要根绝设备序号在官网进行用户注册登录http://www.sdses.com/index.php?c=category&id=73下载完成以后打开:  二、安装驱动 第一次插上机具以后 设…

    2022年4月19日
    139
  • 毕业三年「建议收藏」

    如约而至,一年一度的“毕业N年”系列,2018,毕业三年了。生活这一年生活轨迹变化很大,也清晰了很多。去年底在家里买了房,跟女朋友定了亲,接下来可能就只剩到哪里定居的问题了。学会了做饭,本以为做饭很麻烦,其实逛逛菜市场做做饭,比想象中简单自在多了,很多喜欢吃的东西都可以自己做来试试看,没想到的是,大肠吃着那么香,做起来那么臭,还用一个锅的教训,知道了不粘锅竟然不能用来炸东西。工…

    2022年3月11日
    37

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号