我有一个分段控件,用户可以使用它来选择如何对列表进行排序。工作得很好。
但是,当已经选择的片段被点击时,我希望排序被反转。 我已经将所有代码放在了正确的位置,但我不知道如何注册那些片段的点击事件。似乎你可以使用的唯一控制事件是UIControlEventValueChanged,但这并没有起作用(因为所选的片段实际上没有改变)。
是否有解决方案?如果有,是什么呢?
谢谢!
我有一个分段控件,用户可以使用它来选择如何对列表进行排序。工作得很好。
但是,当已经选择的片段被点击时,我希望排序被反转。 我已经将所有代码放在了正确的位置,但我不知道如何注册那些片段的点击事件。似乎你可以使用的唯一控制事件是UIControlEventValueChanged,但这并没有起作用(因为所选的片段实际上没有改变)。
是否有解决方案?如果有,是什么呢?
谢谢!
你可以创建 UISegmentedControl
的子类,然后 override setSelectedSegmentIndex:
- (void) setSelectedSegmentIndex:(NSInteger)toValue {
if (self.selectedSegmentIndex == toValue) {
[super setSelectedSegmentIndex:UISegmentedControlNoSegment];
} else {
[super setSelectedSegmentIndex:toValue];
}
}
如果使用IB,请确保将您的UISegmentedControl
类设置为您的子类。
现在,您可以像通常一样监听相同的UIControlEventValueChanged
,除非用户取消选择了该段,否则您会看到一个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];
}
if
语句的开头添加 [self setSelectedSegmentIndex:UISegmentedControlNoSegment];
(在我看来,这个 if
语句应该使用花括号)。 - Warpspace我本来也想要这个功能。采用了Julian的解决方案(谢谢!)并进行了一些修改。
下面是一个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];
}
[super touchesBegan:touches withEvent:event]
?在super版本中会发生什么? - ladookie- (IBAction)addSSslotSelectorChange:(id)sender { if(slotSelector.selectedSegmentIndex == [scratch_format.slot intValue]) { slotSelector.selectedSegmentIndex = -1; } scratch_format.slot = [NSNumber numberWithInt:slotSelector.selectedSegmentIndex]; NSLog(@"Slot changed to: %i",slotSelector.selectedSegmentIndex); }
- CommaToast目前提供的解决方案仍然无效,因为除非真的点击了新段,否则不会调用 setSelectedSegmentIndex。至少在我的情况下从未起作用,我使用的是 iOS5,也许这个解决方案在 iOS4 上有效。无论如何,这是我的解决方案。
它需要一个额外的子类方法,如下所示:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setSelectedSegmentIndex:self.selectedSegmentIndex];
[super touchesEnded:touches withEvent:event];
}
祝你好运!
[self setSelectedSegmentIndex:self.selectedSegmentIndex];
是不必要的。[super ...]调用使得该行代码变得多余。 - TyR这是一个相当老的问题,所以我想添加一个非常简单的解决方案,当我在 iOS 5+ 应用程序中遇到此问题时使用了它。
我只是将一个 Tap Gesture Recognizer 拖到我的 .xib 文件中的 UISegmentedControl 上。检查您的新手势识别器的连接,确保分段控件是唯一的 gestureRecognizer outlet,然后将其操作连接到您希望在控制器中触发的方法即可。
这种方法应该在任何时候都会触发,因此只需使用实例变量检查所选索引,以查看用户是否触摸了已经选择的分段。
@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 {
[super touchesBegan:touches withEvent:event];
[self setSelectedSegmentIndex:UISegmentedControlNoSegment];
}
Swift 5
class ReselectableSegmentedControl: UISegmentedControl {
// Captures existing selected segment on touchesBegan.
var oldValue: Int!
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.oldValue = self.selectedSegmentIndex
super.touchesBegan(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
if self.oldValue == self.selectedSegmentIndex {
self.sendActions(for: .valueChanged)
}
}
}
来源于这里
- (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];
}
}
// 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")
}
}
}
解决方案 2:
另一种方法是重写 UISegmentedControl
中的触摸功能,即使段索引没有改变也可以触发 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")
}
}
}
解决方案3: 如果您希望所选的部分是一个切换按钮,那么可以将解决方案2更改为以下代码以使其更加简洁:
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)")
}
}
segmentedValues
是什么? - JonnymySegmentedControl
,那么解决方案1对我不起作用。 - JonnysegmentedValues
实际上应该是 mySegmentedControl
- 我已经修复了,感谢提示。 - hhamm