Dodanie zaokrąglonego narożnika i cienia do UICollectionViewCell

106

Więc przejrzałem już różne posty dotyczące dodawania drugiego widoku w celu dodania cienia, ale nadal nie mogę go uruchomić, jeśli chcę go dodać UICollectionViewCell. Podklasowałem UICollectionViewCell, a oto mój kod, w którym dodaję różne elementy interfejsu użytkownika do widoku zawartości komórki i dodam cień do warstwy:

[self.contentView setBackgroundColor:[UIColor whiteColor]];

self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(0, 1);
self.layer.shadowRadius = 1.0;
self.layer.shadowColor = [UIColor blackColor].CGColor;
self.layer.shadowOpacity = 0.5;
[self.layer setShadowPath:[[UIBezierPath bezierPathWithRect:self.bounds] CGPath]];

Chciałbym wiedzieć, jak dodać zaokrąglony narożnik i cień UICollectionViewCell.

Vincent Yiu
źródło
Myślę, że musisz poprawić swoje pytanie, aby inni zrozumieli. To naprawdę nieporządne, o co prosiłeś
Dinesh Raja
ok zaktualizowane, chcę tylko wiedzieć, jak dodać zaokrąglony róg i cień do UICollectionViewCell
Vincent Yiu.
Nieco na bok - użyj shadowRadius LUB setShadowPath, nie ma sensu robić obu, ponieważ są to zasadniczo te same instrukcje w tym kontekście (wszystkie zaokrąglone rogi). Ścieżka cieni jest konieczna, gdy chcesz, aby bardziej złożone kształty lub zaokrąglone rogi nie były stosowane do wszystkich rogów.
Oliver Dungey

Odpowiedzi:

194

Żadne z tych rozwiązań nie zadziałało dla mnie. Jeśli umieścisz wszystkie widoki podrzędne w widoku zawartości UICollectionViewCell, którym prawdopodobnie jesteś, możesz ustawić cień na warstwie komórki i obramowanie na warstwie contentView, aby osiągnąć oba wyniki.

cell.contentView.layer.cornerRadius = 2.0f;
cell.contentView.layer.borderWidth = 1.0f;
cell.contentView.layer.borderColor = [UIColor clearColor].CGColor;
cell.contentView.layer.masksToBounds = YES;

cell.layer.shadowColor = [UIColor blackColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0f);
cell.layer.shadowRadius = 2.0f;
cell.layer.shadowOpacity = 0.5f;
cell.layer.masksToBounds = NO;
cell.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:cell.contentView.layer.cornerRadius].CGPath;

Swift 3.0

self.contentView.layer.cornerRadius = 2.0
self.contentView.layer.borderWidth = 1.0
self.contentView.layer.borderColor = UIColor.clear.cgColor
self.contentView.layer.masksToBounds = true

self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 2.0)
self.layer.shadowRadius = 2.0
self.layer.shadowOpacity = 0.5
self.layer.masksToBounds = false
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.contentView.layer.cornerRadius).cgPath
Mike Sabatini
źródło
9
To zadziałało dobrze dla mnie po dodaniucell.layer.backgroundColor = [UIColor clearColor].CGColor;
nacross
2
Masz jakiś pomysł, dlaczego to tylko zaokrągla moje górne rogi?
user3344977
@ user3344977 może przycina się dół? Jak w rogach są zaokrąglone, ale znajduje się poniżej widocznej części komórki
CoderNinja
5
Uważam, że to zaokrągla moje górne rogi, a nie także dolne rogi.
fatuhoku
2
Jak sprawić, by rogi pozostały okrągłe, gdy wybierasz / odznaczasz / przenosisz komórki? Moje rogi stają się prostopadłe za każdym razem, gdy oddycham na komórkę, po tym jak początkowo rysuje się prawidłowo.
Adrian
32

Wersja Swift 3:

cell.contentView.layer.cornerRadius = 10
cell.contentView.layer.borderWidth = 1.0

cell.contentView.layer.borderColor = UIColor.clear.cgColor
cell.contentView.layer.masksToBounds = true

cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 2.0
cell.layer.shadowOpacity = 1.0
cell.layer.masksToBounds = false
cell.layer.shadowPath = UIBezierPath(roundedRect:cell.bounds, cornerRadius:cell.contentView.layer.cornerRadius).cgPath
Torre Lasley
źródło
Muszę dodać efekt cienia w prawym rogu i na dole każdej komórce, oraz sposób powyższym kodzie prac, wypełnia komórkę z mrocznym kolorze ...
Joe Sené
25

Jeśli to pomaga: Oto szybki sposób zaokrąglania rogów:

cell.layer.cornerRadius = 10
cell.layer.masksToBounds = true

komórka jest zmienną kontrolującą komórkę: często użyjesz tego w override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Cieszyć się!

rakieta101
źródło
18

Tutaj rozwiązanie Swift 4 , zaktualizowane, aby zaokrąglać wszystkie rogi, a nie tylko górne rogi:

