34 votes

UIScrollview with UIButtons - comment recréer un tremplin?

Je suis en train de créer un tremplin-comme l'interface au sein de mon application. Je suis en train d'utiliser UIButtons ajouté à un UIScrollView. Le problème, je suis en cours d'exécution pour est avec les boutons de ne pas passer n'importe quelle touche à l'UIScrollView - si j'essaie de film/diapositive et appuyez sur le bouton, il ne veut pas s'inscrire pour le UIScrollView, mais si j'ai faites glisser vers l'espace entre les boutons, il va fonctionner. Les boutons de la souris/du travail si je les touche.

Est-il un bien ou un réglage des forces sur le bouton pour envoyer les événements tactiles jusqu'à son parent (superview)? Les boutons doivent être ajoutés à autre chose avant d'être ajoutés à la 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];

44voto

Roman K Points 889

La Solution qui a fonctionné pour moi:

  1. Paramètre canCancelContentTouches en UIScrollView de YES.
  2. S'étendant UIScrollView pour remplacer touchesShouldCancelInContentView:(UIView *)view de rendement YES lorsque view est UIButton.

Selon la documentation, touchesShouldCancelInContentView retours "YES annuler touche supplémentaire de messages à afficher, NO d'avoir la vue de continuer à recevoir ces messages. La valeur par défaut valeur retournée est - YES si la vue n'est pas un UIControl objet; sinon, elle renvoie NO."

Depuis UIButton est UIControl de la prolongation est nécessaire pour obtenir de l' canCancelContentTouches prennent effet qui permet de défilement.

28voto

Brad Larson Points 122629

Pour UIScrollView afin de déterminer la différence entre un clic qui passe à travers le contenu de la vue(s) et d'une touche qui se transforme en un glissement de doigt ou de pincement, il doit retarder le toucher et de voir si votre doigt est déplacé au cours de ce délai. En définissant delaysContentTouches de NO dans votre exemple ci-dessus, vous êtes empêcher que cela se produise. Par conséquent, le défilement de l'affichage est toujours en passant le toucher pour le bouton, au lieu de l'annuler quand il s'avère que l'utilisateur effectue un mouvement de balayage. Essayez de vous fixer delaysContentTouches de YES.

Il pourrait également être une bonne idée, structurellement, ajouter tous les points de vue pour être hébergé dans un défilement d'affichage d'un contenu commun à vue et de n'utiliser que l'un est le défilement de la vue sous-vue.

5voto

Richard Chen Points 237

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é pour uniquement la sous-classe 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
 

1voto

Roger Nolan Points 10248

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.

1voto

Steven Noyes Points 1216

OK, voici votre réponse:

Sous-Classe UIButton. (REMARQUE: appel [super ....] au début de chaque remplacement.

  • Ajouter une propriété. L'une de type BOOL (appelé enableToRestore)
  • Ajouter une propriété. L'une de type CGPoint (appelé startTouchPosition)
  • dans le awakeFromNib et initWithFrame, définissez la enableToRestore à la isEnabled de la propriété)
  • Remplacer "touchesBegan: withEvent:" pour stocker le début de la touche position.
  • Remplacer "touchesMoved: withEvent:" à vérifiez pour voir si il est à l'horizontale mouvement.
  • Si OUI, la valeur activé ou PAS et sélectionné ou PAS.

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 la UIScrollView.

Sous-Classe UIScrollView. (REMARQUE: appel [super ....] au début de chaque remplacement.

  • Remplacer les deux "touchesEnded: withEvent:" et "touchesCancelled: withEvent:"
  • Dans le remplacement, réinitialiser tous les sous-vues (et leurs sous-vues) a permis drapeau.
  • REMARQUE: l'Utilisation d'une Catégorie et ajoutez la méthode de 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];
        }
    }
}

MODIFIER Note: je n'ai jamais eu de Réponse de 3 à travailler. De la même manière: le setDelaysContentTouches:AUCUN (défini dans le point de vue du contrôleur ou de quelque part) est à définir pour de meilleurs résultats sur la Réponse 4. Cela fournit une réponse très rapide aux boutons. Réglage setDelaysContentTouches:OUI met un sérieux impact (150ms) sur les temps de réponse pour les boutons et le rend léger,rapide touchant pas possible.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X