J'ai une application avec de nombreux boutons différents disposés dans une calculatrice comme un format carré/rectangulaire. Il est en fait extrêmement similaire à la calculatrice iOS par défaut. Il y a environ 6 lignes avec 4 colonnes chacune des boutons.
Problème
Le problème que je rencontre concerne les boutons de la rangée du bas (environ le 10e de l'écran en bas sur un iPhone 4). Ils ne se comportent pas normalement lorsqu'ils sont pressés, en ce sens qu'ils doivent être maintenus enfoncés (pendant environ une seconde à peu près) pour enregistrer un "appui de bouton". Ceci est opposé au robinet court standard.
Aucun autre bouton en dehors de cette rangée inférieure ne se comporte de cette façon.
De plus, si ces boutons sont exploités sur leur bord supérieur, ils se comportent normalement et réagissent dès qu'ils sont touchés. Cela me porte à croire que les boutons eux-mêmes ne sont pas les problèmes, mais il y a un problème avec la disposition de mes vues.
Il convient également de noter que ce problème n'est présent que sur les périphériques physiques. Sur le simulateur, les boutons se comportent normalement.
Le contexte
La vue contenant ces boutons n'est pas le contrôleur de vue racine de l'application. Au lieu de cela, il est transféré comme tel (rien d’extraordinaire ici):
[self presentViewController:navController animated:YES completion:nil];
Où self est le contrôleur de vue racine
Le contrôleur de vue avec lequel je rencontre des problèmes est contenu dans un contrôleur de navigation et est présenté de manière modale par le contrôleur de vue racine que vous pouvez voir ci-dessus.
Ce que j'ai essayé jusqu'à présent
Activer et désactiver la mise en page automatique: même problème
Réorganisation de la hiérarchie des vues: j'ai déplacé les boutons problématiques au-dessus et derrière toutes les autres vues Avec le même résultat: même problème
Plusieurs périphériques (iPhone 4, 4s, 5): le même problème (bien que les boutons répondent normalement sur les simulateurs 3,5 pouces et 4 pouces)
Test d'autres applications (lorsque les boutons de cette région sont enfoncés sur d'autres applications, ils se comportent normalement)
Information additionnelle
Cela ressemble à une interaction entre les boutons et le UIScreenEdgePanGestureRecognizer (ou quoi que ce soit d'autre) chargé de détecter que l'utilisateur souhaite faire apparaître le centre de contrôle du système.
Il y a en fait deux problèmes potentiels ici:
Il peut y avoir une interaction (c'est-à-dire un conflit) entre la possibilité d'un geste dirigé vers votre application et un geste dirigé vers le système. Si vous avez des outils de reconnaissance de mouvements, vous devrez peut-être utiliser des méthodes de délégation pour établir une médiation entre elles et les outils de reconnaissance de mouvements du système.
Il y a un bogue bien établi où un tapotement près du bord de l'écran (c'est-à-dire dans la "zone" de reconnaissance de geste du bord à l'écran) fonctionne mais le bouton se comporte mal physiquement, c'est-à-dire qu'il ne ne regarde pas comme si cela avait été exploité alors que la journalisation le prouve (voir ma réponse ici: https://stackoverflow.com/a/22000692/341994 ).
La cause de ce problème est qu’Apple semble placer un Reconnecteur de gestes au bas de l’écran qui retarde tout contact dans une autre vue. Après avoir bricolé avec des dispositifs de reconnaissance de mouvements sur les fenêtres de l’application, j’ai trouvé une solution une sous-classe 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;
}
La méthode donnée est appelée bien que touchesBegan: soit appelée différée. Une vérification si la vue est au bas de l'écran peut être appropriée pour éviter tout effet secondaire qui pourrait survenir avec ce correctif.
réponse de Lukas dans Swift et désélectionner en surbrillance
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
}
}
Solution 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
}
}
J'ai écrit une solution complète dans Swift basée sur Luka's answer. Assurez-vous que tous les boutons en conflit sont conformes à cette classe et le problème aura disparu:
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
}
}
P.S .: Pour ceux qui n'aiment pas les Storyboards/Xib, il suffit de migrer l'implémentation de awakeFromNib()
vers init()
Je me suis souvent heurté à cette situation lors de la mise à jour d'anciens Storyboards vers iOS 7+, généralement lorsque le ViewController en question a une forme UIScrollView. Vérifiez deux fois ces 2 paramètres dans votre Storyboard sur l’objet ViewController (pas la vue, celle avec le cercle jaune). Lorsque j'ai décoché la case "Étendre les bords" sous les barres supérieure et inférieure, le cadre du scrollView a été réduit de 64 points (hauteur des barres de navigation et d'état).
Après avoir remis à 0 l'espace entre NavBar.bottom et scrollView.top, le bouton a commencé à fonctionner. Cela est peut-être dû au fait que scrollView.frame.bottom était à 64 pixels au-dessus du bas de la fenêtre, les touches dans cette zone ont donc été ignorées car elles étaient techniquement hors du cadre de scrollView mais étaient toujours affichées visuellement pour une raison quelconque.
iOS 9.3, Xcode 7.3
Je suggérerais que vous deviez créer une catégorie pour la classe UIButton qui implémente la réponse de Lukas . Pour des instructions sur la création d'une catégorie, consultez cet article: Comment créer une catégorie dans Xcode 6 ou supérieur?
Donnez-lui un nom approprié avec le signe "+" traditionnel, c'est-à-dire si vous l'appelez "BottomOfScreen", le nom du fichier résultant sera "UIButton + BottomOfScreen".
Si vous utilisez objective-c, vous obtiendrez un fichier * .h et * .m avec la nouvelle catégorie.
* .h
#import <UIKit/UIKit.h>
@interface UIButton (BottomOfScreen)
@end
* .m
#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