titlelabel color buttons ios objective-c uibutton interface-builder

ios - color - UIButton no registra correctamente el toque en la región inferior de la pantalla del iPhone



menu ios (7)

Tengo una aplicación con muchos botones diferentes dispuestos en una calculadora, formato cuadrado / rectangular. En realidad, es extremadamente similar a la calculadora iOS por defecto. Hay aproximadamente 6 filas con 4 columnas cada una de los botones.

Problema

El problema que tengo tiene que ver con los botones en la fila inferior (aproximadamente la décima parte inferior de la pantalla en un iPhone 4). No se comportan normalmente cuando se presionan en el sentido de que cuando se presionan, se deben presionar y mantener (durante aproximadamente un segundo) para registrar una "presión de botón". Esto se opone a la pulsación corta estándar.

Ningún otro botón aparte de esta fila inferior se comporta de esta manera.

Además, si estos botones se tocan en su borde superior, se comportan normalmente y responden tan pronto como se tocan. Esto me lleva a creer que los botones en sí no son los problemas, pero hay un problema con el diseño de mis vistas.

También se debe tener en cuenta que este problema solo está presente en los dispositivos físicos. En el simulador, los botones se comportan normalmente.

Contexto

La vista que contiene estos botones no es el controlador de vista raíz de la aplicación. En su lugar, se hace la transición a como tal (nada especial aquí):

[self presentViewController:navController animated:YES completion:nil];

Donde self es el controlador de vista de raíz

El controlador de vista con el que estoy teniendo problemas se encuentra dentro de un controlador de navegación y se presenta de manera modal mediante el controlador de vista raíz que puede ver arriba.

Lo que he intentado hasta ahora

  • Activar y desactivar el diseño automático: el mismo problema

  • Reorganización de la jerarquía de vistas: moví los botones problemáticos encima y detrás de todas las demás vistas con el mismo resultado: el mismo problema

  • Dispositivos múltiples (iPhone 4, 4s, 5): el mismo problema (aunque los botones responden normalmente en simuladores de 3,5 y 4 pulgadas)

  • Probar otras aplicaciones (cuando los botones de esta región se presionan en otras aplicaciones, se comportan normalmente)

Información Adicional

  • Todo se presenta en Interface Builder para el controlador de vista problemático
  • Todos los botones son botones del sistema con configuraciones estándar y son exactamente iguales, además de su texto.
  • Todos los elementos de la pantalla (botones, etiquetas, etc.) son subvistas de la "vista"
  • Los botones están alineados entre sí y no deben superponerse más de uno o dos píxeles.
  • Los botones problemáticos tienen dimensiones: 80 de ancho x 44 de alto.
  • Los botones problemáticos están alineados contra la parte inferior de la pantalla.
  • Además de los botones, hay un UIImage y varias etiquetas, sin embargo, están en la parte superior de la pantalla y no se superponen con ninguno de los botones de ninguna manera.

Esto suena como una interacción entre los botones y UIScreenEdgePanGestureRecognizer (o lo que sea) que es responsable de detectar que el usuario desea abrir el Centro de control del sistema.

En realidad, hay dos problemas potenciales aquí:

  • Puede haber una interacción (es decir, un conflicto) entre la posibilidad de un gesto dirigido a su aplicación y un gesto dirigido al sistema. Si tiene reconocedores de gestos, es posible que tenga que usar métodos delegados para mediar entre ellos y los reconocedores de gestos del sistema.

  • Hay un error bien establecido en el que funciona un toque cerca del borde de la pantalla (es decir, en la "zona" del reconocedor de gestos del borde de la pantalla) pero hace que el botón se comporte mal físicamente , es decir, no parece que se haya tocado aunque haya iniciado sesión muestra que tiene (vea mi respuesta aquí: https://.com/a/22000692/341994 ).


He escrito una solución completa en rápida basada en respuesta . Solo haga que los botones en conflicto se ajusten a esta clase y el problema desaparecerá:

class BorderBugFixButton : UIButton { override func awakeFromNib() { super.awakeFromNib() NSNotificationCenter.defaultCenter().addObserver(self, selector: "unHighlight", name: UIApplicationWillResignActiveNotification, object: nil) } deinit { NSNotificationCenter.defaultCenter().removeObserver(self) } override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { let inside = super.pointInside(point, withEvent: event) if inside != highlighted && event?.type == .Touches { highlighted = inside } return inside } internal func unHighlight() { highlighted = false } }

PD: para aquellos de ustedes que no les gustan los Storyboards / Xib''s, solo migran la implementación de awakeFromNib() a init()


La causa de este problema es que Apple parece colocar un GestureRecognizer en la parte inferior de la pantalla que retrasa los toques en cualquier otra vista. Después de juguetear con reconocedores de gestos en las ventanas de la aplicación, se me ocurrió una solución que incorpora una subclase de UIButton:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL inside = [super pointInside: point withEvent: event]; if (inside && !self.isHighlighted && event.type == UIEventTypeTouches) { self.highlighted = YES; } return inside; }

El método dado se está llamando aunque touchesBegan: se llama retrasado. Una comprobación de si la vista está en la parte inferior de la pantalla puede ser adecuada para evitar cualquier efecto secundario que pueda ocurrir con esta revisión.


Me he encontrado con esto varias veces cuando trabajo con la actualización de Storyboards anteriores para iOS 7+, generalmente cuando el ViewController en cuestión tiene la forma de un UIScrollView. Verifique dos veces estas configuraciones en su Guión gráfico en el objeto ViewController (no la vista, la que tiene el círculo amarillo). Cuando desactivé la opción "Extender bordes" debajo de las barras superior e inferior, el marco del scrollView se ajustó hacia abajo en 64 puntos (altura de las barras de navegación y estado).

Después de configurar el espacio entre NavBar.bottom y scrollView.top de nuevo a 0, el botón comenzó a funcionar. Esto podría deberse al hecho de que scrollView.frame.bottom estaba 64 píxeles por encima de la parte inferior de la ventana, por lo que los toques en esa área no se tuvieron en cuenta porque técnicamente estaban fuera del marco del scrollView pero aún se mostraban visualmente por algún motivo.


Respuesta de Lukas en rápida y deseleccionada resaltada.

extension UIButton { public override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool { var inside = super.pointInside(point, withEvent: event) if inside != highlighted && event?.type == .Touches { highlighted = inside } return inside } }


Solución Swift 3

extension UIControl { open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let inside = super.point(inside: point, with: event) if inside != isHighlighted && event?.type == .touches { isHighlighted = inside } return inside } }


iOS 9.3, Xcode 7.3

Le sugiero que haga una categoría para la clase UIButton que implemente la respuesta de Lukas . Para obtener instrucciones sobre cómo crear una categoría, vea esta publicación: ¿Cómo creo una categoría en Xcode 6 o superior?

Asígnele un nombre apropiado con el signo "+" tradicional, es decir, si lo llama "BottomOfScreen", el nombre del archivo resultante será "UIButton + BottomOfScreen".

Si está utilizando objective-c, obtendrá un archivo * .h y * .m con la nueva categoría.

* .h

#import <UIKit/UIKit.h> @interface UIButton (BottomOfScreen) @end

*.metro

#import "UIButton+BottomOfScreen.h" @implementation UIButton (BottomOfScreen) - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL inside = [super pointInside:point withEvent:event]; if (inside && !self.isHighlighted && (event.type == UIEventTypeTouches)) { self.highlighted = true; } else { nil; } return inside; } @end