仅将 CALayer 阴影遮蔽到矩形之外
Posted
技术标签:
【中文标题】仅将 CALayer 阴影遮蔽到矩形之外【英文标题】:Masking CALayer shadow to outside of rect only 【发布时间】:2014-05-01 15:55:48 【问题描述】:如何用阴影掩盖 CALayer,使阴影只在路径之外?我不想在透明视图后面留下阴影。
shadowLayer.shadowOffset = CGSizeMake(x, y);
shadowLayer.shadowRadius = radius;
shadowLayer.shadowOpacity = opacity;
shadowLayer.shadowColor = color.CGColor;
shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:view.bounds].CGPath;
谢谢。
【问题讨论】:
您可能必须制作一个仅用于阴影的透明图层,并遮盖该图层,然后在其上显示没有阴影的图层。 嗯,掩蔽部分是我遇到问题的地方,只掩蔽内部。 我不确定细节,但您可能需要制作一个大于阴影边缘的形状图层,然后添加一个您要遮盖的区域大小的路径,并将该形状图层用作带有阴影的图层的蒙版。您可能必须使用填充模式才能使路径的交点正常工作。 【参考方案1】:我会回答我自己的问题。为view
添加一个新的阴影层。如果设置正确,这应该适用于任何shadowPath
。
float radius = 8;
float opacity = 0.5f;
float x = 4;
float y = 6;
UIColor *color = [UIColor blackColor];
// Shadow layer
CALayer *shadowLayer = [CALayer layer];
shadowLayer.shadowOffset = CGSizeMake(x, y);
shadowLayer.shadowRadius = radius;
shadowLayer.shadowOpacity = opacity;
shadowLayer.shadowColor = color.CGColor;
shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:view.frame].CGPath; // Or any other path
// Shadow mask frame
CGRect frame = CGRectInset(view.layer.frame, -2*radius, -2*radius);
frame = CGRectOffset(frame, x, y);
// Translate shadowLayer shadow path to mask layer's coordinate system
CGAffineTransform trans = CGAffineTransformMakeTranslation(-view.frame.origin.x-x+2*radius,
-view.frame.origin.y-y+2*radius);
// Mask path
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, nil, (CGRect).origin=0,0, .size=frame.size);
CGPathAddPath(path, &trans, shadowLayer.shadowPath);
CGPathCloseSubpath(path);
// Mask layer
CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
maskLayer.frame = frame;
maskLayer.fillRule = kCAFillRuleEvenOdd;
maskLayer.path = path;
shadowLayer.mask = maskLayer;
[view.layer.superlayer insertSublayer:shadowLayer below:view.layer];
【讨论】:
相当多的代码来实现这样一个简单的事情,但完美无缺!谢谢【参考方案2】:ssteinberg's 答案在 ios 10.2 和 Swift 3 中帮助了我。我能够将他的答案与 UIVisualEffectView 一起使用来创建美丽的模糊,但也可以使用阴影。在此处转换为 Swift 3:
let shadowLayer = CALayer()
let mutablePath = CGMutablePath()
let maskLayer = CAShapeLayer()
let xOffset = CGFloat(4)
let yOffset = CGFloat(6)
let shadowOffset = CGSize(width: xOffset, height: yOffset)
let shadowOpacity = Float(0.5)
let shadowRadius = CGFloat(8)
let shadowPath = UIBezierPath(rect: frame).cgPath
let shadowColor = UIColor.black
let shadowFrame = frame.insetBy(dx: -2 * shadowRadius, dy: -2 * shadowRadius).offsetBy(dx: xOffset, dy: yOffset)
let shadowRect = CGRect(origin: .zero, size: shadowFrame.size)
let shadowTransform = CGAffineTransform(translationX: -frame.origin.x - xOffset + 2 * shadowRadius, y: -frame.origin.y - yOffset + 2 * shadowRadius)
shadowLayer.shadowOffset = shadowOffset
shadowLayer.shadowOpacity = shadowOpacity
shadowLayer.shadowRadius = shadowRadius
shadowLayer.shadowPath = shadowPath
shadowLayer.shadowColor = shadowColor.cgColor
mutablePath.addRect(shadowRect)
mutablePath.addPath(shadowLayer.shadowPath!, transform: shadowTransform)
mutablePath.closeSubpath()
maskLayer.frame = shadowFrame
maskLayer.fillRule = kCAFillRuleEvenOdd
maskLayer.path = mutablePath
shadowLayer.mask = maskLayer
layer.superlayer?.insertSublayer(shadowLayer, above: layer)
【讨论】:
【参考方案3】:只是一个进步:你可以使用 CAShapeLayer 来设置阴影
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = 2
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor.purple.cgColor
shapeLayer.shadowColor = UIColor.black.cgColor
shapeLayer.shadowOffset = CGSize(width: 0, height: 3)
shapeLayer.shadowOpacity = 1
view.layer.addSublayer(shapeLayer)
【讨论】:
以上是关于仅将 CALayer 阴影遮蔽到矩形之外的主要内容,如果未能解决你的问题,请参考以下文章
为啥masksToBounds = YES会阻止CALayer阴影?