我在一个应用程序上工作了几年,收到了一个简单的设计请求:在UIView上圆角并添加投影。做以下所给的事
我想要一个自定义的UIView…:我只是想要一个空白的白色视图与圆角和光滴阴影(没有照明效果)。我可以逐个执行这些操作,但通常会发生clipToBounds/maskToBounds冲突。
我在一个应用程序上工作了几年,收到了一个简单的设计请求:在UIView上圆角并添加投影。做以下所给的事
我想要一个自定义的UIView…:我只是想要一个空白的白色视图与圆角和光滴阴影(没有照明效果)。我可以逐个执行这些操作,但通常会发生clipToBounds/maskToBounds冲突。
当前回答
iOS阴影和拐角半径
[iOS CALayer]
[iOS masksToBounds]
[iOS调试渲染]
你可以使用图层设置阴影
view1.layer.shadowColor = UIColor.magenta.cgColor
view1.layer.shadowOffset = CGSize(width: 0, height: 0)
view1.layer.shadowOpacity = 1
view1.layer.shadowRadius = 0
可视化
1. shadowoffset。宽度,2. shadowoffset。高度,3。shadowOpacity 4。shadowRadius
shadowOffset宽度和高度是任意的 shadowOpacity从0到1 shadowRadius从0开始为正
不是简单的任务
请注意,阴影不是仅根据边界和边角raduis计算的。在创建阴影的过程中,需要考虑以下事项:
子视图层 子层 内容(支持图像)
view1.backgroundColor = .clear
view1.layer.contents = UIImage(named: "ring")?.cgImage
view1.layer.contentsScale = UIScreen.main.scale
ScaleFactor(contentsScale, rasterizationScale) -默认为1.0
currentBitmapSize = layerSize * scaleFactor
//non retina
1 point == 1x pixels
//Retina
1 point == 2x pixels
//or
1 point == 3x pixels
//For example to draw line
point(width: 4, height: 2) == 1x pixels(width: 4, height: 2)(8 pixels) == 2x pixels(width: 8, height: 4)(32 pixels)
使用uisscreen .main.scale =当前屏幕的缩放因子
[iOS像素、点数、单位]
的绩效
使用层。角半径,阴影有一些性能影响
至于层。cornerRadius性能:
应用它的颜色混合使用[阅读更多]
至于影子Xcode提示你:
The layer is using dynamic shadows which are expensive to render. If possible try setting shadowPath, or pre-rendering the shadow into an image and putting it under the layer
1. 另外使用shadowPath
用于内部静态层。默认情况下,它是nil,这就是为什么UIKit应该创建一个屏幕外视图,并基于这个信息创建一个阴影。这就是为什么您能够预定义路径并进行设置。另一个优点是,您可以根据需要创建自定义阴影
view1.layer.shadowPath = UIBezierPath(roundedRect: view1.bounds, cornerRadius: 50).cgPath
缺点-缺乏活力。如果视图改变边界(宽度,高度,角半径…),阴影仍然是它是(旧的边界)。如果视图的位置被改变(移动,滚动),shadowPath将是正确的
2. 缓存栅格化
(iOS shouldRasterize)
其他回答
旧线程仍然当前…
我编辑了Daniel Gindi的方法,使它可以用于按钮等。 如果有人需要圆角,或者想要将圆角和边框结合起来,它必须在视图层上设置,这个视图层被传递给这个方法。我还设置了栅格化来加快一点。
+ (UIView*)putView:(UIView*)view insideShadowWithColor:(CGColorRef)color
andRadius:(CGFloat)shadowRadius
andOffset:(CGSize)shadowOffset
andOpacity:(CGFloat)shadowOpacity
{
// Must have same position like "view"
UIView *shadow = [[UIView alloc] initWithFrame:view.frame];
shadow.layer.contentsScale = [UIScreen mainScreen].scale;
shadow.userInteractionEnabled = YES; // Modify this if needed
shadow.layer.shadowColor = color;
shadow.layer.shadowOffset = shadowOffset;
shadow.layer.shadowRadius = shadowRadius;
shadow.layer.masksToBounds = NO;
shadow.clipsToBounds = NO;
shadow.layer.shadowOpacity = shadowOpacity;
shadow.layer.rasterizationScale = [UIScreen mainScreen].scale;
shadow.layer.shouldRasterize = YES;
[view.superview insertSubview:shadow belowSubview:view];
[shadow addSubview:view];
// Move view to the top left corner inside the shadowview
// ---> Buttons etc are working again :)
view.frame = CGRectMake(0, 0, view.frame.size.width, view.frame.size.height);
return shadow;
}
阴影+边界+角半径
scrollview.backgroundColor = [UIColor whiteColor];
CALayer *ScrlViewLayer = [scrollview layer];
[ScrlViewLayer setMasksToBounds:NO ];
[ScrlViewLayer setShadowColor:[[UIColor lightGrayColor] CGColor]];
[ScrlViewLayer setShadowOpacity:1.0 ];
[ScrlViewLayer setShadowRadius:6.0 ];
[ScrlViewLayer setShadowOffset:CGSizeMake( 0 , 0 )];
[ScrlViewLayer setShouldRasterize:YES];
[ScrlViewLayer setCornerRadius:5.0];
[ScrlViewLayer setBorderColor:[UIColor lightGrayColor].CGColor];
[ScrlViewLayer setBorderWidth:1.0];
[ScrlViewLayer setShadowPath:[UIBezierPath bezierPathWithRect:scrollview.bounds].CGPath];
Swift 4解决方案,使UICollectionViewCell圆形和添加阴影,没有任何扩展和并发症:)
注意:对于简单的视图,例如按钮。请看这篇文章中的@suragch的回答。 https://stackoverflow.com/a/34984063/7698092。按钮测试成功
以防有人还在努力使角落圆润,同时添加阴影。虽然这个解决方案适用于UICollectionViewCell,但它可以推广到任何视图。
这个技巧对我来说很有效,不需要做任何扩展和所有复杂的事情。我正在使用storyBoard。
技术
你必须在storyBoard的UICollectionViewCell中添加一个UIView(让我们说它是“containerView”),并在这个containerView中添加所有必需的视图(按钮,图像等)。 见截图。
连接containerView的出口。在CellforItemAtIndexPath委托函数中添加以下代码行。
//adds shadow to the layer of cell
cell.layer.cornerRadius = 3.0
cell.layer.masksToBounds = false
cell.layer.shadowColor = UIColor.black.cgColor
cell.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.layer.shadowOpacity = 0.6
//makes the cell round
let containerView = cell.containerView!
containerView.layer.cornerRadius = 8
containerView.clipsToBounds = true
输出
查看模拟器截图
如果你因为圆角、子视图和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;
}
在你的视图中调用它。无论你的视图是否有圆角,无论它的大小,它的形状-一个漂亮的阴影将被绘制出来。
只要保留函数的返回值,这样当你想要删除表时就可以引用它(或者例如使用insertSubview:aboveView:)
import UIKit
extension UIView {
func addShadow(shadowColor: UIColor, offSet: CGSize, opacity: Float, shadowRadius: CGFloat, cornerRadius: CGFloat, corners: UIRectCorner, fillColor: UIColor = .white) {
let shadowLayer = CAShapeLayer()
let size = CGSize(width: cornerRadius, height: cornerRadius)
let cgPath = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: size).cgPath //1
shadowLayer.path = cgPath //2
shadowLayer.fillColor = fillColor.cgColor //3
shadowLayer.shadowColor = shadowColor.cgColor //4
shadowLayer.shadowPath = cgPath
shadowLayer.shadowOffset = offSet //5
shadowLayer.shadowOpacity = opacity
shadowLayer.shadowRadius = shadowRadius
self.layer.addSublayer(shadowLayer)
}
}