Невозможно добавить угловой радиус и тень

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

[layer setShadowOffset:CGSizeMake(0, 3)];
[layer setShadowOpacity:0.4];
[layer setShadowRadius:3.0f];
[layer setShouldRasterize:YES];

Здесь слой является CALayer подкласса UIView. Поэтому это срабатывает, когда я устанавливаю

[layer setMasksToBounds:NO];

Теперь, чтобы добавить радиус угла, я делаю это:

[layer setCornerRadius:7.0f];

но мне нужно установить MasksToBounds в YES, чтобы это работало:

[layer setMasksToBounds:YES];

В любом случае я могу добавить оба этих эффекта?

Спасибо за ваше время,

Денис

Ответ 1

Да, да, есть...

Если вы хотите как радиус угла, так и тень, вы не включаете -masksToBounds, а задаете радиус угла и задаете путь безье тени с закругленным прямоугольником. Держите радиус двух одинаковых:

[layer setShadowOffset:CGSizeMake(0, 3)];
[layer setShadowOpacity:0.4];
[layer setShadowRadius:3.0f];
[layer setShouldRasterize:YES];

[layer setCornerRadius:12.0f];
[layer setShadowPath:
                   [[UIBezierPath bezierPathWithRoundedRect:[self bounds]
                                               cornerRadius:12.0f] CGPath]];

Вы можете проверить свою производительность без параметра -shouldRasterize после установки теневого пути. Производительность чертежа имеет тенденцию быть очень хорошей, если вы установили теневой путь.

UPDATE

Я не рассматривал эту проблему довольно долго, но, похоже, вам больше не нужно устанавливать shadowPath, чтобы заставить это работать. Просто установка cornerRadius и shadowOpacity будет работать сейчас. Я думаю, что это имело место с iOS5 (насколько я могу судить). Предоставление этого обновления, вероятно, не нужно, поскольку установка этих параметров "просто работает", но я предоставил его для потомства. Чтобы повторить, это теперь все, что вам нужно:

[layer setShadowOpacity:0.4];
[layer setCornerRadius:12.0f];

Если вам по-прежнему нужна более высокая производительность, вы можете продолжить и установить параметр shouldRasterize:

[layer setShouldRasterize:YES];

И говоря о производительности, стоит отметить, что если вы заметите вялые анимации, вы захотите использовать технику настройки пути тени в конце концов. Это обновление было действительно просто указать, что установка пути больше не требуется для достижения эффекта одновременного отображения радиуса угла и тени. Если производительность - ваш приоритет, используйте путь.

ОБНОВЛЕНИЕ 2

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

- (void)viewDidLoad
{
  [super viewDidLoad];

  CALayer *layer = [CALayer layer];
  [layer setBounds:CGRectMake(0.0f, 0.0f, 100.0f, 200.0f)];
  [layer setPosition:[[self view] center]];
  [layer setBackgroundColor:[[UIColor lightGrayColor] CGColor]];
  [layer setShadowOpacity:0.55f];
  [layer setCornerRadius:8.0f];
  [layer setBorderWidth:1.0f];

  [[[self view] layer] addSublayer:layer];

  [[[self testView] layer] setShadowOpacity:0.55f];
  [[[self testView] layer] setShadowRadius:15.0f];
  [[[self testView] layer] setCornerRadius:8.0f];
  [[[self testView] layer] setBorderWidth:1.0f];
}

testView - это UIView, который я добавил в Interface Builder и установил выход. Это делается для того, чтобы убедиться, что он работает одинаково на обоих уровнях, которые вы добавляете явно, а также на слои в рамках subviews.

Я тестировал это на симуляторах для iOS5 через iOS6.1. Это дает мне результат в каждом из них:

enter image description here

Ответ 2

