Set Shadow on Bottom UIView only - ios

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),
])
}

Related

How to create a solid rectangle border around the circle in UICollectionView Swift4+

I have tried the following but only creates a border around the circle but not a separate rectangle border.
as shown here
cell.layer.borderWidth = 1.0
cell.layer.borderColor = UIColor.black.cgColor
I want to create a rectangle border as shown here
Instead of
cell.layer.borderWidth = 1.0
cell.layer.cornerRadius = 10
cell.layer.borderColor = UIColor.black.cgColor
Have you tried?
cell.layer.borderWidth = 1.0
cell.layer.borderColor = UIColor.black.cgColor
I'm not sure if it'll work for you, but you can try to add an additional layer like that:
var rect = UIView()
var circle: CALayer?
override func loadView() {
// create view with border
rect.frame = CGRect(x: 50, y: 50, width: 300, height: 200)
rect.layer.borderColor = UIColor.black.cgColor
rect.layer.backgroundColor = UIColor.clear.cgColor
rect.layer.borderWidth = 2
// add circle layer
let circle = CALayer()
circle = UIColor.red.cgColor
// add circle layer on view with drawn border
rect.layer.addSublayer(circle)
view.addSubview(rect)
circle = circle
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// layout circle on your view
let radius = min(rect.frame.width, rect.frame.height) * 0.5
circle?.frame = CGRect(x: rect.bounds.width / 2 - radius / 2, y: rect.bounds.height / 2 - radius / 2, width: radius, height: radius)
circle?.cornerRadius = radius / 2
}
But probably that's not the best option, maybe someone gives you better solution.
If it doesn't work for you, please, give more details of you problem.

Border Padding for a UIView

I created a standard border around my UIView like so:
vwGroup.layer.borderColor = UIColor.yellow.cgColor
vwGroup.layer.borderWidth = 2.0;
but I would like to have 5px of padding/margin/spacing between the UIView, and the border that surrounds it.
Right now it just draws the border immediately around it. I'd like to push it out so there is clear space between.
Any suggestions? I suspect insets are the way to go but can't figure it out.
Thank you!
Insets isn't the way to go. You use inset for padding a view's internal content from its margins. For what you need your best option is to wrap your vwGroup inside another UIView and set the border in the wrapping view. Something like:
let wrappingView = UIView(frame: someFrame)
wrappingView.backgroundColor = .clear
wrappingView.layer.borderColor = UIColor.yellow.cgColor
wrappingView.layer.borderWidth = 2.0;
wrappingView.addSubview(vwGroup)
Of course this is just for you to get the big picture. You might want to set proper frames/constraints.
Try this, it is helpful for you.
First, Add this extension
extension CALayer {
func addGradientBorder(colors:[UIColor],width:CGFloat = 1) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(origin: CGPoint.zero, size: self.bounds.size)
gradientLayer.startPoint = CGPoint(x:0.0, y:0.0)
gradientLayer.endPoint = CGPoint(x:1.0,y:1.0)
gradientLayer.colors = colors.map({$0.cgColor})
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = width
shapeLayer.path = UIBezierPath(rect: self.bounds).cgPath
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.red.cgColor
gradientLayer.mask = shapeLayer
self.addSublayer(gradientLayer)
}
}
Then add the UIView with border
let vwGroup = UIView(frame: CGRect(x: 50, y: 150, width: 200, height: 200))
vwGroup.backgroundColor = .red
//-- This is for padding between boarder and view -- you can set padding color ---
vwGroup.layer.addGradientBorder(colors:[UIColor.black,UIColor.black] , width: 40)
//-- This is for outer boarder -- you can also change the color of outer boarder --
vwGroup.layer.addGradientBorder(colors:[UIColor.white,UIColor.white] , width: 10)
self.view.addSubview(vwGroup)
Output is:
swift 5.4
call like this:
customView.layer.innerBorder()
did it, by add a sublayer
extension CALayer {
func innerBorder(borderOffset: CGFloat = 24.0, borderColor: UIColor = UIColor.blue, borderWidth: CGFloat = 2) {
let innerBorder = CALayer()
innerBorder.frame = CGRect(x: borderOffset, y: borderOffset, width: frame.size.width - 2 * borderOffset, height: frame.size.height - 2 * borderOffset)
innerBorder.borderColor = borderColor.cgColor
innerBorder.borderWidth = borderWidth
innerBorder.name = "innerBorder"
insertSublayer(innerBorder, at: 0)
}
}

