2011-09-20 15 views
13

Quiero agregar una sombra paralela usando CALayer a una IU (Imagen) Vista. El código siguiente funciona en general bienUIView shadow y InterfaceBuilder

previewImage.layer.shadowColor = [[UIColor blackColor] CGColor]; 
previewImage.layer.shadowOffset = CGSizeMake(1.0f, 1.0f); 
previewImage.layer.shadowOpacity = 1.0f; 
previewImage.layer.shadowRadius = 8.0f; 

Sin embargo, esto sólo funciona si creo que la vista mediante programación y añadirlo como una subvista a mi vista principal. Cuando esa vista se configura en InterfaceBuilder y se define como IBOutlet UIImageView esto NO funciona. No aparece sombra Entonces, ¿qué es lo que echo de menos aquí?

+1

bastante al azar, acabo de descubrir el problema real no parece ser InterfaceBuilder, pero el hecho de que me puse clipsToBounds de mi vista InterfaceBuilder = SÍ. Tener NO aquí está bien. Así que supongo que tendré que ajustar la vista en una segunda vista con clipsToBound = NO y la sombra. ¿Hay otra manera? – Dennis

+0

Tuve el mismo problema, pero fue porque "Clip Subviews" se verificó en la vista en Interface Builder. Al desmarcar eso, se hizo visible la sombra de CALayer. – azdev

Respuesta

2

No estoy seguro de cuál es el problema: asegúrese de que la propiedad UIImageView de esté configurada en NO. Puede hacer esto en viewDidLoad después de cargar desde el archivo nib al hacer referencia a su IBOutlet. No debería necesitar envolverlo en otra vista.

Editar

A la luz de ustedes que necesitan su imagen que reducirse utilizando relleno de aspecto, puede utilizar la propiedad contentsRect del UIImageView 'capa subyacente s a 'simular' el efecto de los contenidos de recorte. contentsRect es un rectángulo en el espacio de coordenadas de la unidad del contenido de la capa (en este caso su imagen) que define un sub-rectángulo de los contenidos que se deben dibujar.

Con un poco de matemáticas, podemos encontrar este rectángulo comparando el tamaño de vista de imagen con el tamaño de la imagen (que representan el escalamiento de relleno de aspecto):

CGSize imageViewSize = previewImage.size; 
CGSize imageSize = previewImage.image.size; 

// Find the scaling required for the image to fit the image view (as for aspect fill). 
CGFloat imageWidthScale = fabsf(imageViewSize.width/imageSize.width); 
CGFloat imageHeightScale = fabsf(imageViewSize.height/imageSize.height); 
CGFloat imageScale = (imageWidthScale > imageHeightScale) ? imageWidthScale : imageHeightScale; 

// Determine the new image size, after scaling. 
CGSize scaledImageSize = CGSizeApplyAffineTransform(imageSize, CGAffineTransformMakeScale(imageScale, imageScale)); 

// Set the layer's contentsRect property in order to 'clip' the image to the image view's bounds. 
previewImage.layer.contentsRect = CGRectMake(((scaledImageSize.width - imageViewSize.width)/2.0f)/scaledImageSize.width, 
              ((scaledImageSize.height - imageViewSize.height)/2.0f)/scaledImageSize.height, 
              imageViewSize.width/scaledImageSize.width, 
              imageViewSize.height/scaledImageSize.height); 

Al hacer esto, puede dejar clipsToBounds conjunto a NO para su vista de imagen, pero la imagen aún aparecerá recortada. Si necesita cambiar el tamaño de la vista de la imagen, podría ser conveniente ajustar este código en un método que tome un UIImageView como parámetro.

Espero que esto ayude.

+0

Estoy de acuerdo. No es necesario envolver. Simplemente no clipToBounds - como la sombra está fuera de los límites. – bandejapaisa

+0

La razón por la que necesito clipToBounds es que esa imagen es demasiado grande para ajustarse a la vista y necesito usar "Aspect Fill" para que se vea bien. Podría, por supuesto, recortar la imagen en sí dibujándola completamente nueva y luego obteniendo una adecuada a través de UIGraphicsGetImageFromCurrentImageContext(). Pero, ¿no sería mucho por encima? – Dennis

+0

