J'ai un UITableViewCell personnalisé, qui est initialisé par ce qui suit:
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];
self = [nibArray objectAtIndex:0];
[self setSelectionStyle:UITableViewCellSelectionStyleNone];
[self.downButton setBackgroundImage:[UIImage imageNamed:@"button"] forState:UIControlStateNormal];
[self.downButton setBackgroundImage:[UIImage imageNamed:@"buttonSelected"] forState:UIControlStateHighlighted];
}
return self;
}
Le bouton apparaît correctement, avec l'image d'arrière-plan appropriée, mais l'image en surbrillance n'apparaît pas instantanément lorsque le bouton est enfoncé/cliqué. Au lieu de cela, vous devez le maintenir enfoncé pendant une seconde ou deux avant que le changement ne se produise. Le relâchement du bouton, d'autre part, a un instantané retour à l'image d'arrière-plan d'origine.
En essayant d'atténuer le changement tardif lors du passage à l'image en surbrillance, j'ai mis le changement dans la méthode suivante:
- (IBAction)downDown:(id)sender {
[self.downButton setBackgroundColor:[UIColor redColor]];
}
La méthode ci-dessus est définie pour "Touch Down" (contrairement au "Touch Up Inside" plus commun), et j'ai supprimé le setBackgroundImage:forState:
pour l'état en surbrillance. Même problème que mentionné ci-dessus. La couleur ne éventuellement devient rouge, mais seulement après avoir cliqué et maintenu le bouton pendant une seconde ou deux.
J'ai une méthode pour le bouton qui est appelé lorsque "Touch Up Inside" se produit, et cette méthode s'exécute sans problème - que j'appuie rapidement sur le bouton ou que je clique dessus et le maintienne pendant un certain temps avant de le relâcher.
Alors pourquoi le retard pour le "Touch Down" ou UIControlStateHighlighted
? J'essaie de fournir une rétroaction instantanée à l'utilisateur pour montrer que le bouton a été enfoncé.
Je peux fournir plus de code si nécessaire, mais ce sont les seuls bits qui ont quelque chose à voir avec l'apparence de l'arrière-plan.
Cela est dû à la propriété UIScrollView
delaysContentTouches
.
Auparavant, il suffisait de simplement définir cette propriété sur NO
pour le UITableView
lui-même, mais cela ne fonctionnera que pour les sous-vues de la table qui ne sont pas enfermées dans un autre UIScrollView
.
UITableViewCells
contient une vue de défilement interne dans iOS 7, vous devrez donc modifier la valeur de cette propriété au niveau des cellules pour toutes les cellules contenant des boutons.
Voici ce que tu dois faire:
1. dans viewDidLoad
ou quelque part similaire une fois que votre UITableView
a été initialisé, mettez ceci dans:
self.tableView.delaysContentTouches = NO;
2.pour la prise en charge iOS 7, dans la méthode d'initialisation de votre UITableViewCell
(initWithStyle:reuseIdentifier:
ou initWithCoder:
pour les NIB), mettez ceci à la fin:
for (UIView *currentView in self.subviews)
{
if([currentView isKindOfClass:[UIScrollView class]])
{
((UIScrollView *)currentView).delaysContentTouches = NO;
break;
}
}
Ce n'est malheureusement pas une solution permanente à 100% car Apple peut changer la hiérarchie de vue à l'intérieur des cellules à l'avenir (peut-être déplacer la vue de défilement d'une autre couche vers le bas ou quelque chose qui vous obligerait à imbriquer une autre boucle là-dedans), mais jusqu'à ce qu'ils révèlent la classe ou au moins la propriété aux développeurs, c'est le meilleur que nous ayons.
Solution Swift 3 (pour iOS8 +):
Tout d'abord, désactivez les retards dans UITableView
après son chargement réussi, par exemple, à l'intérieur de la méthode viewDidLoad()
:
someTableView.delaysContentTouches = false
Désactivez ensuite les retards dans les vues de défilement contenues dans le UITableView
:
for case let scrollView as UIScrollView in someTableView.subviews {
scrollView.delaysContentTouches = false
}
Remarque pour iOS7: vous devrez peut-être désactiver les retards dans UITableViewCell
. (Vérifiez la réponse de Dima).
Vous pouvez également trouver d'autres conseils ici .
je résous ce problème dans mon code en sous-classant UIButton,
Objectif c
@interface TBButton : UIButton
@end
@implementation TBButton
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.highlighted = true;
[super touchesBegan:touches withEvent:event];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.highlighted = false;
[super touchesEnded:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.highlighted = false;
[super touchesCancelled:touches withEvent:event];
}
@end
Swift
class TBButton: UIButton {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
highlighted = true
super.touchesBegan(touches, withEvent: event)
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
highlighted = false
super.touchesEnded(touches, withEvent: event)
}
override func touchesCancelled(touches: Set<UITouch>?, withEvent event: UIEvent?) {
highlighted = false
super.touchesCancelled(touches, withEvent: event)
}
}
Swift 3
class TBButton: UIButton {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isHighlighted = true
super.touchesBegan(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isHighlighted = false
super.touchesEnded(touches, with: event)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
isHighlighted = false
super.touchesCancelled(touches, with: event)
}
}
Version Swift 3 de Alex 's réponse :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
isHighlighted = true
super.touchesBegan(touches, with: event)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isHighlighted = false
super.touchesEnded(touches, with: event)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
isHighlighted = false
super.touchesCancelled(touches, with: event)
}
Voici une solution récursive que vous pouvez ajouter à votre contrôleur de vue:
+ (void)disableDelayedTouches:(UIView*)view
{
for(UIView *currentView in view.subviews) {
if([currentView isKindOfClass:[UIScrollView class]]) {
((UIScrollView *)currentView).delaysContentTouches = NO;
}
[self disableDelayedTouches:currentView];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.class disableDelayedTouches:self.view];
}
Alors pourquoi le retard pour le "Touch Down" ou
UIControlStateHighlighted
? J'essaie de fournir une rétroaction instantanée à l'utilisateur pour montrer que le bouton a été enfoncé.
N'est-ce pas Apple l'explique encore?
Si vous souhaitez faire défiler la vue et que votre doigt touche à quelque chose de surlignable (par exemple, n'importe quelle cellule de tableau avec le style de sélection par défaut), vous obtenez ces artefacts clignotants:
Vraiment, ils ne savent pas sur touchDown
, si vous allez appuyer ou faire défiler.
Si vous souhaitez faire défiler la vue et que votre doigt touche un UIButton
/UITextField
, la vue n'est pas du tout défilée ! Le comportement par défaut de Button/TextField est "plus fort" que celui de scrollview, il attend toujours un événement touchUpInside
.