UISegmentedControl注册在选定的段上点击

我有一个分段的控制,用户可以select如何订购一个列表。 工作正常。

不过,我希望当一个已经选定的细分被点击时,顺序会颠倒过来。 我有所有的代码,但我不知道如何注册这些细分市场上的水龙头。 看来唯一的控制事件是你可以使用的是UIControlEventValueChanged,但这是行不通的(因为选定的部分实际上并没有改变)。

有这个解决scheme吗? 如果是这样,那是什么?

提前致谢!

您可以inheritanceUISegmentedControl,然后重写setSelectedSegmentIndex:

- (void) setSelectedSegmentIndex:(NSInteger)toValue { if (self.selectedSegmentIndex == toValue) { [super setSelectedSegmentIndex:UISegmentedControlNoSegment]; } else { [super setSelectedSegmentIndex:toValue]; } } 

如果使用IB,请确保将您的UISegmentedControl的类设置为您的子类。

现在,您可以像通常一样监听相同的UIControlEventValueChanged,除非用户取消select该段,否则将看到selectedSegmentIndex等于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]); }} 

如果你使用-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event我认为它会更好一些,因为这是UISegmentedControl的行为。 此外,似乎你不需要重载-(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]; } 

希望这个自己。 采取朱利安的解决scheme(谢谢!),稍作修改。

下面的UISegmentedControl子类只是触发UIControlEventValueChanged事件,即使值没有改变,显然有点奇怪,但在我的情况下工作正常,并保持简单。

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 

这适用于iOS 4和5:

 -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { int oldValue = self.selectedSegmentIndex; [super touchesBegan:touches withEvent:event]; if ( oldValue == self.selectedSegmentIndex ) [self sendActionsForControlEvents:UIControlEventValueChanged]; } 

目前提出的解决scheme仍然无法正常工作,因为除非真的有一个新的段被点击,setSelectedSegmentIndex永远不会被调用。 至less在我的情况下,这从来没有工作,我尽pipe使用iOS5,也许这个解决scheme在iOS4中工作。 无论如何,这是我的解决scheme。 它需要一个额外的子类方法,如下所示:

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

祝你好运!

这是一个相当古老的问题,所以我想我会添加一个相当简单的解决scheme,当我在iOS 5 +应用程序中遇到这个问题时。

我所做的只是将一个Tap Gesture识别器拖到我的.xib文件中的UISegmentedControl上。 检查新手势识别器的连接,确保分段控件是唯一的手势识别器sockets,然后将其动作连接到要在控制器中触发的方法。

这个方法应该在你触摸分段控件的时候触发,所以只需要用一个实例variables来检查select的索引,看看用户是否触摸到了已经select的段。

 @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 

这工作:

 - (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]; } } 

在iOS8上,每个答案似乎都不起作用或触发更改两次。 我想出了一个非常简单的解决scheme – 所以我想分享一下。

在子类中,我只有:

 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; [self setSelectedSegmentIndex:UISegmentedControlNoSegment]; } 

在改变分段的控制段之前,将所选段重置为-1。 它会在touchesEnded方法中发生。

这是我的解决scheme。 我觉得如果你想让ValueChanged事件触发每一个触摸最优雅的…

。H

 @interface UISegmentedControlAllChanges : UISegmentedControl @end 

.M

 @implementation UISegmentedControlAllChanges -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self sendActionsForControlEvents:UIControlEventValueChanged]; [super touchesEnded:touches withEvent:event]; } @end 

Swift 3中,我可以想象至less有两个解决scheme如下。 对于特殊情况,我还发布了第三个解决scheme,其中所选段作为切换button。

解决scheme1:

提示:此解决scheme仅适用于瞬时控制部分! 如果您需要静态控件的解决scheme,请select解决scheme2

这个想法是注册第二个事件,触发在里面:

 // this solution works only for momentary segment control: class Solution1ViewController : UIViewController { var current:Int = UISegmentedControlNoSegment @IBOutlet weak var mySegmentedControl: UISegmentedControl! { didSet { guard mySegmentedControl != nil else { return } self.mySegmentedControl!.addTarget( self, action:#selector(changeSelection(sender:)), for: .valueChanged) self.mySegmentedControl!.addTarget( self, action:#selector(changeSelection(sender:)), for: .touchUpInside) } } func changeSelection(sender: UISegmentedControl) { if current == sender.selectedSegmentIndex { // user hit the same button again! print("user hit the same button again!") } else { current = sender.selectedSegmentIndex // user selected a new index print("user selected a new index") } } } 

