UITableViewCell: закругленные углы и тени

Я меняю ширину UITableViewCell, так что ячейка меньше, но пользователь все еще может прокручивать по краям таблицы.

override func layoutSubviews() {        
    // Set the width of the cell
    self.bounds = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width - 40, self.bounds.size.height)
    super.layoutSubviews()
}

Затем я закругляю углы:

cell.layer.cornerRadius = 8
cell.layer.masksToBounds = true

Все до сих пор. Проблема возникает с тенью. Границы маскируются, поэтому тень, очевидно, не появится. Я искал другие ответы, но не могу понять, как обогнуть углы вдоль границ и показать тень.

cell.layer.shadowOffset = CGSizeMake(0, 0)
cell.layer.shadowColor = UIColor.blackColor().CGColor
cell.layer.shadowOpacity = 0.23
cell.layer.shadowRadius = 4

Итак, мой вопрос: как уменьшить ширину, по углам и одновременно добавить тень в UITableViewCell?

Обновление: Попытка ответить R Moyer

Попытка ответа R Мойера

Ответ 1

Этот вопрос приходит вовремя! Я буквально просто решил эту проблему сам.

  • Создайте UIView (дайте ссылку на него как mainBackground) внутри своего содержимого. Это будет содержать все содержимое вашей ячейки. Расположите его и примените необходимые ограничения в раскадровке.
  • Создайте еще один UIView. Это будет тот, у кого есть тень (давайте обозначим его как shadowLayer). Поместите его точно так же, как вы сделали mainBackground, но за ним, и примените те же ограничения.
  • Теперь вы можете установить закругленные углы и тени следующим образом:

    cell.mainBackground.layer.cornerRadius = 8  
    cell.mainBackground.layer.masksToBounds = true
    
    cell.shadowLayer.layer.masksToBounds = false
    cell.shadowLayer.layer.shadowOffset = CGSizeMake(0, 0)
    cell.shadowLayer.layer.shadowColor = UIColor.blackColor().CGColor
    cell.shadowLayer.layer.shadowOpacity = 0.23
    cell.shadowLayer.layer.shadowRadius = 4
    

Однако проблема заключается в следующем: вычисление тени для каждой отдельной ячейки является медленной задачей. Вы заметите серьезную задержку при прокрутке стола. Лучший способ исправить это - определить UIBezierPath для тени, а затем растрировать его. Поэтому вы можете сделать это:

cell.shadowLayer.layer.shadowPath = UIBezierPath(roundedRect: cell.shadowLayer.bounds, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: 8, height: 8)).CGPath
cell.shadowLayer.layer.shouldRasterize = true
cell.shadowLayer.layer.rasterizationScale = UIScreen.mainScreen().scale

Но это создает новую проблему! Форма UIBezierPath зависит от границ shadowLayer, но границы не установлены должным образом на время, когда вызывается cellForRowAtIndexPath. Итак, вам нужно настроить shadowPath на основе ограничений shadowLayer. Лучший способ сделать это - подкласс UIView и добавить свойство observer в свойство bounds. Затем задайте все свойства тени в didSet. Не забудьте изменить класс вашего shadowLayer в раскадровке, чтобы он соответствовал вашему новому подклассу.

class ShadowView: UIView {
    override var bounds: CGRect {
        didSet {
            setupShadow()
        }
    }

    private func setupShadow() {
        self.layer.cornerRadius = 8
        self.layer.shadowOffset = CGSize(width: 0, height: 3)
        self.layer.shadowRadius = 3
        self.layer.shadowOpacity = 0.3
        self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: .AllCorners, cornerRadii: CGSize(width: 8, height: 8)).CGPath
        self.layer.shouldRasterize = true
        self.layer.rasterizationScale = UIScreen.mainScreen().scale
    }
}

Ответ 2

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

Ответ 3

Чтобы создать тень и угол для ячейки, вам нужен только один backView. См. Мой пример ниже.

введите описание изображения здесь

Вам нужно добавить backView и установить ограничения leading, trailing, top, bottom, равные Content view. Поместите контент в backView с соответствующими ограничениями, но убедитесь, что ваш контент не находится над бухтой r backView.

После этого в коде инициализации вашей ячейки добавьте следующие строки:

override func awakeFromNib() {
    super.awakeFromNib()

    backgroundColor = Colors.colorClear

    self.backView.layer.borderWidth = 1
    self.backView.layer.cornerRadius = 3
    self.backView.layer.borderColor = Colors.colorClear.cgColor
    self.backView.layer.masksToBounds = true

    self.layer.shadowOpacity = 0.18
    self.layer.shadowOffset = CGSize(width: 0, height: 2)
    self.layer.shadowRadius = 2
    self.layer.shadowColor = Colors.colorBlack.cgColor
    self.layer.masksToBounds = false
}

Не забудьте создать IBOutlet для Back View.

И вот результат:

введите описание изображения здесь

Ответ 4

Один альтернативный подход, который вы можете попробовать, возьмите UIView в UITableViewCell. Установите цвет фона UITableViewCell, чтобы очистить цвет. Теперь вы можете сделать круглые углы и добавить тень на UIView. Это будет выглядеть так, как если бы ширина ячейки была уменьшена, и пользователь мог прокручивать по краям таблицыView.

Ответ 5

Я получил то же самое, используя следующий код. Но вы разместили его в методе layoutSubviews() вашего подкласса TableViewCell.

self.contentView.backgroundColor = [UIColor whiteColor];
self.contentView.layer.cornerRadius = 5;
self.contentView.layer.shadowOffset = CGSizeMake(1, 0);
self.contentView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.contentView.layer.shadowRadius = 5;
self.contentView.layer.shadowOpacity = .25;
CGRect shadowFrame = self.contentView.layer.bounds;
CGPathRef shadowPath = [UIBezierPath bezierPathWithRect:shadowFrame].CGPath;
self.contentView.layer.shadowPath = shadowPath;

Ответ 6

Попробуй, это сработало для меня.

    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

Ответ 7

Он работает без дополнительных просмотров!

override func awakeFromNib() {
    super.awakeFromNib()

    layer.masksToBounds = false
    layer.cornerRadius = Constants.cornerRadius
}

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    ...
    let layer = cell.layer
    layer.shadowOffset = CGSize(width: 0, height: 1)
    layer.shadowRadius = 2
    layer.shadowColor = UIColor.lightGray.cgColor
    layer.shadowOpacity = 0.2
    layer.frame = cell.frame
    cell.tagLabel.text = tagItems[indexPath.row].text

    return cell
}