ios 带有圆角和阴影的 UIView?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4754392/
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 18:37:25  来源:igfitidea点击:

UIView with rounded corners and drop shadow?

iphoneioscocoa-touchuiviewrounded-corners

提问by Aditya Vaidyam

I want a custom UIView... : I just wanted a blank white view with rounded corners and a light drop shadow (with no lighting effect). I can do each of those one by one but the usual clipToBounds/maskToBoundsconflicts occur.

我想要一个自定义UIView...:我只想要一个带有圆角和浅色阴影(没有灯光效果)的空白视图。我可以一一完成,但通常会发生clipToBounds/maskToBounds冲突。

回答by Suragch

Swift

迅速

enter image description here

在此处输入图片说明

// corner radius
blueView.layer.cornerRadius = 10

// border
blueView.layer.borderWidth = 1.0
blueView.layer.borderColor = UIColor.black.cgColor

// shadow
blueView.layer.shadowColor = UIColor.black.cgColor
blueView.layer.shadowOffset = CGSize(width: 3, height: 3)
blueView.layer.shadowOpacity = 0.7
blueView.layer.shadowRadius = 4.0

Exploring the options

探索选项

enter image description here

在此处输入图片说明

enter image description here

在此处输入图片说明

enter image description here

在此处输入图片说明

enter image description here

在此处输入图片说明

enter image description here

在此处输入图片说明

Problem 1: Shadow gets clipped off

问题 1:阴影被剪掉

What if there are sublayers or subviews (like an image) whose content we want to clip to the bounds of our view?

如果有子图层或子视图(如图像)的内容我们想要剪辑到我们的视图边界怎么办?

enter image description here

在此处输入图片说明

We can accomplish this with

我们可以用

blueView.layer.masksToBounds = true

(Alternatively, blueView.clipsToBounds = truegives the same result.)

(或者,blueView.clipsToBounds = true给出相同的结果。)

enter image description here

在此处输入图片说明

But, oh no!The shadow was also clipped off because it's outside of the bounds! What to do? What to do?

但是,哦不!阴影也被剪掉了,因为它超出了边界!该怎么办?该怎么办?

Solution

解决方案

Use separate views for the shadow and the border. The base view is transparent and has the shadow. The border view clips any other subcontent that it has to its borders.

对阴影和边框使用单独的视图。基础视图是透明的并且有阴影。边框视图将其具有的任何其他子内容剪辑到其边框。

// add the shadow to the base view
baseView.backgroundColor = UIColor.clear
baseView.layer.shadowColor = UIColor.black.cgColor
baseView.layer.shadowOffset = CGSize(width: 3, height: 3)
baseView.layer.shadowOpacity = 0.7
baseView.layer.shadowRadius = 4.0

// add the border to subview
let borderView = UIView()
borderView.frame = baseView.bounds
borderView.layer.cornerRadius = 10
borderView.layer.borderColor = UIColor.black.cgColor
borderView.layer.borderWidth = 1.0
borderView.layer.masksToBounds = true
baseView.addSubview(borderView)

// add any other subcontent that you want clipped
let otherSubContent = UIImageView()
otherSubContent.image = UIImage(named: "lion")
otherSubContent.frame = borderView.bounds
borderView.addSubview(otherSubContent)

This gives the following result:

这给出了以下结果:

enter image description here

在此处输入图片说明

Problem 2: Poor performance

问题 2:性能不佳

Adding rounded corners and shadows can be a performance hit. You can improve performance by using a predefined path for the shadow and also specifying that it be rasterized. The following code can be added to the example above.

添加圆角和阴影可能会影响性能。您可以通过为阴影使用预定义的路径并指定将其光栅化来提高性能。可以将以下代码添加到上面的示例中。

baseView.layer.shadowPath = UIBezierPath(roundedRect: baseView.bounds, cornerRadius: 10).cgPath
baseView.layer.shouldRasterize = true
baseView.layer.rasterizationScale = UIScreen.main.scale

See this postfor more details. See hereand herealso.

有关更多详细信息,请参阅此帖子。也见这里这里

This answer was tested with Swift 4 and Xcode 9.

这个答案是用 Swift 4 和 Xcode 9 测试过的。

