Adicionando canto arredondado e sombra projetada a UICollectionViewCell


104

Já passei por várias postagens sobre como adicionar uma 2ª visualização para adicionar sombra, mas ainda não consigo fazê-lo funcionar se quiser adicioná-lo UICollectionViewCell. Eu criei uma subclasse UICollectionViewCelle aqui está meu código onde adiciono vários elementos de IU à visualização do conteúdo da célula e adiciono sombra à camada:

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

Gostaria de saber como adicionar cantos arredondados e sombras UICollectionViewCell.


Eu acho que você precisa melhorar sua pergunta para entender por outras pessoas. É realmente confuso o que você perguntou
— Dinesh Raja

ok atualizado, eu só quero saber como adicionar cantos arredondados e sombra a UICollectionViewCell
— Vincent Yiu

Um pouco à parte - use shadowRadius OU setShadowPath, não adianta fazer os dois, pois são essencialmente a mesma instrução neste contexto (todos os cantos arredondados). Um caminho de sombra é necessário quando você deseja formas mais complexas ou cantos arredondados não aplicados a todos os cantos.
— Oliver Dungey de

Respostas:


194

Nenhuma dessas soluções funcionou para mim. Se você colocar todas as suas subvisualizações na visão de conteúdo UICollectionViewCell, o que provavelmente é, você pode definir a sombra na camada da célula e a borda na camada de contentView para obter os dois 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
Isso funcionou bem para mim depois que eu adicioneicell.layer.backgroundColor = [UIColor clearColor].CGColor;
— nacross

2
Alguma ideia de por que isso só contorna meus cantos superiores?
— user3344977

@ user3344977 talvez a parte inferior esteja sendo cortada? Como nos cantos são arredondados, mas está abaixo da parte visível da célula
— CoderNinja

5
Acho que isso circunda meus cantos superiores e não os inferiores também.
— fatuhoku

2
Como você faz com que os cantos permaneçam arredondados ao selecionar / desmarcar / mover células? Meus cantos ficam retos sempre que eu respiro na célula depois que ela é desenhada corretamente.
— Adrian

32

Versão 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

Preciso adicionar um efeito de sombra no canto direito e na parte inferior de cada célula, e da forma como o código acima funciona, ele preenche a célula com uma cor sombreada ...
— Joe Sene

25

Caso ajude: Aqui está a solução para arredondar os cantos:

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

com a célula sendo uma variável que controla a célula: frequentemente, você vai usar isso em override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Aproveitar!


18

Aqui, a solução Swift 4 , atualizada para arredondar todos os cantos e não apenas os cantos 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
Funciona em rápida 4,2 também, obrigado
— ShadeToD

2
Eu estava procurando uma solução ... obrigado Massimo mais jovem: 'D
— Massimo Polimeni

16

Defina os layeratributos da célula, não 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
Isso não parece funcionar para mim. Eu uso um código semelhante para um uitableviewcell, mas não parece funcionar em um collectionviewcell. É estranho como o mesmo código não funciona na célula cv.
— Jason

Uma atualização do meu comentário acima. Descobri que UICollectionViewCells parece usar um deslocamento de sombra diferente de UITableViewCells. Se você não estiver vendo uma sombra, tente alterar o deslocamento (aumentar o valor de Y me ajudou).
— Jason

14

SWIFT 4.2

Deve-se adicionar isso em sua célula ou cellForItemAt customizada: Se você estiver usando 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

Isso lhe dará uma célula com uma borda arredondada e uma sombra projetada.


13

Aqui está minha resposta, perto das outras, mas adiciono um raio de canto à camada, caso contrário, os cantos não serão preenchidos corretamente. Além disso, isso é uma pequena extensão agradável 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
}

}

Você pode chamá-lo collectionView(_:cellForItemAt:)da fonte de dados depois de retirar a fila da célula.


8

Você simplesmente precisa (a) definir cornerRadiuse (b) definir shadowPathcomo um retângulo arredondado com o mesmo raio de cornerRadius:

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

2
Alguma ideia de por que isso só contorna meus cantos inferiores?
— user3344977

Parece que a camada que você está arredondando está parcialmente obscurecida por alguma coisa. Não posso ir além disso sem detalhes.
— Timothy Moose

Ei Tim, acabei de fazer esta pergunta. Tenho a sensação de que você será capaz de obtê-lo rapidamente. É porque eu só tenho sombra na parte inferior / "embaixo" da célula? stackoverflow.com/q/27929735/3344977
— user3344977

6

Tive que fazer algumas pequenas alterações no 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;

3

A resposta de Mike Sabatini funciona bem, se você configurar as propriedades da célula diretamente em collectionView cellForItemAt, mas se você tentar configurá-las em awakeFromNib () de uma subclasse UICollectionViewCell customizada, você terminará com um bezierPath incorreto configurado nos dispositivos que não não coincidir com a largura e altura previamente definidas em seu Storyboard (IB).

A solução para mim foi criar uma função dentro da subclasse de UICollectionViewCell e chamá-la de cellForItemAt assim:

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 no 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 funcionou para mim

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

Eu uso o seguinte método para conseguir esse tipo de efeito:

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

Você pode definir a cor da sombra, raio e deslocamento no método UICollectionViewDataSource ao criar um 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

Aqui está minha opinião sobre a solução. É semelhante a outras respostas, com uma diferença fundamental. Ele não cria um caminho que depende dos limites da visualização. Sempre que você criar um caminho com base nos limites e fornecê-lo à camada, poderá ter problemas durante o redimensionamento e precisar configurar métodos para atualizar o caminho.

Uma solução mais simples é evitar o uso de qualquer coisa que seja dependente de 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

Agora, sempre que o tamanho das células mudar, a API de visualização fará todo o trabalho internamente.


A resposta mais limpa na minha opinião. Adoro a ideia de manter os raios sincronizados.
— Kirill Kudaev

2

Achei uma coisa importante: o UICollectionViewCell deve ter o backgroundColor como clearcor para que funcionem.


Isso é MUITO importante para não eliminar a sombra! Não ignore essa resposta, MUITO obrigado, cara!
— DennyDog
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.