ios 如何在 UIView 下绘制阴影?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/805872/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 15:51:57  来源:igfitidea点击:

How do I draw a shadow under a UIView?

iphoneobjective-cioscocoa-touchcore-graphics

提问by Fraser Speirs

I'm trying to draw a shadow under the bottom edge of a UIViewin Cocoa Touch. I understand that I should use CGContextSetShadow()to draw the shadow, but the Quartz 2D programming guide is a little vague:

我正在尝试UIView在 Cocoa Touch的底部边缘绘制阴影。我明白我应该CGContextSetShadow()用来绘制阴影,但是Quartz 2D编程指南有点模糊:

  1. Save the graphics state.
  2. Call the function CGContextSetShadow, passing the appropriate values.
  3. Perform all the drawing to which you want to apply shadows.
  4. Restore the graphics state
  1. 保存图形状态。
  2. 调用函数CGContextSetShadow,传递适当的值。
  3. 执行所有要应用阴影的绘图。
  4. 恢复图形状态

I've tried the following in a UIViewsubclass:

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

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

..but this doesn't work for me and I'm a bit stuck about (a) where to go next and (b) if there's anything I need to do to my UIViewto make this work?

..但这对我不起作用,而且我对 (a) 下一步要去哪里以及 (b) 是否需要对我做些什么UIView来使这项工作有所困扰?

采纳答案by Christian Brunschen

In your current code, you save the GStateof the current context, configure it to draw a shadow .. and the restore it to what it was before you configured it to draw a shadow. Then, finally, you invoke the superclass's implementation of drawRect: .

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

Any drawing that should be affected by the shadow setting needs to happen after

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

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

but before

之前

CGContextRestoreGState(currentContext);

So if you want the superclass's drawRect:to be 'wrapped' in a shadow, then how about if you rearrange your code like this?

因此,如果您希望超类drawRect:被“包裹”在阴影中,那么如果您像这样重新排列代码呢?

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

回答by ollie

A by far easier approach is to set some layer attributes of the view on initialization:

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

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

You need to import QuartzCore.

您需要导入 QuartzCore。

#import <QuartzCore/QuartzCore.h>

回答by ZYiOS

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;

This will slow down the application. Adding the following line can improve performance as long as your view is visibly rectangular:

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

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

回答by Antzi

Same solution, but just to remind you: You can define the shadow directly in the storyboard.

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

Ex:

前任:

enter image description here

在此处输入图片说明

回答by O-mkar

You can try this .... you can play with the values. The shadowRadiusdictates the amount of blur. shadowOffsetdictates where the shadow goes.

你可以试试这个....你可以玩这些值。该shadowRadius使然模糊量。shadowOffset决定了阴影的去向。

Swift 2.0

斯威夫特 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

Swift 3.0

斯威夫特 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

Example with spread

传播示例

Example with spread

传播示例

To create a basic shadow

创建基本阴影

    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

Swift 2.0 中的基本阴影示例

OUTPUT

输出

回答by Axel Guilmin

Simple and clean solution using Interface Builder

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

Add a file named UIView.swift in your project (or just paste this in any file) :

在您的项目中添加一个名为 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
        }
    }
}

Then this will be available in Interface Builder for every view in the Utilities Panel > Attributes Inspector :

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

Utilities Panel

Utilities Panel

You can easily set the shadow now.

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

Notes:
- The shadow won't appear in IB, only at runtime.
- As Mazen Kasser said

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

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

对于那些未能使其工作的人 [...] 确保clipsToBounds未启用Clip Subviews ( )

回答by Srikar Appalaraju

I use this as part of my utils. With this we can not only set shadow but also can get a rounded corner for any UIView. Also you could set what color shadow you prefer. Normally black is preferred but sometimes, when the background is non-white you might want something else. Here's what I use -

我将它用作我的实用程序的一部分。有了这个,我们不仅可以设置阴影,还可以为任何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;
}

To use this we need to call this - [utils roundedLayer:yourview.layer radius:5.0f shadow:YES];

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

回答by neoneye

Swift 3

斯威夫特 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
    }
}

回答by king_T

If you would like to use StoryBoard and wouldnt like to keep typing in runtime attributes, you can easily create an extension to views and make them usable in storyboard.

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

Step 1. create extension

步骤 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
    }
}
}

step 2. you can now use these attributes in storyboardstoryboard image

步骤 2. 您现在可以在故事板中使用这些属性storyboard image

回答by Mazen Kasser

To those who failed in getting this to work (As myself!) after trying all the answers here, just make sure Clip Subviewsis not enabled at the Attributes inspector...

对于在尝试了所有答案后未能使其正常工作的人(作为我自己!),只需确保在属性检查器中未启用剪辑子视图...