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
You can subclass UISegmentedControl
, and then override setSelectedSegmentIndex:
- (void) setSelectedSegmentIndex:(NSInteger)toValue {
if (self.selectedSegmentIndex == toValue) {
[super setSelectedSegmentIndex:UISegmentedControlNoSegment];
} else {
[super setSelectedSegmentIndex:toValue];
}
}
If using IB, make sure you set the class of your UISegmentedControl
to your subclass.
Now you can listen for the same UIControlEventValueChanged
as you would normally, except if the user deselected the segment, you will see a selectedSegmentIndex
equal to UISegmentedControlNoSegment
:
-(IBAction) valueChanged: (id) sender {
UISegmentedControl *segmentedControl = (UISegmentedControl*) sender;
switch ([segmentedControl selectedSegmentIndex]) {
case 0:
// do something
break;
case 1:
// do something
break;
case UISegmentedControlNoSegment:
// do something
break;
default:
NSLog(@"No option for: %d", [segmentedControl selectedSegmentIndex]);
}
}
On iOS8 every answer here seem to either not work or trigger change twice. I came up with very simple solution - so I'd like to share it.
In subclass I only have:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self setSelectedSegmentIndex:UISegmentedControlNoSegment];
}
What it does is to reset selected segment to -1 before changing segmented control segment. It will happen in touchesEnded method.
This was a pretty old question so I thought I'd add the rather simple solution I used when I ran into this in an iOS 5+ app.
All I did was drag a Tap Gesture Recognizer onto the UISegmentedControl in my .xib file. Check the connections for your new gesture recognizer to make sure the segmented control is the only gestureRecognizer outlet and then just wire up it's action to the method you want to fire in your controller.
This method should fire any time you touch the segmented control, so just check the selected index with perhaps an instance variable to see if the user touched the already selected segment.
@implementation MyViewController
@synthesize selectedSegment;
@synthesize segmentedControl;
// connected to Tap Gesture Recognizer's action
- (IBAction)segmentedControlTouched:(id)sender
{
NSLog(@"Segmented Control Touched");
if (selectedSegment == [segmentedControl selectedSegmentIndex]) {
// Do some cool stuff
}
selectedSegment = [segmentedControl selectedSegmentIndex];
}
@end
The first idea I had was wire up the Touch Up Inside
or Touch Down
actions to your sort method, but this doesn't seem to work.
The second idea is more of a work around, set the Momentary
property on the segmented control. This will then fire a Value Did Change
action every time it is tapped.
Wanted this myself. Took Julian's solution (thanks!) and modified slightly.
The following UISegmentedControl subclass simply triggers the UIControlEventValueChanged
event even when the value didn't change, which obviously reads a bit weird, but works fine in my case and keeps things simple.
AKSegmentedControl.h
#import <UIKit/UIKit.h>
@interface AKSegmentedControl : UISegmentedControl {
}
@end
AKSegmentedControl.m
#import "AKSegmentedControl.h"
@implementation AKSegmentedControl
- (void)setSelectedSegmentIndex:(NSInteger)toValue {
// Trigger UIControlEventValueChanged even when re-tapping the selected segment.
if (toValue==self.selectedSegmentIndex) {
[self sendActionsForControlEvents:UIControlEventValueChanged];
}
[super setSelectedSegmentIndex:toValue];
}
@end
I think it is even a little better if you use -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
---as this is the behaviour of UISegmentedControl. Further, it seems you don't need to overload the -(void)setSelectedSegmentIndex:(NSInteger)toValue
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSInteger current = self.selectedSegmentIndex;
[super touchesBegan:touches withEvent:event];
if (current == self.selectedSegmentIndex)
[self sendActionsForControlEvents:UIControlEventValueChanged];
}