回答by Evan Mulawski

The following code snippet adds a border, border radius, and drop shadow to v, a UIView:

以下代码片段向v, a添加边框、边框半径和投影UIView

// border radius
[v.layer setCornerRadius:30.0f];

// border
[v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[v.layer setBorderWidth:1.5f];

// drop shadow
[v.layer setShadowColor:[UIColor blackColor].CGColor];
[v.layer setShadowOpacity:0.8];
[v.layer setShadowRadius:3.0];
[v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];

You can adjust the settings to suit your needs.

您可以调整设置以满足您的需要。

Also, add the QuartzCore framework to your project and:

此外,将 QuartzCore 框架添加到您的项目中,然后:

#import <QuartzCore/QuartzCore.h>

See my other answerregarding masksToBounds.

请参阅关于masksToBounds.



Note

笔记

This may not work in all cases. If you find that this method interferes with other drawing operations that you are performing, please see this answer.

这可能不适用于所有情况。如果您发现此方法会干扰您正在执行的其他绘图操作,请参阅此答案

回答by David C.

One way to do this is to put the view with rounded corners in a view with the drop shadow.

一种方法是将带有圆角的视图放在带有阴影的视图中。

UIView* roundedView = [[UIView alloc] initWithFrame: frame];
roundedView.layer.cornerRadius = 5.0;
roundedView.layer.masksToBounds = YES;

UIView* shadowView = [[UIView alloc] initWithFrame: frame];
shadowView.layer.shadowColor = [UIColor blackColor].CGColor;
shadowView.layer.shadowRadius = 5.0;
shadowView.layer.shadowOffset = CGSizeMake(3.0, 3.0);
shadowView.layer.shadowOpacity = 1.0;
[shadowView addSubview: roundedView];

Then you can add the shadowView wherever you want.

然后你可以在任何你想要的地方添加 shadowView。

回答by Sergey Grischyov

Check out the example project on GitHubto make sure you use the component correctly.

查看GitHub 上示例项目以确保正确使用该组件。

Simple Swift 5 solution without any additional subviews or subclassing:

简单的 Swift 5 解决方案,没有任何额外的子视图或子类化:

extension UIView {

    func addShadow(offset: CGSize, color: UIColor, radius: CGFloat, opacity: Float) {
        layer.masksToBounds = false
        layer.shadowOffset = offset
        layer.shadowColor = color.cgColor
        layer.shadowRadius = radius
        layer.shadowOpacity = opacity

        let backgroundCGColor = backgroundColor?.cgColor
        backgroundColor = nil
        layer.backgroundColor =  backgroundCGColor
    }
}

Note that you should set up your view with corner radius and other properties before callingaddShadow.

请注意,在调用addShadow.

After that, just call this from viewDidLoadlike this:

之后,只需viewDidLoad像这样调用它:

button.addShadow(offset: CGSize.init(width: 0, height: 3), color: UIColor.black, radius: 2.0, opacity: 0.35)

Final result:

最后结果:

result

结果

Super easy and simple!

超级简单!

回答by Ade

This worked for me. Trick was to move the background color from the main view to the layer.

这对我有用。技巧是将背景颜色从主视图移动到图层。

CALayer *layer = view.layer;
layer.cornerRadius = 15.0f;
layer.masksToBounds = NO;

layer.shadowOffset = CGSizeMake(0, 3);
layer.shadowColor = [[UIColor blackColor] CGColor];
layer.shadowRadius = 2.0f;
layer.shadowOpacity = 0.35f;
layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:layer.bounds cornerRadius:layer.cornerRadius] CGPath];

CGColorRef  bColor = view.backgroundColor.CGColor;
view.backgroundColor = nil;
layer.backgroundColor =  bColor ;

回答by Alex Stone

I solved the problem using the following trick when assigning shadow path for the container view :

在为容器视图分配阴影路径时,我使用以下技巧解决了这个问题:

[UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12]

Notice that the path given to the shadow is a rounded rectangle with the same corner radius as the background that the cell contains:

请注意,给阴影的路径是一个圆角矩形,其角半径与单元格包含的背景相同:

