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
Post a Comment