2013-06-30 11 views
6

Sto cercando di creare un contenitore stradale e sto di mira API 14+Perché chiamare setScaleX durante il gesto di zoom con pinch causa uno sfarfallio?

Nel mio onScale (sto usando lo ScaleGestureDetector per rilevare pinch-zoom) che sto facendo qualcosa di simile:

public boolean onScale (ScaleGestureDetector detector) { 
    float scaleFactor = detector.getScaleFactor(); 
    setScaleX(getScaleX() * scaleFactor); 
    setScaleY(getScaleY() * scaleFactor); 

    return true; 
}; 

Funziona ma lo zoom non è regolare. In effetti, lampeggia notevolmente.

Ho anche provato con il livello hardware pensando che il ridimensionamento si sarebbe verificato sulla GPU una volta caricata la trama e quindi sarebbe super veloce. Ma non ha fatto alcuna differenza: lo zoom non è liscio e talvolta lampeggia a volte stranamente.

Cosa sto sbagliando?

+0

Non voglio inviare una risposta, perché non posso testare la soluzione, ma è possibile, quindi prendi un lokk qui: http://stackoverflow.com/questions/5790503/can-we-use- scale-gesture-detector-per-pinch-zoom-in-android. Dopo averlo provato, torna qui e comunicaci se è stato risolto il problema. Dai un'occhiata all'ultima risposta. – g00dy

+1

Sono consapevole di questa soluzione ma presenta difetti critici: ridimensiona solo la tela per il disegno: nessuna delle clip e dei punti di contatto vengono trasformati. ed è per questo che ho usato setScale che cambia la matrice di trasformazione al contenitore e regola i rects delle clip e trasforma le coordinate di tocco in modo appropriato (senza che tu debba fare da solo il Matrix Matrix) –

+1

Puoi condividere un po 'di più del codice? Specificamente le routine di disegno reali. Hai provato qualche profilo per vedere dove il disegno è in difficoltà? Guarderei minimizzando (possibilmente a zero) la quantità di allocazioni oggetto in stretti cicli di disegno. So che questi sono punti generali (forse ovvi), ma è difficile dire di più senza ulteriori informazioni. – snowdragon

risposta

0

Secondo con la tua domanda, i metodi e le setScaleXsetScaleY sfarfallio perché svolgono all'interno del "disegno per una visualizzazione" contesto (setScaleX e setScaleY appartengono a View). Documentazione dice:

Option "a", il disegno di una vista, è la scelta migliore quando si vuole disegnare una grafica semplice che non hanno bisogno di cambiare in modo dinamico e non fanno parte di un gioco ad alta intensità di prestazioni. Ad esempio, si dovrebbe disegnare la grafica in una vista quando si desidera visualizzare un grafico statico o un'animazione predefinita, all'interno di un'applicazione altrimenti statica.

D'altra parte, se si segue la risposta @ g00dy, si esibiranno all'interno del "disegno a una tela di canapa" contesto (scale() appartiene Canvas). La documentazione dice:

L'opzione "b", che consente di disegnare su una tela, è preferibile quando l'applicazione deve ridisegnarsi regolarmente. Applicazioni come i videogiochi dovrebbero essere disegnate sulla tela per conto proprio.

Un gesto pizzico è intenso, quindi deve essere eseguita in Opzione b ... così si dovrebbe utilizzare la soluzione @ g00dy o qualsiasi approccio del genere.

Here è la documentazione citata.

Spero che ti aiuti.

+1

setScaleX (o alpha o tranx/y) sono ottimizzati non creando la ricreazione degli elenchi di visualizzazione perché tutto ciò che deve fare è invalidare l'elenco di visualizzazione del genitore. e in secondo luogo usando i livelli si suppone che faccia il ridimensionamento sulla GPU. In entrambi i casi, in teoria, dovrebbe essere più veloce del ridisegnare ogni frame (che equivale a ricreare il DL). –

+1

hai letto anche il mio commento al commento di google? questa soluzione è falsificarla perché non sono interessante nel solo mostrare lo zoom (che è un problema banale) ma creare un generico contenitore di zoom (problema più difficile) in cui tutti i bambini hanno clip e punti di contatto appropriati trasformati (oltre a mostrare lo zoom). Posso farlo assumendo totalmente il controllo della manipolazione della matrice del contenitore, ma volevo evitarlo perché sono le proprietà scaleX e scaleY che ci sono in primo luogo (introdotto in api 11+) –

+0

Beh ... prima, la tua domanda è " perché sfarfallio ", quindi hai la tua risposta, in realtà non mi interessa cosa vuoi fare. E se non ti piace la soluzione @ g00dy, come ho detto prima, puoi usare qualsiasi altro approccio del genere. Secondo, Niente è più veloce di "disegnare su una tela", ecco perché le aziende di videogiochi usano sempre la tela per aggiornare dinamicamente le sue cornici grafiche. –

3

Lo sfarfallio assomiglia alla vista che si muove avanti e indietro tra zoom e non zoom? Ciò è dovuto al fatto che lo ScaleGestureDetector gestisce eventi di movimento dalla stessa vista che stai ridimensionando. Quando esegui il setScaleX() che modifica le coordinate del tocco, che attiva un nuovo evento tocco interpretato come invertire lo zoom appena applicato.

Inserire il contenuto della vista zoomabile all'interno di un singolo figlio FrameLayout e impostare la scala su quella vista.

ho postato un layout pinch-zoom a lavorare qui: https://gist.github.com/anorth/9845602

0

Ho affrontato lo stesso problema.Il compito era:

  • creare tela (in sottoclasse di vista o di SurfaceView, non importa)
  • disegnare su di esso alcune immagini e grafici primitive (con metodi drawBitmap(), drawLine() ...)
  • make tela scorrevole e scallable

suppongo, non c'è bisogno di mostrare tutto il codice di classe qui.

La soluzione del problema con lo sfarfallio durante il gesto di scalling era molto semplice. Basta inserire la procedura di ridimensionamento nel metodo onScaleEnd().

private class MyScaleGestureListener implements OnScaleGestureListener 
{ 
    public boolean onScale(ScaleGestureDetector detector) 
    { 
     scaleFactor *= detector.getScaleFactor(); // class variable of type float 
     if (scaleFactor > 5) scaleFactor = 5;  // some limitations 
     if (scaleFactor < 1) scaleFactor = 1; 
     return true; 
    } 
    public boolean onScaleBegin(ScaleGestureDetector detector) 
    { return true;} 

    public void onScaleEnd(ScaleGestureDetector detector) 
    { 
     setScaleX(scaleFactor); setScaleY(scaleFactor); 
     invalidate();  // it seems to me - no effect 
    } 
} 

Testato su dispositivo reale Samsung GALAXY S III mini.