Какой лучший способ добавить тень к моему UIView
Я пытаюсь добавить тень к представлениям, которые накладываются друг на друга друг над другом, сглаживание представлений, позволяющее видеть содержимое в других представлениях, в этом ключе я хочу сохранить view.clipsToBounds
ON, чтобы при просмотре представлений свернуть их содержимое обрезается.
Кажется, мне было сложно добавить тени для слоев, как если бы я включил clipsToBounds
ON, тени также обрезаются.
Я пытаюсь манипулировать view.frame
и view.bounds
, чтобы добавить тень к кадру, но позволить границам быть достаточно большими, чтобы охватить его, однако мне не повезло с этим.
Вот код, который я использую, чтобы добавить Shadow (это работает только с clipsToBounds
OFF, как показано)
view.clipsToBounds = NO;
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowOffset = CGSizeMake(0,5);
view.layer.shadowOpacity = 0.5;
Вот скриншот тени, применяемой к самому светлому серому слою. Надеюсь, это дает представление о том, как мой контент будет перекрываться, если clipsToBounds
выключен.
![Shadow Application.]()
Как добавить тень к моему UIView
и сохранить содержимое подрезанного?
Изменить: просто хотел добавить, что я также играл с использованием фоновых изображений с тенями, что хорошо работает, однако я все равно хотел бы знать лучшее кодированное решение для этого.
Ответы
Ответ 1
Попробуйте следующее:
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:view.bounds];
view.layer.masksToBounds = NO;
view.layer.shadowColor = [UIColor blackColor].CGColor;
view.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
view.layer.shadowOpacity = 0.5f;
view.layer.shadowPath = shadowPath.CGPath;
Прежде всего: UIBezierPath
используется как shadowPath
. Если вы не используете его, вы можете не заметить разницу сначала, но сильный глаз будет наблюдать определенное отставание, возникающее во время таких событий, как вращение устройства и/или подобное. Это важная настройка производительности.
Что касается конкретной проблемы: важная строка view.layer.masksToBounds = NO
. Это отключает обрезку подслоев уровня представления, которые простираются дальше границ представления.
Для тех, кто задается вопросом, какая разница между masksToBounds
(на слое) и собственным свойством clipToBounds
представления: на самом деле нет. Переключение одного будет иметь влияние на другое. Просто другой уровень абстракции.
Swift 2.2:
override func layoutSubviews()
{
super.layoutSubviews()
let shadowPath = UIBezierPath(rect: bounds)
layer.masksToBounds = false
layer.shadowColor = UIColor.blackColor().CGColor
layer.shadowOffset = CGSizeMake(0.0, 5.0)
layer.shadowOpacity = 0.5
layer.shadowPath = shadowPath.CGPath
}
Swift 3:
override func layoutSubviews()
{
super.layoutSubviews()
let shadowPath = UIBezierPath(rect: bounds)
layer.masksToBounds = false
layer.shadowColor = UIColor.black.cgColor
layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
layer.shadowOpacity = 0.5
layer.shadowPath = shadowPath.cgPath
}
Ответ 2
Ответ васабии в Swift 2.3:
let shadowPath = UIBezierPath(rect: view.bounds)
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.blackColor().CGColor
view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
view.layer.shadowOpacity = 0.2
view.layer.shadowPath = shadowPath.CGPath
И в Свифт 3/4/5:
let shadowPath = UIBezierPath(rect: view.bounds)
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
view.layer.shadowOpacity = 0.2
view.layer.shadowPath = shadowPath.cgPath
Поместите этот код в layoutSubviews(), если вы используете AutoLayout.
В SwiftUI все гораздо проще:
Color.yellow // or whatever your view
.shadow(radius: 3)
.frame(width: 200, height: 100)
Ответ 3
Трюк правильно определяет свойство masksToBounds
вашего слоя просмотра:
view.layer.masksToBounds = NO;
и он должен работать.
(Источник)
Ответ 4
Вы можете создать расширение для UIView для доступа к этим значениям в редакторе дизайна.
![Shadow options in design editor]()
extension UIView{
@IBInspectable var shadowOffset: CGSize{
get{
return self.layer.shadowOffset
}
set{
self.layer.shadowOffset = newValue
}
}
@IBInspectable var shadowColor: UIColor{
get{
return UIColor(cgColor: self.layer.shadowColor!)
}
set{
self.layer.shadowColor = newValue.cgColor
}
}
@IBInspectable var shadowRadius: CGFloat{
get{
return self.layer.shadowRadius
}
set{
self.layer.shadowRadius = newValue
}
}
@IBInspectable var shadowOpacity: Float{
get{
return self.layer.shadowOpacity
}
set{
self.layer.shadowOpacity = newValue
}
}
}
Ответ 5
Вы также можете установить тень на свой вид из раскадровки
![enter image description here]()
Ответ 6
В представленииWillLayoutSubviews:
override func viewWillLayoutSubviews() {
sampleView.layer.masksToBounds = false
sampleView.layer.shadowColor = UIColor.darkGrayColor().CGColor;
sampleView.layer.shadowOffset = CGSizeMake(2.0, 2.0)
sampleView.layer.shadowOpacity = 1.0
}
Использование расширения UIView:
extension UIView {
func addDropShadowToView(targetView:UIView? ){
targetView!.layer.masksToBounds = false
targetView!.layer.shadowColor = UIColor.darkGrayColor().CGColor;
targetView!.layer.shadowOffset = CGSizeMake(2.0, 2.0)
targetView!.layer.shadowOpacity = 1.0
}
}
Использование:
sampleView.addDropShadowToView(sampleView)
Ответ 7
Так что да, вы должны предпочесть свойство shadowPath для производительности, но также: Из заголовочного файла CALayer.shadowPath
Явное указание пути с помощью этого свойства обычно * улучшит производительность рендеринга, как и использование одного и того же пути * для нескольких слоев
Менее известная уловка - использовать одну и ту же ссылку на нескольких уровнях. Конечно, они должны использовать одну и ту же форму, но это обычное явление для ячеек таблицы/коллекции.
Я не знаю, почему это происходит быстрее, если вы делитесь экземплярами, я предполагаю, что он кэширует рендеринг тени и может повторно использовать его для других экземпляров в представлении. Интересно, будет ли это еще быстрее с