代码之家  ›  专栏  ›  技术社区  ›  Jablair

uiimage上的圆角

  •  57
  • Jablair  · 技术社区  · 16 年前

    我正在尝试在iPhone上用圆角绘制图像,这是“联系人”应用程序中的联系人图像。我有一些通常可以工作的代码,但它偶尔会在uiimage绘制例程中崩溃,其中 EXEC_BAD_ACCESS - KERN_INVALID_ADDRESS . 我想这可能与 cropping question 几周前我问过,但我相信我设置的剪辑路径是正确的。

    这是我正在使用的代码——当它没有崩溃时,结果看起来很好,任何想要获得相似外观的人都可以随意借用代码。

    - (UIImage *)borderedImageWithRect: (CGRect)dstRect radius:(CGFloat)radius {
        UIImage *maskedImage = nil;
    
        radius = MIN(radius, .5 * MIN(CGRectGetWidth(dstRect), CGRectGetHeight(dstRect)));
        CGRect interiorRect = CGRectInset(dstRect, radius, radius);
    
        UIGraphicsBeginImageContext(dstRect.size);
        CGContextRef maskedContextRef = UIGraphicsGetCurrentContext();
        CGContextSaveGState(maskedContextRef);
    
        CGMutablePathRef borderPath = CGPathCreateMutable();
        CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(180), PNDegreeToRadian(270), NO);
        CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMinY(interiorRect), radius, PNDegreeToRadian(270.0), PNDegreeToRadian(360.0), NO);
        CGPathAddArc(borderPath, NULL, CGRectGetMaxX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(0.0), PNDegreeToRadian(90.0), NO);
        CGPathAddArc(borderPath, NULL, CGRectGetMinX(interiorRect), CGRectGetMaxY(interiorRect), radius, PNDegreeToRadian(90.0), PNDegreeToRadian(180.0), NO);
    
        CGContextBeginPath(maskedContextRef);
        CGContextAddPath(maskedContextRef, borderPath);
        CGContextClosePath(maskedContextRef);
        CGContextClip(maskedContextRef);
    
        [self drawInRect: dstRect];
    
        maskedImage = UIGraphicsGetImageFromCurrentImageContext();
        CGContextRestoreGState(maskedContextRef);
        UIGraphicsEndImageContext();
    
        return maskedImage;
    }
    

    这是事故记录。每次我撞车的时候看起来都一样

    Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
    Exception Codes: KERN_INVALID_ADDRESS at 0x6e2e6181
    Crashed Thread:  0
    
    Thread 0 Crashed:
    0   com.apple.CoreGraphics          0x30fe56d8 CGGStateGetRenderingIntent + 4
    1   libRIP.A.dylib                  0x33c4a7d8 ripc_RenderImage + 104
    2   libRIP.A.dylib                  0x33c51868 ripc_DrawImage + 3860
    3   com.apple.CoreGraphics          0x30fecad4 CGContextDelegateDrawImage + 80
    4   com.apple.CoreGraphics          0x30feca40 CGContextDrawImage + 368
    5   UIKit                           0x30a6a708 -[UIImage drawInRect:blendMode:alpha:] + 1460
    6   UIKit                           0x30a66904 -[UIImage drawInRect:] + 72
    7   MyApp                           0x0003f8a8 -[UIImage(PNAdditions) borderedImageWithRect:radius:] (UIImage+PNAdditions.m:187)
    
    12 回复  |  直到 6 年前
        1
  •  163
  •   MagicSeth Habib    15 年前

    iPhone3.0及更高版本提供了一种更简单的方法。每个基于视图的对象都有一个关联的层。每一层都可以设置一个角半径,这将为您提供所需的:

    UIImageView * roundedView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"wood.jpg"]];
    // Get the Layer of any view
    CALayer * l = [roundedView layer];
    [l setMasksToBounds:YES];
    [l setCornerRadius:10.0];
    
    // You can even add a border
    [l setBorderWidth:4.0];
    [l setBorderColor:[[UIColor blueColor] CGColor]];
    
        2
  •  25
  •   Jonny    11 年前

    我要在这里回答题目中的问题。

    试试这个类别。

    uiimage+添加.h

    #import <UIKit/UIKit.h>
    
    @interface UIImage (additions)
    -(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS;
    @end
    

    uiimage+添加.m

    #import "UIImage+additions.h"
    
    @implementation UIImage (additions)
    -(UIImage*)makeRoundCornersWithRadius:(const CGFloat)RADIUS {
        UIImage *image = self;
    
        // Begin a new image that will be the new image with the rounded corners
        // (here with the size of an UIImageView)
        UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
    
        const CGRect RECT = CGRectMake(0, 0, image.size.width, image.size.height);
        // Add a clip before drawing anything, in the shape of an rounded rect
        [[UIBezierPath bezierPathWithRoundedRect:RECT cornerRadius:RADIUS] addClip];
        // Draw your image
        [image drawInRect:RECT];
    
        // Get the image, here setting the UIImageView image
        //imageView.image
        UIImage* imageNew = UIGraphicsGetImageFromCurrentImageContext();
    
        // Lets forget about that we were drawing
        UIGraphicsEndImageContext();
    
        return imageNew;
    }
    @end
    
        3
  •  21
  •   cuasijoe    15 年前

    如果AppIconImage是uiImageView,则:

    appIconImage.image = [UIImage imageWithContentsOfFile:@"image.png"]; 
    appIconImage.layer.masksToBounds = YES;
    appIconImage.layer.cornerRadius = 10.0;
    appIconImage.layer.borderWidth = 1.0;
    appIconImage.layer.borderColor = [[UIColor grayColor] CGColor];
    

    还要记住:

    #import <QuartzCore/QuartzCore.h>
    
        4
  •  4
  •   Lounges    16 年前

    我不能对你的撞车有任何了解,但我想我可以提供另一个绕过角落的选择。在我正在处理的应用程序中,也出现了类似的问题。我不是写任何代码,而是覆盖另一个掩盖角落的图像。

        5
  •  4
  •   fjoachim    16 年前

    如果在后台线程中调用方法(borderedimagewithrect),则可能会发生崩溃,因为uigraphics函数不是线程安全的。在这种情况下,必须使用cgBitmapContextCreate()创建上下文—请参阅来自SDK的“反射”示例代码。

        6
  •  3
  •   Max Motovilov    16 年前

    最简单的方法是嵌入一个残疾人[!]圆形矩形[不是自定义的!]按钮在视图中(甚至可以在界面生成器中完成所有操作),并将图像与之关联。uibutton的图像设置消息与uiimageview不同(与uiimageview相比),但总体而言,kludge工作起来很有魅力。使用setimage:forstate:如果您想要一个居中的图标或backgroundimage:forstate:如果您想要整个图像的角被剪切(如联系人)。当然,如果您想在DrawRect中显示大量这些图像,这不是正确的方法,但更可能的是,嵌入视图正是您所需要的…

        7
  •  2
  •   Community CDub    8 年前

    我重申一下 fjoachim's answer :在单独线程上运行时尝试绘制时要小心,否则可能会 EXC_BAD_ACCESS 错误。

    我的解决方法是这样的:

    UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
    [self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];
    

    (在我的例子中,我正在调整/缩放uiimages。)

        8
  •  2
  •   Jablair    16 年前

    事实上,在纽约的iPhone技术讲座上,我有机会和苹果公司的人讨论这个问题。当我们谈论它的时候,他很确定这不是线程问题。相反,他认为我需要保留调用时生成的图形上下文 UIGraphicsBeginImageContext . 这似乎违反了处理保留规则和命名方案的一般规则,但这个家伙很肯定他以前见过这个问题。

    如果记忆被另一条线涂鸦,那当然可以解释为什么我只是偶尔看到这个问题。

    我没有时间重新访问代码并测试修复,但PCheese的评论让我意识到我没有在这里发布信息。

    …除非我把它写错了 uigraphicsBeginImageContext 应该是 CGBitmapContextCreate

        9
  •  1
  •   benzado    16 年前

    如果它只是在某些时候崩溃,那么就要弄清楚崩溃案例的共同点。DStrect每次都一样吗?这些图片的大小有什么不同吗?

    另外,你需要 CGPathRelease(borderPath) 尽管我怀疑泄漏是你的问题。

        10
  •  0
  •   tkanzakic Wolfgang    10 年前
    UIImage *originalImage = [UIImage imageNamed:@"OriginalImage.png"] 
    [self performSelectorOnMainThread:@selector(displayImageWithRoundedCorners:) withObject:originalImage waitUntilDone:YES];
    
        11
  •  0
  •   Naresh    6 年前

    在Swift 4.2和Xcode 10.1中

    let imgView = UIImageView()
    imgView.frame = CGRect(x: 200, y: 200, width: 200, height: 200)
    imgView.image = UIImage(named: "yourimagename")
    imgView.imgViewCorners()
    //If you want complete round shape
    //imgView.imgViewCorners(width: imgView.frame.width)//Pass ImageView width
    view.addSubview(imgView)
    
    extension UIImageView {
    //If you want only round corners
    func imgViewCorners() {
        layer.cornerRadius = 10
        layer.borderWidth = 1.0
        layer.borderColor = UIColor.red.cgColor
        layer.masksToBounds = true
    }
    //If you want complete round shape
    func imgViewCorners(width:CGFloat) {
        layer.cornerRadius = width/2
        layer.borderWidth = 1.0
        layer.borderColor = UIColor.red.cgColor
        layer.masksToBounds = true
    }
    
        12
  •  -1
  •   Chris Emerson    8 年前

    在XIB或故事板中设置图像(图像宽度和高度41x41)。

    FirstView控制器.h

    @interface....
    
    IBOutlet UIImageView *testImg;
    
    @end
    

    FirstView控制器.m

    -(void)viewDidLoad{
            testImg.layer.backgroundColor=[[UIColor clearColor] CGColor];
            testImg.layer.cornerRadius=20;
            testImg.layer.masksToBounds = YES;
        }