//this is the border for the UIView that is added to a cell
cell.backgroundView.layer.cornerRadius = 12;
cell.backgroundView.layer.masksToBounds = YES;
cell.backgroundView.layer.borderColor = [UIColor darkGrayColor].CGColor;
cell.backgroundView.layer.borderWidth = 1;

//this is the shadow around the cell itself (cannot have round corners with borders and shadow, need to use two views
cell.layer.shadowRadius = 2;
cell.layer.cornerRadius = 12;
cell.layer.masksToBounds = NO;
[[cell layer] setShadowColor:[[UIColor darkGrayColor] CGColor]];

[[cell layer] setShadowOffset:CGSizeMake(0.0,0.0)];
[[cell layer] setShadowOpacity:1.0];

UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:cell.bounds cornerRadius:12];
[[cell layer] setShadowPath:[path CGPath]];

回答by daniel.gindi

If you are struggling because of the rounded cornersvs. subviewsvs. masksToBounds, then try using my function:

如果您因四舍五入cornersvs. subviewsvs.而苦苦挣扎masksToBounds,请尝试使用我的函数:

- (UIView*)putView:(UIView*)view insideShadowWithColor:(UIColor*)color andRadius:(CGFloat)shadowRadius andOffset:(CGSize)shadowOffset andOpacity:(CGFloat)shadowOpacity
{
    CGRect shadowFrame; // Modify this if needed
    shadowFrame.size.width = 0.f;
    shadowFrame.size.height = 0.f;
    shadowFrame.origin.x = 0.f;
    shadowFrame.origin.y = 0.f;
    UIView * shadow = [[UIView alloc] initWithFrame:shadowFrame];
    shadow.userInteractionEnabled = NO; // Modify this if needed
    shadow.layer.shadowColor = color.CGColor;
    shadow.layer.shadowOffset = shadowOffset;
    shadow.layer.shadowRadius = shadowRadius;
    shadow.layer.masksToBounds = NO;
    shadow.clipsToBounds = NO;
    shadow.layer.shadowOpacity = shadowOpacity;
    [view.superview insertSubview:shadow belowSubview:view];
    [shadow addSubview:view];
    return shadow;
}

call it on your view. whether your view has rounded corners, no matter its size, its shape - a nice shadow will be drawn.

根据您的观点调用它。无论您的视图是否有圆角,无论其大小、形状如何 - 都会绘制一个漂亮的阴影。

Just keep the return value of the function so you can refer to it when you want to remove the table (or for example use insertSubview:aboveView:)

只需保留函数的返回值,以便在要删除表(或例如使用insertSubview:aboveView:)时引用它

回答by rbaldwin

Using Swift 4 and Xcode 9, this is a working example of rounding an ImageViewwith a drop shadow, and a border.

使用 Swift 4 和 Xcode 9,这是一个ImageView带有阴影和边框的四舍五入示例。

    //set dimensions and position of image (in this case, centered)
    let imageHeight: CGFloat = 150, imageWidth: CGFloat = 150
    let xPosition = (self.view.frame.width / 2) - (imageWidth / 2)
    let yPosition = (self.view.frame.height / 2) - (imageHeight / 2)

    //set desired corner radius
    let cornerRadius: CGFloat = 20

    //create container for the image
    let imageContainer = UIView(frame: CGRect(x: xPosition, y: yPosition, width: imageWidth, height: imageHeight))

    //configure the container
    imageContainer.clipsToBounds = false
    imageContainer.layer.shadowColor = UIColor.black.cgColor
    imageContainer.layer.shadowOpacity = 1
    imageContainer.layer.shadowOffset = CGSize(width: 3.0, height: 3.0)
    imageContainer.layer.shadowRadius = 5
    imageContainer.layer.shadowPath = UIBezierPath(roundedRect: imageContainer.bounds, cornerRadius: cornerRadius).cgPath

    //create imageView
    let imageView = UIImageView(frame: imageContainer.bounds)

    //configure the imageView
    imageView.clipsToBounds = true
    imageView.layer.cornerRadius = cornerRadius
    //add a border (if required)
    imageView.layer.borderColor = UIColor.black.cgColor
    imageView.layer.borderWidth = 1.0
    //set the image
    imageView.image = UIImage(named: "bird")

    //add the views to the superview
    view.addSubview(imageContainer)
    imageContainer.addSubview(imageView)

