处理同一个分段按钮上的点击?

Handle tap on same segmented button?

我正在尝试处理分段控件上的点击事件,但是当再次单击所选按钮时。例如,对于下面已选择 "Second" 的屏幕截图,再次单击 "Second" 按钮时如何处理该操作?

我尝试了 IBOutlet,但它仅在值更改时触发。然后我尝试了下面的代码,但同样的事情只在值改变时触发。在这两种情况下,当 "Second" 被选中时,再次单击 "Second" 不会触发任何东西。有办法吗?

segmentedControl.addTarget(self, action: "segementedAnyTap:", forControlEvents: .AllEvents)

在您对问题的评论中,您提到您试图允许用户 select 'unread' 显示所有未读消息,然后让他们再次单击以将所有消息标记为未读。我建议不要为此使用段控件,而是添加一个 "Mark all unread" 按钮,该按钮会在 'unread' 段被 selected 时出现。这将完成您尝试添加的功能,同时也让用户清楚他们有办法将所有内容标记为未读。

这对我有用,将手势识别器添加到 UISegmentedControl

- (void)viewDidLoad
{
  [super viewDidLoad];

  [self.segmentedControl addTarget:self action:@selector(valueChanged:) forControlEvents:UIControlEventValueChanged];
  UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(touched:)];
  [self.segmentedControl addGestureRecognizer:tapGesture];
}

- (void)valueChanged:(id)sender
{
  // value change code
}

- (void)touched:(id)sender
{
  // code to check if the segmented controls index has not changed.
  // execute desired functionality
}

您可以将您的应用程序设置为显示来自未读片段的弹出窗口,并带有一个按钮以将所有片段显示为未读。要放置弹出窗口,请使用:

CGRect frame = [segmentControl frame];
frame =CGRectMake((frame.size.width/2*butIndex), 0, frame.size.width/2, segmentControl.bounds.size.height);

[popOver presentPopoverFromRect:frame inView:segmentControl permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

我不太清楚你为什么要实现这个,但我想建议继承 UISegmentedControl 并覆盖 touchesEnded:withEvent:

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

    [self sendActionsForControlEvents:UIControlEventTouchUpInside];
}

现在,您为 UIControlEventTouchUpInside 预定的选择器将在您每次按下每个段时被调用,并且仍然保留 UISegmentedControl 的默认功能。

注意:如果这是段的第一个选择,您需要自己处理(例如,保留先前值的私有 属性)。如果您为 UIControlEventValueChanged 添加选择器,它也会触发 UIControlEventTouchUpInside 的选择器,这可能会导致一些混乱或错误。

祝你好运,希望对你有所帮助。

我认为这可以解决问题:

- (void)viewDidLoad {
    [super viewDidLoad];

    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(touched:)];
    [self.segmentedControl addGestureRecognizer:tapGesture];
}

- (void) valueChanged:(id) sender {
    // Your segment changed selector
}

- (void) touched:(UITapGestureRecognizer *) tapGesture {
    CGPoint point = [tapGesture locationInView:self.segmentedControl];
    NSUInteger segmentSize = self.segmentedControl.bounds.size.width / self.segmentedControl.numberOfSegments;
    // Warning: If you are using segments not equally sized, you have to adapt the code in the next line
    NSUInteger touchedSegment = point.x / segmentSize;
    if (self.segmentedControl.selectedSegmentIndex != touchedSegment) {
        // Normal behaviour the segment changes
        self.segmentedControl.selectedSegmentIndex = touchedSegment;
    } else {
        // Tap on the already selected segment, I'm switching to No segment selected just to show the effect
        self.segmentedControl.selectedSegmentIndex = UISegmentedControlNoSegment;
    }
    // You have to call your selector because the UIControlEventValueChanged can't work together with UITapGestureRecognizer
    [self valueChanged:self.segmentedControl];
}

添加 KVO 观察。

例子:

#pragma mark - 

- (void)viewDidLoad {
    [_segmentControl addObserver:self forKeyPath:@"selectedSegmentIndex" options:NSKeyValueObservingOptionInitial context:nil];
}


#pragma mark - KVO

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"segment index: %ld", (long)_segmentControl.selectedSegmentIndex);
}

结果:

2015-06-22 12:31:54.155 Location test[27082:13176230] segment index: 0
2015-06-22 12:31:54.740 Location test[27082:13176230] segment index: 0
2015-06-22 12:31:55.821 Location test[27082:13176230] segment index: 1
2015-06-22 12:31:56.529 Location test[27082:13176230] segment index: 1

我对具有 3 个选项 ("categories") 的分段控件执行以下操作。 _selectedCategory 是一个 属性 NSInteger,用于跟踪分段控件当前选定的索引。点击时,如果我发现 _selectedCategory 与按下的相同,则他们按下了选定的分段控件,我将其关闭。

 -(IBAction)categorySelected:(id)sender {
        if (_selectedCategory == [sender selectedSegmentIndex]) {
            sender.selectedSegmentIndex = UISegmentedControlNoSegment;
            // update my model, etc...
        } else {
            _selectedCategory = [sender selectedSegmentIndex];
            switch (_selectedCategory) {
                case 0:
                // do logic...
            }
        }
}

我知道有点晚了,但是另一种对我很有效的技术...

在 UISegmentedControl 的每个部分上添加一个背景清晰的 UIButton。每个 UIButton 都可以有自己的 UIControlEventTouchUpInside 事件处理程序——它可以更改 UISegmentedControl 的 selectedSegmentIndex。

然后将 UISegmentedControl.userInteractionEnabled 设置为 NO,并删除其 UIControlEventValueChanged 事件处理程序。

很好的答案@Sgorbyo,这是它的 Swift 3 版本:

override func viewDidLoad() {
    super.viewDidLoad()
    let segmentedTapGesture = UITapGestureRecognizer(target: self, action: #selector(onTapGestureSegment(_:)))
    segmentedControl.addGestureRecognizer(segmentedTapGesture)
}

@IBAction func onTapGestureSegment(_ tapGesture: UITapGestureRecognizer) {
    let point = tapGesture.location(in: segmentedControl)
    let segmentSize = tipSegmentedControl.bounds.size.width / CGFloat(segmentedControl.numberOfSegments)
    let touchedSegment = Int(point.x / segmentSize)

    if segmentedControl.selectedSegmentIndex != touchedSegment {
        // Normal behaviour the segment changes
        segmentedControl.selectedSegmentIndex = touchedSegment
    } else {
        // Tap on the already selected segment
        segmentedControl.selectedSegmentIndex = touchedSegment
    }
    onSegment(segmentedControl)
}

@IBAction func onSegment(_ sender: Any) {
// Your segment changed selector
}

我遇到一个情况,在选择之前我需要段索引,我不希望 .valueChanged 事件停止触发,所以我想出了这个。

UISegmentedControl 创建子类并覆盖 touchesEnded

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    // Previous selected segment index
    let oldIdx = selectedSegmentIndex

    super.touchesEnded(touches, with: event)

    // New selected segment index
    let newIdx = selectedSegmentIndex

    // If the previously selected segment index is equal to the new one, 
    // then you are tapping on the same segment button.
    // Call a block, delegate method or whatever to notify this
}