Какой лучший способ добавить тень к моему 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

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

Менее известная уловка - использовать одну и ту же ссылку на нескольких уровнях. Конечно, они должны использовать одну и ту же форму, но это обычное явление для ячеек таблицы/коллекции.

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