Reputation: 6903
In my ViewController
, I have 12 custom UIViews
(named CardView).
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-
How can I get my CardViews programmatically. Any help would be appreciated.
Upvotes: 2
Views: 3087
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
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
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
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
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