108

我正在尝试为彼此叠加的视图添加阴影,视图折叠允许看到其他视图中的内容,在这种情况下,我想保持view.clipsToBounds打开,以便当视图折叠时它们的内容被剪裁。

这似乎让我很难为图层添加阴影,因为当我打开时clipsToBounds,阴影也会被剪裁。

我一直在尝试操纵view.frame并向view.bounds框架添加阴影,但允许边界足够大以包含它,但是我没有运气。

这是我用来添加阴影的代码(这只适用于clipsToBounds如图所示的 OFF)

view.clipsToBounds = NO;
view.layer.shadowColor = [[UIColor blackColor] CGColor];
view.layer.shadowOffset = CGSizeMake(0,5);
view.layer.shadowOpacity = 0.5;

这是应用于顶部最浅灰色层的阴影的屏幕截图。clipsToBounds希望这可以让我了解如果关闭,我的内容将如何重叠。

影子应用。

如何为我的内容添加阴影UIView并保持内容被剪裁?

编辑:只是想补充一点,我也玩过使用带有阴影的背景图像,效果很好,但是我仍然想知道最好的编码解决方案。

4

7 回答 7

282

尝试这个:

UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:view.bounds];
view.layer.masksToBounds = NO;
view.layer.shadowColor = [UIColor blackColor].CGColor;
view.layer.shadowOffset = CGSizeMake(0.0f, 5.0f);
view.layer.shadowOpacity = 0.5f;
view.layer.shadowPath = shadowPath.CGPath;

首先UIBezierPath用作shadowPath是至关重要的。如果您不使用它,一开始您可能不会注意到差异,但敏锐的眼睛会观察到在旋转设备和/或类似事件期间发生的某种滞后。这是一个重要的性能调整。

具体针对您的问题:重要的是view.layer.masksToBounds = NO它禁用了视图层的子层的裁剪,这些子层扩展得比视图的边界更远。

masksToBounds对于那些想知道(在层上)和视图自己的属性之间的区别是什么的人clipToBounds:真的没有。切换一个会对另一个产生影响。只是抽象层次不同。


斯威夫特 2.2:

override func layoutSubviews()
{
    super.layoutSubviews()

    let shadowPath = UIBezierPath(rect: bounds)
    layer.masksToBounds = false
    layer.shadowColor = UIColor.blackColor().CGColor
    layer.shadowOffset = CGSizeMake(0.0, 5.0)
    layer.shadowOpacity = 0.5
    layer.shadowPath = shadowPath.CGPath
}

斯威夫特 3:

override func layoutSubviews()
{
    super.layoutSubviews()

    let shadowPath = UIBezierPath(rect: bounds)
    layer.masksToBounds = false
    layer.shadowColor = UIColor.black.cgColor
    layer.shadowOffset = CGSize(width: 0.0, height: 5.0)
    layer.shadowOpacity = 0.5
    layer.shadowPath = shadowPath.cgPath
}
于 2012-03-18T19:06:57.393 回答
66

Wasabii 在 Swift 2.3 中的回答:

let shadowPath = UIBezierPath(rect: view.bounds)
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.blackColor().CGColor
view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
view.layer.shadowOpacity = 0.2
view.layer.shadowPath = shadowPath.CGPath

在 Swift 3/4/5 中:

let shadowPath = UIBezierPath(rect: view.bounds)
view.layer.masksToBounds = false
view.layer.shadowColor = UIColor.black.cgColor
view.layer.shadowOffset = CGSize(width: 0, height: 0.5)
view.layer.shadowOpacity = 0.2
view.layer.shadowPath = shadowPath.cgPath

如果您使用 AutoLayout,请将此代码放在 layoutSubviews() 中。

在 SwiftUI 中,这一切都容易得多:

Color.yellow  // or whatever your view
    .shadow(radius: 3)
    .frame(width: 200, height: 100)
于 2014-12-12T13:45:39.027 回答
13

诀窍是masksToBounds正确定义视图层的属性:

view.layer.masksToBounds = NO;

它应该可以工作。

来源

于 2012-03-18T19:07:04.523 回答
13

您可以为 UIView 创建扩展以在设计编辑器中访问这些值

设计编辑器中的阴影选项

extension UIView{

    @IBInspectable var shadowOffset: CGSize{
        get{
            return self.layer.shadowOffset
        }
        set{
            self.layer.shadowOffset = newValue
        }
    }

    @IBInspectable var shadowColor: UIColor{
        get{
            return UIColor(cgColor: self.layer.shadowColor!)
        }
        set{
            self.layer.shadowColor = newValue.cgColor
        }
    }

    @IBInspectable var shadowRadius: CGFloat{
        get{
            return self.layer.shadowRadius
        }
        set{
            self.layer.shadowRadius = newValue
        }
    }

    @IBInspectable var shadowOpacity: Float{
        get{
            return self.layer.shadowOpacity
        }
        set{
            self.layer.shadowOpacity = newValue
        }
    }
}
于 2017-04-06T15:41:46.713 回答
8

您也可以从情节提要为您的视图设置阴影

在此处输入图像描述

于 2018-03-22T07:12:16.627 回答
2

在 viewWillLayoutSubviews 上:

override func viewWillLayoutSubviews() {
    sampleView.layer.masksToBounds =  false
    sampleView.layer.shadowColor = UIColor.darkGrayColor().CGColor;
    sampleView.layer.shadowOffset = CGSizeMake(2.0, 2.0)
    sampleView.layer.shadowOpacity = 1.0
}

使用 UIView 的扩展:

extension UIView {

    func addDropShadowToView(targetView:UIView? ){
        targetView!.layer.masksToBounds =  false
        targetView!.layer.shadowColor = UIColor.darkGrayColor().CGColor;
        targetView!.layer.shadowOffset = CGSizeMake(2.0, 2.0)
        targetView!.layer.shadowOpacity = 1.0
    }
}

用法:

sampleView.addDropShadowToView(sampleView)
于 2016-04-13T07:12:46.690 回答
0

所以是的,你应该更喜欢 shadowPath 性能,而且:来自 CALayer.shadowPath 的头文件

使用此属性显式指定路径通常会 * 提高渲染性能,共享相同的路径 * 跨多个层的引用

一个鲜为人知的技巧是跨多个层共享相同的引用。当然,它们必须使用相同的形状,但这在表格/集合视图单元格中很常见。

我不知道为什么如果您共享实例它会变得更快,我猜它会缓存阴影的渲染并可以将其重用于视图中的其他实例。我想知道这是否更快

于 2019-05-03T23:39:36.293 回答