Почему masksToBounds = YES предотвращает тень CALayer?


83

С помощью следующего фрагмента я добавляю эффект тени к одному из моих UIView. Что работает очень хорошо. Но как только я установил свойство masksToBounds представления в YES . Эффект падающей тени больше не отображается.

self.myView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.myView.layer.shadowOpacity = 1.0;
self.myView.layer.shadowRadius = 10.0;
self.myView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.myView.layer.cornerRadius = 5.0;
self.myView.layer.masksToBounds = YES; // <-- This is causing the Drop shadow to not be rendered
UIBezierPath *path = [UIBezierPath bezierPathWithCurvedShadowForRect:self.myView.bounds];
self.myView.layer.shadowPath = path.CGPath;
self.myView.layer.shouldRasterize = YES;

У вас есть идеи по этому поводу?

Ответы:


166

Поскольку тень - это эффект, выполняемый за пределами View, и этот параметр masksToBounds, установленный в YES, сообщит UIView не рисовать ничего, что находится вне его.

Если вам нужен вид с закругленными углами и тенью, я предлагаю вам сделать это с двумя видами:

UIView *view1 = [[UIView alloc] init];
UIView *view2 = [[UIView alloc] init];

view1.layer.cornerRadius = 5.0;
view1.layer.masksToBounds = YES;
view2.layer.cornerRadius = 5.0;
view2.layer.shadowColor = [[UIColor blackColor] CGColor];
view2.layer.shadowOpacity = 1.0;
view2.layer.shadowRadius = 10.0;
view2.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
[view2 addSubview:view1];
[view1 release];

Большое спасибо ... Мне это очень помогло. Благодарен вам .. :)
innodeasapps

1
Просто примечание, убедитесь, что супервизор [view2 в данном случае] имеет четкий фоновый цвет, в любом случае это была моя проблема
Адам Картер

@GangstaGraham убедитесь, что вы добавляете view2 в качестве subview view1.
pxpgraphics

Именно то, что мне нужно!
Рохан Санап,

17

Сейчас iOS 6, возможно, все изменилось. Ответ TheSquad не работает для меня, пока мне не удалось добавить еще одну строку view2.layer.masksToBounds = NO;, иначе тень не отображается. Хотя в документации указано « masksToBoundsНЕТ» по умолчанию, мой код показывает обратное.

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

button.layer.masksToBounds = YES;
button.layer.cornerRadius = 10.0f;

