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