解决scheme2:另一种方法是覆盖UISegmentedControl的触摸function,并且即使段索引没有改变也触发valueChanged 。 因此,您可以重写UISegmentedControl ,如下所示:

 // override UISegmentControl to fire event on second hit: class Solution2SegmentControl : UISegmentedControl { private var current:Int = UISegmentedControlNoSegment override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { current = self.selectedSegmentIndex super.touchesBegan(touches, with: event) } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesEnded(touches, with: event) if current == self.selectedSegmentIndex { self.sendActions(for: .valueChanged) } } } // solution2 works with stationary (default) segment controls class Solution2ViewController : UIViewController { var current:Int = UISegmentedControlNoSegment @IBOutlet weak var mySegmentedControl: UISegmentedControl! { didSet { guard mySegmentedControl != nil else { return } self.mySegmentedControl!.addTarget( self, action:#selector(changeSelection(sender:)), for: .valueChanged) } } func changeSelection(sender: UISegmentedControl) { if current == sender.selectedSegmentIndex { // user hit the same button again! print("user hit the same button again!") } else { current = sender.selectedSegmentIndex // user selected a new index print("user selected a new index") } } } 

解决scheme3:如果您的方法是将选定的段设置为切换button,则可以更改解决scheme2来清理代码,如下所示:

 class MyToggleSegmentControl : UISegmentedControl { /// you could enable or disable the toggle behaviour here var shouldToggle:Bool = true private var current:Int = UISegmentedControlNoSegment override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { current = self.selectedSegmentIndex super.touchesBegan(touches, with: event) } override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesEnded(touches, with: event) if shouldToggle, current == self.selectedSegmentIndex { self.selectedSegmentIndex = UISegmentedControlNoSegment } } } 

现在我们可以清理changeSelection函数,如下所示:

 func changeSelection(sender: UISegmentedControl) { switch sender.selectedSegmentIndex { case UISegmentedControlNoSegment: print("none") default: print("selected: \(sender.selectedSegmentIndex)") } } 

我的第一个想法是将Touch Up InsideTouch Down操作连接到sorting方法,但这似乎不起作用。

第二个想法是更多的工作,在分段控制上设置Momentary属性。 这会在每次点击时触发一个Value Did Change操作。

大帮忙! 我想要做的是可以select设置一个button或不设置button – 当设置一个button时,第二个button将会取消它。 这是我的修改:

 - (void)setSelectedSegmentIndex:(NSInteger)toValue { // Trigger UIControlEventValueChanged even when re-tapping the selected segment. if (toValue==self.selectedSegmentIndex) { [super setSelectedSegmentIndex:UISegmentedControlNoSegment]; // notify first [self sendActionsForControlEvents:UIControlEventValueChanged]; // then unset } else { [super setSelectedSegmentIndex:toValue]; } } 

首先通知让您在重置之前阅读控件以查找当前设置。

基于鲍勃·德·格拉夫的回答:

 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self sendActionsForControlEvents:UIControlEventAllTouchEvents]; [super touchesEnded:touches withEvent:event]; } 

请注意使用UIControlEventAllTouchEvents而不是UIControlEventValueChanged

也没有必要调用-(void)setSelectedSegmentIndex:

在为我工作的那段代码之下。 重复点击相同的细分将取消select它。

 @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 

iOS 9解决scheme。 用这样的类覆盖UISegmentedControl:

 @interface SegmentedControl() @property (nonatomic) NSInteger previousCurrent; @end @implementation SegmentedControl - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { self.previousCurrent = self.selectedSegmentIndex; [super touchesBegan:touches withEvent:event]; } - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; if (self.selectedSegmentIndex == self.previousCurrent) { [self sendActionsForControlEvents:UIControlEventValueChanged]; } self.previousCurrent = NSNotFound; } @end 

我正在使用KVO来为iOS8反转已select的段。

 #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 

从目前的iOS v8.x中select的答案的解决scheme不适用于我。 但@Andy提供了一个解决scheme,我将完成:

子类UISegmentedControl ,并覆盖子类中的touchesEnded方法:

 -(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [self sendActionsForControlEvents:UIControlEventAllTouchEvents]; [super touchesEnded:touches withEvent:event]; } 

在您打算使用UISegmentedControl的类中,创build一个iVar currentSelectedSegIndex。 在UIControlEventValueChanged操作方法旁边添加UIControlEventAllTouchEvents:

 NSInteger currentSelectedSegIndex; [aSegmentedController addTarget:self action:@selector(aSegmentedControllerSelection:) forControlEvents:UIControlEventValueChanged]; [aSegmentedController addTarget:self action:@selector(aSegmentedControllerAllTouchEvent:) forControlEvents:UIControlEventAllTouchEvents]; 

实施两个行动方法:

 -(void)aSegmentedControllerAllTouchEvent:(MyUISegmentedControl *)seg { seg.selectedSegmentIndex = UISegmentedControlNoSegment; } -(void)aSegmentedControllerSelection:(MyUISegmentedControl *)seg { if (currentSelectedSegIndex == seg.selectedSegmentIndex) { seg.selectedSegmentIndex = UISegmentedControlNoSegment; currentSelectedSegIndex = NSIntegerMax; NSLog(@"%s Deselected.", __PRETTY_FUNCTION__); // do your stuff if deselected return; } NSLog(@"%s Selected index:%u", __PRETTY_FUNCTION__, seg.selectedSegmentIndex); currentSelectedSegIndex = seg.selectedSegmentIndex; //do your stuff if selected index }