Natasha
Natasha

Reputation: 6903

Programmatically get the custom UIViews embedded inside UIStackView

In my ViewController, I have 12 custom UIViews(named CardView).

enter image description here

I am trying to iterate through the subviews of the ViewController programmatically to find the custom view(CardView) and do some configuration. Following is my code to count the number of CardViews.

    private func cardCount()->Int{
            var count = 0
            for subview in self.view.subviews{
                if subview is CardView{
                    count = count + 1
                }
            }
            return count
    }

However, it is returning me '0' and the reason being my views are embedded inside UIStackViews. I have 3 horizontally aligned stack views inside a vertically aligned one like-

enter image description here

How can I get my CardViews programmatically. Any help would be appreciated.

Upvotes: 2

Views: 3087

Answers (5)

RajeshKumar R
RajeshKumar R

Reputation: 15778

Create an extension method like this. It will count all CardView instances in the view controller.

extension UIView {
    func cardCount() -> Int {
        switch self {
        case let self as CardView:
            return 1
        case let self as UIStackView:
            return self.arrangedSubviews.reduce(0, { $0 + $1.cardCount() })
        default:
            return self.subviews.reduce(0, { $0 + $1.cardCount() })
        }
    }
}

and call this method in viewDidLoad

class ViewControllerd: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        print(self.view.cardCount())
    }
}

Upvotes: 0

Merl
Merl

Reputation: 305

You create IBOutlets to each of the horizontal stack views. Then loop through the subviews in the stackviews.

@IBOutlet weak var StackView1: UIStackView!
@IBOutlet weak var StackView2: UIStackView!
@IBOutlet weak var StackView3: UIStackView!



  for customView in StackView1.arrangedSubviews
  {
     // Do task
  }

Upvotes: 1

Sweeper
Sweeper

Reputation: 273898

You can do a few flat maps to flatten your view structure first, then count them:

private func cardCount()->Int{

    var count = 0
    for subview in self.view.subviews.flatMap { $0.subviews }.flatMap { $0.subviews }{
        if subview is CardView{
            count = count + 1
        }
    }
    return count

}

But I feel like you are doing things the wrong way around. The number of cards sounds like something in your model. You should have a variable called cardCount and the cards on the screen are supposed to change according to that variable, not the other way around.

Upvotes: 2

Nitish
Nitish

Reputation: 14123

From the pictorial diagram you shared, it seems the StackView is the first child. Whenever you get the subviews, only the first child views are returned. So self.view.subviews would result in only one UIStackView. Give a tag to each stack view. Then, in code :

private func cardCount()->Int{
        var count = 0
        for subview in self.view.subviews{
            if subview.tag == 10 {  // parent stack view
                 for subviewStack in subview {  // Get subviews of parent stackview
                      if subviewStack.tag == 11 {  // First stack view child
                          for subViewSubStack in subviewStack.subviews { // Get card views in this stack view
                              // Apply your count logic 
                          }
                      }
                 }

            }
        }
        return count
}  

I have written only the first condition. You might add others.
Having said this, I won't say this is the most optimum solution. This can and should be refactored.

Upvotes: 0

Diptesh
Diptesh

Reputation: 393

Try this

private func cardCount() -> Int
{
    var count = 0
    for subview in self.view.subviews
    {
        if let stackView: UIStackView = subview as? UIStackView
        {
            let arrangedViews = stackView.arrangedSubviews
            for cardView in arrangedViews
            {
                if cardView is CardView
                {
                    count = count + 1
                }
            }

        }
    }
    return count
}

Upvotes: 0

Related Questions