1

I'm trying to create an inner shadow on only the top portion of a UITextView, but I'm having some difficulty. I'm borrowing code from this post, but I don't understand exactly what's going on.

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's 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];

What exactly is "someInnerPath" if I want a simple shadow at only the top of a rectangular UITextView (I don't need the rounded effect).

Community
  • 1
  • 1
Apollo
  • 8,874
  • 32
  • 104
  • 192

1 Answers1

1

Try this instead in your viewDidLoad or wherever fits you best:

CGFloat inset = -20;

UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:CGRectMake(inset, 0,
                                                                       self.textView.bounds.size.width - inset - inset,
                                                                       self.textView.bounds.size.height)];

UIView *overlayView = [[UIView alloc]initWithFrame:self.textView.frame];
overlayView.userInteractionEnabled = NO;
overlayView.clipsToBounds = YES;

CALayer *layer = overlayView.layer;
layer.shadowPath = shadowPath.CGPath;
layer.shadowColor = [UIColor colorWithWhite:0.0 alpha:1.0].CGColor;
layer.shadowOpacity = 1.0;
layer.shadowRadius = 10;
layer.shadowOffset = CGSizeMake(0, self.textView.bounds.size.height * -1);

[self.view addSubview:overlayView];

The inset is to make sure the shadow doesn't stop just before the corners. Try setting it to zero, and you'll see what I mean.

Basically what the code is doing is creating a view who's layer's shadow is offset to the top of the view. I tried adding the overlayView directly to the textView, but it would sort of stick to the scrolling, so when I scrolled down, a big black box appeared. Adding the overlayView to self.view instead solved the problem.

You may want to play around with the shadowColor, shadowOpacity and shadowRadius parameters to your liking.

vegather
  • 470
  • 4
  • 14
  • The parts that helped me were replacing my code's textView.bounds and adding the layer to my view with references to the textView.frame and self.view. Thanks. – Stephen Watson May 19 '18 at 14:14