Effect of inner shadow on a UIView layer?

I have the following CALayer:

CAGradientLayer *gradient = [CAGradientLayer layer]; gradient.frame = CGRectMake(8, 57, 296, 30); gradient.cornerRadius = 3.0f; gradient.colors = [NSArray arrayWithObjects:(id)[RGB(130, 0, 140) CGColor], (id)[RGB(108, 0, 120) CGColor], nil]; [self.layer insertSublayer:gradient atIndex:0]; 

I would like to add the effect of inner shadow , but I'm not quite sure how to do this. I suppose I will need to draw drawRect, however this will add a layer on top of other UIView objects, since it should be a panel behind some buttons, so I don’t understand what to do?

I could add another layer, but again, not sure how to achieve the inner shadow effect (for example:

enter image description here

Help evaluate ...

+91
iphone core-graphics calayer
Dec 13 '10 at 16:55
source share
16 answers

For anyone who wonders how to draw an inner shadow using Core Graphics as suggested by Costique, here's how to do it: (configure iOS if necessary)

In the drawRect method: ...

 CGRect bounds = [self bounds]; CGContextRef context = UIGraphicsGetCurrentContext(); CGFloat radius = 0.5f * CGRectGetHeight(bounds); // Create the "visible" path, which will be the shape that gets the inner shadow // In this case it just a rounded rect, but could be as complex as your want CGMutablePathRef visiblePath = CGPathCreateMutable(); CGRect innerRect = CGRectInset(bounds, radius, radius); CGPathMoveToPoint(visiblePath, NULL, innerRect.origin.x, bounds.origin.y); CGPathAddLineToPoint(visiblePath, NULL, innerRect.origin.x + innerRect.size.width, bounds.origin.y); CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, bounds.origin.y, bounds.origin.x + bounds.size.width, innerRect.origin.y, radius); CGPathAddLineToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, innerRect.origin.y + innerRect.size.height); CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x + bounds.size.width, bounds.origin.y + bounds.size.height, innerRect.origin.x + innerRect.size.width, bounds.origin.y + bounds.size.height, radius); CGPathAddLineToPoint(visiblePath, NULL, innerRect.origin.x, bounds.origin.y + bounds.size.height); CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x, bounds.origin.y + bounds.size.height, bounds.origin.x, innerRect.origin.y + innerRect.size.height, radius); CGPathAddLineToPoint(visiblePath, NULL, bounds.origin.x, innerRect.origin.y); CGPathAddArcToPoint(visiblePath, NULL, bounds.origin.x, bounds.origin.y, innerRect.origin.x, bounds.origin.y, radius); CGPathCloseSubpath(visiblePath); // Fill this path UIColor *aColor = [UIColor redColor]; [aColor setFill]; CGContextAddPath(context, visiblePath); CGContextFillPath(context); // Now create a larger rectangle, which we're going to subtract the visible path from // and apply a shadow CGMutablePathRef path = CGPathCreateMutable(); //(when drawing the shadow for a path whichs bounding box is not known pass "CGPathGetPathBoundingBox(visiblePath)" instead of "bounds" in the following line:) //-42 cuould just be any offset > 0 CGPathAddRect(path, NULL, CGRectInset(bounds, -42, -42)); // Add the visible path (so that it gets subtracted for the shadow) CGPathAddPath(path, NULL, visiblePath); CGPathCloseSubpath(path); // Add the visible paths as the clipping path to the context CGContextAddPath(context, visiblePath); CGContextClip(context); // Now setup the shadow properties on the context aColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.5f]; CGContextSaveGState(context); CGContextSetShadowWithColor(context, CGSizeMake(0.0f, 1.0f), 3.0f, [aColor CGColor]); // Now fill the rectangle, so the shadow gets drawn [aColor setFill]; CGContextSaveGState(context); CGContextAddPath(context, path); CGContextEOFillPath(context); // Release the paths CGPathRelease(path); CGPathRelease(visiblePath); 

So, essentially, the following steps are performed:

  • Create your way
  • Set the desired fill color, add this path to the context and fill the context
  • Now create a large rectangle that can snap the visible path. Before closing this path, add a visible path. Then close the path so that you create a shape with a visible path subtracted from it. You might want to explore filling methods (non-zero even / odd windings) depending on how you created these paths. In essence, for the subfolders to “subtract” when you add them together, you need to draw them (or rather build them) in opposite directions, clockwise, and the other counterclockwise.
  • Then you need to set your visible path as a clipping path in the context so that you don't draw anything outside of it on the screen.
  • Then set the shadow to a context that includes offset, blur, and color.
  • Then fill the large shape with a hole in it. The color does not matter, because if you did everything correctly, you will not see this color, just a shadow.
+106
Apr 04 '11 at 17:30
source share

I know I'm late for this party, but that would help me find on my travels ...

To give a loan in which it is credited, this is essentially a modification of the development of Daniel Thorpe by Kostik’s decision to deduct a smaller region from a larger region. This version is intended for those who use layer composition instead of overriding -drawRect:

The CAShapeLayer class can be used to achieve the same effect:

 CAShapeLayer* shadowLayer = [CAShapeLayer layer]; [shadowLayer setFrame:[self bounds]]; // Standard shadow stuff [shadowLayer setShadowColor:[[UIColor colorWithWhite:0 alpha:1] CGColor]]; [shadowLayer setShadowOffset:CGSizeMake(0.0f, 0.0f)]; [shadowLayer setShadowOpacity:1.0f]; [shadowLayer setShadowRadius:5]; // Causes the inner region in this example to NOT be filled. [shadowLayer setFillRule:kCAFillRuleEvenOdd]; // Create the larger rectangle path. CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, CGRectInset(bounds, -42, -42)); // Add the inner path so it subtracted from the outer path. // someInnerPath could be a simple bounds rect, or maybe // a rounded one for some extra fanciness. CGPathAddPath(path, NULL, someInnerPath); CGPathCloseSubpath(path); [shadowLayer setPath:path]; CGPathRelease(path); [[self layer] addSublayer:shadowLayer]; 

At this point, if your parent layer does not mask its borders, you will see an additional area of ​​the mask layer around the edges of the layer. It will be 42 pixels black if you just copied the example directly. To get rid of it, you can simply use another CAShapeLayer with the same path and set it as a shadow layer mask:

 CAShapeLayer* maskLayer = [CAShapeLayer layer]; [maskLayer setPath:someInnerPath]; [shadowLayer setMask:maskLayer]; 

I did not compare this myself, but I suspect that using this approach in conjunction with rasterization is more indicative than overriding -drawRect:

+46
Jul 11 '12 at 15:55
source share

You can draw the inner shadow using Core Graphics, creating a large rectangle path outside the borders, subtracting the rectangle of the dimensions rectangle and filling the resulting path with a “normal” shadow.

However, since you need to combine it with a gradient layer, I think a simpler solution is to create a transparent PNG image from 9 parts of the inner shadow and stretch it to the desired size. A shadow image of 9 parts will look like this (its size is 21x21 pixels):

alt text

 CALayer *innerShadowLayer = [CALayer layer]; innerShadowLayer.contents = (id)[UIImage imageNamed: @"innershadow.png"].CGImage; innerShadowLayer.contentsCenter = CGRectMake(10.0f/21.0f, 10.0f/21.0f, 1.0f/21.0f, 1.0f/21.0f); 

Then set the innerShadowLayer frame and it should stretch the shadow correctly.

+35
Dec 13 '10 at 17:23
source share

A simplified version using only CALayer in Swift:

 import UIKit final class FrameView : UIView { init() { super.init(frame: CGRect.zero) backgroundColor = UIColor.white } @available(*, unavailable) required init?(coder decoder: NSCoder) { fatalError("unavailable") } override func layoutSubviews() { super.layoutSubviews() addInnerShadow() } private func addInnerShadow() { let innerShadow = CALayer() innerShadow.frame = bounds // Shadow path (1pt ring around bounds) let path = UIBezierPath(rect: innerShadow.bounds.insetBy(dx: -1, dy: -1)) let cutout = UIBezierPath(rect: innerShadow.bounds).reversing() path.append(cutout) innerShadow.shadowPath = path.cgPath innerShadow.masksToBounds = true // Shadow properties innerShadow.shadowColor = UIColor(white: 0, alpha: 1).cgColor // UIColor(red: 0.71, green: 0.77, blue: 0.81, alpha: 1.0).cgColor innerShadow.shadowOffset = CGSize.zero innerShadow.shadowOpacity = 1 innerShadow.shadowRadius = 3 // Add layer.addSublayer(innerShadow) } } 

Note that the innerShadow layer should not have an opaque background color, as this will appear in front of the shadow.

+28
Jun 15 '15 at 8:49
source share

A bit of a circular path, but this avoids the use of images (read: easily change colors, shadow radius, etc.), and these are just a few lines of code.

  • Add a UIImageView as the first UIView routine that you want to include dropshadow on. I use IB, but you can do the same programmatically.

  • Assuming the reference to the UIImageView is "innerShadow"

`

 [[innerShadow layer] setMasksToBounds:YES]; [[innerShadow layer] setCornerRadius:12.0f]; [[innerShadow layer] setBorderColor:[UIColorFromRGB(180, 180, 180) CGColor]]; [[innerShadow layer] setBorderWidth:1.0f]; [[innerShadow layer] setShadowColor:[UIColorFromRGB(0, 0, 0) CGColor]]; [[innerShadow layer] setShadowOffset:CGSizeMake(0, 0)]; [[innerShadow layer] setShadowOpacity:1]; [[innerShadow layer] setShadowRadius:2.0]; 

Caution: you must have a border, otherwise the shadow will not appear. [UIColor clearColor] does not work. In this example, I use a different color, but you can use it to have the same color as the beginning of the shadow. :)

See the bbrame comment below about the UIColorFromRGB macro.

+23
Jun 01 '11 at 17:56 on
source share

Better late than never...

Here's a different approach, maybe no better than the ones that have already been sent, but it's beautiful and simple -

 -(void)drawInnerShadowOnView:(UIView *)view { UIImageView *innerShadowView = [[UIImageView alloc] initWithFrame:view.bounds]; innerShadowView.contentMode = UIViewContentModeScaleToFill; innerShadowView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; [view addSubview:innerShadowView]; [innerShadowView.layer setMasksToBounds:YES]; [innerShadowView.layer setBorderColor:[UIColor lightGrayColor].CGColor]; [innerShadowView.layer setShadowColor:[UIColor blackColor].CGColor]; [innerShadowView.layer setBorderWidth:1.0f]; [innerShadowView.layer setShadowOffset:CGSizeMake(0, 0)]; [innerShadowView.layer setShadowOpacity:1.0]; // this is the inner shadow thickness [innerShadowView.layer setShadowRadius:1.5]; } 
+17
Feb 25 '14 at 17:16
source share

Instead of drawing an inner shadow using drawRect or adding a UIView to the view. You can directly add CALayer to the border, for example: if I want the inner shadow effect on the bottom of UIView V.

 innerShadowOwnerLayer = [[CALayer alloc]init]; innerShadowOwnerLayer.frame = CGRectMake(0, V.frame.size.height+2, V.frame.size.width, 2); innerShadowOwnerLayer.backgroundColor = [UIColor whiteColor].CGColor; innerShadowOwnerLayer.shadowColor = [UIColor blackColor].CGColor; innerShadowOwnerLayer.shadowOffset = CGSizeMake(0, 0); innerShadowOwnerLayer.shadowRadius = 10.0; innerShadowOwnerLayer.shadowOpacity = 0.7; [V.layer addSubLayer:innerShadowOwnerLayer]; 

This adds a bottom inner shadow to the target UIView

+8
Oct 23 '13 at 7:23
source share

Here is the swift version, change startPoint and endPoint to do this on each side.

  let layer = CAGradientLayer() layer.startPoint = CGPointMake(0.5, 0.0); layer.endPoint = CGPointMake(0.5, 1.0); layer.colors = [UIColor(white: 0.1, alpha: 1.0).CGColor, UIColor(white: 0.1, alpha: 0.5).CGColor, UIColor.clearColor().CGColor] layer.locations = [0.05, 0.2, 1.0 ] layer.frame = CGRectMake(0, 0, self.view.frame.width, 60) self.view.layer.insertSublayer(layer, atIndex: 0) 
+6
Oct. 14 '15 at 10:45
source share

This is your solution that I exported from PaintCode :

 -(void) drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); //// Shadow Declarations UIColor* shadow = UIColor.whiteColor; CGSize shadowOffset = CGSizeMake(0, 0); CGFloat shadowBlurRadius = 10; //// Rectangle Drawing UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: self.bounds]; [[UIColor blackColor] setFill]; [rectanglePath fill]; ////// Rectangle Inner Shadow CGContextSaveGState(context); UIRectClip(rectanglePath.bounds); CGContextSetShadowWithColor(context, CGSizeZero, 0, NULL); CGContextSetAlpha(context, CGColorGetAlpha([shadow CGColor])); CGContextBeginTransparencyLayer(context, NULL); { UIColor* opaqueShadow = [shadow colorWithAlphaComponent: 1]; CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, [opaqueShadow CGColor]); CGContextSetBlendMode(context, kCGBlendModeSourceOut); CGContextBeginTransparencyLayer(context, NULL); [opaqueShadow setFill]; [rectanglePath fill]; CGContextEndTransparencyLayer(context); } CGContextEndTransparencyLayer(context); CGContextRestoreGState(context); } 
+5
Oct 16 '14 at 12:50
source share

I'm very late to the party, but I would like to get the community back. This is the method I wrote to remove the background image of a UITextField since I supplied a static library and no resources ... I used this for a PIN input screen of four instances of UITextField that can display a single raw or (BOOL) character [self isUsingBullets] or (BOOL) [self usingAsterisks] in the ViewController. The app is designed for iPhone / iPhone Retina / iPad / iPad Retina, so I do not need to supply four images ...

 #import <QuartzCore/QuartzCore.h> - (void)setTextFieldInnerGradient:(UITextField *)textField { [textField setSecureTextEntry:self.isUsingBullets]; [textField setBackgroundColor:[UIColor blackColor]]; [textField setTextColor:[UIColor blackColor]]; [textField setBorderStyle:UITextBorderStyleNone]; [textField setClipsToBounds:YES]; [textField.layer setBorderColor:[[UIColor blackColor] CGColor]]; [textField.layer setBorderWidth:1.0f]; // make a gradient off-white background CAGradientLayer *gradient = [CAGradientLayer layer]; CGRect gradRect = CGRectInset([textField bounds], 3, 3); // Reduce Width and Height and center layer gradRect.size.height += 2; // minimise Bottom shadow, rely on clipping to remove these 2 pts. gradient.frame = gradRect; struct CGColor *topColor = [UIColor colorWithWhite:0.6f alpha:1.0f].CGColor; struct CGColor *bottomColor = [UIColor colorWithWhite:0.9f alpha:1.0f].CGColor; // We need to use this fancy __bridge object in order to get the array we want. gradient.colors = [NSArray arrayWithObjects:(__bridge id)topColor, (__bridge id)bottomColor, nil]; [gradient setCornerRadius:4.0f]; [gradient setShadowOffset:CGSizeMake(0, 0)]; [gradient setShadowColor:[[UIColor whiteColor] CGColor]]; [gradient setShadowOpacity:1.0f]; [gradient setShadowRadius:3.0f]; // Now we need to Blur the edges of this layer "so it blends" // This rasterizes the view down to 4x4 pixel chunks then scales it back up using bilinear filtering... // it EXTREMELY fast and looks ok if you are just wanting to blur a background view under a modal view. // To undo it, just set the rasterization scale back to 1.0 or turn off rasterization. [gradient setRasterizationScale:0.25]; [gradient setShouldRasterize:YES]; [textField.layer insertSublayer:gradient atIndex:0]; if (self.usingAsterisks) { [textField setFont:[UIFont systemFontOfSize:80.0]]; } else { [textField setFont:[UIFont systemFontOfSize:40.0]]; } [textField setTextAlignment:UITextAlignmentCenter]; [textField setEnabled:NO]; } 

I hope this helps someone as this forum helped me.

+3
Jul 17 '12 at 6:21
source share

Check out the great article Inner Shadows in Chris Emery Quartz , which explains how inner shadows are drawn by PaintCode and gives a clean and neat code snippet:

 - (void)drawInnerShadowInContext:(CGContextRef)context withPath:(CGPathRef)path shadowColor:(CGColorRef)shadowColor offset:(CGSize)offset blurRadius:(CGFloat)blurRadius { CGContextSaveGState(context); CGContextAddPath(context, path); CGContextClip(context); CGColorRef opaqueShadowColor = CGColorCreateCopyWithAlpha(shadowColor, 1.0); CGContextSetAlpha(context, CGColorGetAlpha(shadowColor)); CGContextBeginTransparencyLayer(context, NULL); CGContextSetShadowWithColor(context, offset, blurRadius, opaqueShadowColor); CGContextSetBlendMode(context, kCGBlendModeSourceOut); CGContextSetFillColorWithColor(context, opaqueShadowColor); CGContextAddPath(context, path); CGContextFillPath(context); CGContextEndTransparencyLayer(context); CGContextRestoreGState(context); CGColorRelease(opaqueShadowColor); } 
+3
Jan 21 '16 at 7:43
source share

Here is my solution in Swift 4.2. Want to try?

 final class ACInnerShadowLayer : CAShapeLayer { var innerShadowColor: CGColor? = UIColor.black.cgColor { didSet { setNeedsDisplay() } } var innerShadowOffset: CGSize = .zero { didSet { setNeedsDisplay() } } var innerShadowRadius: CGFloat = 8 { didSet { setNeedsDisplay() } } var innerShadowOpacity: Float = 1 { didSet { setNeedsDisplay() } } override init() { super.init() masksToBounds = true contentsScale = UIScreen.main.scale setNeedsDisplay() } override init(layer: Any) { if let layer = layer as? InnerShadowLayer { innerShadowColor = layer.innerShadowColor innerShadowOffset = layer.innerShadowOffset innerShadowRadius = layer.innerShadowRadius innerShadowOpacity = layer.innerShadowOpacity } super.init(layer: layer) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func draw(in ctx: CGContext) { ctx.setAllowsAntialiasing(true) ctx.setShouldAntialias(true) ctx.interpolationQuality = .high let colorspace = CGColorSpaceCreateDeviceRGB() var rect = bounds var radius = cornerRadius if borderWidth != 0 { rect = rect.insetBy(dx: borderWidth, dy: borderWidth) radius -= borderWidth radius = max(radius, 0) } let innerShadowPath = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath ctx.addPath(innerShadowPath) ctx.clip() let shadowPath = CGMutablePath() let shadowRect = rect.insetBy(dx: -rect.size.width, dy: -rect.size.width) shadowPath.addRect(shadowRect) shadowPath.addPath(innerShadowPath) shadowPath.closeSubpath() if let innerShadowColor = innerShadowColor, let oldComponents = innerShadowColor.components { var newComponets = Array<CGFloat>(repeating: 0, count: 4) // [0, 0, 0, 0] as [CGFloat] let numberOfComponents = innerShadowColor.numberOfComponents switch numberOfComponents { case 2: newComponets[0] = oldComponents[0] newComponets[1] = oldComponents[0] newComponets[2] = oldComponents[0] newComponets[3] = oldComponents[1] * CGFloat(innerShadowOpacity) case 4: newComponets[0] = oldComponents[0] newComponets[1] = oldComponents[1] newComponets[2] = oldComponents[2] newComponets[3] = oldComponents[3] * CGFloat(innerShadowOpacity) default: break } if let innerShadowColorWithMultipliedAlpha = CGColor(colorSpace: colorspace, components: newComponets) { ctx.setFillColor(innerShadowColorWithMultipliedAlpha) ctx.setShadow(offset: innerShadowOffset, blur: innerShadowRadius, color: innerShadowColorWithMultipliedAlpha) ctx.addPath(shadowPath) ctx.fillPath(using: .evenOdd) } } } } 
+3
Aug 08 '18 at 10:19
source share

Using a gradient layer:

 UIView * mapCover = [UIView new]; mapCover.frame = map.frame; [view addSubview:mapCover]; CAGradientLayer * vertical = [CAGradientLayer layer]; vertical.frame = mapCover.bounds; vertical.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor, (id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor, (id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor, (id)[UIColor whiteColor].CGColor, nil]; vertical.locations = @[@0.01,@0.1,@0.9,@0.99]; [mapCover.layer insertSublayer:vertical atIndex:0]; CAGradientLayer * horizontal = [CAGradientLayer layer]; horizontal.frame = mapCover.bounds; horizontal.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor, (id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor, (id)[[UIColor whiteColor] colorWithAlphaComponent:0.0f].CGColor, (id)[UIColor whiteColor].CGColor, nil]; horizontal.locations = @[@0.01,@0.1,@0.9,@0.99]; horizontal.startPoint = CGPointMake(0.0, 0.5); horizontal.endPoint = CGPointMake(1.0, 0.5); [mapCover.layer insertSublayer:horizontal atIndex:0]; 
0
Sep 14 '16 at 19:54
source share

this code worked for me

 class InnerDropShadowView: UIView { override func draw(_ rect: CGRect) { //Drawing code let context = UIGraphicsGetCurrentContext() //// Shadow Declarations let shadow: UIColor? = UIColor.init(hexString: "a3a3a3", alpha: 1.0) //UIColor.black.withAlphaComponent(0.6) //UIColor.init(hexString: "d7d7da", alpha: 1.0) let shadowOffset = CGSize(width: 0, height: 0) let shadowBlurRadius: CGFloat = 7.5 //// Rectangle Drawing let rectanglePath = UIBezierPath(rect: bounds) UIColor.groupTableViewBackground.setFill() rectanglePath.fill() ////// Rectangle Inner Shadow context?.saveGState() UIRectClip(rectanglePath.bounds) context?.setShadow(offset: CGSize.zero, blur: 0, color: nil) context?.setAlpha((shadow?.cgColor.alpha)!) context?.beginTransparencyLayer(auxiliaryInfo: nil) do { let opaqueShadow: UIColor? = shadow?.withAlphaComponent(1) context?.setShadow(offset: shadowOffset, blur: shadowBlurRadius, color: opaqueShadow?.cgColor) context!.setBlendMode(.sourceOut) context?.beginTransparencyLayer(auxiliaryInfo: nil) opaqueShadow?.setFill() rectanglePath.fill() context!.endTransparencyLayer() } context!.endTransparencyLayer() context?.restoreGState() } } 
0
Apr 03 '18 at 11:24
source share

Scalable solution using CALayer in Swift

Using the described InnerShadowLayer you can also enable inner shadows only for certain edges, excluding others. (for example, you can only include inner shadows on the left and top edges of your view)

You can then add InnerShadowLayer to your view using:

 init(...) { // ... your initialization code ... super.init(frame: .zero) layer.addSublayer(shadowLayer) } public override func layoutSubviews() { super.layoutSubviews() shadowLayer.frame = bounds } 

InnerShadowLayer implementation

 /// Shadow is a struct defining the different kinds of shadows public struct Shadow { let x: CGFloat let y: CGFloat let blur: CGFloat let opacity: CGFloat let color: UIColor } /// A layer that applies an inner shadow to the specified edges of either its path or its bounds public class InnerShadowLayer: CALayer { private let shadow: Shadow private let edge: UIRectEdge public init(shadow: Shadow, edge: UIRectEdge) { self.shadow = shadow self.edge = edge super.init() setupShadow() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } public override func layoutSublayers() { updateShadow() } private func setupShadow() { shadowColor = shadow.color.cgColor shadowOpacity = Float(shadow.opacity) shadowRadius = shadow.blur / 2.0 masksToBounds = true } private func updateShadow() { shadowOffset = { let topWidth: CGFloat = 0 let leftWidth = edge.contains(.left) ? shadow.y / 2 : 0 let bottomWidth: CGFloat = 0 let rightWidth = edge.contains(.right) ? -shadow.y / 2 : 0 let topHeight = edge.contains(.top) ? shadow.y / 2 : 0 let leftHeight: CGFloat = 0 let bottomHeight = edge.contains(.bottom) ? -shadow.y / 2 : 0 let rightHeight: CGFloat = 0 return CGSize(width: [topWidth, leftWidth, bottomWidth, rightWidth].reduce(0, +), height: [topHeight, leftHeight, bottomHeight, rightHeight].reduce(0, +)) }() let insets = UIEdgeInsets(top: edge.contains(.top) ? -bounds.height : 0, left: edge.contains(.left) ? -bounds.width : 0, bottom: edge.contains(.bottom) ? -bounds.height : 0, right: edge.contains(.right) ? -bounds.width : 0) let path = UIBezierPath(rect: bounds.inset(by: insets)) let cutout = UIBezierPath(rect: bounds).reversing() path.append(cutout) shadowPath = path.cgPath } } 
0
Jul 30 '19 at 16:05
source share



All Articles