2010-07-12 20 views
17

¿es posible crear una UILabel con sombra interna y externa?Sombra interior en UILabel

alt text http://dl.getdropbox.com/u/80699/Bildschirmfoto%202010-07-12%20um%2021.28.57.png

yo sólo sé shadowColor y shadowOffset

Zoomed:

alt text http://dl.getdropbox.com/u/80699/Bildschirmfoto%202010-07-12%20um%2021.39.56.png

gracias!

+0

También quería saber esto para simular un UITextField hace bastante tiempo y lo hice usando Quartz (como se sugiere) pero hay algunos problemas de rendimiento, estoy bastante seguro de que animando los límites de su UILabel representando sombras de esa manera no se verá bien Se verá lento. En mi caso terminé usando un UIImage estirado: stretchableImageWithLeftCapWidth: topCapHeight: es mucho más rápido si se ajusta a tus necesidades – nacho4d

+3

Los enlaces de imagen en tu pregunta están rotos – jjxtra

Respuesta

125

La respuesta por dmaclach sólo es adecuado para formas que pueden ser fácilmente invertida. Mi solución es una vista personalizada que funciona con cualquier forma y también texto. Requiere iOS 4 y es independiente de la resolución.

Primero, una explicación gráfica de lo que hace el código. La forma aquí es un círculo. alt text

El código dibuja texto con una sombra blanca. Si no es necesario, el código podría refactorizarse más, porque la sombra de gotas debe enmascararse de manera diferente. Si lo necesita en una versión anterior de iOS, tendría que reemplazar el bloque y usar un (molesto) 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]; 
} 
+0

¡Guau, eso fue realmente útil! No sé por qué hubo cero votos ... Lamentablemente, no se puede establecer más de +1 para la solución. :) –

+6

Creé algunas funciones para facilitar aún más el uso de este enfoque disponible en GitHub: https://github.com/mruegenberg/objc-utils/tree/master/UIKitAdditions. Vea los archivos InnerShadowDrawing.h/.m. – mrueg

+0

excelente material –

0

Tendrás que hacer tu propio dibujo personalizado para obtener una sombra interna. No hay manera de hacerlo actualmente con un UILabel estándar.

Aquí hay una explicación razonable sobre cómo hacer sombra interna con Quartz.

Inner shadow in Core Graphics

13

Aunque la respuesta de Steve funciona, no escalar a mi caso particular, y por lo que acabó creando una sombra interior mediante la aplicación de una sombra a una CGPath después de cortar mi contexto:

CGContextRef context = UIGraphicsGetCurrentContext(); 

// clip context so shadow only shows on the inside 
CGPathRef roundedRect = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:4].CGPath; 
CGContextAddPath(context, roundedRect); 
CGContextClip(context); 

CGContextAddPath(context, roundedRect); 
CGContextSetShadowWithColor(UIGraphicsGetCurrentContext(), CGSizeMake(0, 0), 3, [UIColor colorWithWhite:0 alpha:1].CGColor); 
CGContextSetStrokeColorWithColor(context, [UIColor colorWithWhite:0 alpha:1].CGColor); 
CGContextStrokePath(context); 

que se traduce en:

enter image description here

puede cambiar el desplazamiento de sombra y desenfoque para cambiar el estilo de sombra. Si necesita que sea más oscuro, también puede agregar sucesivamente y luego aplicar el mismo CGPath, lo que hará que las sombras se acumulen.

+0

Hola Sam, esto es genial y funciona bien para mí, pero ¿sabes cómo obtener el mismo efecto sin el borde? ¿O tal vez solo un borde que está a la mitad de la opacidad que este? –

2

Sí, tengo una publicación en el blog al respecto here. La respuesta corta es que pedir prestado el JTAInnerShadowLayer de here, subclase UILabel, y cambiar su layerclass anulando + (Class)layerClass para que vuelva clase JTAInnerShadowLayer así:

+ (Class)layerClass 
{ 
    return [JTAInnerShadowLayer class]; 
} 

Luego, en el método init para la capa de configurar el algo JTAInnerShadowLayer de esta manera:

[self setBackgroundColor:[UIColor clearColor]]; 
JTAInnerShadowLayer *innerShadow = (JTAInnerShadowLayer *)[self layer]; 
[innerShadow setClipForAnyAlpha:YES]; 
[innerShadow setOutsideShadowSize:CGSizeMake(0.0, 1.0) radius:1.0]; 
[innerShadow setInsideShadowSize:CGSizeMake (0.0, 4.0) radius:6.0]; 
/* Uncomment this to make the label also draw the text (won't work well 
    with black text!*/ 
//[innerShadow drawOriginalImage]; 

(o simplemente tome prestada la clase JTAIndentLabel).

0

Probar PaintCode versión de prueba!Para principiantes, aprenderá cómo crear dibujos personalizados. ¡Es muy bonito! : 3 Puede usarlo para practicar o para aprender, pero no lo use todo el tiempo, también debe aprender cómo crear dibujos por su cuenta.

Descargo de responsabilidad: No soy un endosante, solo me sorprendió mi descubrimiento. ;)