Agregar esquinas redondeadas y sombras paralelas a UICollectionViewCell


105

Así que ya revisé varias publicaciones sobre cómo agregar una segunda vista para agregar sombras, pero todavía no puedo hacer que funcione si quiero agregarlas UICollectionViewCell. Subclasé UICollectionViewCell, y aquí está mi código donde agrego varios elementos de la interfaz de usuario a la vista de contenido de la celda y agrego sombra a la capa:

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

Me gustaría saber cómo agregar esquinas redondeadas y sombras UICollectionViewCell.


Creo que necesitas mejorar tu pregunta para que otros la entiendan. Es realmente complicado lo que has preguntado
Dinesh Raja

ok actualizado, solo quiero saber cómo agregar esquinas redondeadas y sombras a UICollectionViewCell
Vincent Yiu

Un poco a un lado: use shadowRadius O setShadowPath, no tiene sentido hacer ambas cosas ya que son esencialmente la misma instrucción en este contexto (todas las esquinas redondeadas). Un camino de sombra es necesario cuando desea que las formas más complejas o las esquinas redondeadas no se apliquen a todas las esquinas.
Oliver Dungey

Respuestas:


194

Ninguna de estas soluciones funcionó para mí. Si coloca todas sus subvistas en la vista de contenido UICollectionViewCell, que probablemente sea, puede establecer la sombra en la capa de la celda y el borde en la capa de contentView para lograr ambos resultados.

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
Esto funcionó bien para mí después de que agreguécell.layer.backgroundColor = [UIColor clearColor].CGColor;
nacross

2
¿Alguna idea de por qué esto solo redondea mis esquinas superiores?
user3344977

@ user3344977 ¿tal vez se está recortando la parte inferior? Como en las esquinas están redondeadas, pero está debajo de la parte visible de la celda
CoderNinja

5
Encuentro que esto redondea mis esquinas superiores y no también mis esquinas inferiores.
fatuhoku

2
¿Cómo consigue que las esquinas permanezcan redondas cuando selecciona / deselecciona / mueve celdas? Mis esquinas se cuadran cada vez que respiro en la celda después de que inicialmente se dibuja correctamente.
Adrian

32

Versión 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

Necesito agregar un efecto de sombra en la esquina derecha y la parte inferior de cada celda, y la forma en que funciona el código anterior, llena la celda con un color sombreado ...
Joe Sene

25

En caso de que sirva de ayuda: aquí está la rapidez para redondear las esquinas:

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

con celda como una variable que controla la celda: a menudo, usará esto en override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

¡Disfrutar!


18

Aquí la solución Swift 4 , actualizada para redondear todas las esquinas y no solo las esquinas superiores:

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
También funciona en Swift 4,2, gracias
ShadeToD

2
Estaba buscando una solución ... gracias joven Massimo: 'D
Massimo Polimeni

16

Establezca los layeratributos de la celda, no 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
Esto no parece funcionar para mí. Utilizo un código similar para una celda de vista uitable, pero no parece funcionar en una celda de vista de colección. Es extraño que el mismo código no funcione en la celda cv.
Jason

Una actualización de mi comentario anterior. Encontré que UICollectionViewCells parece usar un desplazamiento de sombra diferente al de UITableViewCells. Si no ve una sombra, intente cambiar el desplazamiento (aumentar el valor de Y me ayudó).
Jason

14

SWIFT 4.2

Uno debe agregar esto en su celda personalizada o cellForItemAt: Si está utilizando cellForItemAt: enfoque sustituto self -> celda

        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

Esto le dará una celda con un borde redondeado y una sombra paralela.


13

Aquí está mi respuesta, cercana a las demás, pero agrego un radio de esquina a la capa, de lo contrario, las esquinas no se llenarán correctamente. Además, esto hace una pequeña extensión agradable en 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
}

}

Puede llamarlo desde collectionView(_:cellForItemAt:)la fuente de datos una vez que retire la cola de su celda.


8

Simplemente necesita (a) establecer cornerRadiusy (b) establecer shadowPathpara que sea un rectángulo redondeado con el mismo radio que cornerRadius:

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

2
¿Alguna idea de por qué esto solo redondea mis esquinas inferiores?
user3344977

Parece que la capa que está redondeando está parcialmente oscurecida por algo. No puedo ir más lejos sin detalles.
Timothy Moose

Hola Tim, acabo de hacer esta pregunta. Tengo la sensación de que podrá conseguirlo rápidamente. ¿Es porque solo tengo sombra en la parte inferior / "debajo" de la celda? stackoverflow.com/q/27929735/3344977
user3344977

6

Tuve que hacer algunos cambios leves para 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 respuesta de Mike Sabatini funciona bien, si configura las propiedades de la celda directamente en collectionView cellForItemAt, pero si intenta configurarlas en awakeFromNib () de una subclase UICollectionViewCell personalizada, terminará con un bezierPath incorrecto configurado en los dispositivos que no no coincide con el ancho y el alto establecidos previamente en su Storyboard (IB).

La solución para mí fue crear una función dentro de la subclase de UICollectionViewCell y llamarla desde cellForItemAt así:

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

Y en 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

Este funcionó para mi

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

Utilizo el siguiente método para lograr este tipo de efecto:

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

Puede establecer el color de la sombra, el radio y el desplazamiento en el método UICollectionViewDataSource mientras crea una 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

Aquí está mi opinión sobre la solución. Es similar a otras respuestas, con una diferencia clave. No crea una ruta que dependa de los límites de la vista. Cada vez que crea una ruta basada en los límites y la proporciona a la capa, puede tener problemas al cambiar el tamaño y necesita configurar métodos para actualizar la ruta.

Una solución más sencilla es evitar el uso de cualquier elemento que dependa de los límites.

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

Ahora, cuando el tamaño de las celdas cambie, la API de vista hará todo el trabajo internamente.


La respuesta más limpia en mi opinión. Me encanta la idea de mantener los radios sincronizados.
Kirill Kudaev

2

Encontré algo importante: UICollectionViewCell debe tener backgroundColor como clearcolor para que estos funcionen.


¡Esto es MUY importante para lograr no cortar la sombra! No ignores esta respuesta, ¡MUCHAS gracias, hombre!
DennyDog
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.