2013-07-11 10 views
13

Ich bin ein UIImageView für jedes meiner UITableViewCells verwenden, als Thumbnails. Mein Code verwendet SDWebImage, um diese Bilder asynchron aus meinem Backend zu übernehmen und sie zu laden und dann zwischenzuspeichern. Das funktioniert gut.Mit corner auf einem UIImageView in einem UITableViewCell

Meine UIImageView ist ein 50x50 Quadrat, in Interface Builder erstellt. Sein Hintergrund ist undurchsichtig, weiße Farbe (selbe wie meine UITableViewCell Hintergrundfarbe, für Leistung). Allerdings würde ich gerne glatte Ecken für eine bessere Ästhetik verwenden. Wenn ich dies tun:

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

Mein Tableview fällt um 5-6 Frames sofort, Capping etwa 56 FPS beim schnellen Scrollen (was in Ordnung ist), aber wenn ich die Refresh-Steuer ziehen und ziehen, hinkt es ein wenig und fällt auf etwa 40 FPS. Wenn ich die cornerRadius Linie entferne, ist alles in Ordnung und keine Verzögerung. Dies wurde auf einem iPod touch 5G mit Instrumenten getestet.

Gibt es einen anderen Weg, könnte ich eine abgerundete UIImageView für meine Zellen haben und keinen Leistungseinbruch erleiden? Ich hatte bereits meine cellForRowAtIndexPath optimiert und ich bekomme 56-59 FPS beim schnellen Scrollen ohne cornerRadius.

Antwort

30

Ja, das ist, weil corner und ClipToBounds Rendering erfordert Offscreen, empfehle ich Ihnen diese Antwort von einem meiner question zu lesen. Ich zitiere auch zwei WWDC-Sitzungen, die Sie sehen sollten.
Das Beste, was Sie tun können, ist, das Bild direkt nach dem Herunterladen zu schnappen und auf einem anderen Thread eine Methode zu versenden, die die Bilder umrundet. Es ist vorzuziehen, dass Sie an dem Bild statt an der Bildansicht arbeiten.

// 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(); 

Methode griff here Sie können auch die tableviewcell Unterklasse und die drawRect Methode außer Kraft setzen.
Die dreckige, aber sehr effektive Art ist eine Maske in Photoshop mit innen Alpha und um die passende Farbe des Hintergrunds der Zelle zu zeichnen und ein weiteres imageView, nicht undurchsichtig mit klarer Hintergrundfarbe, auf dem mit Bildern.

3

Es gibt eine andere gute Lösung dafür. Ich habe es ein paar Mal in meinen Projekten gemacht. Wenn Sie eine abgerundete Ecke oder etwas anderes erstellen möchten, können Sie einfach ein Titelbild vor Ihrem Hauptbild verwenden.

Zum Beispiel möchten Sie abgerundete Ecken machen. In diesem Fall benötigen Sie eine quadratische Bildschicht mit einem ausgeschnittenen Kreis in der Mitte.

Mit dieser Methode erhalten Sie 60 fps beim Scrollen innerhalb UITableView oder UICollectionView. Weil diese Methode kein Offscreen-Rendering für das Anpassen von UIImageView's (wie Avatare und etc.) benötigt.

4

Non Blocking-Lösung

Als Nachfolger von Andrea Antwort, hier ist eine Funktion, die seinen Code im Hintergrund ausgeführt wird.

+ (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); 
      } 
     }); 
    }); 
} 
0

Swift 3-Version Antwort des thedeveloper3124

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