Domanda

Sto cercando di creare un'interfaccia simile a un trampolino di lancio all'interno della mia app. Sto cercando di utilizzare UIButtons aggiunti a un UIScrollView. Il problema a cui mi sto imbattendo è che i pulsanti non passano alcun tocco su UIScrollView - se provo a scorrere / scorrere e mi capita di premere il pulsante, non si registra per UIScrollView, ma se faccio scorrere lo spazio tra pulsanti funzionerà. I pulsanti fanno clic / funzionano se li tocco.

Esiste una proprietà o un'impostazione che forza il pulsante a inviare gli eventi touch fino al suo genitore (superview)? I pulsanti devono essere aggiunti a qualcos'altro prima di aggiungere UIScrollView?

Ecco il mio codice:

//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];
È stato utile?

Soluzione

Affinché UIScrollView determini la differenza tra un clic che passa alle sue viste di contenuto e un tocco che si trasforma in un colpo o pizzico, è necessario ritardare il tocco e vedere se il dito si è mosso durante quel ritardo. Impostando delaysContentTouches su NO nell'esempio sopra, impedisci che ciò accada. Pertanto, la vista di scorrimento passa sempre il tocco al pulsante, invece di annullarlo quando si scopre che l'utente sta eseguendo un gesto di scorrimento. Prova a impostare ritardiContentTouches su YES .

Potrebbe anche essere una buona idea, strutturalmente, aggiungere tutte le viste da ospitare nella vista di scorrimento a una vista di contenuto comune e utilizzare solo quella vista come vista secondaria della vista di scorrimento.

Altri suggerimenti

La soluzione che ha funzionato per me ha incluso:

  1. Impostazione di canCancelContentTouches in UIScrollView su YES .
  2. Estensione di UIScrollView per sovrascrivere i tocchi ShouldCancelInContentView: (UIView *) view per restituire YES quando view è un < code> UIButton .

Secondo la documentazione tocca TohouldCancelInContentView restituisce " per annullare ulteriori tocchi per visualizzare, NO per visualizzare continua a ricevere quei messaggi. Il valore restituito predefinito è YES se view non è un oggetto UIControl ; in caso contrario, restituisce NO . "

Poiché UIButton è un UIControl l'estensione è necessaria per rendere canCancelContentTouches per rendere effettive le operazioni che consentono lo scorrimento.

Ho un caso simile a quello di un numero di pulsanti su UIScrollView e voglio scorrere questi pulsanti. All'inizio, ho eseguito la sottoclasse di UIScrollView e UIButton. Tuttavia, ho notato che il mio UIScrollView della sottoclasse non ha ricevuto l'evento touchesEnded, quindi sono passato solo alla sottoclasse 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 gestisce molti eventi stessi. È necessario gestire i tocchi DidEnd e premere test per i pulsanti all'interno di UIScrollView manualmente.

OK, ecco la tua risposta:

UIButton sottoclasse. (NOTA: chiama [super ....] all'inizio di ogni sostituzione.

  • Aggiungi una proprietà. Uno di tipo BOOL (chiamato enableToRestore)
  • Aggiungi una proprietà. Uno di tipo CGPoint (chiamato startTouchPosition)
  • in awakeFromNib e initWithFrame, imposta il enableToRestore in isEnabled proprietà)
  • Sostituisci " touchesBegan: withEvent: " per memorizzare l'inizio del tocco Posizione.
  • Sostituisci " touchesMoved: withEvent: " a controlla se c'è orizzontale movimento.
  • Se SÌ, impostare abilitato su NO e selezionato su NO.

Codice di esempio:

- (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];
    } 
}

Questo attiverà UIScrollView.

Sottoclasse UIScrollView. (NOTA: chiama [super ....] all'inizio di ogni sostituzione.

  • Sostituisci entrambi " touchesEnded: withEvent: " e " touchesCancelled: withEvent: "
  • Nella sostituzione, ripristina il flag abilitato per tutte le visualizzazioni secondarie (e le relative visualizzazioni secondarie).
  • NOTA: utilizzare una categoria e aggiungere il metodo a 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];
}
  • Nella categoria:

.

-(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 Nota: non ho mai avuto risposta 3 per funzionare. Allo stesso modo: setDelaysContentTouches: NO (impostato nel controller di visualizzazione o da qualche parte) deve essere impostato per i migliori risultati sulla risposta 4. Ciò fornisce una risposta molto rapida ai pulsanti. Impostazione setDelaysContentTouches: SÌ influisce notevolmente (150 ms) sui tempi di risposta ai pulsanti e rende impossibile un tocco leggero e veloce.

Un altro modo è:
1. Sostituisci il pulsante con un semplice UIView personalizzato
2. Inserisci il flag " userInterationEnable = yes; " sul metodo init
3. Nella vista sovrascrivere il metodo UIResponder " touchesEnded " qui puoi attivare l'azione che ti serve come un pulsante.

Nella mia esperienza, la prima risposta, vale a dire, semplicemente impostando delaysContentTouches su YES , non cambia nulla riguardo al problema. I pulsanti non forniranno comunque risultati di tracciamento alla vista di scorrimento. La terza risposta è sia semplice che molto utilizzabile. Grazie sieroaoj!

Tuttavia, affinché la terza risposta funzioni, è necessario anche ritardiContentTouches impostato su YES . Altrimenti il ??metodo touchesEnded verrà chiamato anche per il tracciamento all'interno della vista. Pertanto ho potuto risolvere il problema:

  
      
  1. Sostituisci il pulsante de con una semplice UIView personalizzata
  2.   
  3. Metti il ??flag " userInterationEnable = yes; " sul metodo init
  4.   
  5. Nella vista sovrascrivere il metodo UIResponder "touchesEnded" Qui   puoi attivare l'azione
  6.   

Quarto. imposta ritardiContentTouches su YES

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top