2

I'm working on my view and I'm having an issue with getting a shadow around a button within the stack view. Most of the work I have done has been within the storyboard directly.

Storyboard render showing background

Simulator render missing background

Here is the method I am using to apply the shadow to the view

func addShadow(to view: UIView) {
    view.layer.shadowColor = shadowColor
    view.layer.shadowOpacity = shadowOpacity
    view.layer.shadowOffset = shadowOffset
    if let bounds = view.subviews.first?.bounds {
        view.layer.shadowPath = UIBezierPath(rect: bounds).cgPath
    }

    view.layer.shouldRasterize = true
}

and this is how I'm finding the button within the view from ViewController.swift

for subview in self.view.subviews {
    if subview.isKind(of: UIButton.self) && subview.tag == 1 {
        addShadow(to: subview)
    }
}

I know the problem stems from the stack view and the UIView inside of the stack view that holds the button. (self.view > UIStackView > UIView > [UIButton, UILabel])

I know I could do this with recursion in the for-loop but I'm trying to be a little more precise to optimize performance and would prefer to add the shadows in one shot.

Vinodh
  • 5,262
  • 4
  • 38
  • 68
Bob R.
  • 21
  • 3

1 Answers1

0

You have a few options:

  1. add the shadow in the storyboard itself
  2. add an outlet to the button, then add shadow in code
  3. add the button to a collection, then enumerate over the collection adding shadows
  4. recursively add the shadows (this isn't going to hit performance nearly as hard as you're thinking, adding the shadows hurts performance more than doing this recursively)

You are correct in that the button is a view on the stack view, so your for loop doesn't hit the button directly to add a shadow to it.

The easiest way to solve this is by far the recursive way, or something like this:

func addShadowsTo(subviews: [UIView]) {
    for subview in subviews {
        if subview.isKind(of: UIButton.self) && subview.tag == 1 {
            addShadow(to: subview)
        }

        if let stackView = subview as? UIStackView {
            addShadowToSubviews(subviews: stackView.subviews)
        }
    }
}

func viewDidload() {
    super.viewDidLoad()

    addShadowsTo(subviews: view.subviews)
}

If you want some instructions on how to do any of the other ways, just comment.

ColdLogic
  • 7,206
  • 1
  • 28
  • 46
  • I understand that shadows are a performance hit but they do nicely to hint at what a button is since my early UI Alpha testers didn't realize some of the icons were a button. It's a necessary evil in this case, I'm just not trying to compound it. Thank you for your response, I'll give that a shot. – Bob R. Jan 31 '17 at 16:30
  • Even after the recursion it still wasn't working as the UIView that the button is in doesn't convert to a stackview. Instead, I did like breaking out the loop into a separate method and took your other advice and just made an outlet for the button. – Bob R. Jan 31 '17 at 16:48
  • Oh, you have your button in a view inside of a stack view? Yea, the above code wouldnt work for that. – ColdLogic Jan 31 '17 at 20:57
  • Could change the stackView check to be something like `let subviewsSubviews = subview.subviews; if subviewsSubviews.count > 0 {` – ColdLogic Jan 31 '17 at 21:03