ios - How to deselect a segment in Segmented control button permanently till its clicked again -


i have uisegmentedcontrol 4 segments. when selected, should maintain selected state. when same segment clicked again, should deselect itself. how achieve this?

since uisegmentedcontrol sends action if not selected segment selected, have subclass uisegmentedcontrol make tiny change in touch handling. use class:

@implementation mbsegmentedcontrol  // sends value changed event if reselect selected segment - (void)touchesbegan:(nsset *)touches withevent:(uievent *)event {     nsinteger current = self.selectedsegmentindex;     [super touchesbegan:touches withevent:event];     if (current == self.selectedsegmentindex) {         [self sendactionsforcontrolevents:uicontroleventvaluechanged];     } }  @end 

now uicontroleventvaluechanged events if segment selected. save current index in variable , compare in action. if 2 indexes match have unselect touched segment.

// _selectedsegmentindex instance variable of view controller  - (void)viewwillappear:(bool)animated {     [super viewwillappear:animated];     _selectedsegmentindex = self.segment.selectedsegmentindex; }  - (ibaction)segmentchanged:(uisegmentedcontrol *)sender {     if (sender.selectedsegmentindex == _selectedsegmentindex) {         nslog(@"segment %d deselected", sender.selectedsegmentindex);         sender.selectedsegmentindex =  uisegmentedcontrolnosegment;         _selectedsegmentindex = uisegmentedcontrolnosegment;     }     else {         nslog(@"segment %d selected", sender.selectedsegmentindex);         _selectedsegmentindex = sender.selectedsegmentindex;     } } 

ios 7 changed how touches handled uisegmentedcontrol. selectedsegmentindex changed during touchesended:.

so updated subclass should this:

@implementation mbsegmentedcontrol  + (bool)isios7 {     static bool isios7 = no;     static dispatch_once_t oncetoken;     dispatch_once(&oncetoken, ^{         nsinteger devicesystemmajorversion = [[[[[uidevice currentdevice] systemversion] componentsseparatedbystring:@"."] objectatindex:0] integervalue];         if (devicesystemmajorversion >= 7) {             isios7 = yes;         }         else {             isios7 = no;         }     });     return isios7; }  - (void)touchesbegan:(nsset *)touches withevent:(uievent *)event {     nsinteger previousselectedsegmentindex = self.selectedsegmentindex;     [super touchesbegan:touches withevent:event];     if (![[self class] isios7]) {         // before ios7 segment selected in touchesbegan         if (previousselectedsegmentindex == self.selectedsegmentindex) {             // if selectedsegmentindex before selection process equal selectedsegmentindex             // after selection process superclass won't send uicontroleventvaluechanged event.             // have ourselves.             [self sendactionsforcontrolevents:uicontroleventvaluechanged];         }     } }  - (void)touchesended:(nsset *)touches withevent:(uievent *)event {     nsinteger previousselectedsegmentindex = self.selectedsegmentindex;     [super touchesended:touches withevent:event];     if ([[self class] isios7]) {         // on ios7 segment selected in touchesended         if (previousselectedsegmentindex == self.selectedsegmentindex) {             [self sendactionsforcontrolevents:uicontroleventvaluechanged];         }     } }  @end 

swift 2.2 version, fixed problem grzegorz noticed.

class reselectablesegmentedcontrol: uisegmentedcontrol {     @ibinspectable var allowreselection: bool = true      override func touchesended(touches: set<uitouch>, withevent event: uievent?) {         let previousselectedsegmentindex = self.selectedsegmentindex         super.touchesended(touches, withevent: event)         if allowreselection && previousselectedsegmentindex == self.selectedsegmentindex {             if let touch = touches.first {                 let touchlocation = touch.locationinview(self)                 if cgrectcontainspoint(bounds, touchlocation) {                     self.sendactionsforcontrolevents(.valuechanged)                 }             }         }     } } 

swift 3.0 changes fix following:

class mydeselectablesegmentedcontrol: uisegmentedcontrol {     override func touchesended(_ touches: set<uitouch>, event: uievent?) {         let previousindex = selectedsegmentindex          super.touchesended(touches, with: event)          if previousindex == selectedsegmentindex {             let touchlocation = touches.first!.location(in: self)              if bounds.contains(touchlocation) {                 sendactions(for: .valuechanged)             }         }     } } 

Comments