views:

183

answers:

2

is it possible to create such a UILabel with inner and outer shadow?

alt text

i only know shadowColor and shadowOffset

zoomed:

alt text

thanks!

A: 

You will have to do your own custom drawing to get an inner shadow. There's no way currently to do it with a standard UILabel.

Here's a reasonable explanation on doing inner shadow with Quartz.

http://stackoverflow.com/questions/2169119/inner-shadow-in-core-graphics

dmaclach
A: 

The answer by dmaclach is only suitable for shapes that can easily be inverted. My solution is a custom view that works with any shape and also text. It requires iOS 4 and is resolution independent.

First, a graphical explanation of what the code does. The shape here is a circle. alt text

The code draws text with a white dropshadow. If it's not required, the code could be refactored further, because the dropshadow needs to be masked differently. If you need it on an older version of iOS, you would have to replace the block and use an (annoying) CGBitmapContext.

- (UIImage*)blackSquareOfSize:(CGSize)size {
  UIGraphicsBeginImageContextWithOptions(size, NO, 0);  
  [[UIColor blackColor] setFill];
  CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, size.width, size.height));
  UIImage *blackSquare = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();
  return blackSquare;
}


- (CGImageRef)createMaskWithSize:(CGSize)size shape:(void (^)(void))block {
  UIGraphicsBeginImageContextWithOptions(size, NO, 0);  
  block();
  CGImageRef shape = [UIGraphicsGetImageFromCurrentImageContext() CGImage];
  UIGraphicsEndImageContext();  
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(shape),
                                      CGImageGetHeight(shape),
                                      CGImageGetBitsPerComponent(shape),
                                      CGImageGetBitsPerPixel(shape),
                                      CGImageGetBytesPerRow(shape),
                                      CGImageGetDataProvider(shape), NULL, false);
  return mask;
}


- (void)drawRect:(CGRect)rect {
  UIFont *font = [UIFont fontWithName:@"HelveticaNeue-Bold" size:40.0f];
  CGSize fontSize = [text_ sizeWithFont:font];

  CGImageRef mask = [self createMaskWithSize:rect.size shape:^{
    [[UIColor blackColor] setFill];
    CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
    [[UIColor whiteColor] setFill];
    // custom shape goes here
    [text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), 0) withFont:font];
    [text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -1) withFont:font];
  }];

  CGImageRef cutoutRef = CGImageCreateWithMask([self blackSquareOfSize:rect.size].CGImage, mask);
  CGImageRelease(mask);
  UIImage *cutout = [UIImage imageWithCGImage:cutoutRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUp];
  CGImageRelease(cutoutRef);  

  CGImageRef shadedMask = [self createMaskWithSize:rect.size shape:^{
    [[UIColor whiteColor] setFill];
    CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
    CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(0, 1), 1.0f, [[UIColor colorWithWhite:0.0 alpha:0.5] CGColor]);
    [cutout drawAtPoint:CGPointZero];
  }];

  // create negative image
  UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
  [[UIColor blackColor] setFill];
  // custom shape goes here
  [text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -1) withFont:font];
  UIImage *negative = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext(); 

  CGImageRef innerShadowRef = CGImageCreateWithMask(negative.CGImage, shadedMask);
  CGImageRelease(shadedMask);
  UIImage *innerShadow = [UIImage imageWithCGImage:innerShadowRef scale:[[UIScreen mainScreen] scale] orientation:UIImageOrientationUp];
  CGImageRelease(innerShadowRef);

  // draw actual image
  [[UIColor whiteColor] setFill];
  [text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -0.5) withFont:font];
  [[UIColor colorWithWhite:0.76 alpha:1.0] setFill];
  [text_ drawAtPoint:CGPointMake((self.bounds.size.width/2)-(fontSize.width/2), -1) withFont:font];  

  // finally apply shadow
  [innerShadow drawAtPoint:CGPointZero];
}
Steven XM