2010-09-11 10 views
76

Con el siguiente fragmento de código, estoy agregando un efecto de sombra a uno de mis UIView. Lo cual funciona bastante bien. Pero tan pronto como establezco la propiedad masksToBounds de la vista en . El efecto de sombra no se representa más.¿Por qué masksToBounds = YES previene la sombra de CALayer?

self.myView.layer.shadowColor = [[UIColor blackColor] CGColor]; 
self.myView.layer.shadowOpacity = 1.0; 
self.myView.layer.shadowRadius = 10.0; 
self.myView.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); 
self.myView.layer.cornerRadius = 5.0; 
self.myView.layer.masksToBounds = YES; // <-- This is causing the Drop shadow to not be rendered 
UIBezierPath *path = [UIBezierPath bezierPathWithCurvedShadowForRect:self.myView.bounds]; 
self.myView.layer.shadowPath = path.CGPath; 
self.myView.layer.shouldRasterize = YES; 

¿Tiene alguna idea sobre esto?

Respuesta

152

Como shadow es un efecto hecho fuera de la Vista, y que las máscarasToBounds establecidas en SÍ le indicarán a la UIView que no dibuje nada que esté fuera de ella.

Si quieres una vista roundedCorner con la sombra le sugiero que lo hace con 2 puntos de vista:

UIView *view1 = [[UIView alloc] init]; 
UIView *view2 = [[UIView alloc] init]; 

view1.layer.cornerRadius = 5.0; 
view1.layer.masksToBounds = YES; 
view2.layer.cornerRadius = 5.0; 
view2.layer.shadowColor = [[UIColor blackColor] CGColor]; 
view2.layer.shadowOpacity = 1.0; 
view2.layer.shadowRadius = 10.0; 
view2.layer.shadowOffset = CGSizeMake(0.0f, 0.0f); 
[view2 addSubview:view1]; 
[view1 release]; 
+9

Damned! ¡Eso tiene sentido! – jchatard

+0

Muchas gracias ... Me ayudó mucho. Agradecido a ti .. :) – innodeasapps

+0

¡Feliz de ayudar! – TheSquad

14

Es iOS 6 ahora, las cosas podrían haber cambiado. La respuesta de TheSquad no funciona para mí hasta que logré agregar una línea más view2.layer.masksToBounds = NO;, de lo contrario, no aparece la sombra. Aunque la documentación dice masksToBounds es NO por defecto, mi código muestra lo contrario.

Así es como hago un botón de esquina redondeada con la sombra, que es uno de los fragmentos de código más utilizados en mi aplicación.

button.layer.masksToBounds = YES; 
button.layer.cornerRadius = 10.0f; 

view.layer.masksToBounds = NO;  // critical to add this line 
view.layer.cornerRadius = 10.0f; 
view.layer.shadowOpacity = 1.0f; 
// set shadow path to prevent horrible performance 
view.layer.shadowPath = 
    [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath;  

[view addSubview:button]; 

EDITAR

Si las vistas deben ser animados o desplazado, masksToBounds = YES rendimiento de impuestos de manera significativa, lo que significa que la animación se consigue probablemente tartamudeaba. Para obtener esquina redondeada y de la sombra y la animación lisa o desplazamiento, utilice el código siguiente en su lugar:

button.backgroundColor = [UIColor clearColor]; 
button.layer.backgroundColor = [UIColor redColor].CGColor; 
button.layer.masksToBounds = NO; 
button.layer.cornerRadius = 10.0f; 

view.layer.shadowOpacity = 0.5f; 
view.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:_button.bounds cornerRadius:10.0f].CGPath; 
view.layer.shadowOffset = CGSizeMake(0.0f, 4.0f); 
view.layer.shadowRadius = 2.0f; 
view.layer.masksToBounds = NO; 
view.layer.cornerRadius = 10.0f; 

[view addSubview:button]; 
+0

Gracias por el fragmento, especialmente aprecio la parte de shadowPath ... –

+4

+1 por la primera respuesta. Su respuesta actualizada no funcionará para esquinas redondeadas. Si establece "masksToBounds" en "NO", las esquinas redondeadas desaparecerán. En lugar de cambiar eso, puede usar la propiedad "shouldRasterize" para obtener el buen rendimiento. –

1

También tuve problemas de rendimiento drásticas con las sombras y esquinas redondeadas. En lugar de utilizar la parte Shadowpath, he utilizado las siguientes líneas que resolvió a la perfección el impacto en el rendimiento:

self.layer.shouldRasterize = YES; 
self.layer.rasterizationScale = UIScreen.mainScreen.scale; 
+0

Sin embargo, no puede animar o retransmitir la pantalla con esto. –

2

Ésta es la versión Swift 3 y IBDesignable de la respuesta Publicado por @TheSquad.

Utilicé el mismo concepto al hacer cambios en el archivo del guión gráfico. Primero moví mi targetView (el que requiere el radio de la esquina y la sombra) dentro de un nuevo contenedor containerView. Luego añade las siguientes líneas de código (Referencia: https://stackoverflow.com/a/35372901/419192) para agregar algunos atributos IBDesignable para UIView Clase:

@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 
    } 
} 

/* The corner radius of the view. */ 
@IBInspectable var cornerRadius: CGFloat { 
    set { 
     layer.cornerRadius = newValue 
    } 
    get { 
     return layer.cornerRadius 
    } 
} 

Después de añadir este código, que volvió al guión gráfico y en la selección de mi containerView Podría ahora encontrar un nuevo conjunto de atributos en el inspector de atributos:

enter image description here

Aparte de la adición de valores para estos atributos como por mi elección, también agregué un radio de esquina a mi TargetView y establece la propiedad masksToBounds como verdadera.

espero que esto ayude :)

1

Swift versión 3.0 con StoryBoard

La misma idea con @TheSquad. Cree una vista nueva debajo de la vista real y agregue sombra a la vista inferior.

1. Crear una visión bajo el punto de vista real

Arrastre un UIView a Storyboard con misma restricción como su punto de vista objetivo. Verifique el clip para ver la vista de destino. También asegúrese de que la vista nueva esté en la lista antes de la vista de destino para que la vista de destino cubra la nueva vista.

enter image description here

2. Ahora enlazar la nueva vista a su código podrás invitar a la sombra en ella

Esto es sólo una muestra. Usted puede hacer de cualquier manera que usted quiere aquí

shadowView.layer.masksToBounds = false 
shadowView.layer.shadowColor = UIColor.red.cgColor 
shadowView.layer.shadowOpacity = 0.5 
shadowView.layer.shadowOffset = CGSize(width: -1, height: 1) 
shadowView.layer.shadowRadius = 3 

shadowView.layer.shadowPath = UIBezierPath(rect: coverImage.bounds).cgPath 
shadowView.layer.shouldRasterize = true 
0

Aquí es una de las soluciones:

 @IBOutlet private weak var blockView: UIView! { 
     didSet { 
      blockView.backgroundColor = UIColor.white 
      blockView.layer.shadowColor = UIColor.black.cgColor 
      blockView.layer.shadowOpacity = 0.5 
      blockView.layer.shadowOffset = CGSize.zero 

      blockView.layer.cornerRadius = 10 
     } 
     } 
     @IBOutlet private weak var imageView: UIImageView! { 
     didSet { 
      imageView.layer.cornerRadius = 10 
      imageView.layer.masksToBounds = true 

      imageView.layer.shouldRasterize = true 
     } 
     } 

enter image description here

Cuestiones relacionadas