Несколько теневых теней на одном экране iOS

Я ищу, чтобы добавить несколько теней теней с различными непрозрачностью в представление. Спецификации для теней следующие:

  • Y-смещение 4 с радиусом размытия 1
  • Y-смещение 10 с радиусом размытия 10
  • Y-смещение 2 с радиусом размытия 4
  • Радиус размытия 1, распространение 1 (без смещений, вероятно, должно быть 4 разных тени)

Я могу полностью справиться с этим, используя CALayer s. Вот код, на котором я работаю для этого (обратите внимание, что я еще не потрудился установить shadowPath и не буду, пока не получу работу нескольких теней):

layer.cornerRadius = 4
layer.masksToBounds = false
layer.shouldRasterize = true
let layer2 = CALayer(layer: layer), layer3 = CALayer(layer: layer), layer4 = CALayer(layer: layer)
layer.shadowOffset = CGSizeMake(0, 4)
layer.shadowRadius = 1
layer2.shadowOffset = CGSizeMake(0, 10)
layer2.shadowRadius = 10
layer2.shadowColor = UIColor.blackColor().CGColor
layer2.shouldRasterize = true //Evidently not copied during initialization from self.layer
layer3.shadowOffset = CGSizeMake(0, 2)
layer3.shadowRadius = 4
layer3.shouldRasterize = true
layer4.shadowOffset = CGSizeMake(0, 1)
layer4.shadowRadius = 1
layer4.shadowOpacity = 0.1
layer4.shouldRasterize = true
layer.addSublayer(layer2)
layer.addSublayer(layer3)
layer.addSublayer(layer4)

(Хотя этот код находится в Swift, я считаю, что он выглядит достаточно знакомым для большинства разработчиков Cocoa/Objective-C, чтобы он имел смысл. Просто знайте, что layer эквивалентен self.layer в этом контексте. )

Проблема, однако, возникает, когда я пытаюсь использовать разные непрозрачности для каждой тени. Свойство shadowOpacity layer заканчивается тем, что применяется ко всем его подслоям. Это проблема, поскольку мне нужно, чтобы все они обладали собственной непрозрачностью. Я попытался установить непрозрачность теневого слоя на его правильное значение (0.04, 0.12 и т.д.), Но затем непрозрачность 0.04 of layer применяется ко всем подслоям. Поэтому я попытался установить layer.shadowOpacity на 1.0, но это сделало все тени сплошными черными. Я также старался быть умным и делать layer2.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.12).CGColor, но он был просто изменен на полный черный, без прозрачности.

Я предполагаю, что это имеет какой-то смысл, что слои должны иметь ту же непрозрачность теней. Но какой способ получить эту работу, различную непрозрачность и все (не нужно использовать CALayer, если это проще другим способом)?

Пожалуйста, не отвечайте "просто используйте изображение" : как бы ни было разумно, я стараюсь избегать этого. Просто пошутите меня.

Спасибо.

EDIT: согласно запросу, вот что мне нужно: Goal.

Ответ 1

Ключевым моментом, который нужно добавить, является установка слоев shadowPath. По умолчанию Core Graphics рисует тень вокруг видимого содержимого слоя, но в вашем коде не установлены ни backgroundColor, ни bounds для слоев, поэтому слои фактически пусты.

Предполагая, что у вас есть подкласс UIView, вы можете заставить его работать, добавив что-то вроде этого:

override func layoutSubviews() {
    super.layoutSubviews()
    layer.sublayers?.forEach { (sublayer) in
        sublayer.shadowPath = UIBezierPath(rect: bounds).cgPath
    }
}

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

Ответ 2

Как насчет добавления альфа-канала к цвету тени вместо непрозрачности слоя?

т.е. вместо

layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.5

делать

layer.shadowColor = UIColor.black.withAlphaComponent(0.5).cgColor

для каждого слоя.