2011-05-31 13 views
15

Da una visione semplicistica ho una vista personalizzata che contiene alcuni bitmap l'utente può trascinare intorno e ridimensionare.Overriding onTouchEvent competere con ScrollView

Il mio modo di fare questo è abbastanza standard come in sovrascrivo onTouchEvent nel mio CustomView e controllare se l'utente sta toccando all'interno di un'immagine, ecc

Il mio problema arriva quando voglio mettere questo CustomView in uno ScrollView . Funziona, ma ScrollView e CustomView sembrano competere per MotionEvents, cioè quando provo a trascinare un'immagine si muove lentamente o la vista scorre.

Sto pensando che potrebbe essere necessario estendere un ScrollView così posso eseguire l'override suInterceptTouchEvent e far sapere se l'utente si trova entro i limiti di un'immagine per non provare a scorrere. Ma poi perché ScrollView è più in alto nella gerarchia come potrei accedere allo stato attuale di CustomView?

C'è un modo migliore?

+1

Penso che la visualizzazione personalizzata dovrebbe attuare onInterceptTouchEvent e non lo ScrollView al fine di decidere se deve gestire l'evento di tocco di conseguenza e poi mani fuori l'evento, se non decide per gestirlo. – Nadewad

risposta

38

Normalmente Android utilizza una pressione prolungata per iniziare un trascinamento in casi come questi in quanto aiuta disambiguare quando l'utente intende trascinare un elemento contro di scorrimento contenitore dell'elemento. Ma se si dispone di un segnale inequivocabile quando l'utente inizia a trascinare un elemento, provare getParent().requestDisallowInterceptTouchEvent(true) dalla visualizzazione personalizzata quando si sa che l'utente sta iniziando un trascinamento. (Documenti per questo metodo here.) Ciò impedirà a ScrollView di intercettare gli eventi di tocco fino alla fine del gesto corrente.

+2

Grazie mille, ha funzionato! C'è una grande conoscenza di api qui su SO :) – brk3

+1

Aiuta quando le persone mantengono queste cose nella piattaforma stessa rispondendo alle tue domande. ;) – adamp

+0

Grazie per questo :) –

8

Nessuna delle soluzioni trovate lavorato "out of the box" per me, probabilmente perché la mia vista personalizzata estende Vista, non ViewGroup, e quindi non in grado di implementare onInterceptTouchEvent.

anche chiamando getParent().requestDisallowInterceptTouchEvent(true) stato gettando NPE, o fare nulla.

Infine, questa è come ho risolto il problema:
Dentro la vostra abitudine onTouchEvent chiamata requestDisallow... quando la vista si prenderà cura della manifestazione. Per esempio:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    Point pt = new Point((int)event.getX(), (int)event.getY()); 
    if (event.getAction() == MotionEvent.ACTION_DOWN) { 
     if (/*this is an interesting event my View will handle*/) { 
      // here is the fix! now without NPE 
      if (getParent() != null) { 
       getParent().requestDisallowInterceptTouchEvent(true); 
      } 

      clicked_on_image = true; 
     } 
    } else if (event.getAction() == MotionEvent.ACTION_MOVE) { 
     if (clicked_on_image) { 
      //do stuff, drag the image or whatever 
     } 
    } else if (event.getAction() == MotionEvent.ACTION_UP) { 
     clicked_on_image = false; 
    } 
    return true; 
} 

Ora la mia vista personalizzata funziona bene, la manipolazione alcuni eventi e lasciando ScrollView prendere quelli che non si preoccupano. Ho trovato la soluzione qui: http://android-devblog.blogspot.com.es/2011/01/scrolling-inside-scrollview.html

Spero che aiuti.

+0

, che ha aiutato! :) Ma suggerisco di cambiare il controllo NullPointer a: ViewParent parent = getParent(); if (parent! = Null) { parent.requestDisallowInterceptTouchEvent (true); } – netzpurist

+0

grazie a questo ha funzionato perfettamente – Ryan

0

C'è un evento Android chiamato MotionEvent.ACTION_CANCEL (valore = 3). Tutto ciò che faccio è sovrascrivere il metodo onTouchEvent del mio controllo personalizzato e acquisire questo valore. Se rilevo questa condizione, rispondo di conseguenza.

Ecco il codice:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    if(isTouchable) { 
     int maskedAction = event.getActionMasked();   
     if (maskedAction == MotionEvent.ACTION_DOWN) { 
      this.setTextColor(resources.getColor(R.color.octane_orange)); 
      initialClick = event.getX(); 
     } else if (maskedAction == MotionEvent.ACTION_UP) { 
      this.setTextColor(defaultTextColor); 
      endingClick = event.getX(); 
      checkIfSwipeOrClick(initialClick, endingClick, range); 
     } else if(maskedAction == MotionEvent.ACTION_CANCEL) 
      this.setTextColor(defaultTextColor); 
    } 
    return true; 
}