Hinzufügen von abgerundeten Ecken und Schlagschatten zu UICollectionViewCell

104

Ich habe bereits verschiedene Beiträge zum Hinzufügen der zweiten Ansicht zum Hinzufügen von Schatten durchgearbeitet, kann sie jedoch immer noch nicht zum Laufen bringen, wenn ich sie hinzufügen möchte UICollectionViewCell. Ich habe eine Unterklasse erstellt UICollectionViewCell, und hier ist mein Code, in dem ich der Inhaltsansicht der Zelle verschiedene UI-Elemente hinzufüge und der Ebene Schatten hinzufüge:

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

Ich würde gerne wissen, wie man abgerundete Ecken und Schatten hinzufügt UICollectionViewCell.

Vincent Yiu
quelle
Ich denke, Sie müssen Ihre Frage verbessern, um von anderen verstanden zu werden. Es ist wirklich chaotisch, was Sie gefragt haben
Dinesh Raja
ok aktualisiert, ich möchte nur wissen, wie man abgerundete Ecken und Schatten zu UICollectionViewCell hinzufügt
Vincent Yiu
Leicht beiseite - verwenden Sie shadowRadius ODER setShadowPath. Es macht keinen Sinn, beides zu tun, da es sich in diesem Zusammenhang im Wesentlichen um dieselbe Anweisung handelt (alle abgerundeten Ecken). Ein Schattenpfad ist erforderlich, wenn komplexere Formen oder abgerundete Ecken nicht auf alle Ecken angewendet werden sollen.
Oliver Dungey

Antworten:

194

Keine dieser Lösungen hat bei mir funktioniert. Wenn Sie alle Ihre Unteransichten in die Inhaltsansicht von UICollectionViewCell einfügen, die Sie wahrscheinlich sind, können Sie den Schatten auf der Ebene der Zelle und den Rand auf der Ebene der Inhaltsansicht festlegen, um beide Ergebnisse zu erzielen.

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
quelle
9
Dies funktionierte gut für mich, nachdem ich hinzugefügt hattecell.layer.backgroundColor = [UIColor clearColor].CGColor;
Nacross
2
Irgendeine Idee, warum dies nur meine oberen Ecken abrundet?
user3344977
@ user3344977 Vielleicht wird der Boden abgeschnitten? Wie in den Ecken sind abgerundet, aber es ist unter dem sichtbaren Teil der Zelle
CoderNinja
5
Ich finde, dass dies meine oberen Ecken und nicht auch meine unteren Ecken abrundet.
Fatuhoku
2
Wie bringen Sie die Ecken dazu, rund zu bleiben, wenn Sie Zellen auswählen / abwählen / verschieben? Meine Ecken werden immer quadratisch, wenn ich auf der Zelle atme, nachdem sie anfänglich richtig gezeichnet hat.
Adrian
32

Swift 3 Version:

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
quelle
Ich muss einen Schatteneffekt an der rechten Ecke und am unteren Rand jeder Zelle hinzufügen, und so wie der obige Code funktioniert, füllt er die Zelle mit einer Schattenfarbe ...
Joe Sene
24

Für den Fall, dass es hilft: Hier ist die schnelle Abrundung der Ecken:

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

wobei cell eine Variable ist, die die Zelle steuert: Oft werden Sie diese in verwenden override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Genießen!

Rakete101
quelle
18

Hier die Swift 4- Lösung, die aktualisiert wurde, um alle Ecken und nicht nur die oberen Ecken abzurunden:

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
quelle
1
Funktioniert auch in schnellen 4,2, danke
ShadeToD
2
Ich suchte nach einer Lösung ... danke jüngerer Massimo: 'D
Massimo Polimeni
16

Legen Sie die layerAttribute für die Zelle fest, nicht 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
quelle
2
Das scheint bei mir nicht zu funktionieren. Ich verwende ähnlichen Code für eine uitableviewcell, aber es scheint nicht in einer collectionviewcell zu funktionieren. Es ist seltsam, wie derselbe Code in der Lebenslaufzelle nicht funktioniert.
Jason
Ein Update zu meinem obigen Kommentar. Ich habe festgestellt, dass UICollectionViewCells einen anderen Schattenversatz als UITableViewCells zu verwenden scheinen. Wenn Sie keinen Schatten sehen, versuchen Sie, den Versatz zu ändern (das Erhöhen des Y-Werts hat mir geholfen).
Jason
14

