Sonic Master
Sonic Master

Reputation: 1248

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!

Upvotes: 49

Views: 74668

Answers (9)

Pramodya Abeysinghe
Pramodya Abeysinghe

Reputation: 1210

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
}
}

enter image description here

Upvotes: 26

iago849
iago849

Reputation: 1854

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

Upvotes: 1

Kerim Khasbulatov
Kerim Khasbulatov

Reputation: 722

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")
  }
}

enter image description here

Upvotes: 3

M.Hem
M.Hem

Reputation: 175

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

enter image description here

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

enter image description here

Example here

https://github.com/hemo87/ExampleShadow/tree/master

Upvotes: 7

Zedenem
Zedenem

Reputation: 2559

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,

Upvotes: 17

Srinivasan.M
Srinivasan.M

Reputation: 267

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)

Upvotes: 21

Hemang
Hemang

Reputation: 27050

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

Upvotes: 12

Elvin
Elvin

Reputation: 1159

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

Upvotes: 81

Luan Tran
Luan Tran

Reputation: 1142

Change your shadowOffset

 view.layer.shadowOffset = CGSize(width: 0, height: 3)

Upvotes: 16

Related Questions