Aggiunta di angoli arrotondati e ombreggiatura a UICollectionViewCell


105

Quindi ho già esaminato vari post sull'aggiunta della seconda vista per l'aggiunta di ombre, ma non riesco ancora a farlo funzionare se voglio aggiungerlo UICollectionViewCell. Ho sottoclasse UICollectionViewCell, ed ecco il mio codice in cui aggiungo vari elementi dell'interfaccia utente alla visualizzazione del contenuto della cella e aggiungo l'ombra al livello:

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

Vorrei sapere come aggiungere angoli arrotondati e ombre a UICollectionViewCell.


Penso che tu debba migliorare la tua domanda per capire dagli altri. È davvero complicato quello che hai chiesto
Dinesh Raja

ok aggiornato, voglio solo sapere come aggiungere angoli arrotondati e ombre a UICollectionViewCell
Vincent Yiu

Leggero a parte: usa shadowRadius OPPURE setShadowPath, non ha senso fare entrambe le cose poiché sono essenzialmente le stesse istruzioni in questo contesto (tutti gli angoli arrotondati). Un percorso ombra è necessario quando si desidera che forme più complesse o angoli arrotondati non vengano applicati a tutti gli angoli.
Oliver Dungey

Risposte:


194

Nessuna di queste soluzioni ha funzionato per me. Se posizioni tutte le tue sottoview nella visualizzazione del contenuto di UICollectionViewCell, come probabilmente sei, puoi impostare l'ombra sul livello della cella e il bordo sul livello del contentView per ottenere entrambi i risultati.

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
Questo ha funzionato bene per me dopo aver aggiuntocell.layer.backgroundColor = [UIColor clearColor].CGColor;
nacross

2
Qualche idea sul perché questo arrotonda solo i miei angoli superiori?
user3344977

@ user3344977 forse il fondo è stato tagliato? Poiché gli angoli sono arrotondati, ma è sotto la parte visibile della cella
CoderNinja

5
Trovo che questo arrotonda i miei angoli superiori e non anche quelli inferiori.
fatuhoku

2
Come fai a mantenere gli angoli rotondi quando selezioni / deselezioni / sposti le celle? I miei angoli diventano quadrati ogni volta che respiro sulla cella dopo che inizialmente disegna correttamente.
Adrian

32

Versione 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

Devo aggiungere un effetto ombra nell'angolo destro e nella parte inferiore di ogni cella, e il modo in cui funziona il codice sopra, riempie la cella con un colore ombroso ...
Joe Sene

25

Nel caso in cui aiuti: ecco il rapido per arrotondare gli angoli:

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

con cell come variabile che controlla la cella: spesso, lo userai in override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Godere!


18

Ecco la soluzione Swift 4 , aggiornata per arrotondare ogni angolo e non solo gli angoli superiori:

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
Funziona anche in swift 4,2, grazie
ShadeToD

2
Cercavo una soluzione ... grazie il giovane Massimo: 'D
Massimo Polimeni

16

Imposta gli layerattributi per la cella, non 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
Questo non sembra funzionare per me. Uso un codice simile per un uitableviewcell ma non sembra funzionare in un collectionviewcell. È strano come lo stesso codice non funzioni nella cella cv.
Jason

Un aggiornamento al mio commento sopra. Ho scoperto che UICollectionViewCells sembra utilizzare un offset ombra diverso da UITableViewCells. Se non vedi un'ombra, prova a cambiare l'offset (l'aumento del valore Y mi ha aiutato).
Jason

14

SWIFT 4.2

Dovresti aggiungerlo nella tua cella personalizzata o cellForItemAt: Se stai usando cellForItemAt: avvicinati a 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

Questo ti darà una cella con un bordo arrotondato e un'ombra esterna.


13

Ecco la mia risposta, vicina alle altre, ma aggiungo un raggio d'angolo al livello altrimenti gli angoli non si riempiranno correttamente. Inoltre, questo fa una bella piccola estensione su 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
}

}

Puoi richiamarlo collectionView(_:cellForItemAt:)dall'origine dati dopo aver rimosso dalla coda la cella.


8

Devi semplicemente (a) impostare cornerRadiuse (b) impostare shadowPathper essere un rettangolo arrotondato con lo stesso raggio di cornerRadius:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];

2
Qualche idea sul perché questo arrotonda solo i miei angoli inferiori?
user3344977

Sembra che qualsiasi strato che stai arrotondando sia parzialmente oscurato da qualcosa. Non si può andare oltre senza dettagli.
Timothy Moose

Ehi Tim, ho appena fatto questa domanda. Ho la sensazione che sarai in grado di ottenerlo rapidamente. È perché ho solo l'ombra sul fondo / "sotto" la cella? stackoverflow.com/q/27929735/3344977
user3344977

6

Ho dovuto apportare alcune lievi modifiche per 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

La risposta di Mike Sabatini funziona bene, se configuri le proprietà della cella direttamente su collectionView cellForItemAt, ma se provi a impostarle in awakeFromNib () di una sottoclasse UICollectionViewCell personalizzata, finirai con un bezierPath errato impostato sui dispositivi che non non corrispondono alla larghezza e all'altezza precedentemente impostate nel tuo Storyboard (IB).

La soluzione per me è stata creare una funzione all'interno della sottoclasse di UICollectionViewCell e chiamarla da cellForItemAt in questo modo:

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

E su 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

Questo ha funzionato per me

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

Uso il seguente metodo per ottenere questo tipo di effetto:

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

È possibile impostare il colore dell'ombra, il raggio e l'offset nel metodo UICollectionViewDataSource durante la creazione di un 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

Ecco la mia opinione sulla soluzione. È simile ad altre risposte, con una differenza fondamentale. Non crea un percorso che dipende dai limiti della vista. Ogni volta che crei un percorso basato sui limiti e lo fornisci al livello, puoi incorrere in problemi durante il ridimensionamento e devi impostare metodi per aggiornare il percorso.

Una soluzione più semplice è evitare di utilizzare tutto ciò che dipende dai limiti.

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

Ora, ogni volta che le dimensioni delle celle cambiano, l'API di visualizzazione farà tutto il lavoro internamente.


La risposta più pulita secondo me. Adoro l'idea di mantenere i raggi sincronizzati.
Kirill Kudaev

2

Ho trovato una cosa importante: UICollectionViewCell deve avere backgroundColor come clearcolore per far funzionare questi sopra.


Questo è MOLTO importante per non tagliare l'ombra! Non ignorare questa risposta, grazie mille, amico!
DennyDog
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.