view.layer.masksToBounds = NO;      // critical to add this line
view.layer.cornerRadius = 10.0f;
view.layer.shadowOpacity = 1.0f;
// set shadow path to prevent horrible performance
view.layer.shadowPath = 
    [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath;      

[view addSubview:button];

РЕДАКТИРОВАТЬ

Если просмотры нужно анимировать или прокручивать, это masksToBounds = YESзначительно снизит производительность, а это означает, что анимация, вероятно, будет зависать. Чтобы получить закругленный угол и тень, а также плавную анимацию или прокрутку, используйте вместо этого следующий код:

button.backgroundColor = [UIColor clearColor];
button.layer.backgroundColor = [UIColor redColor].CGColor;
button.layer.masksToBounds = NO;
button.layer.cornerRadius = 10.0f;

view.layer.shadowOpacity = 0.5f;
view.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath;
view.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
view.layer.shadowRadius = 2.0f;
view.layer.masksToBounds = NO;
view.layer.cornerRadius = 10.0f;  

[view addSubview:button];

4
+1 за первый ответ. Ваш обновленный ответ не будет работать для закругленных углов. Если вы установите "masksToBounds" на "NO", закругленные углы исчезнут. Вместо того, чтобы менять это, вы можете использовать свойство shouldRasterize для получения хорошей производительности.
Динеш Раджа

Это работает сейчас в 2020 году. Такое простое решение, просто добавить одну строку.
GeneCode

4

Это Swift 3 и IBDesignable версия ответа, опубликованная @TheSquad.

Я использовал ту же концепцию при внесении изменений в файл раскадровки. Сначала я переместил свой targetView (тот, который требует углового радиуса и тени) внутрь нового containerView . Затем я добавил следующие строки кода (Ссылка: https://stackoverflow.com/a/35372901/419192 ), чтобы добавить некоторые атрибуты IBDesignable для класса UIView:

@IBDesignable extension UIView {
/* The color of the shadow. Defaults to opaque black. Colors created
 * from patterns are currently NOT supported. Animatable. */
@IBInspectable var shadowColor: UIColor? {
    set {
        layer.shadowColor = newValue!.cgColor
    }
    get {
        if let color = layer.shadowColor {
            return UIColor(cgColor: color)
        }
        else {
            return nil
        }
    }
}

/* The opacity of the shadow. Defaults to 0. Specifying a value outside the
 * [0,1] range will give undefined results. Animatable. */
@IBInspectable var shadowOpacity: Float {
    set {
        layer.shadowOpacity = newValue
    }
    get {
        return layer.shadowOpacity
    }
}

/* The shadow offset. Defaults to (0, -3). Animatable. */
@IBInspectable var shadowOffset: CGPoint {
    set {
        layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
    }
    get {
        return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
    }
}

/* The blur radius used to create the shadow. Defaults to 3. Animatable. */
@IBInspectable var shadowRadius: CGFloat {
    set {
        layer.shadowRadius = newValue
    }
    get {
        return layer.shadowRadius
    }
}

/* The corner radius of the view. */
@IBInspectable var cornerRadius: CGFloat {
    set {
        layer.cornerRadius = newValue
    }
    get {
        return layer.cornerRadius
    }
}

После добавления этого кода я вернулся к раскадровке и, выбрав свой containerView, теперь смог найти новый набор атрибутов в инспекторе атрибутов:

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

Помимо добавления значений для этих атрибутов по моему выбору, я также добавил радиус угла в свой targetView и установил для свойства masksToBounds значение true.

Надеюсь, это поможет :)


4

Версия Swift 3.0 с StoryBoard

Та же идея с @TheSquad. Создайте новый вид под фактическим видом и добавьте тень к нижнему виду.

1. Создайте представление под фактическим представлением.

Перетащите UIViewна StoryBoard с тем же ограничением, что и в целевом представлении. Отметьте клип для привязки к целевому виду. Также убедитесь, что новое представление указано перед целевым представлением, чтобы целевое представление перекрывало новое представление.

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

2. Теперь свяжите новое представление с вашим кодом, добавьте тень на него.

Это всего лишь образец. Вы можете делать здесь все, что хотите

shadowView.layer.masksToBounds = false
shadowView.layer.shadowColor = UIColor.red.cgColor
shadowView.layer.shadowOpacity = 0.5
shadowView.layer.shadowOffset = CGSize(width: -1, height: 1)
shadowView.layer.shadowRadius = 3

shadowView.layer.shadowPath = UIBezierPath(rect: coverImage.bounds).cgPath
shadowView.layer.shouldRasterize = true

2

У меня также были серьезные проблемы с производительностью с тенями и закругленными углами. Вместо использования части shadowPath я использовал следующие строки, которые отлично решили проблему производительности:

self.layer.shouldRasterize = YES;
self.layer.rasterizationScale = UIScreen.mainScreen.scale;

Однако с этим нельзя анимировать или ретранслировать экран.
Ван Ду Тран,

1

Вот одно из решений:

     @IBOutlet private weak var blockView: UIView! {
         didSet {
          blockView.backgroundColor = UIColor.white
          blockView.layer.shadowColor = UIColor.black.cgColor
          blockView.layer.shadowOpacity = 0.5
          blockView.layer.shadowOffset = CGSize.zero

          blockView.layer.cornerRadius = 10
        }
      }
      @IBOutlet private weak var imageView: UIImageView! {
        didSet {
          imageView.layer.cornerRadius = 10
          imageView.layer.masksToBounds = true

          imageView.layer.shouldRasterize = true
        }
      }

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.