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

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


当前回答

Evan Mulawski提供的答案将会非常有效。问题是你必须将视图的背景色设置为clearColor,并将masksToBounds属性设置为NO。

你可以为视图设置任何你想要的颜色

v.layer.backgroundColor = your color;

希望这能有所帮助。

其他回答

这是我的版本在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)

丹尼尔。Gindi上面的回答对我很有用!然而,我不得不做一些小的调整-改变shadowFrame的大小与视图的帧大小相同,并启用用户交互。以下是更新后的代码:

+ (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed

    // Modified this line
    shadowFrame.size = CGSizeMake(view.frame.size.width, view.frame.size.height);

    shadowFrame.origin.x = 0.f;
    shadowFrame.origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];

    // Modified this line
    shadow.userInteractionEnabled = YES;
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;

    [shadow addSubview:view];
    return shadow;
}

我想补充的是,在我的情况下,我试图将此添加到第三方视图控制器,即我没有对代码的直接控制。下面是我如何使用上面的函数:

UIView *shadow = [self putView:vc.view 
         insideShadowWithColor:[UIColor blackColor]
                     andRadius:5.0 
                     andOffset:CGSizeMake(0.0, 0.0) 
                    andOpacity:1.0];
vc.view = shadow;
vc.view.layer.cornerRadius = 5.0;
vc.view.layer.masksToBounds = YES;

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)

我写了这个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;
}

如果你特别想为uibutton定制圆角,有很多不同的方法来实现。

下面的代码示例(感谢Erica)很好地概述了所有可能性。

iOS 15之前的圆角按钮

在iOS 15之前,你可以通过设置图层来制作圆角按钮。cornerRadius, backgroundColor和setTitleColor。

let button = UIButton(type: .system)
button.setTitle("Button", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemPink
button.layer.cornerRadius = 8

button.contentEdgeInsets = UIEdgeInsets(
  top: 10,
  left: 20,
  bottom: 10,
  right: 20
)

胶囊按钮

如果我们增加足够大的角半径值,您可以创建一个胶囊风格的按钮。为了创建一个胶囊风格的按钮,我们设置角半径等于按钮高度的一半。由于按钮的高度可能会根据标题大小或布局而变化,我通常为胶囊样式创建一个UIButton子类。

class CapsuleButton: UIButton {
  override func layoutSubviews() {
    super.layoutSubviews()
    let height = bounds.height
    layer.cornerRadius = height/2
  }
}

let capsule = CapsuleButton(type: .system)
capsule.setTitle("Button", for: .normal)
capsule.setTitleColor(.white, for: .normal)
capsule.backgroundColor = .systemPink
capsule.contentEdgeInsets = UIEdgeInsets(
  top: 10,
  left: 20,
  bottom: 10,
  right: 20
)

光滑的角落

如果你想复制苹果平滑角,你也可以用拐角曲线属性来做。要创建连续的平滑角,请设置图层。按钮连续的曲线。

let button = UIButton(type: .system)
button.setTitle("Button", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemPink
button.layer.cornerRadius = 8
button.layer.cornerCurve = .continuous

button.contentEdgeInsets = UIEdgeInsets(
  top: 10,
  left: 20,
  bottom: 10,
  right: 20
)

圆角按钮在iOS 15使用UIButton。配置

在iOS 15中,苹果引入了一种通过UIButton.Configuration自定义按钮的新方法。

var configuration = UIButton.Configuration.filled()

configuration.title = "Button"
configuration.baseBackgroundColor = UIColor.systemPink
configuration.contentInsets = NSDirectionalEdgeInsets(
  top: 10,
  leading: 20,
  bottom: 10,
  trailing: 20
)

let button = UIButton(configuration: configuration, primaryAction: nil)

使用cornerStyle控制角的半径

UIButton。配置有许多内置的角样式供您选择。你可以用cornerStyle属性来设置。

configuration.cornerStyle = .small
configuration.cornerStyle = .medium
configuration.cornerStyle = .large
configuration.cornerStyle = .capsule

自定义角半径

如果你想要一些更独特的东西,你可以通过UIBackgroundConfiguration的cornerRadius指定角的半径。

var configuration = UIButton.Configuration.filled()
configuration.title = "Button"
configuration.baseBackgroundColor = UIColor.systemPink
configuration.contentInsets = NSDirectionalEdgeInsets(
  top: 10,
  leading: 20,
  bottom: 10,
  trailing: 20
)
configuration.background.cornerRadius = 20

configuration.cornerStyle = .fixed


let button = UIButton(configuration: configuration, primaryAction: nil)