Question

J'essaie de créer une interface semblable à un tremplin dans mon application. J'essaie d'utiliser les boutons UIB ajoutés à un UIScrollView. Le problème que je rencontre est lié au fait que les boutons ne transmettent aucun contact à UIScrollView. Si j'essaie de glisser / glisser et que j'appuie sur le bouton, cela ne s'inscrit pas dans UIScrollView, mais si je balaye l'espace entre boutons cela fonctionnera. Les boutons cliquent / fonctionnent si je les touche.

Existe-t-il une propriété ou un paramètre obligeant le bouton à envoyer les événements tactiles à son parent (superview)? Les boutons doivent-ils être ajoutés à quelque chose avant d’être ajoutés à UIScrollView?

Voici mon code:

//init scrolling area
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 480)];
scrollView.contentSize = CGSizeMake(480, 1000);
scrollView.bounces = NO;
scrollView.delaysContentTouches = NO;

//create background image
UIImageView *rowsBackground = [[UIImageView alloc] initWithImage:[self scaleAndRotateImage:[UIImage imageNamed:@"mylongbackground.png"]]];
rowsBackground.userInteractionEnabled = YES;

//create button
UIButton *btn = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
btn.frame = CGRectMake(100, 850, 150, 150);
btn.bounds = CGRectMake(0, 0, 150.0, 150.0);
[btn setImage:[self scaleAndRotateImage:[UIImage imageNamed:@"basicbutton.png"]] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];

//add "stuff" to scrolling area
[scrollView addSubview:rowsBackground];
[scrollView addSubview:btn];

//add scrolling area to cocos2d
//this is just a UIWindow
[[[Director sharedDirector] openGLView] addSubview:scrollView];

//mem-mgmt
[rowsBackground release];
[btn release];
[scrollView release];
Était-ce utile?

La solution

Pour que UIScrollView détermine la différence entre un clic qui passe dans sa vue de contenu et un contact qui se transforme en un glissement ou un pincement, il doit retarder le toucher et voir si votre doigt a bougé pendant ce délai. En définissant delayContentTouches sur NO dans votre exemple ci-dessus, vous empêchez cela de se produire. Par conséquent, la vue de défilement transmet toujours le toucher au bouton au lieu de l’annuler s’il s’avère que l’utilisateur effectue un geste de balayage. Essayez de définir delayContentTouches sur OUI .

Il pourrait également être judicieux, structurellement, d'ajouter toutes les vues à héberger dans votre vue de défilement à une vue de contenu commune et de n'utiliser que cette vue en tant que sous-vue de la vue de défilement.

Autres conseils

La solution qui a fonctionné pour moi inclut:

  1. Définition de canCancelContentTouches dans UIScrollView sur OUI .
  2. Extension de UIScrollView pour remplacer touchesShouldCancelInContentView: (UIView *) Voir pour renvoyer YES lorsque view est un < code> UIButton .

Selon la documentation , toucheShouldCancelInContentView renvoie " OUI " pour annuler d'autres messages tactiles à afficher, NON pour que ce dernier continue à recevoir ces messages. La valeur renvoyée par défaut est YES si view n'est pas un objet UIControl . sinon, il retourne NO . "

Puisque UIButton est un UIControl , l'extension est nécessaire pour que canCancelContentTouches prenne effet, ce qui permet le défilement.

J'ai le même cas qu'un certain nombre de boutons sur un UIScrollView et je souhaite les faire défiler. Au début, j'ai sous-classé UIScrollView et UIButton. Cependant, j’ai remarqué que mon sous-groupe UIScrollView ne recevait pas l’événement touchesEnded, j’ai donc changé en un seul sous-groupe, UIButton.


@interface MyPhotoButton : UIButton {
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
@end

@implementation MyPhotoButton

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];
    [self setEnabled:NO];
    [self setSelected:NO];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    [self setEnabled:YES];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    [self setEnabled:YES];
}

@end

UIScrollView gère un grand nombre d'événements lui-même. Vous devez gérer touchesDidEnd et cliquer sur test pour les boutons à l'intérieur de UIScrollView manuellement.

OK voici votre réponse:

