Tableview Xib Shadow Swift - ios

Here is what I am trying to do:
The screenshot is taken from Iphone:
This is my code:
cell.shadowLayerView.layer.masksToBounds = false
cell.shadowLayerView.layer.shadowOffset = CGSize(width: 0, height: 0)
cell.shadowLayerView.layer.shadowColor = UIColor.black.cgColor
cell.shadowLayerView.layer.shadowOpacity = 0.23
cell.shadowLayerView.layer.shadowRadius = 4
cell.shadowLayerView.layer.shadowPath = UIBezierPath(roundedRect: cell.shadowLayerView.bounds, cornerRadius: 2).cgPath
cell.shadowLayerView.layer.shouldRasterize = true
cell.shadowLayerView.layer.rasterizationScale = UIScreen.main.scale
cell.discriptionLbl.frame.size.width = UIScreen.main.bounds.size.width
This is my tableview xib. In original image show light gray color shadow all side(Top,Bottom,left,Right) but in taken image show all side shadow but why show extra shadow in right side and bottom side.
See Below Image:
Question: How to show same shadow from all side of the view like original image(shadow in light gray color)?
Can someone please explain to me how to solve this , i've tried to solve this issue but no results yet.
Any help would be greatly appreciated.
Thanks in advance.

See the below code:
mainViewCorner.layer.shadowColor = UIColor.red.cgColor;
mainViewCorner.layer.shadowOffset = CGSize.zero //direction of shadow
mainViewCorner.layer.shadowOpacity = 1.0; // opacity for shadow
mainViewCorner.layer.shadowRadius = 0.0; //amount of shadow to blur
mainViewCorner.layer.cornerRadius = 4.0;
issue with your code was shadowOffset. It defines the direction of your shadow. If you want shadow on all sides - it must have zero value for both width and height.

try it
myView.layer.cornerRadius = 10
let shadowPath = UIBezierPath(roundedRect: myView.bounds, cornerRadius: 10)
myView.layer.masksToBounds = false
myView.layer.shadowColor = UIColor.gray.cgColor
myView.layer.shadowOffset = CGSize(width: 0, height: 2)
myView.layer.shadowOpacity = 0.5
Or you can use Sketch Shadow
extension CALayer {
func applySketchShadow(
color: UIColor = .black,
alpha: Float = 0.5,
x: CGFloat = 0,
y: CGFloat = 2,
blur: CGFloat = 4,
spread: CGFloat = 0)
{
shadowColor = color.cgColor
shadowOpacity = alpha
shadowOffset = CGSize(width: x, height: y)
shadowRadius = blur / 2.0
if spread == 0 {
shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
shadowPath = UIBezierPath(rect: rect).cgPath
}
}
}
apply Sketch Shadow
myView.layer.cornerRadius = 10
let shadowPath = UIBezierPath(roundedRect: myView.bounds, cornerRadius: 10)
myView.layer.applySketchShadow(
color: .black,
alpha: 0.5,
x: CGFloat(0),
y: CGFloat(10),
blur: 20,
spread: 0)
myView.layer.shadowPath = shadowPath.cgPath

Related

Uneven Dropshadows on rounded views

I have collectionview cell to which I have a container UIView() which is margined at some distance from the super view. The containerview is rounded and I am trying to apply drop shadow to it. I am acheiving this quite finely until, on some cells it breaks the shadow layer and creates and uneven shadow effect. Following is the current result.:
Following is my code:
extension UIView() {
func dropShadow(color: UIColor, opacity: Float = 0.5, offSet: CGSize, radius: CGFloat = 1, scale: Bool = true) {
self.layer.masksToBounds = false
self.layer.shadowColor = color.cgColor
self.layer.shadowOpacity = opacity
self.layer.shadowOffset = offSet
self.layer.shadowRadius = radius
self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: radius).cgPath
self.layer.shouldRasterize = true
self.layer.rasterizationScale = scale ? UIScreen.main.scale : 1
}
}
Following is UICollectionViewCell.swift
override func layoutSubviews() {
super.layoutSubviews()
containerView.dropShadow(color: .lightGray, opacity: 6, offSet: CGSize(width: 0, height: 0), radius: 6, scale: true)
}
Any help is very much appreciated.
I have made use of shadow in a view inside collectionview cell. Please see below link
View Sample
This is inside cellforItem
myCell.imgIcon.backgroundColor = UIColor.white
myCell.imgIcon.layer.shadowColor = UIColor.lightGray.cgColor
myCell.imgIcon.layer.shadowOpacity = 0.5
myCell.imgIcon.layer.shadowOffset = CGSize(width: 0, height: 0)
myCell.imgIcon.layer.shadowRadius = 5

