具有拐角半径和阴影视图的 UIView 不会在拐角处剪辑子视图

Posted

技术标签:

【中文标题】具有拐角半径和阴影视图的 UIView 不会在拐角处剪辑子视图【英文标题】:UIView with corner Radius and Shadow view doesn't clip subviews in corners 【发布时间】:2018-08-01 10:26:11 【问题描述】:

以下是自定义卡片视图的代码。问题是,当我在界面生成器中添加子视图时,它不会将角半径应用于子视图。在大多数情况下,我可以通过使子视图具有清晰的背景颜色来解决这个问题,但我正在努力使用UIImageView。当我将它添加到卡片时,它最终会出现尖角,我无法修复它。

这里的各种解决方案都建议添加第二层来显示阴影。我已经尝试过了,但它仍然无法按预期工作。我想要实现的是带有圆角、阴影和添加任何子视图(例如UIImageView)的视图也应该保持圆角半径而不是指出。

我尝试了layer.masksToBoundsself.clipsToBounds 的各种设置,但我似乎总是得到具有圆角半径但没有阴影或阴影可见且视图没有剪切的子视图。

@IBDesignable class CardView: UIView 

    @IBInspectable dynamic var cornerRadius: CGFloat = 6
    @IBInspectable dynamic var shadowOffsetWidth: Int = 2
    @IBInspectable dynamic var shadowOffsetHeight: Int = 2
    @IBInspectable dynamic var shadowColor: UIColor? = UIColor(netHex: 0x333333)
    @IBInspectable dynamic var shadowOpacity: Float = 0.5

    override init(frame: CGRect) 
        super.init(frame: frame)
        commonInit()
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
    
    override func layoutSubviews() 
        commonInit()
    

    override func prepareForInterfaceBuilder() 
        commonInit()
    

    func commonInit() 

        layer.cornerRadius = cornerRadius
        let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
        layer.masksToBounds = false

        layer.shadowColor = shadowColor?.cgColor
        layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
        layer.shadowOpacity = shadowOpacity
        layer.shadowPath = shadowPath.cgPath

        // This was how I tried to add a seperate shadow layer
//        let shadowView = UIView(frame: self.frame)
//        shadowView.layer.shadowColor = shadowColor?.cgColor
//        shadowView.layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
//        shadowView.layer.shadowOpacity = shadowOpacity
//        shadowView.layer.shadowPath = shadowPath.cgPath
//        shadowView.layer.masksToBounds = false
//
//        self.addSubview(shadowView)

    


【问题讨论】:

【参考方案1】:

您尝试实现第二个视图来处理阴影的方式几乎是正确的,只是您没有保持正确的顺序。

您的CardView 类已经处理了显示阴影。保持该视图不变,而是添加一个名为“ContentView”的 UIView 作为子视图。该内容视图与您的 CardView 具有相同的框架和角半径。

在“ContentView”上,您无需对阴影进行任何处理。相反,将其层的masksToBounds 属性设置为true。现在将您想要在卡片中显示的所有内容添加到“ContentView”,它应该可以正确剪辑。

func commonInit() 

    layer.cornerRadius = cornerRadius
    let shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius)
    layer.masksToBounds = false

    layer.shadowColor = shadowColor?.cgColor
    layer.shadowOffset = CGSize(width: shadowOffsetWidth, height: shadowOffsetHeight)
    layer.shadowOpacity = shadowOpacity
    layer.shadowPath = shadowPath.cgPath

    let contentView = UIView()
    contentView.frame = self.frame
    contentView.layer.cornerRadius = cornerRadius
    contentView.layer.masksToBounds = true

    // any content you add should now be added to the contentView:
    // contentView.addSubview(aView)

【讨论】:

这似乎对我不起作用。我在界面生成器中添加子视图,而不是以编程方式。我现在正在尝试在卡片视图上方添加 contentView 并查看这是否意味着将子视图添加到内容视图而不是 cardView 本身 我正在尝试 contentView.frame = self.bounds contentView.layer.cornerRadius =cornerRadius contentView.layer.masksToBounds = true contentView.backgroundColor = .red self.insertSubview(contentView, at: 0)。我必须将框架设置为边界(否则 contentView.frame.origin 关闭等于 cardView 在屏幕上的显示方式。我已将其设为红色以便我可以看到它。如果我添加子视图,它会出现在界面生成器中的所有内容上. 如果我在索引 1 处插入,我可以看到它,但子视图仍会添加到卡片视图中。 如果您使用界面构建器,则在 CardView 中添加内容视图并通过@IBOutlet 属性连接它们。从那里您可以对内容视图(corner RadiusmasksToBounds)进行相同的修改,而无需初始化其框架。然后可以在界面构建器中将所有内容添加到 contentView 子视图中。 这是否意味着对我的应用程序中的每个 cardView 都做(有很多,我试图避免通过一个单一的)我可以用 nib 重新创建 cardView 并以这种方式添加 contentView一次。那行得通吗? 我将尝试制作一个带有两个视图的笔尖,一个带有阴影样式和一个剪辑到边界的子视图。它不适合表格视图,因为 cardView 是我在许多不同地方使用过的 UI 功能,包括在 tableViewCells 中。【参考方案2】:

此外,您还可以指定特定的角落。

layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMaxYCorner]

【讨论】:

以上是关于具有拐角半径和阴影视图的 UIView 不会在拐角处剪辑子视图的主要内容,如果未能解决你的问题,请参考以下文章

特定拐角的拐角半径

我的拐角半径仅适用于一个拐角

拐角半径仅在特定拐角处

如何使用 CAShaperLayer 设置拐角半径值?

圆形 UIView 不是一个完整的圆圈

仅将角半径设置为 UIView/UIButton 的特定侧