65

ユーザーがリストの並べ替え方法を選択できるセグメント化されたコントロールがあります。正常に動作します。

ただし、すでに選択されているセグメントがタップされると、順序が反転するようにしたいと思います。すべてのコードを配置しましたが、それらのセグメントにタップを登録する方法がわかりません。使用できる唯一のコントロール イベントは UIControlEventValueChanged のようですが、それは機能していません (選択したセグメントが実際には変化していないため)。

これに対する解決策はありますか?もしそうなら、それは何ですか?

前もって感謝します!

4

20 に答える 20

51

サブクラス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]);
    }
}
于 2010-04-02T23:21:02.937 に答える
32

-(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];
}
于 2011-10-16T18:15:39.127 に答える
19

自分はこれが欲しかった。ジュリアンの解決策を取り (ありがとう!)、わずかに変更しました。

次の 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
于 2010-04-06T20:26:34.897 に答える
12

これは 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];
}
于 2011-12-10T21:34:39.830 に答える
11

実際に新しいセグメントがタップされない限り setSelectedSegmentIndex が呼び出されないため、提示されている現在のソリューションはまだ機能しません。少なくとも私の場合、これは機能しませんでしたが、iOS5 を使用していますが、おそらくこのソリューションは iOS4 で機能しました。とにかく、これが私の解決策です。次のような追加のサブクラス メソッドが 1 つ必要です。

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

幸運を!

于 2011-10-14T13:11:16.010 に答える
9

これはかなり古い質問だったので、iOS 5+ アプリでこれに遭遇したときに使用したかなり単純な解決策を追加すると思いました。

.xib ファイルの UISegmentedControl に Tap Gesture Recognizer をドラッグしただけです。新しいジェスチャ認識エンジンの接続を確認して、セグメント化されたコントロールが唯一のgestureRecognizerアウトレットであることを確認してから、コントローラーで起動するメソッドにそのアクションを接続します。

このメソッドは、セグメント化されたコントロールに触れるたびに起動する必要があるため、選択したインデックスをおそらくインスタンス変数でチェックして、ユーザーが既に選択されているセグメントに触れたかどうかを確認してください。

@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
于 2012-05-14T09:04:35.607 に答える
7

iOS8では、ここでのすべての回答が機能しないか、変更が2回トリガーされるようです。非常にシンプルな解決策を思いついたので、共有したいと思います。

サブクラスでは、次のものしかありません。

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

セグメント化されたコントロール セグメントを変更する前に、選択したセグメントを -1 にリセットします。touchesEnded メソッドで発生します。

于 2016-05-05T10:21:03.197 に答える
6

スイフト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)
        }
    }
}

ここから

于 2020-02-17T10:18:16.863 に答える
5

これは機能します:

- (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];
    }
}
于 2011-12-29T20:03:04.733 に答える
1

大きな助け!私がやりたいのは、ボタンを1つ設定するか、設定しないかを選択できるようにすることです。ボタンが設定されている場合は、2回目のタップで設定が解除されます。これは私の変更です:

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

最初に通知すると、コントロールを読み取って、リセットする前に現在の設定を見つけることができます。

于 2010-04-11T15:40:54.197 に答える
1

Bob de Graafの回答に基づく:

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

UIControlEventAllTouchEventsの代わりに を使用していることに注意してくださいUIControlEventValueChanged

また、電話する必要はありません-(void)setSelectedSegmentIndex:

于 2014-02-09T02:48:46.017 に答える
1

私が最初に思いついたのは、Touch Up InsideorTouch Downアクションを sort メソッドに接続することでしたが、これはうまくいかないようです。

2 番目のアイデアは回避Momentary策であり、セグメント化されたコントロールにプロパティを設定します。これにより、Value Did Changeタップされるたびにアクションが発生します。

于 2009-10-25T14:31:29.463 に答える
1

これが私の解決策です。すべてのタッチで 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
于 2012-04-30T19:22:46.400 に答える
0

KVO を使用して、iOS8 用に既に選択されているセグメントを反転しています。

#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
于 2015-05-19T10:20:21.563 に答える
0

選択した回答の解決策は、現在の iOS v8.x の時点では機能しませんでした。しかし、@Andyは解決策を提供し、私は完了します:

をサブクラス化し、サブクラスのメソッドUISegmentedControlを上書きします。touchesEnded

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

UISegmentedControl を使用する予定のクラスで、iVar currentSelectedSegIndex を作成します。UIControlEventValueChanged アクション メソッドの横に UIControlEventAllTouchEvents を追加します。

NSInteger currentSelectedSegIndex;

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

2 つのアクション メソッドを実装します。

-(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
}
于 2015-09-02T14:30:16.893 に答える