Circular UIImageView w UITableView bez spadku wydajności?


82

Mam UIImageViewna każdej z moich UITableViewkomórek, które wyświetlają zdalny obraz (używając SDWebImage). Zrobiłem kilka QuartzCorestylizacji warstw w widoku obrazu, na przykład:

UIImageView *itemImageView = (UIImageView *)[cell viewWithTag:100];
    itemImageView.layer.borderWidth = 1.0f;
    itemImageView.layer.borderColor = [UIColor concreteColor].CGColor;
    itemImageView.layer.masksToBounds = NO;
    itemImageView.clipsToBounds = YES;

Więc teraz mam kwadrat 50x50 z delikatną szarą obwódką, ale chciałbym, aby był okrągły, a nie kwadratowy. Aplikacja Hemoglobeużywa okrągłych obrazów w widokach tabel i właśnie taki efekt chciałbym osiągnąć. Jednak nie chcę tego używać cornerRadius, ponieważ obniża to mój przewijany FPS.

Oto Hemoglobepokazujący okrągły UIImageViews:

wprowadź opis obrazu tutaj

Czy jest sposób, aby uzyskać taki efekt? Dzięki.


1
not cornerRadius wpływa na wydajność, masksToBounds / clipsToBounds to problem
Calin Chitu

Odpowiedzi:


141

Po prostu ustaw cornerRadiuspołowę szerokości lub wysokości (zakładając, że widok twojego obiektu jest kwadratowy).

Na przykład, jeśli szerokość i wysokość widoku obiektu to 50:

itemImageView.layer.cornerRadius = 25;

Aktualizacja - jak wskazuje użytkownik atulkhatri, nie zadziała, jeśli nie dodasz:

itemImageView.layer.masksToBounds = YES;

30
Dlaczego to może być najlepsza odpowiedź? Cóż, nie sądzę. Korzystanie z cornerRadius powoduje słabą wydajność w widoku przewijania, szczególnie w urządzeniach iPhone4.
Danny Xu

11
Podobał mi się punkt „ustaw cornerRadius na połowę szerokości lub wysokości”, ale po prostu nie zapomnij dodać „itemImageView.layer.masksToBounds = YES;” inaczej to nie zadziała.
atulkhatri

Nawiasem mówiąc, jak skomentował Danny Xu, zmniejszy to wydajność przewijania widoku tabeli, dlatego należy tego unikać w komórkach widoku tabeli.
atulkhatri

4
powinno to rozwiązać problem z wydajnością przewijania widoku tabeli. self.imageView.layer.shouldRasterize = TAK; self.imageView.layer.rasterizationScale = [UIScreen mainScreen] .scale;
hishboy

Dla Swift3: itemImageView.layer.masksToBounds = true;
Loïs Talagrand


14

Użyj tego kodu .. To będzie pomocne ...

    UIImage* image = ...;
    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:50.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();

U mnie działa dobrze. :)


jego naprawdę bardzo proste używanie tego kodu !! dzięki @Shivam
Anilkumar iOS - ReactNative

10

Oto bardziej aktualna metoda wykorzystująca IBDesignable i IBInspectable do podklasy UIImageView

@IBDesignable class RoundableUIImageView: UIImageView {
    private var _round = false
    @IBInspectable var round: Bool {
        set {
            _round = newValue
            makeRound()
        }
        get {
            return self._round
        }
    }
    override internal var frame: CGRect {
        set {
            super.frame = newValue
            makeRound()
        }
        get {
            return super.frame
        }

    }

    private func makeRound() {
        if self.round == true {
            self.clipsToBounds = true
            self.layer.cornerRadius = (self.frame.width + self.frame.height) / 4
        } else {
            self.layer.cornerRadius = 0
        }
    }

    override func layoutSubviews() {
            makeRound()
    }
}

Musiałem dodać następujący kod, aby działał dla mnie (wewnątrz komórki widoku tabeli): override func layoutSubviews () {makeRound ()}
herbert

