puedo por inicio home flotante desactivar control como centro boton assistive aparece activar ios objective-c uibutton uisegmentedcontrol

ios - por - Cómo deseleccionar un segmento en el botón de control Segmentado permanentemente hasta que se haga clic nuevamente



no me aparece el centro de control iphone (8)

¡Muy útil! ¡Gracias! Quería un poco más de control sobre los eventos para mi proyecto, por lo que adapté la respuesta de @ Matthias para enviar un evento "Valor sin cambios" personalizado. Puse un ejemplo en GitHub .

También incorporé la solución de @ Grzegorz para que se comporte correctamente si el usuario arrastra su dedo fuera del control segmentado.

Tengo un UISegmentedControl con 4 segmentos. Cuando se selecciona, debe mantener el selected state . Cuando se vuelve a hacer clic en el mismo segmento, debería deselect itself . ¿Cómo lograr esto?


Aquí hay una solución para un problema que cuando intenta cancelar la selección iniciando el toque en UISegmentControl y luego finaliza el contacto externo, todavía se deselecciona.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { CGPoint locationPoint = [[touches anyObject] locationInView:self]; CGPoint viewPoint = [self convertPoint:locationPoint fromView:self]; if ([self pointInside:viewPoint withEvent:event]) { int oldValue = self.selectedSegmentIndex; [super touchesEnded:touches withEvent:event]; if (oldValue == self.selectedSegmentIndex) { [super setSelectedSegmentIndex:UISegmentedControlNoSegment]; [self sendActionsForControlEvents:UIControlEventValueChanged]; } } }


Aquí hay una solución que es independiente de la versión IOS. Es elegir el comportamiento en sí.

