UISegmentedControl register taps on selected segment

后端 未结 20 2877
渐次进展
渐次进展 2020-12-04 15:28

I have a segmented control where the user can select how to order a list. Works fine.

However, I would like that when an already selected segment is tapped, the orde

相关标签:
20条回答
  • 2020-12-04 16:06

    Here is my solution. The most elegant I think if you want the ValueChanged event to fire on every touches...

    .h

    @interface UISegmentedControlAllChanges : UISegmentedControl
    @end
    

    .m

    @implementation UISegmentedControlAllChanges
    
    -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {    
        [self sendActionsForControlEvents:UIControlEventValueChanged];
        [super touchesEnded:touches withEvent:event];
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-04 16:08

    In Swift 3 I could imagine at least 2 solutions as follows. For a special case I posted also a third solution, where the selected segment works as toggle button.

    Solution 1:

    Hint: This solution only works on momentary controlSegments! If you need a solution for stationary controls, choose Solution 2

    The idea is to register a second event that fires up on touch-up-inside:

    // this solution works only for momentary segment control:
    class Solution1ViewController : UIViewController {
        var current:Int = UISegmentedControlNoSegment
        @IBOutlet weak var mySegmentedControl: UISegmentedControl! {
            didSet {
                guard mySegmentedControl != nil else { return }
    
                self.mySegmentedControl!.addTarget(
                    self,
                    action:#selector(changeSelection(sender:)),
                    for: .valueChanged)
    
                self.mySegmentedControl!.addTarget(
                    self,
                    action:#selector(changeSelection(sender:)),
                    for: .touchUpInside)
            }
        }
    
        func changeSelection(sender: UISegmentedControl) {
            if current == sender.selectedSegmentIndex {
                // user hit the same button again!
                print("user hit the same button again!")
            }
            else {
                current = sender.selectedSegmentIndex
                // user selected a new index
                 print("user selected a new index")
            }
        }
    }
    

    Solution 2: The other way is to override the touch functions in UISegmentedControl and to fire the valueChanged even if the segment index has not changed. Therefore you could override the UISegmentedControl as follows:

    // override UISegmentControl to fire event on second hit:
    class Solution2SegmentControl : UISegmentedControl
    {
        private var current:Int = UISegmentedControlNoSegment
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            current = self.selectedSegmentIndex
            super.touchesBegan(touches, with: event)
        }
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesEnded(touches, with: event)
            if current == self.selectedSegmentIndex {
                self.sendActions(for: .valueChanged)
            }
        }
    }
    
    // solution2 works with stationary (default) segment controls
    class Solution2ViewController : UIViewController {
        var current:Int = UISegmentedControlNoSegment
    
        @IBOutlet weak var mySegmentedControl: UISegmentedControl! {
            didSet {
                guard mySegmentedControl != nil else { return }
    
                self.mySegmentedControl!.addTarget(
                    self,
                    action:#selector(changeSelection(sender:)),
                    for: .valueChanged)
            }
        }
    
        func changeSelection(sender: UISegmentedControl) {
            if current == sender.selectedSegmentIndex {
                // user hit the same button again!
                print("user hit the same button again!")
            }
            else {
                current = sender.selectedSegmentIndex
                // user selected a new index
                print("user selected a new index")
            }
        }
    }
    

    Solution 3: If your approach was to have the selected segment be a toggle button than Solution 2 could be changed to clean up the code like this:

    class MyToggleSegmentControl : UISegmentedControl {
        /// you could enable or disable the toggle behaviour here
        var shouldToggle:Bool = true
    
        private var current:Int = UISegmentedControlNoSegment
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            current = self.selectedSegmentIndex
            super.touchesBegan(touches, with: event)
        }
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesEnded(touches, with: event)
            if shouldToggle, current == self.selectedSegmentIndex {
                self.selectedSegmentIndex = UISegmentedControlNoSegment
            }
        }
    }
    

    Now we could clean up the changeSelection function as follows:

    func changeSelection(sender: UISegmentedControl) {
        switch sender.selectedSegmentIndex {
        case UISegmentedControlNoSegment:
            print("none")
        default:
            print("selected: \(sender.selectedSegmentIndex)")
        }
    }
    
    0 讨论(0)
提交回复
热议问题