14

我为我的UIImageView每个UITableViewCells, 作为缩略图使用。我的代码用于SDWebImage从我的后端异步抓取这些图像并将它们加载进去,然后缓存它们。这工作正常。

MyUIImageView是一个 50x50 的正方形,在 Interface Builder 中创建。它的背景是不透明的白色(与我的UITableViewCell背景颜色相同,用于性能)。但是,我想使用光滑的角落以获得更好的美感。如果我这样做:

UIImageView *itemImageView = (UIImageView *)[cell viewWithTag:100];
    itemImageView.layer.cornerRadius = 2.5f;
    itemImageView.layer.masksToBounds = NO;
    itemImageView.clipsToBounds = YES;

我的 tableview 立即下降了大约 5-6 帧,在快速滚动期间限制了大约 56 FPS(这没关系),但是当我拖动刷新控件时,它有点滞后并下降到大约 40 FPS。如果我删除这cornerRadius条线,一切都很好,没有滞后。这已使用 Instruments 在 iPod touch 5G 上进行了测试。

有没有其他方法可以UIImageView对我的细胞进行四舍五入而不会对性能造成影响?我已经优化了我的cellForRowAtIndexPath,并且在没有cornerRadius.

4

4 回答 4

32

是的,这是因为cornerRadius 和clipToBounds 需要离屏渲染,我建议您从我的一个问题中阅读这些答案。我还引用了您应该看到的两个 WWDC 会议。
您可以做的最好的事情是在下载后立即获取图像,然后在另一个线程上调度一个围绕图像的方法。最好是处理图像而不是图像视图。

// Get your image somehow
UIImage *image = [UIImage imageNamed:@"image.jpg"];

// Begin a new image that will be the new image with the rounded corners 
// (here with the size of an UIImageView)
 UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);

 // Add a clip before drawing anything, in the shape of an rounded rect
  [[UIBezierPath bezierPathWithRoundedRect:imageView.bounds 
                        cornerRadius:10.0] addClip];
 // Draw your image
[image drawInRect:imageView.bounds];

 // Get the image, here setting the UIImageView image
  imageView.image = UIGraphicsGetImageFromCurrentImageContext();

 // Lets forget about that we were drawing
  UIGraphicsEndImageContext();

此处抓取的方法 您还可以子类化 tableviewcell 并覆盖 drawRect 方法。
肮脏但非常有效的方法是在 Photoshop 中使用内部 alpha 和单元格背景的匹配颜色绘制蒙版,并在带有图像的图像上添加另一个 imageView,而不是具有清晰背景颜色的不透明。

于 2013-07-11T12:44:29.583 回答
7

对此还有另一个很好的解决方案。我在我的项目中做过几次。如果你想创建一个圆角或其他东西,你可以在你的主图像前面使用一个封面图像。

例如,您想要制作圆角。在这种情况下,您需要一个方形图像层,中间有一个切出的圆圈。

通过使用此方法,您将获得 60fps 的内部滚动UITableViewUICollectionView. 因为这种方法不需要自定义UIImageView的屏幕外渲染(如头像等)。

于 2015-02-19T21:07:40.250 回答
5

非阻塞解决方案

作为对 Andrea 的回应的跟进,这里有一个函数将在后台运行他的代码。

+ (void)roundedImage:(UIImage *)image
          completion:(void (^)(UIImage *image))completion {
    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // 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);
        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:image.size.width/2] addClip];
        // Draw your image
        [image drawInRect:rect];

        // Get the image, here setting the UIImageView image
        UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();

        // Lets forget about that we were drawing
        UIGraphicsEndImageContext();
        dispatch_async( dispatch_get_main_queue(), ^{
            if (completion) {
                completion(roundedImage);
            }
        });
    });
}
于 2015-04-13T23:18:37.020 回答
2

Swift 3 版本的developer3124 的回答

func roundedImage(image: UIImage, completion: @escaping ((UIImage?)->(Void))) {
    DispatchQueue.global().async {
        // Begin a new image that will be the new image with the rounded corners
        // (here with the size of an UIImageView)
        UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
        let rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)

        // Add a clip before drawing anything, in the shape of an rounded rect
        UIBezierPath(roundedRect: rect, cornerRadius: image.size.width/2).addClip()

        // Draw your image
        image.draw(in: rect)

        // Get the image, here setting the UIImageView image
        guard let roundedImage = UIGraphicsGetImageFromCurrentImageContext() else {
            print("UIGraphicsGetImageFromCurrentImageContext failed")
            completion(nil)
            return
        }

        // Lets forget about that we were drawing
        UIGraphicsEndImageContext()

        DispatchQueue.main.async {
            completion(roundedImage)
        }
    }
}
于 2017-07-28T18:05:12.523 回答