Следующий код Swift 3 показывает, как нарисовать тень и радиус угла на изображении, используя CAShapeLayer и CALayer.

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // constants
        let radius: CGFloat = 20, offset = 8
        let rect = CGRect(x: 0, y: 0, width: 200, height: 200)

        // roundedView
        let roundedView = UIView()
        view.addSubview(roundedView)

        // shadow layer
        let shadowLayer = CALayer()
        shadowLayer.shadowColor = UIColor.darkGray.cgColor
        shadowLayer.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath
        shadowLayer.shadowOffset = CGSize(width: offset, height: offset)
        shadowLayer.shadowOpacity = 0.8
        shadowLayer.shadowRadius = 2
        roundedView.layer.addSublayer(shadowLayer)

        // mask layer
        let maskLayer = CAShapeLayer()
        maskLayer.path = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath

        // image layer
        let imageLayer = CALayer()
        imageLayer.mask = maskLayer
        imageLayer.frame = rect
        imageLayer.contentsGravity = kCAGravityResizeAspectFill
        imageLayer.contents = UIImage(named: "image")?.cgImage
        roundedView.layer.addSublayer(imageLayer)

        // auto layout
        roundedView.translatesAutoresizingMaskIntoConstraints = false
        roundedView.widthAnchor.constraint(equalToConstant: rect.width).isActive = true
        roundedView.heightAnchor.constraint(equalToConstant: rect.height).isActive = true
        roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    }

}

Этот код генерирует следующий экран:

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


Предыдущий код может быть реорганизован в следующие быстрые файлы:

CustomView.swift

import UIKit

class CustomView: UIView {

    var imageLayer: CALayer!
    var image: UIImage? {
        didSet { refreshImage() }
    }

    override var intrinsicContentSize:


        CGSize {
        return CGSize(width: 200, height: 200)
    }

    func refreshImage() {
        if let imageLayer = imageLayer, let image = image {
            imageLayer.contents = image.cgImage
        }
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        if imageLayer == nil {
            let radius: CGFloat = 20, offset: CGFloat = 8

            let shadowLayer = CALayer()
            shadowLayer.shadowColor = UIColor.darkGray.cgColor
            shadowLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
            shadowLayer.shadowOffset = CGSize(width: offset, height: offset)
            shadowLayer.shadowOpacity = 0.8
            shadowLayer.shadowRadius = 2
            layer.addSublayer(shadowLayer)

            let maskLayer = CAShapeLayer()
            maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath

            imageLayer = CALayer()
            imageLayer.mask = maskLayer
            imageLayer.frame = bounds
            imageLayer.backgroundColor = UIColor.red.cgColor
            imageLayer.contentsGravity = kCAGravityResizeAspectFill
            layer.addSublayer(imageLayer)
        }


        refreshImage()
    }

}

ViewController.swift

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let roundedView = CustomView()
        roundedView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(roundedView)

        // auto layout
        let horizontalConstraint = roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        let verticalConstraint = roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])

        roundedView.image = UIImage(named: "image")
    }

}

Вы можете найти больше способов комбинировать изображения с закругленными углами и тенью на этом Github repo.

Ответ 3

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

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

button.clipsToBounds=YES;
button.layer.cornerRadius = 25;

UIView *shadowView = [[UIView alloc]initWithFrame:button.frame];

shadowView.backgroundColor = [UIColor whiteColor];//needs this to cast shadow
shadowView.layer.cornerRadius = 25;
shadowView.clipsToBounds = YES;
shadowView.layer.masksToBounds = NO;
shadowView.layer.shadowOffset = CGSizeMake(0, 2);
shadowView.layer.shadowRadius = 1;
shadowView.layer.shadowOpacity = 0.2;


[[button superview]addSubview:shadowView];
[[button superview]bringSubviewToFront:button];

Ответ 4

view.layer.cornerRadius=4;
[view.layer setMasksToBounds:YES];
[view.layer setShadowColor:SHADOW_COLOR];
[view.layer setShadowOpacity:4 ];
[view.layer setShadowRadius:4];
[view.layer setShadowOffset:0];    
[view.layer setShadowPath: [[UIBezierPath bezierPathWithRoundedRect:[view bounds] cornerRadius:CORNER_RADIUS] CGPath]];
view.layer.borderColor=[[UIColor lightGrayColor] colorWithAlphaComponent:.5].CGColor;
view.layer.borderWidth=.4;