enter image description here

在此处输入图片说明

If you want the image to be circular: (and shown without border)

如果您希望图像是圆形的:(并且不带边框显示)

let cornerRadius = imageWidth / 2

enter image description here

在此处输入图片说明

回答by Zayin Krige

I've created a helper on UIView

我在 UIView 上创建了一个助手

@interface UIView (Helper)

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset;
@end

you can call it like this

你可以这样称呼它

[self.view roundCornerswithRadius:5 andShadowOffset:5];

Here's the implementation

这是实现

- (void)roundCornerswithRadius:(float)cornerRadius
               andShadowOffset:(float)shadowOffset
{
    const float CORNER_RADIUS = cornerRadius;
    const float SHADOW_OFFSET = shadowOffset;
    const float SHADOW_OPACITY = 0.5;
    const float SHADOW_RADIUS = 3.0;

    UIView *superView = self.superview;

    CGRect oldBackgroundFrame = self.frame;
    [self removeFromSuperview];

    CGRect frameForShadowView = CGRectMake(0, 0, oldBackgroundFrame.size.width, oldBackgroundFrame.size.height);
    UIView *shadowView = [[UIView alloc] initWithFrame:frameForShadowView];
    [shadowView.layer setShadowOpacity:SHADOW_OPACITY];
    [shadowView.layer setShadowRadius:SHADOW_RADIUS];
    [shadowView.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];

    [self.layer setCornerRadius:CORNER_RADIUS];
    [self.layer setMasksToBounds:YES];

    [shadowView addSubview:self];
    [superView addSubview:shadowView];

}

回答by lwz7512

After one whole day research of the round corner view with shadow, I'm glad to post my custom uiview class here, hope to end this question:

经过一整天的阴影圆角视图研究,我很高兴在这里发布我的自定义uiview类,希望结束这个问题:

RoundCornerShadowView.h

圆角阴影视图.h

#import <UIKit/UIKit.h>

@interface RoundCornerShadowView : UIView

@end

RoundCornerShadowView.m

RoundCornerShadowView.m

#import "RoundCornerShadowView.h"

@implementation RoundCornerShadowView

// *** must override this method, not the other method ***
// otherwise, the background corner doesn't disappear....
// @2015/05/29
-(void) layoutSubviews {
    [super layoutSubviews];//is must to ensure rightly layout children view

    //1. first, create Inner layer with content
    CALayer *innerView = [CALayer layer];
    innerView.frame = CGRectMake(0,0,self.bounds.size.width,self.bounds.size.height);
    //instead of: innerView.frame = self.frame;
    innerView.borderWidth = 1.0f;
    innerView.cornerRadius = 6.0f;
    innerView.masksToBounds = YES;
    innerView.borderColor = [[UIColor lightGrayColor] CGColor];
    innerView.backgroundColor = [[UIColor whiteColor] CGColor];
    //put the layer to the BOTTOM of layers is also a MUST step...
    //otherwise this layer will overlay the sub uiviews in current uiview...
    [self.layer insertSublayer:innerView atIndex:0];

    //2. then, create shadow with self layer
    self.layer.masksToBounds = NO;
    self.layer.shadowColor = [[UIColor darkGrayColor] CGColor];
    self.layer.shadowOpacity = 0.4f;
    //shadow length
    self.layer.shadowRadius = 2.0f;
    //no offset
    self.layer.shadowOffset = CGSizeMake(0, 0);
    //right down shadow
    //[self.layer setShadowOffset: CGSizeMake(1.0f, 1.0f)];

    //3. last but important, MUST clear current view background color, or the color will show in the corner!
    self.backgroundColor = [UIColor clearColor];
}

@end

so, NO need to add subview in view or below in target view, just add one layer in current view, and do 3 step to complete it!

因此,无需在目标视图中或视图下方添加子视图,只需在当前视图中添加一层,然后执行 3 步即可完成!

take a close look at to the comments in the code, it's helpful to understanding the component!

仔细看看代码中的注释,对理解组件很有帮助!