Create sketch type shadow

I created a sketch design with shadows but when i tried implementing this in Xcode with swift i am not getting my desired result this is what i want to achieve
But this is what i keep getting
Here is the code i am using
extension CALayer {
func applySketchShadow(
color: UIColor = .black,
alpha: Float = 0.5,
x: CGFloat = 0,
y: CGFloat = 2,
blur: CGFloat = 4,
spread: CGFloat = 0)
{
shadowColor = color.cgColor
shadowOpacity = alpha
shadowOffset = CGSize(width: x, height: y)
shadowRadius = blur / 2.0
if spread == 0 {
shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
shadowPath = UIBezierPath(rect: rect).cgPath
}
}
}
You only need to do is that you have to increase the value of y.
If you set the value of x and y to 0.0, then it will show the shadow like box. So, when you increase the value of y then the shadow will move to down side. So, you will not see the shadow upside and it looks like what you need.
Hope this will help you.

Unable to set bottom shadow of UIView in iOS?

I want to set the bottom shadow of UIView.I am also setting corner radius.If i set maskToBounds to true then i am not able to set the shadow of UIView please tell how can i set both corner radius & shadow of UIView.
func addShadwToView(){
self.viewContainer.layer.masksToBounds = true;
self.viewContainer.layer.shadowRadius = 15;
self.viewContainer.layer.shadowOffset = CGSize(width: 0, height: 20)
self.viewContainer.layer.shadowOpacity = 0.5;
self.viewContainer.layer.cornerRadius = 5
self.viewContainer.layer.borderColor = UIColor.lightGray.cgColor
self.viewContainer.layer.borderWidth = 0.5
}
If you want both a corner radius and a drop shadow, so don't turn on -masksToBounds, but rather set the corner radius and set the bezier path of the shadow with a rounded rect. Keep the radius of the two the same:
Try it:
func addShadwToView(){
var borderLine = CAShapeLayer()
borderLine.path = UIBezierPath(roundedRect: frame2, byRoundingCorners: [.allCorners], cornerRadii: CGSize(width: 30, height: 0)).cgPath
borderLine.shadowColor = UIColor.white.cgColor
borderLine.shadowOffset = CGSize(width: 0, height: 1)
borderLine.shadowOpacity = 0.3
borderLine.shadowRadius = 10
self.viewContainer.layer.masksToBounds = true;
self.viewContainer.layer.cornerRadius = 5
self.viewContainer.layer.borderColor = UIColor.lightGray.cgColor
self.viewContainer.layer.borderWidth = 0.5
self.viewContainer.layer.addSublayer(borderLine)
}
Try this code...this will solve your problem
func addShadow(){
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: customView.frame.width, height: customView.frame.height))
customView.layer.shadowColor = UIColor.lightGray.cgColor
customView.layer.shadowOffset = CGSize(width: 0, height: 20)
customView.layer.shadowOpacity = 0.5
customView.layer.shadowRadius = 15
customView.layer.masksToBounds = false
customView.layer.shadowPath = shadowPath.cgPath
}

Set Shadow on Bottom UIView only

