Ajout d'un coin arrondi et d'une ombre portée à UICollectionViewCell

106

J'ai donc déjà parcouru divers articles sur l'ajout d'une deuxième vue pour ajouter une ombre, mais je ne peux toujours pas le faire fonctionner si je veux l'ajouter UICollectionViewCell. J'ai sous UICollectionViewCell- classé , et voici mon code dans lequel j'ajoute divers éléments d'interface utilisateur à la vue de contenu de la cellule et ajoute une ombre à la couche:

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

Je voudrais savoir comment ajouter un coin arrondi et une ombre UICollectionViewCell.

Vincent Yiu
la source
Je pense que vous devez améliorer votre question pour la comprendre par les autres. C'est vraiment désordonné ce que vous avez demandé
Dinesh Raja
ok mis à jour, je veux juste savoir comment ajouter un coin arrondi et une ombre à UICollectionViewCell
Vincent Yiu
Légèrement à part - utilisez shadowRadius OU setShadowPath, inutile de faire les deux car il s'agit essentiellement de la même instruction dans ce contexte (tous les coins arrondis). Un shadowpath est nécessaire lorsque vous souhaitez que des formes plus complexes ou des coins arrondis ne soient pas appliqués à tous les coins.
Oliver Dungey

Réponses:

194

Aucune de ces solutions n'a fonctionné pour moi. Si vous placez toutes vos sous-vues dans la vue de contenu UICollectionViewCell, ce que vous êtes probablement, vous pouvez définir l'ombre sur la couche de la cellule et la bordure sur la couche de contentView pour obtenir les deux résultats.

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
la source
9
Cela a bien fonctionné pour moi après avoir ajoutécell.layer.backgroundColor = [UIColor clearColor].CGColor;
nacross
2
Une idée pourquoi cela ne fait que arrondir mes coins supérieurs?
user3344977
@ user3344977 peut-être que le fond est coupé? Comme dans les coins sont arrondis, mais c'est sous la partie visible de la cellule
CoderNinja
5
Je trouve que cela arrondit mes coins supérieurs et non mes coins inférieurs également.
fatuhoku
2
Comment faire en sorte que les coins restent arrondis lorsque vous sélectionnez / désélectionnez / déplacez des cellules? Mes coins deviennent carrés à chaque fois que je respire sur la cellule après qu'elle ait initialement dessiné correctement.
Adrian
32

Version 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
la source
J'ai besoin d'ajouter un effet d'ombre dans le coin droit et en bas de chaque cellule, et la façon dont le code ci-dessus fonctionne, il remplit la cellule avec une couleur ombrée ...
Joe Sene
25

Au cas où cela aiderait: voici le swift pour arrondir les coins:

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

la cellule étant une variable contrôlant la cellule: souvent, vous l'utiliserez dans override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Prendre plaisir!

fusée101
la source
19

Voici la solution Swift 4 , mise à jour pour arrondir tous les coins et pas seulement les coins supérieurs:

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
la source
1
Fonctionne aussi dans Swift 4,2, thanls
ShadeToD
2
Je cherchais une solution ... merci plus jeune Massimo: 'D
Massimo Polimeni
16

Définissez les layerattributs de la cellule, pas 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
la source
2
Cela ne semble pas fonctionner pour moi. J'utilise un code similaire pour un uitableviewcell mais il ne semble pas fonctionner dans un collectionviewcell. C'est bizarre comment le même code ne fonctionnera pas dans la cellule cv.
Jason
Une mise à jour de mon commentaire ci-dessus. J'ai trouvé que UICollectionViewCells semble utiliser un décalage d'ombre différent de UITableViewCells. Si vous ne voyez pas d'ombre, essayez de changer le décalage (l'augmentation de la valeur Y m'a aidé).
Jason
14

SWIFT 4.2

Il faut ajouter ceci dans votre cellule personnalisée ou cellForItemAt: Si vous utilisez la cellule cellForItemAt: approche 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

Cela vous donnera une cellule avec une bordure arrondie et une ombre portée.

Alexandre
la source
13

Voici ma réponse, proche des autres, mais j'ajoute un rayon de coin au calque sinon les coins ne se rempliront pas correctement. En outre, cela fait une belle petite extension sur 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
}

}

Vous pouvez l'appeler dans collectionView(_:cellForItemAt:)la source de données une fois que vous avez retiré votre cellule de la file d'attente.

smileBot
la source
8

Vous devez simplement (a) définir cornerRadiuset (b) définir shadowPathpour être un rect arrondi avec le même rayon que cornerRadius:

self.layer.cornerRadius = 10;
self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.layer.cornerRadius] CGPath];
Timothy Moose
la source
2
Une idée pourquoi cela n'arrondit que mes coins inférieurs?
user3344977
On dirait que le calque que vous arrondissez est partiellement masqué par quelque chose. Je ne peux pas aller plus loin que cela sans détails.
Timothy Moose
Hey Tim, je viens de poser cette question. J'ai le sentiment que vous pourrez l'obtenir rapidement. Est-ce parce que je n'ai qu'une ombre en bas / "sous" la cellule? stackoverflow.com/q/27929735/3344977
user3344977
6

J'ai dû faire quelques légers changements pour 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
la source
4

La réponse de Mike Sabatini fonctionne très bien, si vous configurez les propriétés de la cellule directement sur la collectionView cellForItemAt, mais si vous essayez de les définir dans awakeFromNib () d'une sous-classe UICollectionViewCell personnalisée, vous vous terminerez par un mauvais ensemble de bezierPath sur les appareils qui ne ne correspondent pas à la largeur et à la hauteur précédemment définies dans votre Storyboard (IB).

La solution pour moi était de créer une fonction dans la sous-classe de UICollectionViewCell et de l'appeler à partir de cellForItemAt comme ceci:

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

Et sur le 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
la source
3

Celui-ci a fonctionné pour moi

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
la source
3

J'utilise la méthode suivante pour accomplir ce genre d'effet:

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
la source
2

Vous pouvez définir la couleur, le rayon et le décalage de l' ombre dans la méthode UICollectionViewDataSource lors de la création d'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
Rahul Panzade
la source
2

Voici mon avis sur la solution. C'est similaire à d'autres réponses, avec une différence essentielle. Il ne crée pas de chemin dépendant des limites de la vue. Chaque fois que vous créez un chemin basé sur les limites et que vous le fournissez à la couche, vous pouvez rencontrer des problèmes lors du redimensionnement et vous devez configurer des méthodes pour mettre à jour le chemin.

Une solution plus simple consiste à éviter d'utiliser tout ce qui dépend des limites.

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

Désormais, chaque fois que la taille des cellules change, l'API de vue fera tout le travail en interne.

Adam
la source
La réponse la plus claire à mon avis. J'adore l'idée de synchroniser les rayons.
Kirill Kudaev
2

J'ai trouvé une chose importante: l'UICollectionViewCell doit avoir le backgroundColor comme clearcouleur pour que ces derniers fonctionnent.

Khang Azun
la source
Ceci est TRÈS important pour ne pas couper l'ombre! N'ignorez pas cette réponse, merci BEAUCOUP, mec!
DennyDog