iphone ios objective-c uitableview ios7

iphone - UIButton no muestra el resaltado de barrido en iOS7



objective-c uitableview (17)

Aquí está la respuesta de Roman B en Swift 2:

for view in tableView.subviews { if view is UIScrollView { (view as? UIScrollView)!.delaysContentTouches = false break } }

He visto un montón de publicaciones sobre cosas similares, pero ninguna de ellas coincide o soluciona este problema. Desde iOS 7, cada vez que agrego un UIButton a una UITableViewCell o incluso a la vista de pie de página, funciona "bien", lo que significa que recibe la acción de destino, pero no muestra el pequeño resaltado que normalmente ocurre al tocar un UIButton . Hace que la interfaz de usuario parezca funky y no muestra el botón que reacciona al tacto.

Estoy bastante seguro de que esto cuenta como un error en iOS7, pero alguien ha encontrado una solución o podría ayudarme a encontrar uno :)

Editar: Olvidé mencionar que resaltará si mantengo presionado el botón durante mucho tiempo, pero no un toque rápido como lo hace si se agrega a una vista estándar.

Código:

Creando el botón:

UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; button.titleLabel.font = [UIFont systemFontOfSize:14]; button.titleLabel.textColor = [UIColor blueColor]; [button setTitle:@"Testing" forState:UIControlStateNormal]; [button addTarget:self action:@selector(buttonPressed:) forControlEvents: UIControlEventTouchDown]; button.frame = CGRectMake(0, 0, self.view.frame.size.width/2, 40);

Cosas que he probado:

// Eliminar los reconocedores de gestos en UITableView en caso de que se UITableView en el camino.

for (UIGestureRecognizer *recognizer in self.tableView.gestureRecognizers) { recognizer.enabled = NO; }

// Eliminar gestos de la Celda

for (UIGestureRecognizer *recognizer in self.contentView.gestureRecognizers) { recognizer.enabled = NO; }

// Esto muestra el pequeño toque ligero, pero este no es el aspecto deseado

button.showsTouchWhenHighlighted = YES;


Como objc es dinámico, y scrollView es la única clase que responde a delaysContentTouches, esto debería funcionar tanto para ios 7 como para 8 (póngalo en algún lugar temprano en su tableViewController, como awakeFromNib):

for (id view in self.tableView.subviews) { if ([view respondsToSelector:@selector(delaysContentTouches)]) { UIScrollView *scrollView = (UIScrollView *)view; scrollView.delaysContentTouches = NO; break; } }

También puede tener que desactivar "delaysContentTouches" en su guión gráfico o punta seleccionando la tabla dentro de su viewController. Por cierto, esto podría no funcionar en ios 7 si estás usando tableView dentro de viewController, al menos no podría hacerlo funcionar.


Desde iOS 8, necesitamos aplicar la misma técnica a las subvistas de UITableView (la tabla contiene una vista de desplazamiento UITableViewWrapperView oculta). Ya no es necesario iterar las subvistas UITableViewCell.

for (UIView *currentView in tableView.subviews) { if ([currentView isKindOfClass:[UIScrollView class]]) { ((UIScrollView *)currentView).delaysContentTouches = NO; break; } }

Esta respuesta debe estar relacionada con esta pregunta.


En Swift 3 esta extensión UIView se puede usar en UITableViewCell. Preferiblemente en el método cellForRowAt .

func removeTouchDelayForSubviews() { for subview in subviews { if let scrollView = subview as? UIScrollView { scrollView.delaysContentTouches = false } else { subview.removeTouchDelayForSubviews() } } }


En esa tabla, simplemente agrega esta propiedad.

tableview.delaysContentTouches = NO;

Y agregue cellForRowAtIndexPath después de iniciar la celda que acaba de agregar debajo del código. La estructura de la célula es aparentemente diferente en iOS 6 e iOS 7.
iOS 7 tenemos un control UITableViewCellScrollView entre UITableViewCell y la vista de contenido.

for (id obj in cell.subviews) { if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"]) { UIScrollView *scroll = (UIScrollView *) obj; scroll.delaysContentTouches = NO; break; } }


Esa solución para mí no funciona, arreglé la subclase TableView y la implementación de estos dos métodos

- (instancetype)initWithCoder:(NSCoder *)coder{ self = [super initWithCoder:coder]; if (self) { for (id obj in self.subviews) { if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]){ [obj performSelector:@selector(setDelaysContentTouches:) withObject:NO]; } } } return self; } - (BOOL)delaysContentTouches{ return NO; }


