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.


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

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

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ę!


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

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]];

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.


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.


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];

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;

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

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

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

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

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.


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.


Jest to BARDZO ważne, aby nie odcinać cienia! Nie ignoruj ​​tej odpowiedzi, wielkie dzięki, stary!
— DennyDog
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.