如何在UIView下绘制阴影?

Fra*_*irs 347 iphone cocoa-touch core-graphics objective-c ios

我想UIView在Cocoa Touch 的底部边缘画一个阴影.我明白我应该用CGContextSetShadow()它画阴影,但Quartz 2D编程指南有点模糊:

  1. 保存图形状态.
  2. 调用函数CGContextSetShadow,传递适当的值.
  3. 执行要应用阴影的所有绘图.
  4. 恢复图形状态

我在UIView子类中尝试了以下内容:

- (void)drawRect:(CGRect)rect {
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    CGContextSaveGState(currentContext);
    CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
    CGContextRestoreGState(currentContext);
    [super drawRect: rect];
}
Run Code Online (Sandbox Code Playgroud)

..但这对我不起作用,我有点不知道(a)下一步该去哪里,(b)如果有什么我需要做的让我UIView做这个工作?

0ll*_*lie 786

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

self.layer.masksToBounds = NO;
self.layer.shadowOffset = CGSizeMake(-15, 20);
self.layer.shadowRadius = 5;
self.layer.shadowOpacity = 0.5;
Run Code Online (Sandbox Code Playgroud)

您需要导入QuartzCore.

#import <QuartzCore/QuartzCore.h>
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案还需要在.h文件中添加`#import <QuartzCore/QuartzCore.h>"`. (118认同)
  • 将`masksToBounds`设置为`NO`会否定`cornerRadius`,不是吗? (26认同)
  • 但请注意,这仅适用于iOS 3.2+,因此如果您的应用程序应该使用旧版本,则必须使用Christian的解决方案或视图后面的静态图像(如果这是一个选项). (4认同)
  • 好的,要解决这个问题,需要在图层上设置backgroundColor,并且视图需要透明. (4认同)

ZYi*_*iOS 230

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;
Run Code Online (Sandbox Code Playgroud)

这会降低应用程序的速度.只要视图是明显的矩形,添加以下行可以提高性能:

self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.bounds].CGPath;
Run Code Online (Sandbox Code Playgroud)

  • @NathanGaskin - 绘制阴影是一项昂贵的操作,例如,如果您的应用程序允许其他界面方向并且您开始旋转设备,而没有明确指定阴影的路径,则必须在该动画期间多次渲染阴影,这取决于形状,可能明显减慢了动画 (10认同)
  • @BenjaminDobell该特定行仅适用于矩形,但您也可以创建非矩形路径.例如,如果你有一个圆角矩形,你可以使用bezierPathWithRoundedRect:cornerRadius: (9认同)
  • 除了其他之外,只需添加额外的行. (2认同)

Ant*_*tzi 158

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

例如:

在此输入图像描述

  • 使人们更容易复制和粘贴:layer.masksToBound,layer.shadowOffset,layer.shadowRadius,layer.shadowOpacity.错别字会杀了你. (6认同)
  • layer.shadowOpacity值应为0.5而不是0.5 (3认同)
  • 可悲的是,我认为CGColor在故事板上是遥不可及的:( (2认同)

小智 95

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

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

CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
Run Code Online (Sandbox Code Playgroud)

之前

CGContextRestoreGState(currentContext);
Run Code Online (Sandbox Code Playgroud)

因此,如果您希望超级类drawRect:被"包裹"在阴影中,那么如果您重新排列代码如何呢?

- (void)drawRect:(CGRect)rect {
    CGContextRef currentContext = UIGraphicsGetCurrentContext();
    CGContextSaveGState(currentContext);
    CGContextSetShadow(currentContext, CGSizeMake(-15, 20), 5);
    [super drawRect: rect];
    CGContextRestoreGState(currentContext);
}
Run Code Online (Sandbox Code Playgroud)


O-m*_*kar 42

你可以尝试这个......你可以玩这些值.这shadowRadius决定了模糊的数量.shadowOffset决定阴影的去向.

Swift 2.0

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
Run Code Online (Sandbox Code Playgroud)

Swift 3.0

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
Run Code Online (Sandbox Code Playgroud)

传播的例子

传播的例子

创建基本阴影

    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
Run Code Online (Sandbox Code Playgroud)

Swift 2.0中的基本阴影示例

OUTPUT


Axe*_*min 19

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

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

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,这将在Interface Builder中为Utilities面板> Attributes Inspector中的每个视图提供:

公用事业小组

您现在可以轻松设置阴影.

注意:
- 阴影不会出现在IB中,仅在运行时出现.
- 正如Mazen Kasser所说

对于那些未能使其工作的人[...],请确保clipsToBounds未启用剪辑子视图()


Sri*_*aju 13

我用它作为我的utils的一部分.有了这个,我们不仅可以设置阴影,还可以获得任何圆角UIView.您也可以设置您喜欢的颜色阴影.通常黑色是首选,但有时,当背景为非白色时,您可能需要其他东西.这是我用的 -

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;
}
Run Code Online (Sandbox Code Playgroud)

要使用它,我们需要调用它 - [utils roundedLayer:yourview.layer radius:5.0f shadow:YES];


neo*_*eye 7

斯威夫特3

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
    }
}
Run Code Online (Sandbox Code Playgroud)


kin*_*g_T 6

如果您想使用StoryBoard并不想继续输入运行时属性,则可以轻松地创建视图的扩展并使它们在情节提要中可用。

步骤1.建立扩充功能

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
    }
}
}
Run Code Online (Sandbox Code Playgroud)

步骤2.您现在可以在情节提要中使用这些属性故事板图像