I want to create bottom only shadow on UIView. Right now with this function, will create shadow in top, bottom, left, and right.
func setCardView(view : UIView){
view.layer.masksToBounds = false
view.layer.shadowOffset = CGSize(width: 0, height: 0)
view.layer.shadowRadius = 2
view.layer.shadowOpacity = 0.5
}
Is there anyway to only create shadow in the bottom?
Any help would be appreciated. Thank you!
I think the proper way of thinking of shadow is, the shadow belongs to the object, which is the button, the uiview, not just part of the side. Imagining there is a virtual light source. You can't really just create a shadow for one side.
With that being said, the shadow will always be the shadow of the view as a whole. However, you can change the shadow offset to make it towards to the bottom.
view.layer.shadowOffset = CGSize(width: 0, height: 3)
This means you want the light source shoot the light from top to make the shadow to the bottom. The reason you still see some shadow at the top is the shadow radius. which is to simulate the diffuse of the light. The more diffuse the light is, the softer the shadow will be so you will see top shadow still.
view.layer.shadowRadius = 1 or 0.5
try to reduce the radius also. it will give you a better visual result.
To understand umbra, penumbra and antumbra if you need, check out https://en.wikipedia.org/wiki/Umbra,_penumbra_and_antumbra
This adds a shadow only to bottom. Implemented as an extension to UIView
extension UIView {
func addBottomShadow() {
layer.masksToBounds = false
layer.shadowRadius = 4
layer.shadowOpacity = 1
layer.shadowColor = UIColor.gray.cgColor
layer.shadowOffset = CGSize(width: 0 , height: 2)
layer.shadowPath = UIBezierPath(rect: CGRect(x: 0,
y: bounds.maxY - layer.shadowRadius,
width: bounds.width,
height: layer.shadowRadius)).cgPath
}
}
This code working for swift 4 and shadow applying for view Bottom:
view.layer.masksToBounds = false
view.layer.shadowRadius = 4
view.layer.shadowOpacity = 1
view.layer.shadowColor = UIColor.gray.cgColor
view.layer.shadowOffset = CGSize(width: 0 , height:2)
If you really want a shadow only on one side of your UIView, you should set your view.layer.shadowPath to a UIBezierPath.
Here is an example which will only display a shadow at the bottom of the view:
view.layer.shadowPath = UIBezierPath(rect: CGRect(x: 0,
y: bounds.maxY - layer.shadowRadius,
width: bounds.width,
height: layer.shadowRadius)).cgPath
Deconstructing the CGRect value, you get:
x and width make sure the shadow takes the full horizontal width of your view (you might want to adjust them, for example using the layer.shadowRadius value as a basis for your offsetting)
y and height make sure the shadow starts as low as possible and then is only as big as the radius
Of course, there are some cases where this won't work, for example when you want a shadowRadius larger than your view's height. In these cases, I would recommend using an image view or a masked layer.
Hope this helps,
Change your shadowOffset
view.layer.shadowOffset = CGSize(width: 0, height: 3)
Here's the proper way of applying shadow in Swift:
yourView.layer.shadowOffset = CGSize(width: 0, height: 3)
yourView.layer.shadowOpacity = 0.6
yourView.layer.shadowRadius = 3.0
yourView.layer.shadowColor = UIColor.red.cgColor
Old question but it seems none of the answers really answer the question.
While the above answers will work with a low shadowRadius you don't really get a 'shadow' effect.
You can absolutely add a shadow to just the bottom by using UIBezierPath
Heres how -
let shadowWidth: CGFloat = 1.2 // Shadow width, will be the width furthest away from the view, this is equivalent to 120% of the views width
let shadowHeight: CGFloat = 0.3 // Shadow height, again this is equivalent to 30%
let shadowRadius: CGFloat = 5
let width = someView.frame.width
let height = someView.frame.height // Get width and height of the view
// Plot the path
let shadowPath = UIBezierPath()
shadowPath.move(to: CGPoint(x: shadowRadius / 2, y: height - shadowRadius / 2))
shadowPath.addLine(to: CGPoint(x: width - shadowRadius / 2, y: height - shadowRadius / 2))
shadowPath.addLine(to: CGPoint(x: width * shadowWidth, y: height + (height * shadowHeight)))
shadowPath.addLine(to: CGPoint(x: width * -(shadowWidth - 1), y: height + (height * shadowHeight)))
// Add shadow
someView.layer.shadowPath = shadowPath.cgPath
someView.layer.shadowRadius = shadowRadius
someView.layer.shadowOffset = .zero
someView.layer.shadowOpacity = 0.2
This outputs this
Or if you wanted a simpler solution, with less options you could go with this
let buttonHeight = someButton.frame.height
let buttonWidth = someButton.frame.width
let shadowSize: CGFloat = 15
let contactRect = CGRect(x: -shadowSize, y: buttonHeight - (shadowSize * 0.2), width: buttonWidth + shadowSize * 2, height: shadowSize)
someButton.layer.shadowPath = UIBezierPath(ovalIn: contactRect).cgPath
someButton.layer.shadowRadius = 5
someButton.layer.shadowOpacity = 0.6
Which will output this
Example here
https://github.com/hemo87/ExampleShadow/tree/master
class ViewBottomShadow: UIView {
init() {
super.init(frame: .zero)
backgroundColor = .white
layer.masksToBounds = false
layer.shadowRadius = 2
layer.shadowOpacity = 1
layer.shadowColor = UIColor.gray.cgColor
layer.shadowOffset = CGSize(width: 0 , height:2)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Just draw regular shadow and rotate it upside down, as simple as that
#objc func shadowView() -> UIView {
let shadowView = UIView(frame: .zero)
shadowView.backgroundColor = .white
shadowView.layer.shadowColor = UIColor.grey.cgColor
shadowView.layer.shadowOffset = CGSize(width: 0, height: 2)
shadowView.layer.shadowOpacity = 1.0
shadowView.layer.shadowRadius = 4
shadowView.layer.compositingFilter = "multiplyBlendMode"
return shadowView
}
func idtm_addBottomShadow() {
let shadow = shadowView()
shadow.transform = transform.rotated(by: 180 * CGFloat(Double.pi))
shadow.transform = transform.rotated(by: -1 * CGFloat(Double.pi))
shadow.translatesAutoresizingMaskIntoConstraints = false
addSubview(shadow)
NSLayoutConstraint.activate([
shadow.leadingAnchor.constraint(equalTo: leadingAnchor),
shadow.trailingAnchor.constraint(equalTo: trailingAnchor),
shadow.bottomAnchor.constraint(equalTo: bottomAnchor),
shadow.heightAnchor.constraint(equalToConstant: 1),
])
}

How to control shadow spread and blur?

I have designed UI elements in sketch, and one of them has a shadow with blur 1 and spread 0. I looked at the doc for the views layer property and layer doesn't have anything named spread or blur, or anything equivalent (the only control was merely shadowOpacity). How can control things like blur and spread?
Here are my settings in Sketch:
And here is what I want my shadow to look like:
And here is what it looks like at the moment:
Note, you have to click on the picture to actually see the shadow.
My code is as follows:
func setupLayer(){
view.layer.cornerRadius = 2
view.layer.shadowColor = Colors.Shadow.CGColor
view.layer.shadowOffset = CGSize(width: 0, height: 1)
view.layer.shadowOpacity = 0.9
view.layer.shadowRadius = 5
}
Here's how to apply all 6 Sketch shadow properties to a UIView's layer with near perfect accuracy:
extension CALayer {
func applySketchShadow(
color: UIColor = .black,
alpha: Float = 0.5,
x: CGFloat = 0,
y: CGFloat = 2,
blur: CGFloat = 4,
spread: CGFloat = 0)
{
masksToBounds = false
shadowColor = color.cgColor
shadowOpacity = alpha
shadowOffset = CGSize(width: x, height: y)
shadowRadius = blur / 2.0
if spread == 0 {
shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
shadowPath = UIBezierPath(rect: rect).cgPath
}
}
}
Say we want to represent the following:
You can easily do this via:
myView.layer.applySketchShadow(
color: .black,
alpha: 0.5,
x: 0,
y: 0,
blur: 4,
spread: 0)
or more succinctly:
myView.layer.applySketchShadow(y: 0)
Example:
Left: iPhone 8 UIView screenshot; right: Sketch rectangle.
Note:
When using a non-zero spread, it hardcodes a path based on the bounds of the CALayer. If the layer's bounds ever change, you'd want to call the applySketchShadow() method again.
You can try this .... you can play with the values.
The shadowRadius dictates the amount of blur. shadowOffset dictates where the shadow goes.
Swift 2.0
let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
//Change 2.1 to amount of spread you need and for height replace the code for height
demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.blackColor().CGColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4) //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds = false
demoView.layer.shadowPath = shadowPath.CGPath
Swift 3.0
let radius: CGFloat = demoView.frame.width / 2.0 //change it to .height if you need spread for height
let shadowPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 2.1 * radius, height: demoView.frame.height))
//Change 2.1 to amount of spread you need and for height replace the code for height
demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.black.cgColor
demoView.layer.shadowOffset = CGSize(width: 0.5, height: 0.4) //Here you control x and y
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
demoView.layer.masksToBounds = false
demoView.layer.shadowPath = shadowPath.cgPath
Example with spread
To create a basic shadow
demoView.layer.cornerRadius = 2
demoView.layer.shadowColor = UIColor.blackColor().CGColor
demoView.layer.shadowOffset = CGSizeMake(0.5, 4.0); //Here your control your spread
demoView.layer.shadowOpacity = 0.5
demoView.layer.shadowRadius = 5.0 //Here your control your blur
Basic Shadow example in Swift 2.0
Sketch Shadow Using IBDesignable and IBInspectable in Swift 4
SKETCH AND XCODE SIDE BY SIDE
CODE
#IBDesignable class ShadowView: UIView {
#IBInspectable var shadowColor: UIColor? {
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.shadowColor = color.cgColor
} else {
layer.shadowColor = nil
}
}
}
#IBInspectable var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set {
layer.shadowOpacity = newValue
}
}
#IBInspectable var shadowOffset: CGPoint {
get {
return CGPoint(x: layer.shadowOffset.width, y:layer.shadowOffset.height)
}
set {
layer.shadowOffset = CGSize(width: newValue.x, height: newValue.y)
}
}
#IBInspectable var shadowBlur: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowRadius = newValue / 2.0
}
}
#IBInspectable var shadowSpread: CGFloat = 0 {
didSet {
if shadowSpread == 0 {
layer.shadowPath = nil
} else {
let dx = -shadowSpread
let rect = bounds.insetBy(dx: dx, dy: dx)
layer.shadowPath = UIBezierPath(rect: rect).cgPath
}
}
}
}
OUTPUT
HOW TO USE IT
This code worked very well for me:
yourView.layer.shadowOpacity = 0.2 // opacity, 20%
yourView.layer.shadowColor = UIColor.black.cgColor
yourView.layer.shadowRadius = 2 // HALF of blur
yourView.layer.shadowOffset = CGSize(width: 0, height: 2) // Spread x, y
yourView.layer.masksToBounds = false
For those who are attempting to apply a shadow to a predefined path (Like for a circular view, for instance), here's what I ended up with:
extension CALayer {
func applyShadow(color: UIColor = .black,
alpha: Float = 0.5,
x: CGFloat = 0,
y: CGFloat = 2,
blur: CGFloat = 4,
spread: CGFloat = 0,
path: UIBezierPath? = nil) {
shadowColor = color.cgColor
shadowOpacity = alpha
shadowRadius = blur / 2
if let path = path {
if spread == 0 {
shadowOffset = CGSize(width: x, height: y)
} else {
let scaleX = (path.bounds.width + (spread * 2)) / path.bounds.width
let scaleY = (path.bounds.height + (spread * 2)) / path.bounds.height
path.apply(CGAffineTransform(translationX: x + -spread, y: y + -spread).scaledBy(x: scaleX, y: scaleY))
shadowPath = path.cgPath
}
} else {
shadowOffset = CGSize(width: x, height: y)
if spread == 0 {
shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
shadowPath = UIBezierPath(rect: rect).cgPath
}
}
shouldRasterize = true
rasterizationScale = UIScreen.main.scale
}
}
I'll post some examples later, but this has worked spot on for circular views for me.
My solution based on this post replies: (Swift 3)
let shadowPath = UIBezierPath(rect: CGRect(x: -1,
y: -2,
width: target.frame.width + 2,
height: target.frame.height + 2))
target.layer.shadowColor = UIColor(hexString: shadowColor).cgColor
target.layer.shadowOffset = CGSize(width: CGFloat(shadowOffsetX), height: CGFloat(shadowOffsetY))
target.layer.masksToBounds = false
target.layer.shadowOpacity = Float(shadowOpacity)
target.layer.shadowPath = shadowPath.cgPath
Change a little bit from #Senseful 's answer and works fine to my project.
Support shadow corner radius (for some round corner view)
spread == 0 it still apply shadow effect(looks like border)
struct SketchShadow {
var color: UIColor = .black
let alpha: Float = 0.1
let x: CGFloat
let y: CGFloat
let blur: CGFloat
let spread: CGFloat
let cornorRadius: CGFloat
func applyToLayer(_ layer: CALayer) {
layer.masksToBounds = false
layer.shadowColor = color.cgColor
layer.shadowOpacity = alpha
layer.shadowOffset = CGSize(width: x, height: y)
layer.shadowRadius = blur / 2.0
if spread == 0 {
layer.shadowPath = UIBezierPath(roundedRect: layer.bounds, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornorRadius, height: cornorRadius)).cgPath
} else {
let dx = -(spread)
let rect = layer.bounds.insetBy(dx: dx, dy: dx)
layer.shadowPath = UIBezierPath(roundedRect: rect, byRoundingCorners: .allCorners, cornerRadii: CGSize(width: cornorRadius, height: cornorRadius)).cgPath
}
}
}
I really like the answer posted here and suggestions in the comments. This is how I modified that solution:
extension UIView {
func applyShadow(color: UIColor, alpha: Float, x: CGFloat, y: CGFloat, blur: CGFloat, spread: CGFloat) {
layer.masksToBounds = false
layer.shadowColor = color.cgColor
layer.shadowOpacity = alpha
layer.shadowOffset = CGSize(width: x, height: y)
layer.shadowRadius = blur / UIScreen.main.scale
if spread == 0 {
layer.shadowPath = nil
} else {
let dx = -spread
let rect = bounds.insetBy(dx: dx, dy: dx)
layer.shadowPath = UIBezierPath(rect: rect).cgPath
}
}
}
USAGE:
myButton.applyShadow(color: .black, alpha: 0.2, x: 0, y: 1, blur: 2, spread: 0)
It might be a little diggin in history, but maybe some had same issue. I useed code sample from accepted answer. However the effects are quite different:
- y value has to be around half compared to same value in sketch
- I tried to apply shadow on navigation bar and the effect is terribly different - barely visible while using same values that sketch had.
So there seems that the method is totally not reflecting sketch parameters.
Any hints?

Resources