1
+ 1 dla @herbert. Całkowicie zadziałało, kiedy nadpisuję layoutSubviews wewnątrz klasy, powinieneś zaktualizować kod
Abdoelrhman

Dziękuję Ci!! W końcu zrobiłem to (podklasa, ale w Objective-C), aby obsłużyć niektóre okrągłe UIImageViews, które po prostu nie STAY ROUND.
John Stewart

7

Tak, to jest możliwe, aby dać layer.cornerRadius (trzeba dodać #import <QuartzCore/QuartzCore.h>)
do tworzenia okrągły żadnej kontroli, ale w Twoim przypadku zamiast zestawu layerz UIImageViewto jest najlepszy sposób, aby stworzyć swój wizerunek jako okrągłe i dodać go na UIImageViewktóre mają backGroundColorto ClearColor.

Odnieś się również do tego Two Source of code.

https://www.cocoacontrols.com/controls/circleview

i

https://www.cocoacontrols.com/controls/mhlazytableimages

Może to być pomocne w Twoim przypadku:


4
Wreszcie wydaje mi się, że tylko @iPatel dba o wydajność. Uważaj na cornerRadius, jeśli chcesz uzyskać wysoką wydajność podczas przewijania.
Danny Xu

Jestem trochę zdezorientowany ... dlaczego opublikowałeś link do projektu z widokiem kręgu? To nie ma nic wspólnego z pytaniem ani odpowiedzią, której udzieliłeś.
user717452

@iPatel - aktualizacja: drugi link został wycofany przez autora i nie można go już pobrać.
trdavidson

3

Ustaw wysokość i szerokość UIImageView, aby były takie same, np .: Height=60& Width = 60, wtedy cornerRadiuspowinno być dokładnie połowę. W moim przypadku zostawiłem 30. Zadziałało dla mnie.

 self.imageView.layer.cornerRadius = 30;
 self.imageView.layer.borderWidth = 3;
 self.imageView.layer.borderColor = [UIColor whiteColor].CGColor;
 self.imageView.layer.masksToBounds = YES;

2

Jeśli używasz jakiegoś autoukładu i różnych wysokości komórek, lepiej zrób to w ten sposób:

   override func layoutSubviews() {
        super.layoutSubviews()
        logo.layer.cornerRadius = logo.frame.size.height / 2;
        logo.clipsToBounds      = true;
    }

1

Używam klasy Round Image View… Więc po prostu używam jej zamiast UIImageView i nie mam nic do poprawiania…

Ta klasa rysuje również opcjonalną ramkę wokół koła. Często wokół okrągłych zdjęć znajduje się ramka.

Nie jest to podklasa UIImageView, ponieważ UIImageView ma własny mechanizm renderowania i nie wywołuje metody drawRect.

Interfejs:

#import <UIKit/UIKit.h>

@interface MFRoundImageView : UIView

@property(nonatomic,strong) UIImage* image;

@property(nonatomic,strong) UIColor* strokeColor;
@property(nonatomic,assign) CGFloat strokeWidth;

@end

Realizacja :

#import "MFRoundImageView.h"


@implementation MFRoundImageView

-(void)setImage:(UIImage *)image
{
    _image = image;
    [self setNeedsDisplay];
}

-(void)setStrokeColor:(UIColor *)strokeColor
{
    _strokeColor = strokeColor;
    [self setNeedsDisplay];
}

-(void)setStrokeWidth:(CGFloat)strokeWidth
{
    _strokeWidth = strokeWidth;
    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGPathRef path = CGPathCreateWithEllipseInRect(self.bounds, NULL);
    CGContextAddPath(ctx, path);
    CGContextClip(ctx);
    [self.image drawInRect:rect];

    if ( ( _strokeWidth > 0.0f ) && _strokeColor ) {
        CGContextSetLineWidth(ctx, _strokeWidth*2); // Half border is clipped
        [_strokeColor setStroke];
        CGContextAddPath(ctx, path);
        CGContextStrokePath(ctx);
    }
    CGPathRelease(path);
}

@end

1

Użyteczne rozwiązanie w Swiftużyciu extension:

extension UIView{
  func circleMe(){
      let radius = CGRectGetWidth(self.bounds) / 2
      self.layer.cornerRadius = radius
      self.layer.masksToBounds = true
  }
}

Stosowanie:

self.venueImageView.circleMe()

Czy nie byłoby lepiej zastosować rozszerzenie UIImageView? Ten kod działa, ale sprawia, że ​​rozszerzenie jest ogólne dla wszystkich UIViewobiektów.
swiftcode

UIImageViewjuż sięga od UIView. W niektórych przypadkach może być konieczne zakreślenie niektórych UIViews, więc ta metoda będzie działać dla wszystkich.
Hossam Ghareeb

0

Tworzenie okrągłego widoku obrazu, co jest dość łatwe dzięki poniższemu linkowi SO, wystarczy mieć niestandardowe komórki dla widoku tabeli zamiast przydzielać wszystko w metodzie cellForRowAtIndexPath.

jak zrobić okrągły przycisk z tłem obrazu w iPhonie?

Powyższy link daje przykład przycisków, po prostu użyj go do widoków obrazów.


0

Jeśli wyświetlasz obrazy na jednolitym kolorze tła, prostym rozwiązaniem może być użycie obrazu nakładki z przezroczystym okręgiem pośrodku.

W ten sposób nadal możesz używać kwadratowych obrazów i dodawać nad nimi okrągły obraz, aby uzyskać okrągły efekt.

Jeśli nie musisz manipulować obrazami ani wyświetlać ich na złożonym kolorze tła, może to być proste rozwiązanie bez spadku wydajności.


Nie, ja nie. To tylko proste ładowanie, automatyczne buforowanie (kwadratowa miniatura) i wyświetlanie.
swiftcode

To naprawdę wyszło. Używałem wcześniej tego trudnego sposobu. Ale teraz nie jest odpowiedni dla mojej nowej wersji aplikacji.
Danny Xu

0

Szybko , w Twojej viewDidLoadmetodzie, z userImagegniazdem:

self.userImage.layer.borderWidth = 1;
self.userImage.layer.borderColor = UIColor.whiteColor().CGColor;
self.userImage.layer.cornerRadius = self.userImage.frame.size.width / 2;
self.userImage.clipsToBounds = true;

0

W języku Swift użyj tego rozszerzenia dla CircularImageView lub RoundedImageView:

extension UIView {

    func circular(borderWidth: CGFloat = 0, borderColor: UIColor = UIColor.whiteColor()) {
        let radius = CGRectGetWidth(self.bounds) / 2
        self.layer.cornerRadius = radius
        self.layer.masksToBounds = true

        self.layer.borderWidth = borderWidth
        self.layer.borderColor = borderColor.CGColor
    }

    func roundedCorner(borderWidth: CGFloat = 0, borderColor: UIColor = UIColor.whiteColor()) {
        let radius = CGRectGetWidth(self.bounds) / 2
        self.layer.cornerRadius = radius / 5
        self.layer.masksToBounds = true

        self.layer.borderWidth = borderWidth
        self.layer.borderColor = borderColor.CGColor
    }

}

Stosowanie:

self.ImageView.circular()
self.ImageView.roundedCorner()

0

W przypadku okrągłego widoku obrazu użyj poniższego kodu.

self.imageView.layer.cornerRadius = self.imageView.frame.size.width / 2;
self.imageView.clipsToBounds = true

Nie zapomnij zmienić cornerRadius w metodzie viewDidLayoutSubviews twojego UIView.

Przykład:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.imageView.layer.cornerRadius = self.imageView.frame.size.width / 2;
    self.imageView.clipsToBounds = true
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.