UISegmentedControl register taps on selected segment

后端 未结 20 2875
渐次进展
渐次进展 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 15:43

    Because the UISegmentedControl is in charge of setting the segment, it should only reset the state. I modify a little the suggestions of other guys for swift 5:

    //MARK: Custom segmentedControl
    ///  Every element works like a flipflop  [see](http://stackoverflow.com/questions/17652773/how-to-deselect-a-segment-in-segmented-control-button-permanently-till-its-click)
    @IBDesignable class GRSegmentedControl: UISegmentedControl {
      private let url = Bundle.main.url(forResource: "PlopChoiceCntrl", withExtension: "aiff")!
      private var soundID:SystemSoundID = 0
    
      override init(items: [Any]?) {
        AudioServicesCreateSystemSoundID(url as CFURL, &soundID)
        super.init(items: items)
      }
    
      required init?(coder: NSCoder) {
        AudioServicesCreateSystemSoundID(url as CFURL, &soundID)
        super.init(coder: coder)
      }
    
      override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        AudioServicesPlaySystemSound(soundID)
        let previousSelectedSegmentIndex = self.selectedSegmentIndex
        super.touchesEnded(touches, with: event)
        if previousSelectedSegmentIndex == self.selectedSegmentIndex {
          if let touch = touches.first{
            let touchLocation = touch.location(in: self)
            if bounds.contains(touchLocation) {
              self.selectedSegmentIndex = UISegmentedControl.noSegment
            }
          }
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-04 15:45

    This works:

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        int oldValue = self.selectedSegmentIndex;
        [super touchesBegan:touches withEvent:event];
        if (oldValue == self.selectedSegmentIndex)
        {
            [super setSelectedSegmentIndex:UISegmentedControlNoSegment];
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
    
    0 讨论(0)
  • 2020-12-04 15:48

    Below the piece of code that did work for me. Repeated tap on the same segment will deselect it.

    @implementation WUUnselectableSegmentedControl
    {
        NSUInteger _selectedIndexBeforeTouches;
    }
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
    {
        _selectedIndexBeforeTouches = self.selectedSegmentIndex;
        [super touchesBegan:touches withEvent:event];
    }
    
    -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
        [super touchesEnded:touches withEvent:event];
    
        if (_selectedIndexBeforeTouches == self.selectedSegmentIndex)
        {
            // Selection didn't change after touch - deselect
            self.selectedSegmentIndex = UISegmentedControlNoSegment;
            [self sendActionsForControlEvents:UIControlEventValueChanged];
        }
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-04 15:50

    The current solution presented still does not work, because setSelectedSegmentIndex is never called unless really a new segment is tapped. At least in my case this never worked, I do use iOS5 though, perhaps this solution did work in iOS4. Anyway, this is my solution. It needs one extra subclass method, which is the following:

    -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {    
        [self setSelectedSegmentIndex:self.selectedSegmentIndex];
        [super touchesEnded:touches withEvent:event];
    }
    

    Good luck!

    0 讨论(0)
  • 2020-12-04 15:50

    Swift 5

    class ReselectableSegmentedControl: UISegmentedControl {
        // Captures existing selected segment on touchesBegan.
        var oldValue: Int!
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
            self.oldValue = self.selectedSegmentIndex
            super.touchesBegan(touches, with: event)
        }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            super.touchesEnded(touches, with: event)
    
            if self.oldValue == self.selectedSegmentIndex {
                self.sendActions(for: .valueChanged)
            }
        }
    }
    

    From here

    0 讨论(0)
  • 2020-12-04 15:50

    I'm using KVO to invert already selected segment for iOS8.

    #import "QCSegmentedControl.h"
    
    static void *QCSegmentedControlContext = &QCSegmentedControlContext;
    
    @implementation QCSegmentedControl
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self registerKVO];
        }
    
        return self;
    }
    
    - (void)dealloc {
        [self removeObserver:self forKeyPath:@"selectedSegmentIndex"];
    }
    
    #pragma mark -
    
    - (void)registerKVO {
        [self addObserver:self
               forKeyPath:@"selectedSegmentIndex"
                  options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
                  context:QCSegmentedControlContext];
    }
    
    - (void)observeValueForKeyPath:(NSString *)keyPath
                          ofObject:(id)object
                            change:(NSDictionary *)change
                           context:(void *)context {
        if (context == QCSegmentedControlContext) {
            NSNumber *new = change[NSKeyValueChangeNewKey];
            NSNumber *old = change[NSKeyValueChangeOldKey];
            if (new.integerValue == old.integerValue) {
                self.selectedSegmentIndex = UISegmentedControlNoSegment;
            }
        }
    }
    
    @end
    
    0 讨论(0)
提交回复
热议问题