2013-07-11 11 views
13

Uso uno per ciascuna delle mie UITableViewCells, come miniature. Il mio codice utilizza SDWebImage per prelevare in modo asincrono quelle immagini dal mio back-end e caricarle, quindi memorizzandole nella cache. Funziona beneUtilizzo di cornerRadius su UIImageView in UITableViewCell

Il mio UIImageView è un quadrato 50x50, creato in Interface Builder. Il suo sfondo è opaco, di colore bianco (come il mio colore di sfondo UITableViewCell, per prestazioni). Tuttavia, mi piacerebbe usare angoli smussati per una migliore estetica. Se faccio questo:

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

mia Tableview gocce intorno 5-6 fotogrammi immediatamente, tappatura circa 56 FPS durante lo scorrimento veloce (che va bene), ma quando ho trascinare e tirare il controllo di aggiornamento, ritarda un po 'e scende a circa 40 FPS. Se rimuovo la riga cornerRadius, tutto va bene e nessun ritardo. Questo è stato testato su un iPod touch 5G usando gli strumenti.

C'è un altro modo in cui potrei avere un arrotondato UIImageView per le mie celle e non subire un calo di prestazioni? Ho già ottimizzato il mio cellForRowAtIndexPath e ottengo 56-59 FPS mentre lo scorrimento veloce senza cornerRadius.

risposta

30

Sì, questo perché cornerRadius e clipToBounds richiedono il rendering offscreen, ti suggerisco di leggere queste risposte da uno dei miei question. Cito anche due sessioni del WWDC che dovresti vedere.
La cosa migliore che puoi fare è catturare l'immagine subito dopo il download e su un altro thread invia un metodo che arrotonda le immagini. È preferibile lavorare sull'immagine anziché sulla visualizzazione di immagini.

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

Metodo afferrato here È inoltre possibile creare una sottoclasse del tableviewcell e l'override del metodo drawRect.
Il modo sporco ma molto efficace è disegnare una maschera in Photoshop con alfa interno e attorno al colore corrispondente dello sfondo della cella e aggiungere un altro imageView, non opaco con un colore di sfondo chiaro, su quello con le immagini.

3

C'è un'altra buona soluzione per questo. L'ho fatto alcune volte nei miei progetti. Se vuoi creare angoli arrotondati o qualcos'altro, puoi semplicemente usare un'immagine di copertina davanti all'immagine principale.

Ad esempio, si desidera realizzare angoli arrotondati. In questo caso hai bisogno di un livello immagine quadrato con un cerchio ritagliato al centro.

Utilizzando questo metodo si otterrà 60 fps sullo scorrimento all'interno di UITableView o UICollectionView. Perché questo metodo non richiede il rendering offscreen per la personalizzazione di UIImageView (come avatar e così via).

4

Soluzione non bloccante

Per dare seguito alla risposta di Andrea, qui è una funzione che verrà eseguito il suo codice in background.

+ (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 versione di risposta di 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) 
     } 
    } 
}