UISegmentedControl регистрирует краны на выбранном сегменте

У меня есть сегментированный элемент управления, где пользователь может выбрать способ заказа списка. Работает отлично.

Тем не менее, мне бы хотелось, чтобы при отборе уже выбранного сегмента порядок был инвертирован. У меня есть весь код на месте, но я не знаю, как регистрировать краны на этих сегментах. Кажется, единственным управляющим событием, которое вы можете использовать, является UIControlEventValueChanged, но это не работает (поскольку выбранный сегмент фактически не меняется).

Есть ли решение для этого? И если да, то что это?

Заранее спасибо!

Вы можете подclassифицировать UISegmentedControl, а затем переопределить setSelectedSegmentIndex:

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

Если вы используете IB, убедитесь, что вы установили class вашего UISegmentedControl в свой подclass.

Теперь вы можете прослушивать тот же 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]; } 

Хотел это сам. Взял решение Джулиана (спасибо!) И немного изменил.

Следующий подclass UISegmentedControl просто запускает событие UIControlEventValueChanged даже когда значение не изменилось, что, очевидно, UIControlEventValueChanged немного странно, но отлично работает в моем случае и сохраняет все просто.

AKSegmentedControl.h

 #import  @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]; } 

Текущее решение, представленное по-прежнему, не работает, потому что setSelectedSegmentIndex никогда не вызывается, если действительно не используется новый сегмент. По крайней мере, в моем случае это никогда не работало, я использую iOS5, хотя, возможно, это решение действительно работает в iOS4. Во всяком случае, это мое решение. Ему нужен один дополнительный метод подclassа, который выглядит следующим образом:

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

Удачи!

Это был довольно старый вопрос, поэтому я подумал, что добавлю довольно простое решение, которое я использовал, когда столкнулся с этим в приложении iOS 5+.

Все, что я сделал, это перетащить Recognizer Tap Gesture на UISegmentedControl в моем .xib-файле. Проверьте соединения для вашего нового распознавателя жестов, чтобы убедиться, что сегментированное управление является единственным выходом gestureRecognizer, а затем просто подключите его к методу, который вы хотите запустить в своем controllerе.

Этот метод должен срабатывать в любое время, когда вы касаетесь сегментированного элемента управления, поэтому просто проверяйте выбранный индекс с помощью, возможно, переменной экземпляра, чтобы увидеть, коснулся ли пользователь уже выбранного сегмента.

 @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 

На iOS8 каждый ответ здесь кажется либо нерабочим, либо триггерным изменением дважды. Я придумал очень простое решение – поэтому я хотел бы поделиться им.

В подclassе у меня есть только:

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

Это делается для сброса выбранного сегмента на -1 перед сменой сегментированного сегмента управления. Это произойдет с помощью метода toucedEnded.

Это работает:

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

В Swift 3 я мог представить себе как минимум 2 решения следующим образом. В специальном случае я разместил также третье решение, в котором выбранный сегмент работает как кнопка переключения.

Решение 1:

Подсказка: это решение работает только с моментальным контролем. Если вам нужно решение для стационарных элементов управления, выберите Решение 2

Идея состоит в том, чтобы зарегистрировать второе событие, которое срабатывает при касании-внутри:

 // 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, with event: UIEvent?) { current = self.selectedSegmentIndex super.touchesBegan(touches, with: event) } override func touchesEnded(_ touches: Set, 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, with event: UIEvent?) { current = self.selectedSegmentIndex super.touchesBegan(touches, with: event) } override func touchesEnded(_ touches: Set, 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)") } } для func changeSelection(sender: UISegmentedControl) { switch sender.selectedSegmentIndex { case UISegmentedControlNoSegment: print("none") default: print("selected: \(sender.selectedSegmentIndex)") } } 

Вот мое решение. Самый элегантный, я думаю, если вы хотите, чтобы событие ValueChanged срабатывало при каждом касании …

.час

 @interface UISegmentedControlAllChanges : UISegmentedControl @end 

.m

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

Первой идеей, с которой я столкнулся, было подключение методов Touch Up Inside или Touch Down к вашему методу сортировки, но это, похоже, не работает.

Вторая идея – это скорее работа, Momentary свойство Momentary на сегментированном элементе управления. Затем он будет запускать действие Value Did Change каждом нажатии.

Большая помощь! То, что я хочу сделать, – это вариант с одной или отсутствующими кнопками – и когда установлена ​​кнопка, второй сигнал отключает ее. Это моя модификация:

 - (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:

Ниже fragmentа кода, который работал для меня. Повторное нажатие на том же сегменте отменит его выбор.

 @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. Переопределить UISegmentedControl с таким classом:

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

Я использую 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 

Решение выбранного ответа не работало для меня с текущего iOS v8.x. Но @Andy предлагает решение, и я завершу:

Подclass UISegmentedControl и перезаписать метод touchesEnded в подclassе:

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

В classе, где вы собираетесь использовать UISegmentedControl, создайте iVar currentSelectedSegIndex. Добавьте UIControlEventAllTouchEvents рядом с вашими методами действия UIControlEventValueChanged:

 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 } 
  • Пользовательский пузырь выноски MKPinAnnotation похож на пузырь по умолчанию
  • 2 различных типа пользовательских UITableViewCells в UITableView
  • Как запустить ssh-сервер на iOS?
  • Могу ли я появиться в Specific ViewController?
  • Как вы вычисляете день года на определенную дату в Objective-C?
  • didReceiveRemoteNotification когда в фоновом режиме
  • Как я могу зашифровать содержимое CoreData на iPhone
  • IPhone / IPad: Как получить ширину экрана программно?
  • Журнал вызовов iPhone / история
  • UIScrollView приостанавливает NSTimer до тех пор, пока прокрутка не завершится
  • В реальном времени Pitch Shifting на iPhone
  • Interesting Posts

    Правильный способ сохранить объединенные соединения в живых (или время их выхода и получить свежие) в течение более длительного времени бездействия для MySQL, приложение Grails 2

    JavaFX 2 и интернационализация

    Что лучше, списки смежности или матрицы смежности для задач графа в C ++?

    поймать салфетки, чтобы отклонить событие

    Синтаксис для создания двумерного массива

    Найти повторяющиеся фразы – любой инструмент или регулярное выражение

    jQuery размещение JSON

    Как построить несколько функций на одной фигуре в Matplotlib?

    Как получить доступ к элементу управления WPF c # в streamовом безопасном режиме?

    Как заставить виртуальные машины VirtualBox использовать DNS хоста?

    Как получить файл apk для сборки сборки с помощью proguard

    Преобразование VMDK в VHD

    Раздел System Reserved больше не отмечен как System

    Добавить ViewPagerIndicator в Android Studio

    Как правильно добавить шестнадцатеричные escape-последовательности в строковый литерал?

    Давайте будем гением компьютера.