SWIFT 4.2

Dies sollte in Ihre benutzerdefinierte Zelle oder cellForItemAt eingefügt werden: Wenn Sie cellForItemAt: verwenden, wenden Sie sich an die Ersatzzelle self ->

        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

Dadurch erhalten Sie eine Zelle mit einem abgerundeten Rand und einem Schlagschatten.

Alexander
quelle
13

Hier ist meine Antwort, nahe an den anderen, aber ich füge der Ebene einen Eckenradius hinzu, da sonst die Ecken nicht richtig ausgefüllt werden. Auch dies macht eine nette kleine Erweiterung auf 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
}

}}

Sie können es in collectionView(_:cellForItemAt:)der Datenquelle aufrufen, sobald Sie Ihre Zelle aus der Warteschlange entfernt haben.

smileBot
quelle
8

Sie müssen lediglich (a) setzen cornerRadiusund (b) setzen shadowPath, um ein abgerundetes Rechteck mit dem gleichen Radius zu sein wie cornerRadius:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];
Timothy Moose
quelle
2
Irgendeine Idee, warum dies nur meine unteren Ecken abrundet?
user3344977
Klingt so, als ob die Ebene, die Sie runden, teilweise durch etwas verdeckt ist. Ohne Details geht es nicht weiter.
Timothy Moose
Hey Tim, ich habe gerade diese Frage gestellt. Ich habe das Gefühl, Sie werden es schnell bekommen. Liegt es daran, dass ich nur Schatten auf der Unterseite / "unter" der Zelle habe? stackoverflow.com/q/27929735/3344977
user3344977
6

Ich musste einige kleine Änderungen für Swift vornehmen :

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
quelle
3

Die Antwort von Mike Sabatini funktioniert einwandfrei. Wenn Sie die Zelleigenschaften direkt in der collectionView cellForItemAt konfigurieren, aber versuchen, sie in awakeFromNib () einer benutzerdefinierten UICollectionViewCell-Unterklasse festzulegen, wird auf den Geräten, die dies nicht tun, ein falscher bezierPath festgelegt Nicht mit der Breite und Höhe übereinstimmen, die zuvor in Ihrem Storyboard (IB) festgelegt wurden.

Die Lösung für mich bestand darin, eine Funktion in der Unterklasse von UICollectionViewCell zu erstellen und diese wie folgt aus cellForItemAt aufzurufen:

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

Und auf der 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
quelle
3

Dieser hat für mich gearbeitet

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
quelle
3

Ich benutze die folgende Methode, um diese Art von Effekt zu erzielen:

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
quelle
2

Sie können Schattenfarbe, Radius und Versatz in der UICollectionViewDataSource- Methode festlegen , während Sie eine UICollectionViewCell erstellen

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
quelle
2

Hier ist meine Sicht auf die Lösung. Es ist ähnlich wie bei anderen Antworten, mit einem wesentlichen Unterschied. Es wird kein Pfad erstellt, der von den Grenzen der Ansicht abhängt. Jedes Mal, wenn Sie einen Pfad basierend auf den Grenzen erstellen und ihn der Ebene zur Verfügung stellen, können Probleme auftreten, wenn die Größe geändert wird, und Sie müssen Methoden einrichten, um den Pfad zu aktualisieren.

Eine einfachere Lösung besteht darin, die Verwendung von grenzabhängigen Elementen zu vermeiden.

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

Immer wenn sich die Zellengröße ändert, erledigt die Ansichts-API die gesamte Arbeit intern.

Adam
quelle
Die sauberste Antwort meiner Meinung nach. Ich liebe die Idee, Radien synchron zu halten.
Kirill Kudaev
2

Ich habe eine wichtige Sache gefunden: Die UICollectionViewCell muss die Hintergrundfarbe als clearFarbe haben, damit diese oben funktionieren.

Khang Azun
quelle
Dies ist SEHR wichtig, um Schatten nicht abzuschneiden! Ignorieren Sie diese Antwort nicht, vielen Dank, Mann!
DennyDog