2014-12-01 5 views

risposta

7

In primo luogo, è necessario ottenere il drawable dalla vista.

private void forceRippleAnimation(View v, float x, float y){ 
    Drawable background = v.getBackground(); 
    if(background instanceof RippleDrawable){ 
    RippleDrawable ripple = (RippleDrawable)background; 
    ripple.setHotspot(x, y); 
    ripple.setVisible (true, true); 
    } 

} 

Metodo setHotspot(x,y); viene utilizzato per impostare da dove l'animazione ripple inizierà, altrimenti se non impostato, il RippleDrawable prenderà le Rect dove risiede (cioè il Rect della visualizzazione in cui è impostato come sfondo) e inizierà l'effetto a catena dal centro.

setVisible(true, true) renderà visibile il drawable e l'ultimo argomento imporrà l'animazione indipendentemente dallo stato di drawable corrente.

+0

Nizza. L'animazione funziona come un clic o un clic lungo (ovvero la selezione rimarrà)? –

+0

Dovresti provare a impostare lo stato disegnabile a livello di codice. Come: 'int [] state = new int [] {android.R.attr.state_pressed}' e 'ripple.setState (stato);'. Non ho provato se dovessi accoppiarlo con 'setVisible (true, true)'. Poiché il drawable viene automaticamente aggiornato/animato in base alle modifiche dello stato. –

+0

Non capisco. Puoi per favore postare un campione per entrambi i comportamenti? –

23

Sì, c'è! Per attivare un ripple programmaticamente, è necessario impostare lo stato di RippleDrawable con setState(). La chiamata setVisible() fa NON lavoro!


La soluzione

Per mostrare il ripple è necessario impostare lo stato di premuto e ha permesso allo stesso tempo:

rippleDrawable.setState(new int[] { android.R.attr.state_pressed, android.R.attr.state_enabled }); 

L'ondulazione verrà mostrato purché tali Stati sono impostato. Quando si desidera nascondere il ripple di nuovo impostare lo stato a un vuoto int[]:

rippleDrawable.setState(new int[] { }); 

È possibile impostare il punto da cui emana l'ondulazione chiamando setHotspot().


Come funziona

ho debug molto e studiato il codice sorgente di RippleDrawable su e giù fino a quando mi sono reso conto che l'ondulazione viene effettivamente attivato in onStateChange(). Chiamare setVisible() non ha alcun effetto e non fa mai apparire alcun ripple.

La parte rilevante del codice sorgente di RippleDrawable è questo:

@Override 
protected boolean onStateChange(int[] stateSet) { 
    final boolean changed = super.onStateChange(stateSet); 

    boolean enabled = false; 
    boolean pressed = false; 
    boolean focused = false; 

    for (int state : stateSet) { 
     if (state == R.attr.state_enabled) { 
      enabled = true; 
     } 
     if (state == R.attr.state_focused) { 
      focused = true; 
     } 
     if (state == R.attr.state_pressed) { 
      pressed = true; 
     } 
    } 

    setRippleActive(enabled && pressed); 
    setBackgroundActive(focused || (enabled && pressed)); 

    return changed; 
} 

Come si può vedere se sia il permesso e l'attributo pressato vengono impostate allora sia il ripple e lo sfondo saranno attivati ​​e il ripple sarà visualizzato. Inoltre, finché si imposta lo stato attivo, verrà attivato anche lo sfondo. Con questo è possibile attivare l'ondulazione e avere lo sfondo cambiare colore in modo indipendente.

Se si è interessati è possibile visualizzare l'intero codice sorgente di RippleDrawablehere.

11

I incorporato/unito le risposte da @Xaver Kapeller e @Nikola Despotoski sopra:

protected void forceRippleAnimation(View view) 
{ 
    Drawable background = view.getBackground(); 

    if(Build.VERSION.SDK_INT >= 21 && background instanceof RippleDrawable) 
    { 
     final RippleDrawable rippleDrawable = (RippleDrawable) background; 

     rippleDrawable.setState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}); 

     Handler handler = new Handler(); 

     handler.postDelayed(new Runnable() 
     { 
      @Override public void run() 
      { 
       rippleDrawable.setState(new int[]{}); 
      } 
     }, 200); 
    } 
} 

per forzare a livello di codice un effetto a catena a comando, è sufficiente chiamare forceRippleAnimation(), passando la vista che si desidera ad incresparsi come un parametro.

+0

cambia in if (Build.VERSION.SDK_INT> = 21 && background instanceof RippleDrawable), a causa di un arresto anomalo su Android <21 – iscariot

+0

@iscariot. Buona chiamata L'ho appena cambiato. – Luke

+0

Per ripristinare lo stato sui valori correnti chiama 'rippleDrawable.setState (view.getDrawableState())' invece di forzare lo stato vuoto impostato. –

5

Ecco combinazione di setHotSpot di Nikola() e https://stackoverflow.com/a/25415471/1474113

private void forceRipple(View view, int x, int y) { 
    Drawable background = view.getBackground(); 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && background instanceof RippleDrawable) { 
     background.setHotspot(x, y); 
    } 
    view.setPressed(true); 
    // For a quick ripple, you can immediately set false. 
    view.setPressed(false); 
} 
Problemi correlati