Aujourd'hui, pendant mon temps libre, j'ai fait des recherches assez complètes sur la façon de voler les touches d'une UIScrollView et de les envoyer instantanément à une sous-vue spécifique, tout en conservant le comportement par défaut pour le reste de la vue défilante. Considérons le cas d'une UIPickerView à l'intérieur d'une UITableView. Le comportement par défaut est que si vous faites glisser votre doigt sur la vue du sélecteur, la vue défilante défilera et la vue du sélecteur restera inchangée.
La première chose que j'ai essayée, c'est de remplacer
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
et simplement ne pas permettre à l'UIScrollView d'annuler les touches à l'intérieur de la vue du sélecteur. Cette méthode fonctionne, mais elle a un effet secondaire désagréable. Vous aimeriez que la vue du sélecteur réagisse immédiatement, et vous devrez donc définir le paramètre delaysContentTouches
à NO. Le problème est que vous ne voulez pas que le reste de la vue tableau réponde immédiatement, car si c'est le cas, la cellule de la vue tableau sera toujours mise en évidence pendant quelques millisecondes avant que le défilement ne commence.
La deuxième chose que j'ai essayée est de remplacer
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
parce que j'avais lu que la vue défilante se renvoie toujours elle-même, de sorte qu'elle "vole" les touches de ses sous-vues et les envoie plus tard à la sous-vue si elles n'étaient pas intéressantes pour la vue défilante. Cependant, ce n'est plus vrai. L'implémentation par défaut de hitTest:withEvent : de UIScrollView renvoie en fait la sous-vue qui devrait recevoir le toucher. Au lieu de cela, elle utilise des reconnaisseurs de gestes pour intercepter les touchers.
La troisième chose que j'ai tentée a donc été d'implémenter ma propre reconnaissance de gestes et de faire en sorte qu'elle échoue si le toucher est en dehors de la vue du sélecteur et qu'elle réussisse sinon. Ensuite, j'ai configuré tous les dispositifs de reconnaissance des gestes de la vue défilante pour qu'ils échouent si mon dispositif de reconnaissance des gestes échoue en utilisant le code suivant :
for (UIGestureRecognizer * gestureRecognizer in self.tableView.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:myRecognizer];
}
Cela permet en fait de voler les touches de la vue de défilement, mais la vue du sélecteur ne les reçoit jamais. J'ai donc pensé que je pourrais peut-être envoyer tous les touchers que ma reconnaissance de gestes reçoit en utilisant ce code :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
[touch.view touchesBegan:touches withEvent:event];
}
Le code ci-dessus est une version simplifiée. Je m'assure également que la vue est une vue de sélection (ou une de ses sous-vues) et je définis l'état approprié pour la reconnaissance des gestes comme je l'ai mentionné ci-dessus. J'ai également fait la même chose pour annulé, terminé et déplacé. Cependant, la vue du sélecteur ne répondait toujours pas.
J'ai également essayé une dernière chose avant de retourner à mon travail habituel. Lors de mes recherches approfondies sur Internet, j'ai lu que les UIScrollViews imbriquées fonctionnaient comme par magie depuis la version 3.x. J'ai donc essayé de placer ma vue de sélection dans une UIScrollView imbriquée et de lui attribuer les propriétés suivantes :
scrollView.delaysContentTouches = NO;
scrollView.canCancelContentTouches = NO;
Comme on pouvait s'y attendre, la vue de défilement externe n'a pas traité la vue de défilement interne différemment de la vue du sélecteur, de sorte que la vue de défilement interne n'a pas reçu les touches. J'ai pensé que c'était un pari risqué, mais il était assez simple à mettre en œuvre, alors j'ai pensé qu'il valait la peine d'essayer.
Ce que je sais, c'est que UIScrollView a une reconnaissance de gestes nommée UIScrollViewDelayedTouchesBeganGestureRecognizer
qui intercepte les touches et les envoie à la sous-vue appropriée après 150 ( ?) ms. Je pense que je devrais être capable d'écrire une reconnaissance similaire qui fait échouer les reconnaissances par défaut de la vue défilante et qui, au lieu de retarder les touchers, les envoie immédiatement à la vue du sélecteur. Donc si quelqu'un sait comment écrire un tel recognizer, merci de me le faire savoir et si vous avez une autre solution au problème, vous êtes les bienvenus pour la partager également.
Merci d'avoir lu l'ensemble de la question et même si vous ne connaissez pas la réponse, vous pouvez toujours voter en faveur de la question afin qu'elle reçoive plus d'attention (en espérant que quelqu'un puisse y répondre). Merci ! :)