contentView.layer.cornerRadius = 6.0
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.clear.cgColor
contentView.layer.masksToBounds = true

layer.shadowColor = UIColor.lightGray.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2.0)
layer.shadowRadius = 6.0
layer.shadowOpacity = 1.0
layer.masksToBounds = false
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath
layer.backgroundColor = UIColor.clear.cgColor
Massimo Polimeni
źródło
1
Działa również w szybkim 4,2, dzięki
ShadeToD
2
Szukałem rozwiązania ... dzięki młodszemu Massimo: „D
Massimo Polimeni
16

Ustaw layeratrybuty komórki, a nie contentView.

CALayer * layer = [cell layer];
[layer setShadowOffset:CGSizeMake(0, 2)];
[layer setShadowRadius:1.0];
[layer setShadowColor:[UIColor redColor].CGColor] ;
[layer setShadowOpacity:0.5]; 
[layer setShadowPath:[[UIBezierPath bezierPathWithRect:cell.bounds] CGPath]];
inzonemobileDev
źródło
2
To wydaje się nie działać dla mnie. Używam podobnego kodu dla uitableviewcell, ale wydaje się, że nie działa w collectionviewcell. To dziwne, jak ten sam kod nie zadziała w komórce cv.
Jason,
Aktualizacja mojego powyższego komentarza. Zauważyłem, że UICollectionViewCells wydają się używać innego przesunięcia cienia niż UITableViewCells. Jeśli nie widzisz cienia, spróbuj zmienić przesunięcie (pomogło mi zwiększenie wartości Y).
Jason
14

SWIFT 4.2

Należy dodać to w swojej niestandardowej komórce lub cellForItemAt: Jeśli używasz cellForItemAt: approach substitute self -> cell

        self.layer.cornerRadius = 10
        self.layer.borderWidth = 1.0
        self.layer.borderColor = UIColor.lightGray.cgColor

        self.layer.backgroundColor = UIColor.white.cgColor
        self.layer.shadowColor = UIColor.gray.cgColor
        self.layer.shadowOffset = CGSize(width: 2.0, height: 4.0)
        self.layer.shadowRadius = 2.0
        self.layer.shadowOpacity = 1.0
        self.layer.masksToBounds = false

W ten sposób otrzymasz komórkę z zaokrągloną obwódką i cieniem.

Alexander
źródło
13

Oto moja odpowiedź, blisko innych, ale dodaję promień narożnika do warstwy, w przeciwnym razie rogi nie zostaną prawidłowo wypełnione. Jest to również miłe rozszerzenie dla UICollectionViewCell.

extension UICollectionViewCell {
func shadowDecorate() {
    let radius: CGFloat = 10
    contentView.layer.cornerRadius = radius
    contentView.layer.borderWidth = 1
    contentView.layer.borderColor = UIColor.clear.cgColor
    contentView.layer.masksToBounds = true

    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0, height: 1.0)
    layer.shadowRadius = 2.0
    layer.shadowOpacity = 0.5
    layer.masksToBounds = false
    layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
    layer.cornerRadius = radius
}

}

Możesz go wywołać w collectionView(_:cellForItemAt:)źródle danych po usunięciu komórki z kolejki.

smileBot
źródło
8

Wystarczy (a) ustawić cornerRadiusi (b) ustawić shadowPathzaokrąglony prostokąt o takim samym promieniu jak cornerRadius:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];
Timothy Moose
źródło
2
Masz jakiś pomysł, dlaczego to tylko zaokrągla moje dolne rogi?
user3344977
Wygląda na to, że warstwa, którą zaokrąglasz, jest częściowo zasłonięta przez coś. Bez szczegółów nie można pójść dalej.
Timothy Moose
Hej Tim, właśnie zadałem to pytanie. Mam przeczucie, że szybko to zdobędziesz. Czy to dlatego, że mam cień tylko na dole / „pod” komórką? stackoverflow.com/q/27929735/3344977
user3344977
6

Musiałem wprowadzić kilka drobnych zmian dla Swift :

cell.contentView.layer.cornerRadius = 2.0;
cell.contentView.layer.borderWidth = 1.0;
cell.contentView.layer.borderColor = UIColor.clearColor().CGColor;
cell.contentView.layer.masksToBounds = true;

cell.layer.shadowColor = UIColor.grayColor().CGColor;
cell.layer.shadowOffset = CGSizeMake(0, 2.0);
cell.layer.shadowRadius = 2.0;
cell.layer.shadowOpacity = 1.0;
cell.layer.masksToBounds = false;
cell.layer.shadowPath = UIBezierPath(roundedRect:cell.bounds, cornerRadius:cell.contentView.layer.cornerRadius).CGPath;
Keith Holliday
źródło
4