Sous-classe UIButton. (REMARQUE: appelez [super ....] au début de chaque substitution.

  • Ajouter une propriété. Un de type BOOL (appelé enableToRestore)
  • Ajouter une propriété. Un de type CGPoint (appelé startTouchPosition)
  • dans le awakeFromNib et initWithFrame, définissez le enableToRestore to isEnabled propriété)
  • Remplacer " toucheBegan: withEvent: " pour stocker le début de la touche position.
  • Remplacer " touchesMoved: withEvent: " à vérifier pour voir s'il y a horizontal mouvement.
  • Si OUI, définissez Activé sur NON et sélectionné à NO.

Exemple de code:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *touch = [touches anyObject];

    [super touchesBegan:touches withEvent:event];
    [self setStartTouchPosition:[touch locationInView:self]];
}


//
// Helper Function
//
- (BOOL)isTouchMovingHorizontally:(UITouch *)touch 
{
    CGPoint currentTouchPosition = [touch locationInView:self];
    BOOL      rValue = NO;

    if (fabsf([self startTouchPosition].x - currentTouchPosition.x) >= 2.0) 
    {
        rValue = YES;
    }

    return (rValue);
}

//
// This is called when the finger is moved.  If the result is a left or right
// movement, the button will disable resulting in the UIScrollView being the
// next responder.  The parrent ScrollView will then re-enable the button
// when the finger event is ended of cancelled.
//
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesMoved:touches withEvent:event];
    if ([self isTouchMovingHorizontally:[touches anyObject]]) 
    {
        [self setEnabled:NO];
        [self setSelected:NO];
    } 
}

Ceci activera UIScrollView.

Sous-classe UIScrollView. (REMARQUE: appelez [super ....] au début de chaque substitution.

  • Remplacez les deux "touchesEnded: withEvent: " et "toucheCancelled: withEvent:"
  • Dans la substitution, réinitialisez l'indicateur activé de toutes les sous-vues (et de leurs sous-vues).
  • REMARQUE: utilisez une catégorie et ajoutez la méthode à UIView:

.

- (void) restoreAllEnables
{
    NSArray   *views = [self subviews];

    for (UIView *aView in views)
    {
        if ([aView respondsToSelector:@selector(restoreEnable)])
        {
            [aView restoreEnable];
        }
    }
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self restoreAllEnables];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self restoreAllEnables];
}
  • Dans la catégorie:

.

-(void) restoreEnable
{
    NSArray   *views = [self subviews];

    if ([self respondsToSelector:@selector(enableToRestore)])
    {
        [self setEnabled:[self enableToRestore]];
    }

    for (UIView *aView in views)
    {
        if ([aView respondsToSelector:@selector(restoreEnable)])
        {
            [aView restoreEnable];
        }
    }
}

EDIT Remarque: je n'ai jamais eu la réponse 3 au travail. De même: setDelaysContentTouches: NO (défini dans le contrôleur de vue ou ailleurs) doit être défini pour obtenir les meilleurs résultats en réponse 4. Ceci fournit une réponse très rapide aux boutons. La définition de setDelaysContentTouches: YES a un impact important (150 ms) sur le temps de réponse des boutons et rend impossible tout contact rapide et léger.

Une autre façon est:
1. Remplacez le bouton par un simple UIView personnalisé 2. Placez le drapeau " userInterationEnable = yes; " sur la méthode init
3. Dans la vue, remplacez la méthode UIResponder " touchesEnded " Ici, vous pouvez déclencher l'action dont vous avez besoin comme un bouton.

Selon mon expérience, la première réponse, c’est-à-dire que le simple fait de définir delayContentTouches sur YES , ne modifie en rien le problème. Les boutons ne transmettent toujours pas les résultats du suivi à la vue de défilement. La troisième réponse est à la fois simple et très utilisable. Merci sieroaoj!

Toutefois, pour que la troisième réponse fonctionne, vous devez également définir delayContentTouches sur YES . Sinon, la méthode touchesEnded sera également appelée pour effectuer un suivi dans la vue. Par conséquent, je pourrais résoudre le problème en:

  
      
  1. Remplacez le bouton par un simple UIView personnalisé
  2.   
  3. Placez le drapeau " userInterationEnable = yes; " sur la méthode init
  4.   
  5. Dans la vue, remplacez la méthode UIResponder " touchesEnded " ici   vous pouvez déclencher l'action que vous
  6.   

Quatrième. définir delayContentTouches sur OUI

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top