Почему masksToBounds = да мешает CALayer shadow?
С помощью следующего фрагмента я добавляю эффект тени к одному моему UIView. Что работает довольно хорошо. Но как только я установил вид masksToBounds свойство да. Эффект тени больше не отображается.
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;
у вас есть какие-либо идеи по этому поводу?
6 ответов:
потому что тень-это эффект, выполненный вне представления, и что masksToBounds, установленный в YES, скажет UIView не рисовать ничего, что находится вне него.
Если вы хотите roundedCorner вид с тенью я предлагаю вам сделать это с 2 видами:
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];
теперь это 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];
EDIT
если представления должны быть анимированы или прокручены,
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];
Это Swift 3 и IBDesignable версия ответа, опубликованного @TheSquad.
я использовал ту же концепцию при внесении изменений в файл Storyboard. Сначала я переехал мой 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.
надеюсь, это поможет :)
версия Swift 3.0 с раскадровкой
та же идея с @TheSquad. Создайте новый вид под фактическим видом и добавьте тень к нижнему виду.
1. Создайте представление под фактическим видом
перетащите a
UIView
к раскадровке с тем же ограничением, что и ваш целевой вид. Установите флажок клип привязан к целевому виду. Также убедитесь, что новый вид указан перед целевым видом, чтобы целевой вид охватывал новый вид.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
У меня также были серьезные проблемы с производительностью с тенями и закругленными углами. Вместо того, чтобы использовать часть shadowPath, я использовал следующие строки, которые отлично решили хит производительности:
self.layer.shouldRasterize = YES; self.layer.rasterizationScale = UIScreen.mainScreen.scale;
вот одно из решений:
@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 } }