Odpowiedź Mike'a Sabatiniego działa dobrze, jeśli skonfigurujesz właściwości komórki bezpośrednio w collectionView cellForItemAt, ale jeśli spróbujesz ustawić je w awakeFromNib () niestandardowej podklasy UICollectionViewCell, skończysz z niewłaściwym ustawieniem bezierPath na urządzeniach, które nie nie pasują do szerokości i wysokości wcześniej ustawionych w Storyboard (IB).

Rozwiązaniem dla mnie było utworzenie func wewnątrz podklasy UICollectionViewCell i wywołanie jej z komórki cellForItemAt w następujący sposób:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellID", for: indexPath) as? CustomCollectionViewCell{
        cell.configure())
        return cell
    }
    else {
        return UICollectionViewCell()
    }
}

Oraz w CustomCollectionViewCell.swift:

class CustomCollectionViewCell: UICollectionViewCell{
    func configure() {
    contentView.layer.cornerRadius = 20
    contentView.layer.borderWidth = 1.0
    contentView.layer.borderColor = UIColor.clear.cgColor
    contentView.layer.masksToBounds = true
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0, height: 2.0)
    layer.shadowRadius = 2.0
    layer.shadowOpacity = 0.5
    layer.masksToBounds = false
    layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: contentView.layer.cornerRadius).cgPath}
 }
frantenerelli
źródło
3

Ten pracował dla mnie

cell.contentView.layer.cornerRadius = 5.0
cell.contentView.layer.borderColor = UIColor.gray.withAlphaComponent(0.5).cgColor
cell.contentView.layer.borderWidth = 0.5

let border = CALayer()
let width = CGFloat(2.0)
border.borderColor = UIColor.darkGray.cgColor
border.frame = CGRect(x: 0, y: cell.contentView.frame.size.height - width, width:  cell.contentView.frame.size.width, height: cell.contentView.frame.size.height)

border.borderWidth = width
cell.contentView.layer.addSublayer(border)
cell.contentView.layer.masksToBounds = true
cell.contentView.clipsToBounds = true
Tom Derry Marion Mantilla
źródło
3

Aby osiągnąć taki efekt, używam następującej metody:

extension UICollectionViewCell {
    /// Call this method from `prepareForReuse`, because the cell needs to be already rendered (and have a size) in order for this to work
    func shadowDecorate(radius: CGFloat = 8,
                        shadowColor: UIColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.3),
                        shadowOffset: CGSize = CGSize(width: 0, height: 1.0),
                        shadowRadius: CGFloat = 3,
                        shadowOpacity: Float = 1) {
        contentView.layer.cornerRadius = radius
        contentView.layer.borderWidth = 1
        contentView.layer.borderColor = UIColor.clear.cgColor
        contentView.layer.masksToBounds = true

        layer.shadowColor = shadowColor.cgColor
        layer.shadowOffset = shadowOffset
        layer.shadowRadius = shadowRadius
        layer.shadowOpacity = shadowOpacity
        layer.masksToBounds = false
        layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
        layer.cornerRadius = radius
    }
}
marcelosalloum
źródło
2

Możesz ustawić kolor cienia, promień i przesunięcie w metodzie UICollectionViewDataSource podczas tworzenia UICollectionViewCell

cell.layer.shadowColor = UIColor.gray.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 2.0)
cell.layer.shadowRadius = 1.0
cell.layer.shadowOpacity = 0.5
cell.layer.masksToBounds = false
Rahul Panzade
źródło
2

Oto moje podejście do rozwiązania. Jest podobny do innych odpowiedzi, z jedną kluczową różnicą. Nie tworzy ścieżki zależnej od granic widoku. Za każdym razem, gdy tworzysz ścieżkę na podstawie granic i udostępniasz ją warstwie, możesz napotkać problemy podczas zmiany rozmiaru i musisz skonfigurować metody aktualizacji ścieżki.

Prostszym rozwiązaniem jest unikanie używania wszystkiego, co jest zależne od granic.

let radius: CGFloat = 10

self.contentView.layer.cornerRadius = radius
// Always mask the inside view
self.contentView.layer.masksToBounds = true

self.layer.shadowColor = UIColor.black.cgColor
self.layer.shadowOffset = CGSize(width: 0, height: 1.0)
self.layer.shadowRadius = 3.0
self.layer.shadowOpacity = 0.5
// Never mask the shadow as it falls outside the view
self.layer.masksToBounds = false

// Matching the contentView radius here will keep the shadow
// in sync with the contentView's rounded shape
self.layer.cornerRadius = radius

Teraz, gdy rozmiar komórek zmieni się, interfejs API widoku wykona całą pracę wewnętrznie.

Adam
źródło
Moim zdaniem najczystsza odpowiedź. Uwielbiam pomysł synchronizacji promieni.
Kirill Kudaev
2

Znalazłem ważną rzecz: UICollectionViewCell musi mieć backgroundColor jako clearkolor, aby powyższe działały.

Khang Azun
źródło
Jest to BARDZO ważne, aby nie odcinać cienia! Nie ignoruj ​​tej odpowiedzi, wielkie dzięki, stary!
DennyDog