We have for example segmented control, and array of buttons. If we select one of button in one segment - button need to save state, and than we move to another segment and choose another button. but if we back to previous button - it should be in the position we chose earlier. that is, each of the segments must store the state of the buttons. how to do it better?
struct SegmentsModel {
let title: String
var answered: Bool
var buttonIndex: Int? = nil
}
@objc private func buttonsTapped(_ sender: UIButton) {
let _ = buttons.map({$0.isSelected = false})
sender.isSelected = true
guard let index = buttons.firstIndex(of: sender) else { return }
switch index {
case 0:
selectedSegment(segmentedControl, buttonSelected: true, indexButton: 0)
case 1:
selectedSegment(segmentedControl, buttonSelected: true, indexButton: 1)
case 2:
selectedSegment(segmentedControl, buttonSelected: true, indexButton: 2)
case 3:
selectedSegment(segmentedControl, buttonSelected: true, indexButton: 3)
default:
break
}
}
@objc private func selectedSegment(_ sender: UISegmentedControl,
buttonSelected: Bool, indexButton: Int) {
let currentIndex = sender.selectedSegmentIndex
if buttonSelected == true {
buttons[indexButton].isSelected = true
} else {
let _ = buttons.map({$0.isSelected = false})
}
switch currentIndex {
case 0:
arrayOfSegments[0].answered = buttonSelected
arrayOfSegments[0].buttonIndex = indexButton
case 1:
arrayOfSegments[1].answered = buttonSelected
arrayOfSegments[1].buttonIndex = indexButton
case 2:
arrayOfSegments[2].answered = buttonSelected
arrayOfSegments[2].buttonIndex = indexButton
default:
break
}
}
As I mentioned in my comments, there are many ways to achieve what you want. I will share one idea with you.
I see that you tried to store all your buttons in an array and had to keep looping over them to figure out which button was selected previously. Since you want the code to have simpler logic, I will give you a different idea.
One way to achieve what you want is using tags. Every UIView object has a tag and the default is set to 0.
Using storyboard I set the tag of the buttons to 100, 101, 102, 103 and this can be done programmatically also.
You can choose any integers that you like but it is important to give them some unique numbers so when you try to get a view by tag, you get only the view you want.
So after setting the tags, this is what I updated in the code.
struct SegmentsModel {
let title: String
var answered = false
var buttonIndex: Int? = nil
{
// Auto-update the value of answered when value of buttonIndex changes
didSet
{
answered = buttonIndex != nil
}
}
}
I did not do any major updates here. I only added a property observer so when the button index gets set, the answered variable also is auto set so you don't have to anything more for this
Next, below is all the logic to manage the segments and the buttons. I used UIViewController with a StoryBoard so you might need to ignore somethings. All the important code has comments so you can follow along.
class ViewController: UIViewController {
// I will store the results in this array
var storedResults: [SegmentsModel] = []
// Segment control outlet
@IBOutlet weak var segmentControl: UISegmentedControl!
// Array of buttons
@IBOutlet var buttons: [UIButton]!
override func viewDidLoad() {
super.viewDidLoad()
// Loop over all segments
for index in 0 ..< segmentControl.numberOfSegments
{
// Initialize and store default results values in storedResults array
if let segmentTile = segmentControl.titleForSegment(at: index)
{
storedResults.append(SegmentsModel(title: segmentTile))
}
}
}
// Segment action
@IBAction func selectedSegment(_ sender: UISegmentedControl)
{
// Update the UI of buttons
reloadButtons()
}
@IBAction func buttonTapped(_ sender: UIButton)
{
// Reset your buttons
let _ = buttons.map({$0.isSelected = false})
// Set the current button to selected
sender.isSelected = true
// Get the current result so we can update it
var currentResult = storedResults[segmentControl.selectedSegmentIndex]
// Update the current segments selected button index using tag
currentResult.buttonIndex = sender.tag
// Put the result back into the array as structs as value types
storedResults[segmentControl.selectedSegmentIndex] = currentResult
}
// Reload button data
private func reloadButtons()
{
// Reset your buttons
let _ = buttons.map({$0.isSelected = false})
let currentResult = storedResults[segmentControl.selectedSegmentIndex]
// Check if current index has a selected button and if it does retrieve it
// with a tag
if let selectedButtonIndex = currentResult.buttonIndex,
let selectedButton = view.viewWithTag(selectedButtonIndex) as? UIButton
{
// Show the selected button in the UI
selectedButton.isSelected = true
}
}
}
The end result achieved can be seen in this youtube video which I believe is what you wanted.