@Dennis: si la imagen es estática y solo se usará en ese tamaño, mi primera sugerencia sería volver a crear la imagen en el software de edición de imágenes primero y luego usarla en la vista de imagen de su proyecto sin la necesidad de modificar su geometría Sin embargo, si esta no es una opción, vea mi edición anterior. – Stuart

14

Sé que esta pregunta ha sido larga, pero recientemente estaba en una situación similar, así que decidí poner mi respuesta para aquellos que se encuentran en una situación como esta.

que quería ser capaz de establecer el borderColor y shadowColor en una UIView a través de la Interfaz del generador, pero el tipo de propiedad de una capa borderColor es CGColor (al igual que shadowColor) que no es uno de los tipos permitidos para ser cambiado en la característica de atributos de tiempo de ejecución definida por el usuario.

así que hice una extensión para CALayer y añadí dos propiedades llamadas borderColorIB y shadowColorIB que son de tipo UIColor:

RuntimeAttributes.h

@import QuartzCore; 

@interface CALayer (IBConfiguration) 

@property(nonatomic, assign) UIColor* borderColorIB; 
@property(nonatomic, assign) UIColor* shadowColorIB; 

@end 

RuntimeAttributes.m

#import <UIKit/UIKit.h> 
#import "RuntimeAttributes.h" 

@implementation CALayer (IBConfiguration) 

-(void)setBorderColorIB:(UIColor*)color 
{ 
    self.borderColor = color.CGColor; 
} 

-(UIColor*)borderColorIB 
{ 
    return [UIColor colorWithCGColor:self.borderColor]; 
} 

-(void)setShadowColorIB:(UIColor*)color 
{ 
    self.shadowColor = color.CGColor; 
} 

-(UIColor*)shadowColorIB 
{ 
    return [UIColor colorWithCGColor:self.shadowColor]; 
} 

@end 

Ahora i todavia ser capaz de establecer estas dos propiedades a través de Interface Builder como esto:

  1. En la sección 'atributos de ejecución definidos por el usuario' (Identidad inspector)
  2. Asegúrese se selecciona el UIView y añada el siguiente atributos de ejecución:

    • layer.borderWidth, Número, 1
    • layer.borderColorIB, Color, someColor <- my custom property to set the borderColor
    • layer.shadowColorIB, Color, someColor <- my custom property to set the shadowColor
    • layer.shadowOpacity, Número, 0,8
    • layer.shadowOffset, tamaño, {5,5}
    • capa. CornerRadius, Número, 5

Aquí está una imagen para mostrar cómo lo hice:

enter image description here

... y el resultado será evidente durante el tiempo de ejecución, no en Xcode:

enter image description here

espero que esto puede ayudar a algunas personas por ahí!

16

Añadir un archivo llamado UIView.swift en su proyecto (o simplemente pegar esto en cualquier archivo):

import UIKit 

@IBDesignable extension UIView { 

    /* The color of the shadow. Defaults to opaque black. Colors created 
    * from patterns are currently NOT supported. Animatable. */ 
    @IBInspectable var shadowColor: UIColor? { 
     set { 
      layer.shadowColor = newValue!.CGColor 
     } 
     get { 
      if let color = layer.shadowColor { 
       return UIColor(CGColor:color) 
      } 
      else { 
       return nil 
      } 
     } 
    } 

    /* The opacity of the shadow. Defaults to 0. Specifying a value outside the 
    * [0,1] range will give undefined results. Animatable. */ 
    @IBInspectable var shadowOpacity: Float { 
     set { 
      layer.shadowOpacity = newValue 
     } 
     get { 
      return layer.shadowOpacity 
     } 
    } 

    /* The shadow offset. Defaults to (0, -3). Animatable. */ 
    @IBInspectable var shadowOffset: CGPoint { 
     set { 
      layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y) 
     } 
     get { 
      return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height) 
     } 
    } 

    /* The blur radius used to create the shadow. Defaults to 3. Animatable. */ 
    @IBInspectable var shadowRadius: CGFloat { 
     set { 
      layer.shadowRadius = newValue 
     } 
     get { 
      return layer.shadowRadius 
     } 
    } 
} 

entonces esto va a estar disponible en Interface Builder para cada vista en el panel Utilidades> Atributos Inspector:

Utilities Panel

podrá ajustar fácilmente la sombra ahora.

Notas:
- La sombra solo aparecerá en el tiempo de ejecución.
- clipsToBounds debe ser falso (por defecto es)