uiview core-animation uiimageview calayer roundedcorners-dropshadow

uiview - ¿No se puede establecer CornerRadius AND shadow on layer que tenga una vista de imagen extendida a sus límites?



core-animation uiimageview (5)

¿Ha intentado establecer los límites de la UIImageView secundaria para que también tenga esquinas redondeadas? Tal vez entonces no anularía la sombra de la vista del contenedor. Sólo un pensamiento, no estoy seguro de si funcionará.

Esto me está parando. Tengo un UIView (llámelo "padre"). La subvista inferior de esa vista es un UIImageView (llámelo "hijo"), cuyo marco ocupa la totalidad de los límites "principales".

Quiero redondear las esquinas en la vista "principal" y establecer una sombra paralela. Hago esto en el CALayer de "padre" como de costumbre:

[[parent layer] setShadowOffset:CGSizeMake(5, 5)]; [[parent layer] setShadowRadius:6]; [[parent layer] setShadowOpacity:0.4]; [[parent layer] setCornerRadius:6];

Esto muestra la sombra correctamente, pero no redondea las esquinas.

Aquí está el kicker:

  1. Si elimino la vista de imagen "secundaria", o la contrajo para que no ocupe todos los límites de la vista "primaria", obtengo las esquinas redondeadas y la sombra correctamente en la matriz.
  2. Si dejo el "hijo" solo pero pongo "clipsToBounds" en la vista "padre", obtengo las esquinas correctamente. Pero ahora la sombra se ha ido.
  3. Establecer el radio de la esquina en la capa del niño también parece no tener efecto.

Parece que la vista de la imagen "secundaria" simplemente está oscureciendo las esquinas redondeadas de la vista "primaria", ya que ocupa todo el rectángulo, y el recorte basado en la vista principal obtiene las esquinas, pero también se enmascara de la sombra. No estoy seguro de por qué el # 3 no funciona.

¿Qué me estoy perdiendo? ¿He estado pasando por alto algo obvio al mirar esto demasiado tiempo?

Gracias.

(Sorprendentemente, la etiqueta "roundedcorners-dropshadow" ya existe. Impresionante.)


Con Swift 3, puede elegir uno de los dos fragmentos de código siguientes para establecer cornerRadius y shadow en una vista de imagen o en una vista que contenga una capa de imagen.

# 1. Usando UIView , CALayer y Spring and Struts

import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // constants let radius: CGFloat = 20, dimension: CGFloat = 200, offset = 8 let frame = CGRect(x: 0, y: 0, width: 200, height: 200) // custom view let customView = UIView(frame: frame) customView.contentMode = .scaleAspectFill // image layer let imageLayer = CALayer() imageLayer.contentsGravity = kCAGravityResizeAspectFill imageLayer.contents = UIImage(named: "image")!.cgImage imageLayer.masksToBounds = true imageLayer.frame = frame imageLayer.cornerRadius = radius imageLayer.masksToBounds = true // rounded layer let roundedLayer = CALayer() roundedLayer.shadowColor = UIColor.darkGray.cgColor roundedLayer.shadowPath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: dimension, height: dimension), cornerRadius: radius).cgPath roundedLayer.shadowOffset = CGSize(width: offset, height: offset) roundedLayer.shadowOpacity = 0.8 roundedLayer.shadowRadius = 2 roundedLayer.frame = frame // views and layers hierarchy customView.layer.addSublayer(imageLayer) customView.layer.insertSublayer(roundedLayer, below: imageLayer) view.addSubview(customView) // layout customView.center = CGPoint(x: view.bounds.midX, y: view.bounds.midY) customView.autoresizingMask = [UIViewAutoresizing.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin] } }

# 2. Usando UIView , UIImageView , CALayer y Auto Layout

import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // constants let radius: CGFloat = 20, dimension: CGFloat = 200, offset = 8 // image view let imageView = UIImageView(image: UIImage(named: "image")) imageView.contentMode = .scaleAspectFill imageView.layer.cornerRadius = radius imageView.layer.masksToBounds = true // rounded view let roundedView = UIView() roundedView.layer.shadowColor = UIColor.darkGray.cgColor roundedView.layer.shadowPath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: dimension, height: dimension), cornerRadius: radius).cgPath roundedView.layer.shadowOffset = CGSize(width: offset, height: offset) roundedView.layer.shadowOpacity = 0.8 roundedView.layer.shadowRadius = 2 // views hierarchy roundedView.addSubview(imageView) view.addSubview(roundedView) // layout imageView.translatesAutoresizingMaskIntoConstraints = false roundedView.translatesAutoresizingMaskIntoConstraints = false roundedView.widthAnchor.constraint(equalToConstant: dimension).isActive = true roundedView.heightAnchor.constraint(equalToConstant: dimension).isActive = true imageView.widthAnchor.constraint(equalTo: roundedView.widthAnchor).isActive = true imageView.heightAnchor.constraint(equalTo: roundedView.heightAnchor).isActive = true roundedView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true roundedView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true imageView.centerXAnchor.constraint(equalTo: roundedView.centerXAnchor).isActive = true imageView.centerYAnchor.constraint(equalTo: roundedView.centerYAnchor).isActive = true } }

Ambos fragmentos de código generan la siguiente visualización:

Puede encontrar más formas de combinar imágenes con esquinas redondeadas y sombras en este repositorio de Github .


Necesitará dos vistas anidadas, la interior con esquinas redondeadas y recorte a encuadernación, y la vista exterior con la sombra (y, por lo tanto, no recorte). En su caso, la vista interna y externa probablemente será "secundaria" y "primaria", pero supongo que no estableció los valores de recorte correctos para estas vistas.

Vea la respuesta en ¿Por qué masksToBounds = YES previene la sombra de CALayer? .


Normalmente, tiene que configurar clipsToBounds para que tenga esquinas redondeadas, pero como desea conservar la sombra, también debe redondear las esquinas de la sombra. ¿Has intentado configurar la ruta de la sombra utilizando una ruta de bezier? Mantenga clipsToBounds / masksToBounds a los valores predeterminados, NO. Algo como:

[[parent layer] setCornerRadius:6.0f]; [[parent layer] setShadowPath: [[UIBezierPath bezierPathWithRoundedRect:[parent bounds] cornerRadius:6.0f] CGPath]];


Si desea una capa de sombra con un radio de esquina para la visualización de la imagen, es la mejor solución poner una vista de la vista de una vista como una subvista con un margen de 1 punto ... y

imgBrandLogo.backgroundColor = UIColor.blue imgBrandLogo.layer.cornerRadius = imgBrandLogo.frame.height/2 imgBrandLogo.clipsToBounds = true viewBrandLogo.layer.shadowColor = UIColor(rgb:0x262626,alpha:0.24).cgColor viewBrandLogo.layer.shadowOffset = CGSize(width: 0, height: 1) viewBrandLogo.layer.shadowOpacity = 1 viewBrandLogo.layer.shadowPath = UIBezierPath(roundedRect:imgBrandLogo.bounds , cornerRadius: imgBrandLogo.frame.height/2).cgPath viewBrandLogo.backgroundColor = UIColor.clear.withAlphaComponent(0.0)