I'm calling a function that sets up a UIImageView:
func setupImageView(_ imageView: UIImageView) {}
I want to give that UIImageView an image, round its corners, and give it two different borders.
Here is what I am currently doing:
imageView.image = imageConstants.imageThatIsWanted
imageView.clipsToBounds = true
imageView.layer.cornerRadius = imageView.frame.height / 2
imageView.layer.borderWidth = 3.0
imageView.layer.borderColor = UIColor.white.cgColor
What is the best way to apply a second borderColor of color blue around the white border?
I tried creating a sublayer as a CALayer and giving it a blue border, but this goes behind the image, and also inside of the white border. I also tried drawing a UIBezierPath, but that stays inside of the white border as well.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var secondView: UIView!
#IBOutlet weak var imgView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imgView.layer.cornerRadius = imgView.frame.size.height/2
secondView.layer.cornerRadius = secondView.frame.size.height/2
imgView.layer.borderWidth = 5.0
imgView.layer.borderColor = UIColor.red.cgColor
imgView.clipsToBounds = true
secondView.clipsToBounds = true
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can add UIlabel or UIImageview at back of your image view having size little bit larger than your image view and applying corner radius, if you want to reduce line of your code (Please check below code)
imgview.layer.masksToBounds = true
imgview.layer.cornerRadius = imgview.frame.size.width/2
imgview.layer.borderWidth = 5
imgview.layer.borderColor = UIColor.white.cgColor
Add new image view programatically at back side of image view already taken
let img = UIImageView(frame: CGRect(x: imgview.frame.origin.x - 2, y: imgview.frame.origin.y - 2, width: imgview.frame.size.width + 4, height: imgview.frame.size.height + 4))
img.layer.masksToBounds = true
img.layer.cornerRadius = img.frame.size.width/2
//img.backgroundColor = UIColor.blue // You can also use background color instead of border
img.layer.borderWidth = 5
img.layer.borderColor = UIColor.blue.cgColor
self.view.addSubview(img)
self.view.sendSubview(toBack: img)
I know its not proper solution but we can use this to reduce lines of code
Hope it will helps you
Related
My image is not coming out as a circle for some reason. What I did is defining the corner radius as half of the image width. Does this have to do something with the constraints I set for the image?
Image circle code:
profileImage.layer.cornerRadius = profileImage.layer.frame.width / 2
profileImage.clipsToBounds = true
profileImage.layer.borderWidth = 3.0
profileImage.layer.borderColor = UIColor.white.cgColor
What it looks like on storyboard:
What it looks like on iPhone:
swift 4:
#IBOutlet weak var photoImage: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
photoImage.layer.borderWidth = 1
photoImage.layer.masksToBounds = false
photoImage.layer.borderColor = UIColor.black.cgColor
photoImage.layer.cornerRadius = photoImage.frame.height/2
photoImage.clipsToBounds = true
}
I am trying to create an ImageView that has rounded corners and a shadow to give it some depth. I was able to create a shadow for the UIImageView, but whenever I added the code to also make it have rounded corners, it only had rounded corners with no shadow. I have an IBOutlet named myImage, and it is inside of the viewDidLoad function. Does anybody have any ideas on how to make it work? What am I doing wrong?
override func viewDidLoad() {
super.ViewDidLoad()
myImage.layer.shadowColor = UIColor.black.cgColor
myImage.layer.shadowOpacity = 1
myImage.layer.shadowOffset = CGSize.zero
myImage.layer.shadowRadius = 10
myImage.layer.shadowPath = UIBezierPath(rect: myImage.bounds).cgPath
myImage.layer.shouldRasterize = false
myImage.layer.cornerRadius = 10
myImage.clipsToBounds = true
}
If you set clipsToBounds to true, this will round the corners but prevent the shadow from appearing. In order to resolve this, you can create two views. The container view should have the shadow, and its subview should have the rounded corners.
The container view has clipsToBounds set to false, and has the shadow properties applied. If you want the shadow to be rounded as well, use the UIBezierPath constructor that takes in a roundedRect and cornerRadius.
let outerView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
outerView.clipsToBounds = false
outerView.layer.shadowColor = UIColor.black.cgColor
outerView.layer.shadowOpacity = 1
outerView.layer.shadowOffset = CGSize.zero
outerView.layer.shadowRadius = 10
outerView.layer.shadowPath = UIBezierPath(roundedRect: outerView.bounds, cornerRadius: 10).cgPath
Next, set the image view (or any other type of UIView) to be the same size of the container view, set clipsToBounds to true, and give it a cornerRadius.
let myImage = UIImageView(frame: outerView.bounds)
myImage.clipsToBounds = true
myImage.layer.cornerRadius = 10
Finally, remember to make the image view a subview of the container view.
outerView.addSubview(myImage)
The result should look something like this:
Swift 5:
You can use the below extension:
extension UIImageView {
func applyshadowWithCorner(containerView : UIView, cornerRadious : CGFloat){
containerView.clipsToBounds = false
containerView.layer.shadowColor = UIColor.black.cgColor
containerView.layer.shadowOpacity = 1
containerView.layer.shadowOffset = CGSize.zero
containerView.layer.shadowRadius = 10
containerView.layer.cornerRadius = cornerRadious
containerView.layer.shadowPath = UIBezierPath(roundedRect: containerView.bounds, cornerRadius: cornerRadious).cgPath
self.clipsToBounds = true
self.layer.cornerRadius = cornerRadious
}
}
How to use:
Drag a UIView on the storyboard
Drag an ImageView inside that UIView
Storyboard should look like this:
Create IBOutlet for both Views, call extension on your ImageView, and pass above created UIView as an argument.
Here is the output :
Finally here is how to
Properly have an image view, with rounded corners AND shadows.
It's this simple:
First some bringup code ..
class ShadowRoundedImageView: UIView {
override init(frame: CGRect) {
super.init(frame: frame); common() }
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder); common() }
private func common() {
backgroundColor = .clear
clipsToBounds = false
self.layer.addSublayer(shadowLayer)
self.layer.addSublayer(imageLayer) // (in that order)
}
#IBInspectable var image: UIImage? = nil {
didSet {
imageLayer.contents = image?.cgImage
shadowLayer.shadowPath = (image == nil) ? nil : shapeAsPath
}
}
and then the layers ...
var imageLayer: CALayer = CALayer()
var shadowLayer: CALayer = CALayer()
var shape: UIBezierPath {
return UIBezierPath(roundedRect: bounds, cornerRadius:50)
}
var shapeAsPath: CGPath {
return shape.cgPath
}
var shapeAsMask: CAShapeLayer {
let s = CAShapeLayer()
s.path = shapeAsPath
return s
}
override func layoutSubviews() {
super.layoutSubviews()
imageLayer.frame = bounds
imageLayer.contentsGravity = .resizeAspectFill // (as preferred)
imageLayer.mask = shapeAsMask
shadowLayer.shadowPath = (image == nil) ? nil : shapeAsPath
shadowLayer.shadowOpacity = 0.80 // etc ...
}
}
Here is the
Explanation
UIImageView is useless, you use a UIView
You need two layers, one for the shadow and one for the image
To round an image layer you use a mask
To round a shadow layer you use a path
For the shadow qualities, obviously add code as you see fit
shadowLayer.shadowOffset = CGSize(width: 0, height: 20)
shadowLayer.shadowColor = UIColor.purple.cgColor
shadowLayer.shadowRadius = 5
shadowLayer.shadowOpacity = 0.80
For the actual shape (the bez path) make it any shape you wish.
(For example this tip https://stackoverflow.com/a/41553784/294884 shows how to make only one or two corners rounded.)
Summary:
• Use two layers on a UIView
Make your bezier and ...
• Use a mask on the image layer
• Use a path on the shadow layer
Here is a another solution (tested code) in swift 2.0
If you set clipsToBounds to true, this will round the corners but prevent the shadow from appearing. So, you can add same size UIView in storyboard behind imageview and we can give shadow to that view
SWIFT 2.0
outerView.layer.cornerRadius = 20.0
outerView.layer.shadowColor = UIColor.blackColor().CGColor
outerView.layer.shadowOffset = CGSizeMake(0, 2)
outerView.layer.shadowOpacity = 1
outerView.backgroundColor = UIColor.whiteColor()
You can use a simple class I have created to add image with rounded corners and shadow directly from Storyboard
You can find the class here
I have a method for repeating or tiling an image across a view using UIColor patternImage:
view.backgroundColor = UIColor(patternImage: UIImage(named:imageName))
The default behaviour of UIColor patternImage is to start the pattern from the top left, the result shown in Image 1.
Question:
How can I get UIColor patternImage to start always from the very center of a view, patterning outwards to give the result shown in Image 2?
This works. It is a generalised method that applies more broadly, adapting dynamically to both pattern images and views of different heights and widths. It gives the desired result in the question and is tested on different iOS simulators.
view.backgroundColor = UIColor(patternImage: UIImage(named: "imageName")!)
view.bounds.origin.x = (UIImage(named: "imageName")!.size.width/2) - (view.bounds.size.width/2)
view.bounds.origin.y = (UIImage(named: "imageName")!.size.height/2) - (view.bounds.size.height/2)
If your image size is 50*50 then you can do something like this,
myView = UIVIew(frame: CGRect(x: (self.view.frame.size.width/2)-25, y: (self.view.frame.size.height/2)-25, width: 50, height: 50))
So this view(imageview in yourcase may be) will be place at exact middle of view. Like wise you can arrange other view by adding or substracting view's width and height to center view's x and y origin. Hope this will help you. :)
I created reusable class PatternView, reusing idea of #user4806509. It's really drop-in component for showing patterns. Also, patternImage can be set via Interface Builder
class PatternView: UIView {
#IBInspectable var patternImage: UIImage?
override func awakeFromNib() {
super.awakeFromNib()
self.setupBackgroundColor()
}
private func setupBackgroundColor() {
guard let patternImage = self.patternImage else {
return
}
self.backgroundColor = UIColor(patternImage: patternImage)
}
override func layoutSubviews() {
super.layoutSubviews()
self.centerPattern()
}
private func centerPattern() {
guard let patternSize = self.patternImage?.size,
patternSize.width > 0, patternSize.height > 0 else {
return
}
let x = -self.bounds.width.remainder(dividingBy: patternSize.width)/2
let y = -self.bounds.height.remainder(dividingBy: patternSize.height)/2
self.bounds.origin = CGPoint(x: x, y: y)
}}
Basing on the source code below:
#IBOutlet var myUIImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.makingRoundedImageProfileWithRoundedBorder()
}
private func makingRoundedImageProfileWithRoundedBorder() {
// Making a circular image profile.
// self.myUIImageView.layer.cornerRadius = self.myUIImageView.frame.size.width / 2
// Making a rounded image profile.
self.myUIImageView.layer.cornerRadius = 20.0
self.myUIImageView.clipsToBounds = true
// Adding a border to the image profile
self.myUIImageView.layer.borderWidth = 10.0
self.myUIImageView.layer.borderColor = UIColor.whiteColor().CGColor
}
Indeed I am able to render a circular or rounded UIImageView, but the problem is that if we add the border, the image leaks a bit. It's way worse with a circular UIImageView, it leaks whenever the border is bent, so LEAKS EVERYWHERE! You can find a screenshot of the result below:
Any way to fix that in Swift? Any sample code which answers to this question will be highly appreciated.
Note: as far as possible the solution has to be compatible with iOS 7 and 8+.
First Solution
Basing on the #Jesper Schläger suggestion
"If I may suggest a quick and dirty solution:
Instead of adding a border to the image view, you could just add another white view below the image view. Make the view extend 10 points in either direction and give it a corner radius of 20.0. Give the image view a corner radius of 10.0."
Please find the Swift implementation below:
import UIKit
class ViewController: UIViewController {
#IBOutlet var myUIImageView: UIImageView!
#IBOutlet var myUIViewBackground: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Making a circular UIView: cornerRadius = self.myUIImageView.frame.size.width / 2
// Making a rounded UIView: cornerRadius = 10.0
self.roundingUIView(self.myUIImageView, cornerRadiusParam: 10)
self.roundingUIView(self.myUIViewBackground, cornerRadiusParam: 20)
}
private func roundingUIView(let aView: UIView!, let cornerRadiusParam: CGFloat!) {
aView.clipsToBounds = true
aView.layer.cornerRadius = cornerRadiusParam
}
}
Second Solution
Would be to set a circle mask over a CALayer.
Please find the Objective-C implementation of this second solution below:
CALayer *maskedLayer = [CALayer layer];
[maskedLayer setFrame:CGRectMake(50, 50, 100, 100)];
[maskedLayer setBackgroundColor:[UIColor blackColor].CGColor];
UIBezierPath *maskingPath = [UIBezierPath bezierPath];
[maskingPath addArcWithCenter:maskedLayer.position
radius:40
startAngle:0
endAngle:360
clockwise:TRUE];
CAShapeLayer *maskingLayer = [CAShapeLayer layer];
[maskingLayer setPath:maskingPath.CGPath];
[maskedLayer setMask:maskingLayer];
[self.view.layer addSublayer:maskedLayer];
If you comment out from line UIBezierPath *maskingPath = [UIBezierPath bezierPath]; through [maskedLayer setMask:maskingLayer]; you will see that the layer is a square. However when these lines are not commented the layer is a circle.
Note: I neither tested this second solution nor provided the Swift implementation, so feel free to test it and let me know if it works or not through the comment section below. Also feel free to edit this post adding the Swift implementation of this second solution.
If I may suggest a quick and dirty solution:
Instead of adding a border to the image view, you could just add another white view below the image view. Make the view extend 10 points in either direction and give it a corner radius of 20.0. Give the image view a corner radius of 10.0.
I worked on improving the code but it keeps crashing. I'll work on it, but I appear to have got a (rough) version working:
Edit Updated with a slightly nicer version. I don't like the init:coder method but maybe that can factored out/improved
class RoundedImageView: UIView {
var image: UIImage? {
didSet {
if let image = image {
self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
}
}
var cornerRadius: CGFloat?
private class func frameForImage(image: UIImage) -> CGRect {
return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
override func drawRect(rect: CGRect) {
if let image = self.image {
image.drawInRect(rect)
let cornerRadius = self.cornerRadius ?? rect.size.width/10
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
UIColor.whiteColor().setStroke()
path.lineWidth = cornerRadius
path.stroke()
}
}
}
let image = UIImage(named: "big-teddy-bear.jpg")
let imageView = RoundedImageView()
imageView.image = image
Let me know if that's the sort of thing you're looking for.
A little explanation:
As I'm sure you've found, the "border" that iOS can apply isn't perfect, and shows the corners for some reason. I found a few other solutions but none seemed to work. The reason this is a subclass of UIView, and not UIImageView, is that drawRect: is not called for subclasses of UIImageView. I am not sure about the performance of this code, but it seems good from my (limited) testing
Original code:
class RoundedImageView: UIView {
var image: UIImage? {
didSet {
if let image = image {
self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
}
}
private class func frameForImage(image: UIImage) -> CGRect {
return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale)
}
override func drawRect(rect: CGRect) {
if let image = self.image {
self.image?.drawInRect(rect)
let path = UIBezierPath(roundedRect: rect, cornerRadius: 50)
UIColor.whiteColor().setStroke()
path.lineWidth = 10
path.stroke()
}
}
}
let image = UIImage(named: "big-teddy-bear.jpg")
let imageView = RoundedImageView()
imageView.image = image
imageView.layer.cornerRadius = 50
imageView.clipsToBounds = true
I am trying to create an ImageView that has rounded corners and a shadow to give it some depth. I was able to create a shadow for the UIImageView, but whenever I added the code to also make it have rounded corners, it only had rounded corners with no shadow. I have an IBOutlet named myImage, and it is inside of the viewDidLoad function. Does anybody have any ideas on how to make it work? What am I doing wrong?
override func viewDidLoad() {
super.ViewDidLoad()
myImage.layer.shadowColor = UIColor.black.cgColor
myImage.layer.shadowOpacity = 1
myImage.layer.shadowOffset = CGSize.zero
myImage.layer.shadowRadius = 10
myImage.layer.shadowPath = UIBezierPath(rect: myImage.bounds).cgPath
myImage.layer.shouldRasterize = false
myImage.layer.cornerRadius = 10
myImage.clipsToBounds = true
}
If you set clipsToBounds to true, this will round the corners but prevent the shadow from appearing. In order to resolve this, you can create two views. The container view should have the shadow, and its subview should have the rounded corners.
The container view has clipsToBounds set to false, and has the shadow properties applied. If you want the shadow to be rounded as well, use the UIBezierPath constructor that takes in a roundedRect and cornerRadius.
let outerView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
outerView.clipsToBounds = false
outerView.layer.shadowColor = UIColor.black.cgColor
outerView.layer.shadowOpacity = 1
outerView.layer.shadowOffset = CGSize.zero
outerView.layer.shadowRadius = 10
outerView.layer.shadowPath = UIBezierPath(roundedRect: outerView.bounds, cornerRadius: 10).cgPath
Next, set the image view (or any other type of UIView) to be the same size of the container view, set clipsToBounds to true, and give it a cornerRadius.
let myImage = UIImageView(frame: outerView.bounds)
myImage.clipsToBounds = true
myImage.layer.cornerRadius = 10
Finally, remember to make the image view a subview of the container view.
outerView.addSubview(myImage)
The result should look something like this:
Swift 5:
You can use the below extension:
extension UIImageView {
func applyshadowWithCorner(containerView : UIView, cornerRadious : CGFloat){
containerView.clipsToBounds = false
containerView.layer.shadowColor = UIColor.black.cgColor
containerView.layer.shadowOpacity = 1
containerView.layer.shadowOffset = CGSize.zero
containerView.layer.shadowRadius = 10
containerView.layer.cornerRadius = cornerRadious
containerView.layer.shadowPath = UIBezierPath(roundedRect: containerView.bounds, cornerRadius: cornerRadious).cgPath
self.clipsToBounds = true
self.layer.cornerRadius = cornerRadious
}
}
How to use:
Drag a UIView on the storyboard
Drag an ImageView inside that UIView
Storyboard should look like this:
Create IBOutlet for both Views, call extension on your ImageView, and pass above created UIView as an argument.
Here is the output :
Finally here is how to
Properly have an image view, with rounded corners AND shadows.
It's this simple:
First some bringup code ..
class ShadowRoundedImageView: UIView {
override init(frame: CGRect) {
super.init(frame: frame); common() }
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder); common() }
private func common() {
backgroundColor = .clear
clipsToBounds = false
self.layer.addSublayer(shadowLayer)
self.layer.addSublayer(imageLayer) // (in that order)
}
#IBInspectable var image: UIImage? = nil {
didSet {
imageLayer.contents = image?.cgImage
shadowLayer.shadowPath = (image == nil) ? nil : shapeAsPath
}
}
and then the layers ...
var imageLayer: CALayer = CALayer()
var shadowLayer: CALayer = CALayer()
var shape: UIBezierPath {
return UIBezierPath(roundedRect: bounds, cornerRadius:50)
}
var shapeAsPath: CGPath {
return shape.cgPath
}
var shapeAsMask: CAShapeLayer {
let s = CAShapeLayer()
s.path = shapeAsPath
return s
}
override func layoutSubviews() {
super.layoutSubviews()
imageLayer.frame = bounds
imageLayer.contentsGravity = .resizeAspectFill // (as preferred)
imageLayer.mask = shapeAsMask
shadowLayer.shadowPath = (image == nil) ? nil : shapeAsPath
shadowLayer.shadowOpacity = 0.80 // etc ...
}
}
Here is the
Explanation
UIImageView is useless, you use a UIView
You need two layers, one for the shadow and one for the image
To round an image layer you use a mask
To round a shadow layer you use a path
For the shadow qualities, obviously add code as you see fit
shadowLayer.shadowOffset = CGSize(width: 0, height: 20)
shadowLayer.shadowColor = UIColor.purple.cgColor
shadowLayer.shadowRadius = 5
shadowLayer.shadowOpacity = 0.80
For the actual shape (the bez path) make it any shape you wish.
(For example this tip https://stackoverflow.com/a/41553784/294884 shows how to make only one or two corners rounded.)
Summary:
• Use two layers on a UIView
Make your bezier and ...
• Use a mask on the image layer
• Use a path on the shadow layer
Here is a another solution (tested code) in swift 2.0
If you set clipsToBounds to true, this will round the corners but prevent the shadow from appearing. So, you can add same size UIView in storyboard behind imageview and we can give shadow to that view
SWIFT 2.0
outerView.layer.cornerRadius = 20.0
outerView.layer.shadowColor = UIColor.blackColor().CGColor
outerView.layer.shadowOffset = CGSizeMake(0, 2)
outerView.layer.shadowOpacity = 1
outerView.backgroundColor = UIColor.whiteColor()
You can use a simple class I have created to add image with rounded corners and shadow directly from Storyboard
You can find the class here