【问题标题】:Using cornerRadius on a UIImageView in a UITableViewCell在 UITableViewCell 中的 UIImageView 上使用cornerRadius
【发布时间】:2013-07-09 17:36:20
【问题描述】:

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

我的UIImageView 是一个 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 的情况下快速滚动时获得了 56-59 FPS。

【问题讨论】:

    标签: objective-c uitableview uiimageview quartz-graphics


    【解决方案1】:

    是的,这是因为cornerRadius 和clipToBounds 需要离屏渲染,我建议您从我的question 之一阅读这些答案。我还引用了您应该看到的两个 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();
    

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

        【解决方案3】:

        非阻塞解决方案

        作为对 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);
                    }
                });
            });
        }
        

        【讨论】:

          【解决方案4】:

          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)
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-03-11
            • 2013-11-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多