移动分段控件时保存按钮状态

Save button states when we move segmented control

例如,我们有分段控件和按钮数组。如果我们 select 一个段中的按钮之一 - 按钮需要保存状态,然后我们移动到另一个段并选择另一个按钮。但如果我们回到上一个按钮——它应该在我们之前选择的位置。 也就是说,每个段都必须存储按钮的状态。 如何做得更好?

struct SegmentsModel {
      let title: String
      var answered: Bool
      var buttonIndex: Int? = nil
}

@objc private func buttonsTapped(_ sender: UIButton) {
        let _ = buttons.map({[=10=].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({[=10=].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
        }
    }
    

正如我在评论中提到的,有很多方法可以实现您想要的。我将与您分享一个想法。

我看到您试图将所有按钮存储在一个数组中,并且不得不不断遍历它们以找出之前选择了哪个按钮。既然你希望代码逻辑更简单,我给你一个不同的思路。

实现您想要的目标的一种方法是使用标签。每个 UIView 对象都有一个标签,默认设置为 0。

我使用故事板将按钮的标签设置为 100、101、102、103,这也可以通过编程方式完成。

您可以选择任何您喜欢的整数,但重要的是要给它们一些唯一的数字,这样当您尝试通过标签获取视图时,您只会得到您想要的视图。

所以在设置标签后,这是我在代码中更新的。

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
        }
    }
}

我没有在这里做任何重大更新。我只添加了一个 属性 观察器,所以当设置按钮索引时,回答的变量也是自动设置的,所以你不需要为此做任何其他事情

接下来,下面是管理段和按钮的所有逻辑。我将 UIViewController 与 StoryBoard 一起使用,因此您可能需要忽略某些内容。 所有重要的代码都有注释,因此您可以跟进。

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({[=11=].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({[=11=].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
        }
    }
}

最终的结果可以seen in this youtube video,我相信这就是你想要的。