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
UIView with rounded corners and drop shadow?
提问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
/maskToBounds
conflicts occur.
我想要一个自定义UIView
...:我只想要一个带有圆角和浅色阴影(没有灯光效果)的空白视图。我可以一一完成,但通常会发生clipToBounds
/maskToBounds
冲突。
回答by Suragch
Swift
迅速
// 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
探索选项
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?
如果有子图层或子视图(如图像)的内容我们想要剪辑到我们的视图边界怎么办?
We can accomplish this with
我们可以用
blueView.layer.masksToBounds = true
(Alternatively, blueView.clipsToBounds = true
gives the same result.)
(或者,blueView.clipsToBounds = true
给出相同的结果。)
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:
这给出了以下结果:
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.
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 viewDidLoad
like this:
之后,只需viewDidLoad
像这样调用它:
button.addShadow(offset: CGSize.init(width: 0, height: 3), color: UIColor.black, radius: 2.0, opacity: 0.35)
Final 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 corners
vs. subviews
vs. masksToBounds
, then try using my function:
如果您因四舍五入corners
vs. subviews
vs.而苦苦挣扎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 ImageView
with 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)
If you want the image to be circular: (and shown without border)
如果您希望图像是圆形的:(并且不带边框显示)
let cornerRadius = imageWidth / 2
回答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!
仔细看看代码中的注释,对理解组件很有帮助!