美文网首页iOS图形处理相关iOS头条干货iOS备忘录
iOS/OC: Quartz2D画圆角矩形时的线宽不一致问题-

iOS/OC: Quartz2D画圆角矩形时的线宽不一致问题-

作者: 疯狂的向日葵 | 来源:发表于2016-06-27 19:48 被阅读604次

    版权声明:本文为博主原创文章,未经博主允许不得转载。

    圆角矩形一般直接AddArc...或者用BezierPath,

    + (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius;
    
    +(instancetype)ImageFromFrame:(CGSize)size
                      BorderColor:(UIColor *)color
                     BorderRadius:(CGFloat)radius
                      BorderWidth:(CGFloat)width
    {
        CGFloat x = size.width;
        CGFloat y = size.height;
        UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor (context,  1.0, 1.0, 1.0, 1.0);//设置填充颜色(白色)
        CGContextSetLineWidth(context, width);//线的宽度
        CGContextSetStrokeColorWithColor(context, color.CGColor);//线框颜色
    //方法1
        //    CGPathRef clippath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0,0, x, y)cornerRadius:radius].CGPath;
        //    CGContextAddPath(context, clippath);
    //方法2
        CGContextMoveToPoint(context, x, y-radius);  // 开始坐标右边开始
        CGContextAddArcToPoint(context, x, y, x-radius, y, radius);  // 右下角角度
        CGContextAddLineToPoint(context, radius, y);
        CGContextAddArcToPoint(context, 0, y, 0, y-radius, radius); // 左下角角度
        CGContextAddLineToPoint(context, 0, radius);
        CGContextAddArcToPoint(context, 0, 0, radius, 0, radius); // 左上角
        CGContextAddLineToPoint(context, x-radius, 0);
        CGContextAddArcToPoint(context, x, 0, x, radius, radius); // 右上角
        CGContextClosePath(context);
    
        CGContextDrawPath(context, kCGPathFillStroke); 
        UIImage *newImage=UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    

    这个方法看上去没什么问题,的确是按背景大小沿着路径画的,但是调试一下就会发现,当背景的clipsToBounds = YES时,画出来的圆角矩形圆角处的线宽和直线的线宽是不一致的,效果非常诡异.感觉边缘都被截去了,也就是说 画出的圆角矩形超出了背景大小

    9E7D47FF-40E5-4465-ACD7-0BC5F6983F4B.png

    找了好久,后发现一篇有用的博文

    跟Quartz2D的绘制时的抗锯齿机制有关
    http://my.oschina.net/lych0317/blog/126215
    具体原理看博文,不过里面的代码也是有问题的.

    正确完美的解决方案如下:

    路径及半径要往里扣除线宽的一半 !!!!

    UIImage的分类

    #import <UIKit/UIKit.h>
    @interface UIImage (JLImage)
    /**
     绘制圆角矩形
     
     @param size 画布大小
     @param borderColor 边缘颜色
     @param borderRadius 圆角半径
     @param borderWidth 线宽
     @param margin 上下左右间距
     */
    + (instancetype)roundRectImageWithFrame:(CGSize)size
                                borderColor:(UIColor *)borderColor
                               borderRadius:(CGFloat)borderRadius
                                borderWidth:(CGFloat)borderWidth
                                     margin:(CGFloat)margin;
    @end
    
    #import "UIImage+JLImage.h"
    @implementation UIImage (JLImage)
    + (instancetype)roundRectImageWithFrame:(CGSize)size
                                borderColor:(UIColor *)borderColor
                               borderRadius:(CGFloat)borderRadius
                                borderWidth:(CGFloat)borderWidth
                                     margin:(CGFloat)margin
    {
           CGFloat x = size.width;
        CGFloat y = size.height;
        CGFloat radius = borderRadius - margin;
        UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextSetRGBFillColor (context,  1.0, 1.0, 1.0, 1.0);//设置填充颜色(白色)
        CGContextSetLineWidth(context, borderWidth);//线的宽度
        CGContextSetStrokeColorWithColor(context, borderColor.CGColor);//线框颜色
        //绘制path 方法1
        CGPathRef clippath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(borderWidth/2 +margin,borderWidth/2 +margin, x - borderWidth - margin*2, y - borderWidth - margin*2)cornerRadius:radius].CGPath;
        CGContextAddPath(context, clippath);
        //绘制path 方法2
    //    CGContextMoveToPoint(context, x-borderWidth/2 -margin, y-radius - margin);  // 开始坐标右边开始
    //    CGContextAddArcToPoint(context, x-borderWidth/2 -margin, y-borderWidth/2 - margin, x-radius -margin, y-borderWidth/2-margin, radius - borderWidth/2);  // 右下角角度
    //    CGContextAddLineToPoint(context, radius+margin, y-borderWidth/2-margin);
    //    CGContextAddArcToPoint(context,  borderWidth/2+margin, y-borderWidth/2-margin, borderWidth/2+margin, y-radius-margin, radius-borderWidth/2); // 左下角角度
    //    CGContextAddLineToPoint(context, borderWidth/2 +margin, radius+margin);
    //    CGContextAddArcToPoint(context, borderWidth/2+margin, borderWidth/2+margin, radius+margin, borderWidth/2+margin, radius-borderWidth/2); // 左上角
    //    CGContextAddLineToPoint(context, x-radius-borderWidth/2-margin, borderWidth/2 +margin);
    //    CGContextAddArcToPoint(context, x-borderWidth/2- margin, borderWidth/2 +margin, x-borderWidth/2 - margin, radius +margin, radius-borderWidth/2); // 右上角
    //    CGContextClosePath(context);
        //填充
        CGContextDrawPath(context, kCGPathFillStroke); 
        UIImage *newImage=UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        
        return newImage;
    }
    @end
    

    方法1和方法2效果是一样的

    A2AC47A0-C9B5-48A8-86B9-8C498DC1C2C1.png

    相关文章

      网友评论

      • S型身材的猪:挺好的,解决了我的问题。不过值得说的是,margin必须要小于或等于半径borderRadius。如果margin比borderRadius还大,那么画出来的圆角是反方向的(凹的,非凸的)
        疯狂的向日葵:@乐升平 主要还是画的圆角矩形超出了view的bounds ,你设置cliptobounds=no看看
        S型身材的猪:我今天又发现一个蛮严重的问题,当线的宽度设置为矩形高的1/10,半径为线宽的3倍时,用贝赛尔曲线那种方法会有一个断开现象。不知你是否有空测试一下。我是在做圆角矩形的时候遇到的 ,不是图片。你画一个矩形 ,然后用你的这种方法设置圆角试一下,我不知道原因出在哪里

      本文标题:iOS/OC: Quartz2D画圆角矩形时的线宽不一致问题-

      本文链接:https://www.haomeiwen.com/subject/srozdttx.html