【问题标题】:Why masksToBounds = YES prevents CALayer shadow?为什么masksToBounds = YES会阻止CALayer阴影?
【发布时间】:2011-04-11 02:19:25
【问题描述】:

通过以下 sn-p,我正在向我的 UIView 添加投影效果。效果很好。但只要我将视图的 ma​​sksToBounds 属性设置为 YES。不再渲染阴影效果。

self.myView.layer.shadowColor = [[UIColor blackColor] CGColor];
self.myView.layer.shadowOpacity = 1.0;
self.myView.layer.shadowRadius = 10.0;
self.myView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
self.myView.layer.cornerRadius = 5.0;
self.myView.layer.masksToBounds = YES; // <-- This is causing the Drop shadow to not be rendered
UIBezierPath *path = [UIBezierPath bezierPathWithCurvedShadowForRect:self.myView.bounds];
self.myView.layer.shadowPath = path.CGPath;
self.myView.layer.shouldRasterize = YES;

您对此有什么想法吗?

【问题讨论】:

    标签: ios objective-c uiview calayer


    【解决方案1】:

    因为阴影是在 View 之外完成的效果,并且将 maskToBounds 设置为 YES 将告诉 UIView 不要绘制任何在其外部的东西。

    如果您想要一个带阴影的圆角视图,我建议您使用 2 个视图:

    UIView *view1 = [[UIView alloc] init];
    UIView *view2 = [[UIView alloc] init];
    
    view1.layer.cornerRadius = 5.0;
    view1.layer.masksToBounds = YES;
    view2.layer.cornerRadius = 5.0;
    view2.layer.shadowColor = [[UIColor blackColor] CGColor];
    view2.layer.shadowOpacity = 1.0;
    view2.layer.shadowRadius = 10.0;
    view2.layer.shadowOffset = CGSizeMake(0.0f, 0.0f);
    [view2 addSubview:view1];
    [view1 release];
    

    【讨论】:

    • 非常感谢...对我帮助很大。谢谢你.. :)
    • 请注意,确保超级视图 [view2 在这种情况下] 具有清晰的背景颜色,这无论如何都是我的问题
    • @GangstaGraham 确保将 view2 添加为 view1 的子视图。
    • 正是我需要的!
    【解决方案2】:

    现在是 iOS 6,情况可能有所改变。在我设法再添加一行view2.layer.masksToBounds = NO; 之前,TheSquad 的答案对我不起作用,否则阴影不会显示。虽然文档说 masksToBounds 默认为 NO,但我的代码显示相反。

    以下是我如何制作带阴影的圆角按钮,这是我的应用程序中最常用的代码 sn-p 之一。

    button.layer.masksToBounds = YES;
    button.layer.cornerRadius = 10.0f;
    
    view.layer.masksToBounds = NO;      // critical to add this line
    view.layer.cornerRadius = 10.0f;
    view.layer.shadowOpacity = 1.0f;
    // set shadow path to prevent horrible performance
    view.layer.shadowPath = 
        [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath;      
    
    [view addSubview:button];
    

    编辑

    如果视图需要动画或滚动,masksToBounds = YES 会显着降低性能,这意味着动画可能会卡顿。要获得圆角和阴影以及平滑动画或滚动,请改用以下代码:

    button.backgroundColor = [UIColor clearColor];
    button.layer.backgroundColor = [UIColor redColor].CGColor;
    button.layer.masksToBounds = NO;
    button.layer.cornerRadius = 10.0f;
    
    view.layer.shadowOpacity = 0.5f;
    view.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath;
    view.layer.shadowOffset = CGSizeMake(0.0f, 4.0f);
    view.layer.shadowRadius = 2.0f;
    view.layer.masksToBounds = NO;
    view.layer.cornerRadius = 10.0f;  
    
    [view addSubview:button];
    

    【讨论】:

    • +1 第一个答案。您更新的答案不适用于圆角。如果您将“masksToBounds”设置为“NO”,那么圆角将消失。您可以使用“shouldRasterize”属性来获得良好的性能,而不是更改它。
    • 这在 2020 年有效。如此简单的解决方案只需添加一行。
    【解决方案3】:

    带有 StoryBoard 的 Swift 3.0 版本

    @TheSquad 的想法相同。在实际视图下新建一个视图,并为下方视图添加阴影。

    1.在实际视图下创建视图

    UIView 拖动到StoryBoard,约束与目标视图相同。检查剪辑以绑定目标视图。还要确保新视图列在目标视图之前,以便目标视图覆盖新视图。

    2。现在将新视图链接到您的代码添加阴影

    这只是一个示例。你可以在这里做任何你想做的事情

    shadowView.layer.masksToBounds = false
    shadowView.layer.shadowColor = UIColor.red.cgColor
    shadowView.layer.shadowOpacity = 0.5
    shadowView.layer.shadowOffset = CGSize(width: -1, height: 1)
    shadowView.layer.shadowRadius = 3
    
    shadowView.layer.shadowPath = UIBezierPath(rect: coverImage.bounds).cgPath
    shadowView.layer.shouldRasterize = true
    

    【讨论】:

      【解决方案4】:

      这是@TheSquad 发布的答案的 Swift 3 和 IBDesignable 版本。

      我在更改情节提要文件时使用了相同的概念。首先,我将我的 targetView(需要圆角半径和阴影的那个)移动到一个新的 containerView 中。然后我添加了以下代码行(参考:https://stackoverflow.com/a/35372901/419192)为 UIView 类添加一些 IBDesignable 属性:

      @IBDesignable extension UIView {
      /* The color of the shadow. Defaults to opaque black. Colors created
       * from patterns are currently NOT supported. Animatable. */
      @IBInspectable var shadowColor: UIColor? {
          set {
              layer.shadowColor = newValue!.cgColor
          }
          get {
              if let color = layer.shadowColor {
                  return UIColor(cgColor: color)
              }
              else {
                  return nil
              }
          }
      }
      
      /* The opacity of the shadow. Defaults to 0. Specifying a value outside the
       * [0,1] range will give undefined results. Animatable. */
      @IBInspectable var shadowOpacity: Float {
          set {
              layer.shadowOpacity = newValue
          }
          get {
              return layer.shadowOpacity
          }
      }
      
      /* The shadow offset. Defaults to (0, -3). Animatable. */
      @IBInspectable var shadowOffset: CGPoint {
          set {
              layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
          }
          get {
              return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
          }
      }
      
      /* The blur radius used to create the shadow. Defaults to 3. Animatable. */
      @IBInspectable var shadowRadius: CGFloat {
          set {
              layer.shadowRadius = newValue
          }
          get {
              return layer.shadowRadius
          }
      }
      
      /* The corner radius of the view. */
      @IBInspectable var cornerRadius: CGFloat {
          set {
              layer.cornerRadius = newValue
          }
          get {
              return layer.cornerRadius
          }
      }
      

      添加此代码后,我返回故事板并选择我的 containerView,现在我可以在属性检查器中找到一组新属性:

      除了根据我的选择为这些属性添加值之外,我还在 targetView 中添加了一个圆角半径并将 maskToBounds 属性设置为 true。

      我希望这会有所帮助:)

      【讨论】:

        【解决方案5】:

        在阴影和圆角方面我也遇到了严重的性能问题。我没有使用 shadowPath 部分,而是使用以下行完美解决了性能问题:

        self.layer.shouldRasterize = YES;
        self.layer.rasterizationScale = UIScreen.mainScreen.scale;
        

        【讨论】:

        • 但是,不能用这个动画或重新布局屏幕。
        【解决方案6】:

        这是解决方案之一:

             @IBOutlet private weak var blockView: UIView! {
                 didSet {
                  blockView.backgroundColor = UIColor.white
                  blockView.layer.shadowColor = UIColor.black.cgColor
                  blockView.layer.shadowOpacity = 0.5
                  blockView.layer.shadowOffset = CGSize.zero
        
                  blockView.layer.cornerRadius = 10
                }
              }
              @IBOutlet private weak var imageView: UIImageView! {
                didSet {
                  imageView.layer.cornerRadius = 10
                  imageView.layer.masksToBounds = true
        
                  imageView.layer.shouldRasterize = true
                }
              }
        

        【讨论】:

          猜你喜欢
          • 2015-09-19
          • 2010-11-13
          • 1970-01-01
          • 2016-12-09
          • 2012-04-17
          • 2013-01-28
          • 1970-01-01
          • 2019-08-09
          • 1970-01-01
          相关资源
          最近更新 更多