Добавление закругленного угла и тени к UICollectionViewCell


106

Итак, я уже просмотрел различные сообщения о добавлении второго вида для добавления тени, но я все еще не могу заставить его работать, если я хочу добавить его UICollectionViewCell. Я создал подклассы UICollectionViewCell, и вот мой код, в котором я добавляю различные элементы пользовательского интерфейса в представление содержимого ячейки и добавляю тень к слою:

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

Я хотел бы знать, как добавить закругленный угол и тень UICollectionViewCell.


Я думаю, вам нужно улучшить свой вопрос, чтобы его поняли другие. То, о чем ты спросил, действительно грязно
Динеш Раджа

хорошо, обновлено, я просто хочу знать, как добавить закругленный угол и тень в UICollectionViewCell
Винсент Ю,

Немного в сторону - используйте shadowRadius ИЛИ setShadowPath, нет смысла делать и то и другое, поскольку в этом контексте они по сути являются одной и той же инструкцией (все закругленные углы). Теневой путь необходим, если вы хотите, чтобы более сложные формы или закругленные углы применялись не ко всем углам.
Оливер Данжи

Ответы:


194

Ни одно из этих решений не помогло мне. Если вы поместите все свои подпредставления в представление содержимого UICollectionViewCell, что вы, вероятно, и есть, вы можете установить тень на слое ячейки и границу на слое contentView для достижения обоих результатов.

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
У меня это сработало хорошо после того, как я добавилcell.layer.backgroundColor = [UIColor clearColor].CGColor;
2014, 16:41

2
Есть идеи, почему это округляет только мои верхние углы?
user3344977

@ user3344977 может быть подрезается дно? Как и в углах закруглены, но это под видимой частью ячейки
CoderNinja 05

5
Я считаю, что это закругляет мои верхние углы, а не нижние.
fatuhoku

2
Как сделать так, чтобы углы оставались круглыми, когда вы выбираете / снимаете выделение / перемещаете ячейки? Мои углы становятся квадратными каждый раз, когда я дышу на ячейку после того, как она изначально нарисована правильно.
Адриан

32

Версия 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

Мне нужно добавить эффект тени к правому углу и внизу каждой ячейки, и, как работает приведенный выше код, он заполняет ячейку темным цветом ...
Джо

25

На случай, если это поможет: вот быстрый способ скругления углов:

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

где ячейка является переменной, управляющей ячейкой: часто вы будете использовать это в override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell

Наслаждайтесь!


19

Вот решение Swift 4 , обновленное, чтобы скруглить все углы, а не только верхние углы:

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
Тоже работает в swift 4,2, thanls
ShadeToD

2
Я искал решение ... спасибо младшему Массимо: 'D
Массимо

16

Установите layerатрибуты для ячейки, а не 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
Похоже, у меня это не работает. Я использую аналогичный код для uitableviewcell, но, похоже, он не работает в collectionviewcell. Странно, как тот же код не работает в ячейке cv.
Джейсон

Обновление моего комментария выше. Я обнаружил, что UICollectionViewCells, похоже, использует другое смещение тени, чем UITableViewCells. Если вы не видите тени, попробуйте изменить смещение (мне помогло увеличение значения Y).
Джейсон

14

SWIFT 4.2

Следует добавить это в свою настраиваемую ячейку или cellForItemAt: если вы используете cellForItemAt: подход, замените себя -> ячейка

        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

Это даст вам ячейку с закругленной рамкой и тенью.


13

Вот мой ответ, близкий к другим, но я добавляю к слою радиус угла, иначе углы не будут правильно заполнены. Кроме того, это неплохое небольшое расширение 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
}

}

Вы можете вызвать его collectionView(_:cellForItemAt:)из источника данных, как только вы удалите свою ячейку из очереди.


8

Вам просто нужно (a) установить cornerRadiusи (b) установить shadowPathзакругленный прямоугольник с тем же радиусом, что и cornerRadius:

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

2
Есть идеи, почему это только округляет мои нижние углы?
user3344977

Похоже, какой бы слой вы ни скругляли, он чем-то частично закрыт. Не могу пойти дальше этого без подробностей.
Тимоти Мус

Привет, Тим, я только что задал этот вопрос. Я чувствую, что ты сможешь получить это быстро. Это потому, что у меня тень только внизу / «под» ячейкой? stackoverflow.com/q/27929735/3344977
user3344977

6

Пришлось внести небольшие изменения в 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

Ответ Майка Сабатини работает нормально, если вы настраиваете свойства ячейки непосредственно в collectionView cellForItemAt, но если вы попытаетесь установить их в awakeFromNib () пользовательского подкласса UICollectionViewCell, вы закончите с неправильным bezierPath, установленным на устройствах, которые не не соответствуют ширине и высоте, ранее установленным в вашей раскадровке (IB).

Решением для меня было создать функцию внутри подкласса UICollectionViewCell и вызвать ее из cellForItemAt следующим образом:

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

И в 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

Это сработало для меня

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

Я использую следующий метод для достижения такого эффекта:

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

Вы можете установить цвет тени, радиус и смещение в методе UICollectionViewDataSource при создании 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

Вот мой взгляд на решение. Он похож на другие ответы, с одним ключевым отличием. Он не создает путь, который зависит от границ представления. Каждый раз, когда вы создаете путь, основанный на границах, и предоставляете его слою, вы можете столкнуться с проблемами при изменении его размера, и вам потребуется настроить методы для обновления пути.

Более простое решение - избегать использования всего, что зависит от границ.

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

Теперь, когда размер ячеек изменится, API представления выполнит всю внутреннюю работу.


На мой взгляд, самый чистый ответ. Мне нравится идея синхронизировать радиусы.
Кирилл Кудаев

2

Я обнаружил важную вещь: UICollectionViewCell должен иметь backgroundColor в качестве clearцвета, чтобы они работали выше.


Это ОЧЕНЬ важно, чтобы не срезать тени! Не игнорируйте этот ответ, ОГРОМНОЕ спасибо, чувак!
DennyDog
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.