Escribí una extensión de categoría en UITableViewCell para hacer que este problema sea fácil de abordar. Básicamente, es lo mismo que la respuesta aceptada, excepto que UITableViewCell contentView la jerarquía de vista (en lugar de hacia abajo) desde el UITableViewCell contentView .

Consideré una solución completamente "automágica" que haría que todas las células agregadas a un UITableView establecieran su estado delaysContentTouches para que coincida con el estado de UITableView de delaysContentTouches . Para que esto funcione, tendría que UITableView o requerir que el desarrollador use una subclase de UITableView . Al no querer exigir nada, me decidí por esta solución que creo que es más simple y más flexible.

Extensión de categoría y arnés de muestra aquí:

https://github.com/TomSwift/UITableViewCell-TS_delaysContentTouches

Es muy fácil de usar:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // using static cells from storyboard... UITableViewCell* cell = [super tableView: tableView cellForRowAtIndexPath: indexPath]; cell.ts_delaysContentTouches = NO; cell.selectionStyle = UITableViewCellSelectionStyleNone; return cell; }

Aquí está el código para la categoría:

@interface UITableViewCell (TS_delaysContentTouches) @property (nonatomic, assign) BOOL ts_delaysContentTouches; @end @implementation UITableViewCell (TS_delaysContentTouches) - (UIScrollView*) ts_scrollView { id sv = self.contentView.superview; while ( ![sv isKindOfClass: [UIScrollView class]] && sv != self ) { sv = [sv superview]; } return sv == self ? nil : sv; } - (void) setTs_delaysContentTouches:(BOOL)delaysContentTouches { [self willChangeValueForKey: @"ts_delaysContentTouches"]; [[self ts_scrollView] setDelaysContentTouches: delaysContentTouches]; [self didChangeValueForKey: @"ts_delaysContentTouches"]; } - (BOOL) ts_delaysContentTouches { return [[self ts_scrollView] delaysContentTouches]; } @end


Esta es una versión Swift de la respuesta anterior de Raphaël Pinto. No te olvides de invitarlo también :)

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { super.touchesBegan(touches, withEvent: event) NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = true } } override func touchesCancelled(touches: NSSet!, withEvent event: UIEvent!) { super.touchesCancelled(touches, withEvent: event) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) dispatch_after(time, dispatch_get_main_queue()) { self.setDefault() } } override func touchesEnded(touches: NSSet, withEvent event: UIEvent) { super.touchesEnded(touches, withEvent: event) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) dispatch_after(time, dispatch_get_main_queue()) { self.setDefault() } } func setDefault() { NSOperationQueue.mainQueue().addOperationWithBlock { () -> Void in self.highlighted = false } }


Estaba teniendo problemas similares con un UIButton de solo texto en una UITableViewCell que no se resalta al tocar. Lo que lo solucionó fue cambiar el buttonType de Custom a System.

El establecimiento de retardosContentTouches a NO hizo el truco para el UIButton de solo imagen en la misma UITableViewCell.

self.tableView.delaysContentTouches = NO;


La respuesta aceptada no funcionó en algunos "toques" para mí.

Finalmente agrego el código siguiente en una categoría de uibutón (/ subclase) y funciona al cien por cien.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { self.backgroundColor = [UIColor greenColor]; [UIView animateWithDuration:0.05 delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ self.backgroundColor = [UIColor clearColor]; } completion:^(BOOL finished) { }]; [super touchesBegan:touches withEvent:event]; }


Lo que hice para resolver el problema fue una categoría de UIButton utilizando el siguiente código:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; [NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = YES; }]; } - (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesCancelled:touches withEvent:event]; [self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1]; } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesEnded:touches withEvent:event]; [self performSelector:@selector(setDefault) withObject:nil afterDelay:0.1]; } - (void)setDefault { [NSOperationQueue.mainQueue addOperationWithBlock:^{ self.highlighted = NO; }]; }

el botón reacciona correctamente cuando lo presiono en una UITableViewCell, y mi UITableView se comporta normalmente ya que el delaysContentTouches no está forzado.


Para una solución que funcione tanto en iOS7 como en iOS8, cree una subclase de UITableViewCell personalizada y una subclase personalizada de UITableViewCell .

Utilice este ejemplo UITableView de initWithFrame:

- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // iterate over all the UITableView''s subviews for (id view in self.subviews) { // looking for a UITableViewWrapperView if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"]) { // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7 if([view isKindOfClass:[UIScrollView class]]) { // turn OFF delaysContentTouches in the hidden subview UIScrollView *scroll = (UIScrollView *) view; scroll.delaysContentTouches = NO; } break; } } } return self; }

Use este ejemplo initWithStyle:reuseIdentifier:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // iterate over all the UITableViewCell''s subviews for (id view in self.subviews) { // looking for a UITableViewCellScrollView if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewCellScrollView"]) { // this test is here for safety only, also there is no UITableViewCellScrollView in iOS8 if([view isKindOfClass:[UIScrollView class]]) { // turn OFF delaysContentTouches in the hidden subview UIScrollView *scroll = (UIScrollView *) view; scroll.delaysContentTouches = NO; } break; } } } return self; }


Solución en Swift para iOS 7 y 8:

Primero escribí una función de utilidad:

class func classNameAsString(obj: AnyObject) -> String { return _stdlib_getDemangledTypeName(obj).componentsSeparatedByString(".").last! }

luego subclasto UITableView e implemento esto:

required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) for view in self.subviews { if (Utility.classNameAsString(view) == "UITableViewWrapperView") { if view.isKindOfClass(UIScrollView) { var scroll = (view as UIScrollView) scroll.delaysContentTouches = false } break } } }

También subclasto UITableViewCell e implemento esto:

required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) for view in self.subviews { if (Utility.classNameAsString(view) == "UITableViewCellScrollView") { if view.isKindOfClass(UIScrollView) { var scroll = (view as UIScrollView) scroll.delaysContentTouches = false } } } }

En mi caso, se ejecutará el init (codificador :). Ponga el punto de depuración en sus funciones de inicio para saber qué función de inicio se ejecutará y luego use el código anterior para que funcione. Espero ayudar a alguien


Solución en Swift, iOS8 solamente (necesita el trabajo adicional en cada una de las celdas para iOS7):

// // NoDelayTableView.swift // DivineBiblePhone // // Created by Chris Hulbert on 30/03/2015. // Copyright (c) 2015 Chris Hulbert. All rights reserved. // // This solves the delayed-tap issue on buttons on cells. import UIKit class NoDelayTableView: UITableView { required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) delaysContentTouches = false // This solves the iOS8 delayed-tap issue. // http://.com/questions/19256996/uibutton-not-showing-highlight-on-tap-in-ios7 for view in subviews { if let scroll = view as? UIScrollView { scroll.delaysContentTouches = false } } } override func touchesShouldCancelInContentView(view: UIView!) -> Bool { // So that if you tap and drag, it cancels the tap. return true } }

Para usar, todo lo que tienes que hacer es cambiar la clase a NoDelayTableView en tu guión gráfico.

Puedo confirmar que en iOS8, los botones colocados dentro de un contentView en una celda ahora se resaltan al instante.


Traté de agregar esto a la respuesta aceptada, pero nunca pasó. Esta es una forma mucho más segura de desactivar las celdas delaysContentTouches propiedad ya que no busca una clase específica, sino algo que responda al selector.

En Célula:

for (id obj in self.subviews) { if ([obj respondsToSelector:@selector(setDelaysContentTouches:)]) { [obj setDelaysContentTouches:NO]; } }

En TableView:

self.tableView.delaysContentTouches = NO;


Versión ligeramente modificada de la respuesta de Chris Harrison . Swift 2.3:

class HighlightButton: UIButton { override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) { super.touchesBegan(touches, withEvent: event) NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = true } } override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) { super.touchesCancelled(touches, withEvent: event) setDefault() } override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { super.touchesEnded(touches, withEvent: event) setDefault() } private func setDefault() { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { NSOperationQueue.mainQueue().addOperationWithBlock { _ in self.highlighted = false } } } }


- (void)viewDidLoad { [super viewDidLoad]; for (id view in self.tableView.subviews) { // looking for a UITableViewWrapperView if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"]) { // this test is necessary for safety and because a "UITableViewWrapperView" is NOT a UIScrollView in iOS7 if([view isKindOfClass:[UIScrollView class]]) { // turn OFF delaysContentTouches in the hidden subview UIScrollView *scroll = (UIScrollView *) view; scroll.delaysContentTouches = NO; } break; } } }