How can I add shadow to a circle UIImageView or UIView?
Solution 1
Use the CALayer
's shadowPath
property and add a UIBezierPath
with rounded rect
self.pic.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.pic.frame cornerRadius:50.0].CGPath;
EDIT
For a square-ish image view this technique does not work directly because, as you said, the image view goes back to square. Reason: You set clipsToBounds = NO
to show the shadow which removes the clipping for corner radius, where imageView
is subview of container
.
Workaround:
Add your imageview in a container view and then apply the layer shadow to this container. Following is the code I tried.
[self.imageView.layer setCornerRadius:60.0];
[self.imageView.layer setMasksToBounds:YES];
self.imageView.clipsToBounds = YES;
self.container.backgroundColor = [UIColor clearColor];
self.container.layer.shadowColor = [UIColor blackColor].CGColor;
self.container.layer.shadowOffset = CGSizeMake(5,15);
self.container.layer.shadowOpacity = 0.5;
self.container.layer.shadowRadius = 2.0;
self.container.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.container.bounds cornerRadius:100.0].CGPath;
The resultant effect is as shown in the screenshot,
Solution 2
Without a container but with a background view here is my 2 cents
As a swift 2.2 extension
image?.applyCircleShadow(5, shadowOpacity: 1)
extension UIView {
func applyCircleShadow(shadowRadius: CGFloat = 2,
shadowOpacity: Float = 0.3,
shadowColor: CGColor = UIColor.blackColor().CGColor,
shadowOffset: CGSize = CGSize.zero) {
layer.cornerRadius = frame.size.height / 2
layer.masksToBounds = false
layer.shadowColor = shadowColor
layer.shadowOffset = shadowOffset
layer.shadowRadius = shadowRadius
layer.shadowOpacity = shadowOpacity
}
}
extension UIImageView {
override func applyCircleShadow(shadowRadius: CGFloat = 2,
shadowOpacity: Float = 0.3,
shadowColor: CGColor = UIColor.blackColor().CGColor,
shadowOffset: CGSize = CGSize.zero) {
// Use UIImageView.hashvalue as background view tag (should be unique)
let background: UIView = superview?.viewWithTag(hashValue) ?? UIView()
background.frame = frame
background.backgroundColor = backgroundColor
background.tag = hashValue
background.applyCircleShadow(shadowRadius, shadowOpacity: shadowOpacity, shadowColor: shadowColor, shadowOffset: shadowOffset)
layer.cornerRadius = background.layer.cornerRadius
layer.masksToBounds = true
superview?.insertSubview(background, belowSubview: self)
}
}
Solution 3
In case anyone looks for Swift 3 or 4 working solution:
let imageSize: CGFloat = 64.0
// Create a container which has a shadow
let imageCotainer = UIView(frame: CGRect(x: 0, y: 0, width: imageSize, height: imageSize))
imageCotainer.clipsToBounds = false
imageCotainer.layer.shadowColor = UIColor.black.cgColor
imageCotainer.layer.shadowOpacity = 0.2
imageCotainer.layer.shadowOffset = CGSize(width: 0, height: 1)
imageCotainer.layer.shadowRadius = 2
// Create an image view that will be inserted into the container view
let imageView = UIImageView(frame: imageCotainer.bounds)
imageView.image = yourImage
imageView.clipsToBounds = true
let cornerRadius = imageView.frame.height / 2
imageView.layer.cornerRadius = cornerRadius
// Draw a shadow
imageCotainer.layer.shadowPath = UIBezierPath(roundedRect: imageCotainer.bounds, cornerRadius: cornerRadius).cgPath
// Add image into container
imageCotainer.addSubview(imageView)
Sometimes you also need to set constraints for image inside of the container, but it may work without it too in some cases. But if it's not, add this:
// Set constraints for the image inside the container view
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.topAnchor.constraint(equalTo: imageCotainer.topAnchor).isActive = true
imageView.leftAnchor.constraint(equalTo: imageCotainer.leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: imageCotainer.rightAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: imageCotainer.bottomAnchor).isActive = true
imageView.heightAnchor.constraint(equalToConstant: imageSize).isActive = true
imageView.widthAnchor.constraint(equalToConstant: imageSize).isActive = true
Solution 4
I created custom classes (swift 3 or 4) and it works very well :
class RoundShadowImageView: RoundView {
var imageView = RoundImageView()
var image: UIImage! {
didSet {
imageView.image = image
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(imageView)
needsUpdateConstraints()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
addSubview(imageView)
needsUpdateConstraints()
}
override func layoutSubviews() {
super.layoutSubviews()
clipsToBounds = false
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.1
layer.shadowOffset = CGSize(width: 0, height: 10)
layer.shadowRadius = 10
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: frame.height / 2.0).cgPath
}
override func updateConstraints() {
super.updateConstraints()
imageView.snp.makeConstraints { (make) -> Void in
make.height.width.equalTo(self)
make.center.equalTo(self)
}
}
}
class RoundImageView: UIImageView {
override func layoutSubviews() {
super.layoutSubviews()
let radius: CGFloat = self.bounds.size.height / 2.0
layer.cornerRadius = radius
clipsToBounds = true
}
}
class RoundView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
let radius: CGFloat = self.bounds.size.height / 2.0
layer.cornerRadius = radius
clipsToBounds = true
}
}
There are 2 classes to make a container and an image view round. And the main class which combines both of them: the one that you'll call.
Solution 5
I might be a bit late.
You can easily set the required attributes on the storyboard attribute inspector.
The result would be something like this.
Related videos on Youtube
Newbie
Updated on July 19, 2022Comments
-
Newbie almost 2 years
I am trying to make a circle
UIImageView
, and it works. Below is the way I use to make it:[self.pic.layer setMasksToBounds:YES]; [self.pic.layer setCornerRadius:50.0];
I would like to add some shadow to the
UIImageView
. The below code does add some shadow to my image view, however, the image view changes back to square shape. Can someone give me some pointers to solve this problem? Below is the code I use to add the shadow:self.pic.layer.shadowColor = [UIColor purpleColor].CGColor; self.pic.layer.shadowOffset = CGSizeMake(0, 1); self.pic.layer.shadowOpacity = 1; self.pic.layer.shadowRadius = 1.0; self.pic.clipsToBounds = NO;
-
Newbie over 10 yearsI have added the line of code that you suggest into my code, but it doesn't work. Can you elaborate more on how to make use of the above code? thank you.
-
Amar over 10 years@Newbie Did that help?
-
Newbie over 10 yearsya, that helps. Thanks a lot.
-
mkc842 over 10 yearsNote that when he says "Add your imageview in a container view," he means add it as a subview of a normal UIView; using IB's "Container View" object would complicate things.
-
CoderNinja almost 10 yearshow does shadowradius affect the actual circular shadow?
-
Fayza Nawaz about 7 yearsgreat solution, but i don't know why it's not working in case of 7+
-
A. Bandtock about 6 yearsWhile this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.
-
akaralar about 5 yearsThis doesn't answer the question as the author wants to clip the image view to a circle, and this code disables clipping
-
Sandeep Rana almost 5 yearsI still can. Please check that you have selected the type as Number
-
Shai Balassiano over 4 yearsI think the use of "isShadowPathAutosizing" requires this pod: github.com/CosmicMind/Material
-
Antonio Adrian Chavez over 4 yearshow to add ring behind the shadow, which means look familiar to SwiftUI style? Thanks.