J'ai un problème avec un UITableView
dans un UIScrollView
. Lorsque je fais défiler la scrollView
externe, la table
ne reçoit pas l'événement willSelect/didSelect
au premier toucher, mais au second. Ce qui est encore plus étrange, c'est que la cellule elle-même reçoit les contacts et l'état mis en surbrillance, même lorsque la variable delegate
ne le fait pas.
Ma hiérarchie de vues:
UIView
- UIScrollView (outerscroll)
- Some other views and buttons
- UITableView (tableView)
À l'intérieur de la vue de défilement, j'ai quelques vues supplémentaires qui sont développées/fermées dynamiquement. La vue sous forme de tableau doit être "réparée" par-dessus, avec quelques autres éléments de la vue. C’est pourquoi j’ai créé cette présentation, qui me permet de déplacer facilement les éléments de la même manière que celle recommandée par Apple en utilisant des transformations lorsque le parchemin arrive.
La vue de table est transformée avec un effet de traduction lorsque le défilement extérieur se déplace comme suit:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == self.outerScrollView) {
CGFloat tableOffset = scrollView.contentOffset.y - self.fixedHeaderFrame.Origin.y;
if (tableOffset > 0) {
self.tableView.contentOffset = CGPointMake(0, tableOffset);
self.tableView.transform = CGAffineTransformMakeTranslation(0, tableOffset);
}
else {
self.tableView.contentOffset = CGPointMake(0, 0);
self.tableView.transform = CGAffineTransformIdentity;
}
// Other similar transformations are done here, but not involving the table
}
Dans ma cellule, si j'implémente ces méthodes:
- (void)setSelected:(BOOL)selected {
[super setSelected:selected];
if (selected) {
NSLog(@"selected");
}
}
- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
[super setHighlighted:highlighted animated:animated];
if (highlighted) {
NSLog(@"highlighted");
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSLog(@"touchesBegan");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
NSLog(@"touchesEnded");
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
NSLog(@"touchesCancelled");
}
Y peut voir cette sortie en cas d'échec (première frappe):
2014-02-10 13:04:40.940 MyOrderApp[5588:70b] highlighted
2014-02-10 13:04:40.940 MyOrderApp[5588:70b] touchesBegan
2014-02-10 13:04:40.978 MyOrderApp[5588:70b] touchesEnded
Et celui-ci quand ça marche (deuxième tap):
2014-02-10 13:05:30.359 MyOrderApp[5588:70b] highlighted
2014-02-10 13:05:30.360 MyOrderApp[5588:70b] touchesBegan
2014-02-10 13:05:30.487 MyOrderApp[5588:70b] touchesEnded
2014-02-10 13:05:30.498 MyOrderApp[5588:70b] expanded
Aucun autre changement d'image, animation ou autre interaction de vue n'est effectué entre le premier et le deuxième tapotement. De plus, le bogue n'apparaît que lorsque le défilement est important, mais avec un défilement de quelques pixels seulement, tout continue à fonctionner correctement.
J'ai également essayé de changer certaines propriétés, mais sans succès. Certaines des choses que j'ai faites:
userInteractionEnabled
des vues autres que le défilement et la tablesetNeedsLayout
sur la table, le défilement et la vue principale lorsque scrollViewDidScroll
apparaît.J'ai vu des commentaires sur le comportement inattendu de l'intégration de UITableViews
dans UIScrollViews
, mais je ne vois pas un tel avertissement dans la documentation officielle d'Apple. Je m'attends donc à ce que cela fonctionne.
L'application est uniquement iOS7 +.
Quelqu'un at-il rencontré des problèmes similaires? Pourquoi est-ce et comment puis-je le résoudre? Je pense pouvoir intercepter le geste de tapoter sur la cellule et le transmettre à un délégué personnalisé ou similaire, mais j'aimerais que la table reçoive les événements appropriés} et ainsi ma UITableViewDelegate
le reçoit comme prévu .
Dans Documentation Apple , vous ne devez pas incorporer une UITableView
informations à une UIScrollView
.
Important: vous ne devez pas incorporer d'objets UIWebView ou UITableView dans Objets UIScrollView. Si vous le faites, un comportement inattendu peut en résulter parce que les événements tactiles pour les deux objets peuvent être mélangés et erronés traité.
Votre problème est vraiment lié à ce que votre UIScrollView
fait.
Mais s'il ne s'agit que de masquer la table si nécessaire (c'était mon cas), vous pouvez simplement déplacer UITableView
dans sa vue d'ensemble.
J'ai écrit un petit exemple ici: https://github.com/rvirin/SoundCloud/
laissez la propriété scrollEnabled
de la UITableView intérieure définie sur YES
. Ceci permet à la UITableView
intérieure de gérer correctement les touches de défilement associées à la UIScrollView
.
J'ai rencontré ce même problème et trouvé une solution!
Vous devez définir la valeur delaysTouchesBegan
sur true dans votre vue de défilement pour que celle-ci envoie son geste de défilement ayant échoué (c’est-à-dire le toucher) à ses enfants.
var delaysTouchesBegan: Bool
-Une valeur booléenne déterminant si le destinataire retarde l'envoi des contacts dans une phase de début de sa vue.
Lorsque la valeur de la propriété est YES, la fenêtre suspend la livraison de touchez les objets de la phase UITouchPhaseBegan dans la vue. Si la reconnaissance de geste reconnaît ensuite son geste, ces contacts les objets sont jetés. Si la reconnaissance de geste, cependant, ne le fait pas reconnaît son geste, la fenêtre livre ces objets à la vue dans une toucheBegan: withEvent: message (et éventuellement un suivi touchesMoved: withEvent: message pour l’informer des emplacements actuels de la touche ).
Mais il y a un piège ... ça ne marche pas si vous le faites directement sur le scrollview!
// Does NOT work
self.myScrollview.delaysTouchesBegan = true
Apparemment, il s’agit d’un bogue iOS dans lequel la définition de cette propriété ne fonctionne pas (merci Apple). Cependant, il existe une solution simple: définissez la propriété directement sur le geste panoramique de la vue de défilement. Effectivement, cela a parfaitement fonctionné pour moi:
// This works!!
self.myScrollview.panGestureRecognizer.delaysTouchesBegan = true
Il semble que votre UiTableView ne reconnaisse pas votre tap. Avez-vous essayé d'utiliser cela:
- (BOOL)gestureRecognizer:(UIPanGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UISwipeGestureRecognizer *)otherGestureRecognizer
{
if ([otherGestureRecognizer.view isKindOfClass:[UITableView class]]) {
return YES;
}
return NO;
}
Note d'Apple:
appelé lorsque la reconnaissance de l'un des gestureRecognizer ou otherGestureRecognizer serait bloquée par l'autre. renvoyer YES pour permettre aux deux de se reconnaître simultanément. l'implémentation par défaut renvoie NO (par défaut, deux gestes ne peuvent être reconnus simultanément)
remarque: le retour de YES est garanti pour permettre la reconnaissance simultanée. renvoyer NON n'est pas garanti pour empêcher la reconnaissance simultanée, car le délégué de l'autre geste peut renvoyer OUI
J'espère que ça va aider.
Les identificateurs de mouvements ne fonctionneront pas correctement pour deux vues ou sous-classes de défilement incorporées.
Essayez une solution de contournement:
Utilisez les éléments transparents, personnalisés et superposés de la cellule UIButton
avec la balise ou la sous-classe UIButton
appropriée, ajoutez une propriété de chemin d'index et remplacez-la chaque fois dans la cellule réutilisée.
Ajoutez ce bouton en tant que propriété à votre cellule personnalisée.
Ajoutez une cible pour la UIControlEvent
souhaitée (une ou plusieurs) qui pointe vers votre classe d’adoption de protocole UITableViewDelegate.
Désactiver la sélection dans IB et gérer manuellement la sélection à partir du code.
Cette solution nécessite une attention particulière dans les cas de sélection unique/multiple.
J'ai rencontré un UITableView avec scrollEnabled non dans un code UIScrollView. Je n'ai pas été en mesure de changer facilement la hiérarchie existante, ni d'activer le défilement, mais j'ai trouvé la solution de contournement suivante pour le problème du premier contact:
@interface YourOwnTableView : UITableView
@end
@implementation YourOwnTableView
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
// Note that this is a hack and it can stop working at some point.
// Looks like a table view with scrollEnabled being NO does not handle cancellation cleanly,
// so let's repeat begin/end touch sequence here hoping it'll reset its own internal state properly
// but won't trigger cell selection (the touch passed is in its cancelled phase, perhaps there is a part
// of code inside which actually checks it)
[super touchesBegan:touches withEvent:event];
[super touchesEnded:touches withEvent:event];
}
@end
Encore une fois, ceci est juste une solution de contournement qui fonctionne dans mon cas spécifique. Avoir une vue de tableau dans une vue de défilement est toujours une mauvaise chose.
J'ai le même problème avec UITableView imbriqué et j'ai trouvé une solution pour cela:
innerTableView.scrollEnabled = YES;
innerTableView.alwaysBounceVertical = NO;
Vous devez définir la hauteur de la vue de table interne pour qu'elle corresponde à la hauteur totale de ses cellules afin qu'elle ne défile pas lorsque l'utilisateur fait défiler la vue externe.
J'espère que cela t'aides.
Mon erreur a été d'implémenter la méthode des délégués:
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
au lieu de celui que je voulais implémenter:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Par conséquent, l'appel n'est effectué que sur la deuxième cellule sélectionnée, car c'est à ce moment-là que la première cellule serait sélectionnée de. Super erreur commise à l'aide de la saisie semi-automatique. Juste une pensée pour ceux d'entre vous qui peuvent errer ici sans se rendre compte que vous avez aussi fait la même erreur.
Je vous recommande de rechercher des options telles que ne pas laisser votre cellule en surbrillance lorsque vous faites défiler la vue de défilement extérieure, qui est très facile à gérer et qui est recommandée. Vous pouvez le faire simplement en prenant un booléen et en le basculant dans la méthode ci-dessous
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
Scrollview tente de déterminer si l'intention de l'utilisateur est de faire défiler l'écran ou non, ce qui retarde donc le contact initial. Vous pouvez désactiver cette option en définissant delaysContentTouches
sur NO
.
Dans votre contrôleur de vue, mettez ce code dans cellForRowAtIndexPath
cell.btnRowSelect.tag = indexPath.row
cell.btnRowSelect.addTarget(self, action: Selector("rowSelect:"), forControlEvents: .TouchUpInside)
Ajoutez cette fonction à votre viewController ainsi
func rowSelect (sender:UIButton) {
// "sendet.tag" give you the selected row
// do whatever you want to do in didSelectRowAtIndexPath
}
Cette fonction "rowSelect" fonctionnera comme didSelectRowAtIndexPath où vous obtenez la ligne "indexPath.row" comme "sender.tag"
Que ça, si vue table tactile ça va fonctionner correctement. également avec vue de défilement dans le même contrôleur de vue aussi.
tableview.scrollEnabled = true;
Comme d'autres réponses le disent, vous ne devriez pas placer une tableview dans une scrollview. Une UITableView hérite de toute façon de UIScrollView, alors je suppose que c'est là que les choses deviennent confuses. Ce que je fais toujours dans cette situation est:
1) Sous-classe UITableViewController et incluez une propriété UIView * headView.
2) Dans le parent UIViewController, créez tous les éléments principaux d’un conteneur UIView.
3) Initialisez votre UITableView personnalisé et ajoutez la vue de la tableView au contrôleur de vue en taille réelle
[self.view addSubview: self.myTableView.view];
4) Définissez le headView pour qu’il soit votre gubbins UIView
self.tableView.headView = myHeadViewGubbins.
5) Dans la méthode tableViewController
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger *)section;
Faire:
if ( section == 0 ) {
return self.headView;
}
Maintenant, vous avez une vue de table avec un tas d'autres shizzle au sommet.
Prendre plaisir!
J'ai le même problème, puis référez-vous à "Imbrication des vues de défilement" comme l'a dit lxx.
Vous trouverez un exemple de défilement transversal dans l'application Stocks. La vue de dessus est une vue de tableau, mais la vue de dessous est une vue de défilement horizontal configurée en utilisant le mode de pagination. Tandis que deux de ses trois sous-vues sont des vues personnalisées, la troisième vue (qui contient les articles de presse) est une UITableView (une sous-classe de UIScrollView) qui est une sous-vue de la vue de défilement horizontal. Une fois que vous avez fait défiler horizontalement la vue des actualités, vous pouvez faire défiler son contenu verticalement.
C'est du travail