porque - radio para iphone
No se puede agregar un radio de esquina y una sombra (4)
El siguiente código de Swift 3 muestra cómo dibujar una sombra y un radio de esquina en una imagen usando CAShapeLayer
y CALayer
.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// constants
let radius: CGFloat = 20, offset = 8
let rect = CGRect(x: 0, y: 0, width: 200, height: 200)
// roundedView
let roundedView = UIView()
view.addSubview(roundedView)
// shadow layer
let shadowLayer = CALayer()
shadowLayer.shadowColor = UIColor.darkGray.cgColor
shadowLayer.shadowPath = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath
shadowLayer.shadowOffset = CGSize(width: offset, height: offset)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
roundedView.layer.addSublayer(shadowLayer)
// mask layer
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: rect, cornerRadius: radius).cgPath
// image layer
let imageLayer = CALayer()
imageLayer.mask = maskLayer
imageLayer.frame = rect
imageLayer.contentsGravity = kCAGravityResizeAspectFill
imageLayer.contents = UIImage(named: "image")?.cgImage
roundedView.layer.addSublayer(imageLayer)
// auto layout
roundedView.translatesAutoresizingMaskIntoConstraints = false
roundedView.widthAnchor.constraint(equalToConstant: rect.width).isActive = true
roundedView.heightAnchor.constraint(equalToConstant: rect.height).isActive = true
roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
Este código genera la siguiente pantalla:
El código anterior se puede refactorizar en los siguientes archivos swift:
CustomView.swift
import UIKit
class CustomView: UIView {
var imageLayer: CALayer!
var image: UIImage? {
didSet { refreshImage() }
}
override var intrinsicContentSize:
CGSize {
return CGSize(width: 200, height: 200)
}
func refreshImage() {
if let imageLayer = imageLayer, let image = image {
imageLayer.contents = image.cgImage
}
}
override func layoutSubviews() {
super.layoutSubviews()
if imageLayer == nil {
let radius: CGFloat = 20, offset: CGFloat = 8
let shadowLayer = CALayer()
shadowLayer.shadowColor = UIColor.darkGray.cgColor
shadowLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
shadowLayer.shadowOffset = CGSize(width: offset, height: offset)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
layer.addSublayer(shadowLayer)
let maskLayer = CAShapeLayer()
maskLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: radius).cgPath
imageLayer = CALayer()
imageLayer.mask = maskLayer
imageLayer.frame = bounds
imageLayer.backgroundColor = UIColor.red.cgColor
imageLayer.contentsGravity = kCAGravityResizeAspectFill
layer.addSublayer(imageLayer)
}
refreshImage()
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let roundedView = CustomView()
roundedView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(roundedView)
// auto layout
let horizontalConstraint = roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let verticalConstraint = roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
roundedView.image = UIImage(named: "image")
}
}
Puede encontrar más formas de combinar imágenes con esquinas redondeadas y sombras en este repositorio de Github .
Estoy tratando de dibujar una sombra y un radio de esquina en una imagen. Puedo agregarlos por separado, pero no tengo forma de agregar ambos efectos al mismo tiempo. Estoy agregando una sombra con:
[layer setShadowOffset:CGSizeMake(0, 3)];
[layer setShadowOpacity:0.4];
[layer setShadowRadius:3.0f];
[layer setShouldRasterize:YES];
Aquí, layer es un CALayer de una subclase UIView. Así que esto funciona cada vez que configuro
[layer setMasksToBounds:NO];
Ahora para agregar un radio de esquina hago esto:
[layer setCornerRadius:7.0f];
pero necesito configurar MasksToBounds en YES para que esto funcione:
[layer setMasksToBounds:YES];
¿Hay de todos modos puedo obtener estos dos efectos para agregar?
Gracias por tu tiempo,
Denis
Porque uso un UIButton
con una imagen de fondo, ninguna de estas respuestas funcionó para mí. Sigo sin sombras ni bordes redondos en mis botones.
La forma más fácil en mi escenario era simplemente agregar otra vista detrás del botón y agregarle la sombra así:
button.clipsToBounds=YES;
button.layer.cornerRadius = 25;
UIView *shadowView = [[UIView alloc]initWithFrame:button.frame];
shadowView.backgroundColor = [UIColor whiteColor];//needs this to cast shadow
shadowView.layer.cornerRadius = 25;
shadowView.clipsToBounds = YES;
shadowView.layer.masksToBounds = NO;
shadowView.layer.shadowOffset = CGSizeMake(0, 2);
shadowView.layer.shadowRadius = 1;
shadowView.layer.shadowOpacity = 0.2;
[[button superview]addSubview:shadowView];
[[button superview]bringSubviewToFront:button];
Si si hay
Si desea un radio de esquina y una sombra paralela , no active -masksToBounds , sino que establezca el radio de la esquina y establezca la ruta más ancha de la sombra con un rectángulo redondeado. Mantenga el radio de los dos iguales:
[layer setShadowOffset:CGSizeMake(0, 3)];
[layer setShadowOpacity:0.4];
[layer setShadowRadius:3.0f];
[layer setShouldRasterize:YES];
[layer setCornerRadius:12.0f];
[layer setShadowPath:
[[UIBezierPath bezierPathWithRoundedRect:[self bounds]
cornerRadius:12.0f] CGPath]];
Es posible que desee comprobar su rendimiento sin el conjunto de parámetros -shouldRasterize una vez que esté configurando la ruta de la sombra. El rendimiento del dibujo tiende a ser muy bueno una vez que ha establecido una ruta de sombra.
ACTUALIZAR
No había examinado este problema en bastante tiempo, pero parece que ya no es necesario establecer una shadowPath
para que esto funcione. Simplemente configurando cornerRadius
y shadowOpacity
funcionarán ahora. Creo que este ha sido el caso desde iOS5 (por lo que puedo decir). Proporcionar esta actualización es probablemente innecesario ya que la configuración de esos parámetros "simplemente funciona", pero la proporcionaré para la posteridad. Para resumir, esto es ahora todo lo que necesita:
[layer setShadowOpacity:0.4];
[layer setCornerRadius:12.0f];
Si aún necesita un mejor rendimiento, puede seguir adelante y configurar el parámetro shouldRasterize
también:
[layer setShouldRasterize:YES];
Y hablando de rendimiento, vale la pena señalar que si está notando animaciones lentas, querrá usar la técnica de configuración de la ruta de la sombra después de todo. Esta actualización realmente fue solo para señalar que ya no es necesario establecer la ruta para lograr el efecto de mostrar tanto un radio de esquina como una sombra al mismo tiempo. Si el rendimiento es su prioridad, sin embargo, utilice una ruta.
ACTUALIZACIÓN 2
Ya que la gente parece tener problemas para que esto funcione en algunos casos, publicaré aquí un fragmento de código más completo de un proyecto de ejemplo que creé:
- (void)viewDidLoad
{
[super viewDidLoad];
CALayer *layer = [CALayer layer];
[layer setBounds:CGRectMake(0.0f, 0.0f, 100.0f, 200.0f)];
[layer setPosition:[[self view] center]];
[layer setBackgroundColor:[[UIColor lightGrayColor] CGColor]];
[layer setShadowOpacity:0.55f];
[layer setCornerRadius:8.0f];
[layer setBorderWidth:1.0f];
[[[self view] layer] addSublayer:layer];
[[[self testView] layer] setShadowOpacity:0.55f];
[[[self testView] layer] setShadowRadius:15.0f];
[[[self testView] layer] setCornerRadius:8.0f];
[[[self testView] layer] setBorderWidth:1.0f];
}
El testView
es un UIView que agregué en Interface Builder y puse una salida en. Esto es para asegurarse de que funciona igual en las dos capas que agrega explícitamente, así como en las capas dentro de las subvistas.
He probado esto en los simuladores para iOS5 hasta iOS6.1. Me da este resultado en cada uno de ellos:
view.layer.cornerRadius=4;
[view.layer setMasksToBounds:YES];
[view.layer setShadowColor:SHADOW_COLOR];
[view.layer setShadowOpacity:4 ];
[view.layer setShadowRadius:4];
[view.layer setShadowOffset:0];
[view.layer setShadowPath: [[UIBezierPath bezierPathWithRoundedRect:[view bounds] cornerRadius:CORNER_RADIUS] CGPath]];
view.layer.borderColor=[[UIColor lightGrayColor] colorWithAlphaComponent:.5].CGColor;
view.layer.borderWidth=.4;