I have a vertical UIStackView and i append a horizontal UIStackView and some UILabels inside this view. I attach the UITapGestureRecognizer to handle the tap actions. How can i change for example the label(which is a subview) when i tap on a row?
Here is my code so far:
for article in articleType {
//Create a row
let row = UIStackView()
row.axis = NSLayoutConstraint.Axis.horizontal
//Create a label and indicator
let label = UILabel()
label.text = article.label
let indicator = UILabel()
indicator.text = "off"
//Add label to row and row to parent stack view
row.addSubView(label)
row.addSubView(indicator)
mainUiStackView.addArrangedSubview(row)
//Create tap handled
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(sender:)))
row.addGestureRecognizer(tap)
}
@objc func handleTap(sender: UITapGestureRecognizer? = nil) {
print(sender.view)
//This is where i'm stuck, how can i change the second label's text to "on" for example?
sender.view.indicator.text = "on"
}
Your code goes through a loop and creates a whole series of stack views in the local variable row
. Then you don't add those stack views to your view hierarchy, so they get "dropped on the floor."
For this line:
let row = UIStackView()
After each pass through your for loop, that stack view you create will go out of scope and be deallocated.
After you pointed it out, I see now where you add your row
stack views to your mainUiStackView
.
I gather based on the comments you've made that you want to have taps on one of your "row" stack views set the indicator
label in that stack view to "on".
I would suggest building an array of your row stack views and their label views (As structs). Then find the row that was tapped and set it's label to the on state:
struct RowStackViewStruct {
let stackView: UIStackView
let label: UILabel
}
var rowStackViews = [RowStackViewStruct]()
for article in articleType {
//Create a row
let row = UIStackView()
row.axis = NSLayoutConstraint.Axis.horizontal
//Create a label and indicator
let label = UILabel()
label.text = article.label
let indicator = UILabel()
indicator.text = "off"
//Add label to row and row to parent stack view
row.addSubView(label)
row.addSubView(indicator)
mainUiStackView.addArrangedSubview(row)
//Create tap handled
let tap = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(sender:)))
row.addGestureRecognizer(tap)
//Build a RowStackViewStruct for this row
let newRowStackViewStruct = RowStackViewStruct(stackView: row,
label: indicator)
rowStackViews.append(newRowStackViewStruct)
}
And then in your tap handler code:
@objc func handleTap(sender: UITapGestureRecognizer? = nil) {
print(sender.view)
if let aStruct = rowStackViews.first(where: { sender?.view == $0.stackView }) {
aStruct.label.text = "on"
}
I banged the above code out in the SO editor. It likely contains minor syntax errors, and is intended as a guide, not copy-paste code that you can drop in.
It seems like you should really keep track of the on-off state of your rows. It seems like you should have an array of model objects that represent the state of your rows, and use that to build and maintain your main vertical stack view. In fact, it might be better to switch to a table view or collection view, since those are made to be driven from a model.