@interface CustomSegmentedControl : UISegmentedControl @end @implementation CustomSegmentedControl{ BOOL _touchBegan; BOOL _reactOnTouchBegan; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { _touchBegan = YES; NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex; [super touchesBegan:touches withEvent:event]; if (_reactOnTouchBegan) { // before iOS7 the segment is selected in touchesBegan if (previousSelectedSegmentIndex == self.selectedSegmentIndex) { [self sendActionsForControlEvents:UIControlEventValueChanged]; } } } -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { _touchBegan = NO; NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex; [super touchesEnded:touches withEvent:event]; if (!_reactOnTouchBegan) { CGPoint locationPoint = [[touches anyObject] locationInView:self]; CGPoint viewPoint = [self convertPoint:locationPoint fromView:self]; if ([self pointInside:viewPoint withEvent:event]) { // on iOS7 the segment is selected in touchesEnded if (previousSelectedSegmentIndex == self.selectedSegmentIndex) { [self sendActionsForControlEvents:UIControlEventValueChanged]; } } } } - (void)sendActionsForControlEvents:(UIControlEvents)controlEvents { if(controlEvents == UIControlEventValueChanged){ _reactOnTouchBegan = _touchBegan; } [super sendActionsForControlEvents:controlEvents]; } @end


Dado que UISegmentedControl solo envía una acción si se selecciona un segmento no seleccionado, debe subclase UISegmentedControl para realizar un pequeño cambio en su manejo táctil. Yo uso esta clase:

@implementation MBSegmentedControl // this sends a value changed event even if we reselect the currently selected segment - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSInteger current = self.selectedSegmentIndex; [super touchesBegan:touches withEvent:event]; if (current == self.selectedSegmentIndex) { [self sendActionsForControlEvents:UIControlEventValueChanged]; } } @end

Ahora obtendrás eventos UIControlEventValueChanged , incluso si el segmento ya está seleccionado. Simplemente guarde el índice actual en una variable y compárelo en la acción. Si los dos índices coinciden, debe deseleccionar el segmento tocado.

// _selectedSegmentIndex is an instance variable of the view controller - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; _selectedSegmentIndex = self.segment.selectedSegmentIndex; } - (IBAction)segmentChanged:(UISegmentedControl *)sender { if (sender.selectedSegmentIndex == _selectedSegmentIndex) { NSLog(@"Segment %d deselected", sender.selectedSegmentIndex); sender.selectedSegmentIndex = UISegmentedControlNoSegment; _selectedSegmentIndex = UISegmentedControlNoSegment; } else { NSLog(@"Segment %d selected", sender.selectedSegmentIndex); _selectedSegmentIndex = sender.selectedSegmentIndex; } }

iOS 7 cambió la forma en que se manejan los toques para UISegmentedControl. touchesEnded: seleccionado ahora se cambia durante los touchesEnded:

Así que la Subclase actualizada debería verse así:

@implementation MBSegmentedControl + (BOOL)isIOS7 { static BOOL isIOS7 = NO; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSInteger deviceSystemMajorVersion = [[[[[UIDevice currentDevice] systemVersion] componentsSeparatedByString:@"."] objectAtIndex:0] integerValue]; if (deviceSystemMajorVersion >= 7) { isIOS7 = YES; } else { isIOS7 = NO; } }); return isIOS7; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex; [super touchesBegan:touches withEvent:event]; if (![[self class] isIOS7]) { // before iOS7 the segment is selected in touchesBegan if (previousSelectedSegmentIndex == self.selectedSegmentIndex) { // if the selectedSegmentIndex before the selection process is equal to the selectedSegmentIndex // after the selection process the superclass won''t send a UIControlEventValueChanged event. // So we have to do this ourselves. [self sendActionsForControlEvents:UIControlEventValueChanged]; } } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex; [super touchesEnded:touches withEvent:event]; if ([[self class] isIOS7]) { // on iOS7 the segment is selected in touchesEnded if (previousSelectedSegmentIndex == self.selectedSegmentIndex) { [self sendActionsForControlEvents:UIControlEventValueChanged]; } } } @end

Versión Swift 2.2, solucionó el problema que Grzegorz notó.

class ReselectableSegmentedControl: UISegmentedControl { @IBInspectable var allowReselection: Bool = true override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { let previousSelectedSegmentIndex = self.selectedSegmentIndex super.touchesEnded(touches, withEvent: event) if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex { if let touch = touches.first { let touchLocation = touch.locationInView(self) if CGRectContainsPoint(bounds, touchLocation) { self.sendActionsForControlEvents(.ValueChanged) } } } } }

Swift 3.0 cambia la solución para que esto parezca lo siguiente:

class MyDeselectableSegmentedControl: UISegmentedControl { override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { let previousIndex = selectedSegmentIndex super.touchesEnded(touches, with: event) if previousIndex == selectedSegmentIndex { let touchLocation = touches.first!.location(in: self) if bounds.contains(touchLocation) { sendActions(for: .valueChanged) } } } }


En referencia a @Stunner, esta es mi contribución para lograr el objetivo. Cambié algo y agregué la propiedad _previousSelectedSegmentIndex; en el código de @Stunner la variable previousSelectedSegmentIndex fue inútil:

@implementation STASegmentedControl { NSInteger _previousSelectedSegmentIndex; } - (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex { [super setSelectedSegmentIndex: selectedSegmentIndex]; _previousSelectedSegmentIndex = self.selectedSegmentIndex; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; CGPoint locationPoint = [[touches anyObject] locationInView:self]; CGPoint viewPoint = [self convertPoint:locationPoint fromView:self]; if (self.toggleableSegments) { // toggle selected segment on/off if ([self pointInside:viewPoint withEvent:event] && _previousSelectedSegmentIndex == self.selectedSegmentIndex) { self.selectedSegmentIndex = UISegmentedControlNoSegment; [self sendActionsForControlEvents:UIControlEventValueChanged]; } } _previousSelectedSegmentIndex = self.selectedSegmentIndex; }


En referencia a la respuesta publicada por @Matthias Bauch. Tuve que hacer pequeños cambios según Swift 2.2 en Xcode 7.3:

class ReselectableSegmentedControl: UISegmentedControl { @IBInspectable var allowReselection: Bool = true override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { let previousSelectedSegmentIndex = self.selectedSegmentIndex super.touchesEnded(touches, withEvent: event) if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex { if let touch = touches.first { let touchLocation = touch.locationInView(self) if CGRectContainsPoint(bounds, touchLocation) { self.sendActionsForControlEvents(.ValueChanged) } } } } }


Puede hacerlo con lo siguiente (gracias a la respuesta de Grzegorz y la respuesta de Matthias ):

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { NSInteger previousSelectedSegmentIndex = self.selectedSegmentIndex; [super touchesEnded:touches withEvent:event]; CGPoint locationPoint = [[touches anyObject] locationInView:self]; CGPoint viewPoint = [self convertPoint:locationPoint fromView:self]; if ([self pointInside:viewPoint withEvent:event] && previousSelectedSegmentIndex == self.selectedSegmentIndex) { self.selectedSegmentIndex = UISegmentedControlNoSegment; [self sendActionsForControlEvents:UIControlEventValueChanged]; } }

He creado una clase STASegmentedControl código abierto (con licencia MIT) (compatible con iOS 7+), que tiene esta funcionalidad integrada (y más).


Swift 3.1 versión publicada por @Kushal Ashok

class ReselectableSegmentedControl: UISegmentedControl { @IBInspectable var allowReselection: Bool = true override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { let previousSelectedSegmentIndex = self.selectedSegmentIndex super.touchesEnded(touches, with: event) if allowReselection && previousSelectedSegmentIndex == self.selectedSegmentIndex { if let touch = touches.first { let touchLocation = touch.location(in: self) if bounds.contains(touchLocation) { self.sendActions(for: .valueChanged) } } } } }