我在一个应用程序上工作了几年,收到了一个简单的设计请求:在UIView上圆角并添加投影。做以下所给的事

我想要一个自定义的UIView…:我只是想要一个空白的白色视图与圆角和光滴阴影(没有照明效果)。我可以逐个执行这些操作,但通常会发生clipToBounds/maskToBounds冲突。


当前回答

在swift 4中进行了测试

import UIKit

extension UIView {
    @IBInspectable var dropShadow: Bool {
        set{
            if newValue {
                layer.shadowColor = UIColor.black.cgColor
                layer.shadowOpacity = 0.4
                layer.shadowRadius = 1
                layer.shadowOffset = CGSize.zero
            } else {
                layer.shadowColor = UIColor.clear.cgColor
                layer.shadowOpacity = 0
                layer.shadowRadius = 0
                layer.shadowOffset = CGSize.zero
            }
        }
        get {
            return layer.shadowOpacity > 0
        }
    }
}

生产

如果你像这样在检查器中启用它:

它将添加用户定义的运行时属性,结果是:

(我之前添加了拐角半径= 8)

:)

其他回答

Swift 4解决方案,使UICollectionViewCell圆形和添加阴影,没有任何扩展和并发症:)

注意:对于简单的视图,例如按钮。请看这篇文章中的@suragch的回答。 https://stackoverflow.com/a/34984063/7698092。按钮测试成功

以防有人还在努力使角落圆润,同时添加阴影。虽然这个解决方案适用于UICollectionViewCell,但它可以推广到任何视图。

这个技巧对我来说很有效,不需要做任何扩展和所有复杂的事情。我正在使用storyBoard。

技术

你必须在storyBoard的UICollectionViewCell中添加一个UIView(让我们说它是“containerView”),并在这个containerView中添加所有必需的视图(按钮,图像等)。 见截图。

连接containerView的出口。在CellforItemAtIndexPath委托函数中添加以下代码行。

//adds shadow to the layer of cell

cell.layer.cornerRadius = 3.0
    cell.layer.masksToBounds = false
    cell.layer.shadowColor = UIColor.black.cgColor
    cell.layer.shadowOffset = CGSize(width: 0, height: 0)
    cell.layer.shadowOpacity = 0.6

//makes the cell round 

let containerView = cell.containerView!
    containerView.layer.cornerRadius = 8
    containerView.clipsToBounds = true

输出

查看模拟器截图

我写了这个UIView分类方法来解决这个问题,使用单独的视图来表示阴影和角的半径。

-(UIView *)shadowedWrapViewWithBounds:(CGRect)bounds {
UIView *baseView = [[UIView alloc] init];
baseView.bounds = bounds;
baseView.backgroundColor = [UIColor clearColor];
baseView.layer.shadowColor = [UIColor blackColor].CGColor;
baseView.layer.shadowOffset = CGSizeMake(0, 0);
baseView.layer.shadowOpacity = 0.7;
baseView.layer.shadowRadius = 4.0;

// improve performance
baseView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:baseView.bounds cornerRadius:4].CGPath;
baseView.layer.shouldRasterize = YES;
baseView.layer.rasterizationScale = [UIScreen mainScreen].scale;

[baseView addSubview:self];
//use Masonry autolayout, self can set corner radius
[self makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(baseView);
}];

return baseView;
}

这是我的版本在Swift 3的UIView

let corners:UIRectCorner = [.bottomLeft, .topRight]
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
let mask = CAShapeLayer()

mask.path = path.cgPath
mask.fillColor = UIColor.white.cgColor

let shadowLayer = CAShapeLayer()
shadowLayer.shadowColor = UIColor.black.cgColor
shadowLayer.shadowOffset = CGSize(width: 0.0, height: 4.0)
shadowLayer.shadowRadius = 6.0
shadowLayer.shadowOpacity = 0.25
shadowLayer.shadowPath = mask.path

self.layer.insertSublayer(shadowLayer, at: 0)
self.layer.insertSublayer(mask, at: 1)
var shadows = UIView()
shadows.frame = view.frame
shadows.clipsToBounds = false
view.addSubview(shadows)


let shadowPath0 = UIBezierPath(roundedRect: shadows.bounds, cornerRadius: 10)
let layer0 = CALayer()
layer0.shadowPath = shadowPath0.cgPath
layer0.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.23).cgColor
layer0.shadowOpacity = 1
layer0.shadowRadius = 6
layer0.shadowOffset = CGSize(width: 0, height: 3)
layer0.bounds = shadows.bounds
layer0.position = shadows.center

shadows.layer.addSublayer(layer0)

iOS阴影和拐角半径

[iOS CALayer]

[iOS masksToBounds]

[iOS调试渲染]

你可以使用图层设置阴影

view1.layer.shadowColor = UIColor.magenta.cgColor

view1.layer.shadowOffset = CGSize(width: 0, height: 0)
view1.layer.shadowOpacity = 1
view1.layer.shadowRadius = 0

可视化

1. shadowoffset。宽度,2. shadowoffset。高度,3。shadowOpacity 4。shadowRadius

shadowOffset宽度和高度是任意的 shadowOpacity从0到1 shadowRadius从0开始为正

不是简单的任务

请注意,阴影不是仅根据边界和边角raduis计算的。在创建阴影的过程中,需要考虑以下事项:

子视图层 子层 内容(支持图像)

view1.backgroundColor = .clear
view1.layer.contents = UIImage(named: "ring")?.cgImage
view1.layer.contentsScale = UIScreen.main.scale

ScaleFactor(contentsScale, rasterizationScale) -默认为1.0

currentBitmapSize = layerSize * scaleFactor

//non retina
1 point == 1x pixels

//Retina
1 point == 2x pixels
//or
1 point == 3x pixels

//For example to draw line 
point(width: 4, height: 2) == 1x pixels(width: 4, height: 2)(8 pixels) == 2x pixels(width: 8, height: 4)(32 pixels)

使用uisscreen .main.scale =当前屏幕的缩放因子

[iOS像素、点数、单位]

的绩效

使用层。角半径,阴影有一些性能影响

至于层。cornerRadius性能:

应用它的颜色混合使用[阅读更多]

至于影子Xcode提示你:

The layer is using dynamic shadows which are expensive to render. If possible try setting shadowPath, or pre-rendering the shadow into an image and putting it under the layer

1. 另外使用shadowPath

用于内部静态层。默认情况下,它是nil,这就是为什么UIKit应该创建一个屏幕外视图,并基于这个信息创建一个阴影。这就是为什么您能够预定义路径并进行设置。另一个优点是,您可以根据需要创建自定义阴影

view1.layer.shadowPath = UIBezierPath(roundedRect: view1.bounds, cornerRadius: 50).cgPath

缺点-缺乏活力。如果视图改变边界(宽度,高度,角半径…),阴影仍然是它是(旧的边界)。如果视图的位置被改变(移动,滚动),shadowPath将是正确的

2. 缓存栅格化

(iOS shouldRasterize)