Tableview Xib Shadow Swift

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

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
}

Circular UIView Not A Full Circle

I have an interesting issue, but I'm not sure how to solve it. I am attempting to extend UIView with an #IBInspectable. However, with this method the corner radius seems to be set from the nib files default side, not the actual size of the view.
So, when in IB I set the "View as" to iPhoneSE and build for iPhoneSE, the view is a circle. However, if I build for iPhone7, the corners are not fully rounded into a circle. Conversely, if I set "View as" to iPhone7 and build for iPhone7, the view is a circle, However, if I build for iPhoneSE the corners are over-rounded.
Pictures and code below:
Extension
extension UIView {
#IBInspectable var cornerRadius:Double {
get {
return Double(layer.cornerRadius)
}
set {
layer.cornerRadius = CGFloat(newValue)
layer.masksToBounds = newValue > 0
}
}
#IBInspectable var circleView:Bool {
get {
return layer.cornerRadius == min(self.frame.width, self.frame.height) / CGFloat(2.0) ? true : false
}
set {
if newValue {
layer.cornerRadius = min(self.frame.width, self.frame.height) / CGFloat(2.0)
layer.masksToBounds = true
}
else{
layer.cornerRadius = 0.0
layer.masksToBounds = false
}
}
}
}
"View as" set as iPhoneSE in IB
Built for iPhoneSE
Build for iPhone 7
"View as" set as iPhone7
Build for iPhone SE
Build for iPhone 7
IB Settings
You will only get a full circle if your view is a square.
If you're view is a rectangle and you set the cornerRadius with a value less than half the smallest dimension, you will get the second view and if it's a value greater than that you will get the diamond shaped one.
Check your constraints and you should compute the cornerRadius after the view finishes layout in viewDidLayout so you get the correct size.
Here is a Playground showing this (I've added an animation to show better the issue):
import UIKit
import PlaygroundSupport
extension UIView
{
func addCornerRadiusAnimation(from: CGFloat, to: CGFloat, duration: CFTimeInterval)
{
let animation = CABasicAnimation(keyPath:"cornerRadius")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.fromValue = from
animation.toValue = to
animation.duration = duration
self.layer.add(animation, forKey: "cornerRadius")
self.layer.cornerRadius = to
}
}
let v = UIView(frame: CGRect(x: 0, y: 0, width: 350, height: 450))
PlaygroundPage.current.liveView = v
let squareView = UIView(frame: CGRect(x: 10, y: 10, width: 100, height: 100))
squareView.backgroundColor = .red
squareView.layer.masksToBounds = true
v.addSubview(squareView)
var cornerRadius = CGFloat(0.5*min(squareView.frame.width,
squareView.frame.height))
squareView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5)
let rectangleView = UIView(frame: CGRect(x: 10, y: 200, width: 100, height: 200))
rectangleView.backgroundColor = .blue
rectangleView.layer.masksToBounds = true
v.addSubview(rectangleView)
cornerRadius = CGFloat(0.5*min(rectangleView.frame.width,
rectangleView.frame.height))
rectangleView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5)
let diamondView = UIView(frame: CGRect(x: 200, y: 200, width: 100, height: 200))
diamondView.backgroundColor = .green
diamondView.layer.masksToBounds = true
v.addSubview(diamondView)
cornerRadius = CGFloat(0.5*max(diamondView.frame.width,
diamondView.frame.height))
diamondView.addCornerRadiusAnimation(from: 0, to: cornerRadius, duration: 5)
You mentioned Width and Height as 185.5 but you kept width constraint as 350.
If you don't want to move on viewDidLayout you can simply made the trick before setting your corner radius by adding .layoutIfNeeded().
yourCircleView.layoutIfNeeded()
yourCircleView.layer.cornerRadius = yourCircleView.frame.size.width/2
If still failing, in Xcode remove all (ALL) restraints and add the following in the Cell Class:
override func awakeFromNib() {
super.awakeFromNib()
userImageView.layoutIfNeeded()
userImageView.layer.cornerRadius = userImageView.frame.size.width / 2
userImageView.layer.masksToBounds = true
userImageView.clipsToBounds = true
}

Resources