关于iphone:如何在UIView下绘制阴影?

How do I draw a shadow under a UIView?

我正试图在一个用可可粉触摸的UIView的底边下画一个阴影。我知道我应该用CGContextSetShadow()来画阴影,但是quartz 2d编程指南有点模糊:

  • 保存图形状态。
  • 调用函数CGContextSetShadow,传递适当的值。
  • 执行要应用阴影的所有绘图。
  • 恢复图形状态
  • 我在UIView子类中尝试了以下方法:

    1
    2
    3
    4
    5
    6
    7
    - (void)drawRect:(CGRect)rect {
        CGContextRef currentContext = UIGraphicsGetCurrentContext();
        CGContextSaveGState(currentContext);
        CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
        CGContextRestoreGState(currentContext);
        [super drawRect: rect];
    }

    …但这对我来说不起作用,我有点纠结于(a)下一步该去哪里,(b)如果我需要对我的UIView做些什么来实现这一点?


    一种更简单的方法是在初始化时设置视图的某些层属性:

    1
    2
    3
    4
    self.layer.masksToBounds = NO;
    self.layer.shadowOffset = CGSizeMake(-15, 20);
    self.layer.shadowRadius = 5;
    self.layer.shadowOpacity = 0.5;

    你需要进口夸脱。

    1
    #import <QuartzCore/QuartzCore.h>


    1
    2
    3
    4
    5
    self.layer.masksToBounds = NO;
    self.layer.cornerRadius = 8; // if you like rounded corners
    self.layer.shadowOffset = CGSizeMake(-15, 20);
    self.layer.shadowRadius = 5;
    self.layer.shadowOpacity = 0.5;

    这将减慢应用程序的速度。添加以下行可以提高性能,只要视图是可见的矩形:

    1
    self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;


    同样的解决方案,但只是提醒您:您可以直接在故事板中定义阴影。

    前任:

    enter image description here


    在当前代码中,保存当前上下文的GState,将其配置为绘制阴影。然后将其恢复到配置为绘制阴影之前的状态。最后,调用超类的drawRect实现:。

    任何应该受阴影设置影响的绘图都需要在

    1
    CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);

    但以前

    1
    CGContextRestoreGState(currentContext);

    所以,如果你想让超类的drawRect:被"包裹"在阴影中,那么如果你像这样重新排列你的代码呢?

    1
    2
    3
    4
    5
    6
    7
    - (void)drawRect:(CGRect)rect {
        CGContextRef currentContext = UIGraphicsGetCurrentContext();
        CGContextSaveGState(currentContext);
        CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
        [super drawRect: rect];
        CGContextRestoreGState(currentContext);
    }

    你可以试试这个……你可以玩弄价值观。shadowRadius决定模糊的数量。shadowOffset决定了阴影的去向。

    Swift 2.0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
    let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
    //Change 2.1 to amount of spread you need and for height replace the code for height

    demoView.layer.cornerRadius = 2
    demoView.layer.shadowColor = UIColor.blackColor().CGColor
    demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
    demoView.layer.shadowOpacity = 0.5
    demoView.layer.shadowRadius = 5.0 //Here your control your blur
    demoView.layer.masksToBounds =  false
    demoView.layer.shadowPath = shadowPath.CGPath

    Swift 3.0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
    let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
    //Change 2.1 to amount of spread you need and for height replace the code for height

    demoView.layer.cornerRadius = 2
    demoView.layer.shadowColor = UIColor.black.cgColor
    demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4)  //Here you control x and y
    demoView.layer.shadowOpacity = 0.5
    demoView.layer.shadowRadius = 5.0 //Here your control your blur
    demoView.layer.masksToBounds =  false
    demoView.layer.shadowPath = shadowPath.cgPath

    Example with spread

    Example with spread

    To create a basic shadow

    1
    2
    3
    4
    5
        demoView.layer.cornerRadius = 2
        demoView.layer.shadowColor = UIColor.blackColor().CGColor
        demoView.layer.shadowOffset = CGSizeMake(0.5, 4.0); //Here your control your spread
        demoView.layer.shadowOpacity = 0.5
        demoView.layer.shadowRadius = 5.0 //Here your control your blur

    Basic Shadow example in Swift 2.0

    OUTPUT


    使用Interface Builder的简单而干净的解决方案

    在项目中添加名为uiview.swift的文件(或将其粘贴到任何文件中):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    import UIKit

    @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
            }
        }
    }

    然后,在"工具面板>属性检查器"中的每个视图的"界面生成器"中都可以使用该选项:

    Utilities Panel

    现在可以轻松设置阴影。

    笔记:-阴影不会出现在ib中,只会在运行时出现。-正如Mazen Kasser所说

    To those who failed in getting this to work [...] make sure Clip Subviews (clipsToBounds) is not enabled


    我把它作为实用程序的一部分。这样,我们不仅可以设置阴影,而且可以为任何UIView获得圆角。也可以设置您喜欢的颜色阴影。通常情况下,黑色是首选,但有时,当背景非白色时,您可能需要其他东西。这是我用的-

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    in utils.m
    + (void)roundedLayer:(CALayer *)viewLayer
                  radius:(float)r
                  shadow:(BOOL)s
    {
        [viewLayer setMasksToBounds:YES];
        [viewLayer setCornerRadius:r];        
        [viewLayer setBorderColor:[RGB(180, 180, 180) CGColor]];
        [viewLayer setBorderWidth:1.0f];
        if(s)
        {
            [viewLayer setShadowColor:[RGB(0, 0, 0) CGColor]];
            [viewLayer setShadowOffset:CGSizeMake(0, 0)];
            [viewLayer setShadowOpacity:1];
            [viewLayer setShadowRadius:2.0];
        }
        return;
    }

    要使用这个,我们需要称之为-[utils roundedLayer:yourview.layer radius:5.0f shadow:YES];


    斯威夫特3

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    extension UIView {
        func installShadow() {
            layer.cornerRadius = 2
            layer.masksToBounds = false
            layer.shadowColor = UIColor.black.cgColor
            layer.shadowOffset = CGSize(width: 0, height: 1)
            layer.shadowOpacity = 0.45
            layer.shadowPath = UIBezierPath(rect: bounds).cgPath
            layer.shadowRadius = 1.0
        }
    }


    如果您想使用故事板,并且不想继续在运行时属性中键入内容,那么您可以轻松地创建视图的扩展并使它们在故事板中可用。

    步骤1。创建扩展名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    extension UIView {

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

    @IBInspectable var shadowOpacity: Float {
        get {
            return layer.shadowOpacity
        }
        set {
            layer.shadowOpacity = newValue
        }
    }

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

    @IBInspectable var maskToBound: Bool {
        get {
            return layer.masksToBounds
        }
        set {
            layer.masksToBounds = newValue
        }
    }
    }

    步骤2。现在可以在Storyboardstoryboard image中使用这些属性。


    对于那些没能让这个工作的人(作为我自己!)在这里尝试了所有答案之后,只需确保在属性检查器中没有启用剪辑子视图…


    对于其他的Xamarin,答案的xamarin.ios/c版本如下:

    1
    2
    3
    4
    5
    6
    7
    8
    public override void DrawRect(CGRect area, UIViewPrintFormatter formatter)
    {
        CGContext currentContext = UIGraphics.GetCurrentContext();
        currentContext.SaveState();
        currentContext.SetShadow(new CGSize(-15, 20), 5);
        base.DrawRect(area, formatter);
        currentContext.RestoreState();                
    }

    主要的区别在于,您获取了一个CGContext的实例,在该实例上直接调用适当的方法。


    都回答得很好,但我想再加一分

    如果在有表单元格时遇到问题,请取消新单元格阴影中的不匹配,因此在本例中,需要将阴影代码放在layoutSubviews方法中,以便它在所有条件下都能正常工作。

    1
    2
    3
    4
    5
    6
    7
    -(void)layoutSubviews{
        [super layoutSubviews];

        [self.contentView setNeedsLayout];
        [self.contentView layoutIfNeeded];
        [VPShadow applyShadowView:self];
    }

    或者在特定视图的"视图控制器"中,将阴影代码放在下面的方法中,以便其正常工作

    1
    2
    3
    4
    5
    6
    -(void)viewDidLayoutSubviews{
        [super viewDidLayoutSubviews];

        [self.viewShadow layoutIfNeeded];
        [VPShadow applyShadowView:self.viewShadow];
    }

    我已经修改了新devs的影子实现,以获得更广泛的形式,例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /*!
     @brief Add shadow to a view.

     @param layer CALayer of the view.

     */

    +(void)applyShadowOnView:(CALayer *)layer OffsetX:(CGFloat)x OffsetY:(CGFloat)y blur:(CGFloat)radius opacity:(CGFloat)alpha RoundingCorners:(CGFloat)cornerRadius{
        UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:cornerRadius];
        layer.masksToBounds = NO;
        layer.shadowColor = [UIColor blackColor].CGColor;
        layer.shadowOffset = CGSizeMake(x,y);// shadow x and y
        layer.shadowOpacity = alpha;
        layer.shadowRadius = radius;// blur effect
        layer.shadowPath = shadowPath.CGPath;
    }

    您可以使用我为阴影和拐角半径创建的实用程序函数,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    - (void)addShadowWithRadius:(CGFloat)shadowRadius withShadowOpacity:(CGFloat)shadowOpacity withShadowOffset:(CGSize)shadowOffset withShadowColor:(UIColor *)shadowColor withCornerRadius:(CGFloat)cornerRadius withBorderColor:(UIColor *)borderColor withBorderWidth:(CGFloat)borderWidth forView:(UIView *)view{

        // drop shadow
        [view.layer setShadowRadius:shadowRadius];
        [view.layer setShadowOpacity:shadowOpacity];
        [view.layer setShadowOffset:shadowOffset];
        [view.layer setShadowColor:shadowColor.CGColor];

        // border radius
        [view.layer setCornerRadius:cornerRadius];

        // border
        [view.layer setBorderColor:borderColor.CGColor];
        [view.layer setBorderWidth:borderWidth];
    }

    希望它能帮助你!!!!


    斯威夫特3

    1
    2
    3
    4
    self.paddingView.layer.masksToBounds = false
    self.paddingView.layer.shadowOffset = CGSize(width: -15, height: 10)
    self.paddingView.layer.shadowRadius = 5
    self.paddingView.layer.shadowOpacity = 0.5