2015-08-26 18 views
7

Come animare il gradiente dal colore n. 1 al colore n. 2? Qualcosa di simile aCome animare il gradiente?

enter image description here

ho intenzione di usarlo come la salute-bar per unità (animazione in modo, sarà finit partendo con il verde e termina con rosso)

risposta

22

Mentre googling, io trovato 2 modi per farlo per Android: use ShaderFactory o estende View, utilizzando new Shader(new LinearGradient()). Entrambe le risposte fanno lo stesso - chiamando lo new Shader() ogni chiamata del metodo View.onDraw(Canvas canvas). È davvero costoso se il numero di tali gradienti animati è superiore a ~ 3.

Quindi l'ho fatto in un altro modo. Ho evitato di chiamare new ogni onDraw(), utilizzando il singolo valore predefinito LinearGradient. Ecco come è assomigliare (gif, così animazione decaduto):

enter image description here

Il trucco è quello di creare LinearGradient che è colorsCount volte più grande di View.getWidth(). Successivamente è possibile utilizzare canvas.translate(), mentre si disegna il gradiente, per cambiarne il colore, quindi nessuna chiamata new in onDraw().

Per creare una sfumatura, è necessario larghezza e altezza attuali. L'ho fatto in onSizeChanged(). Anche io ho impostato Shader anche qui.

@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    super.onSizeChanged(w, h, oldw, oldh); 

    width = getWidth(); 
    height = getHeight(); 

    LinearGradient gradient = new LinearGradient(
      0, height/2, width * colors.length - 1, height/2, 
      colors, null, Shader.TileMode.REPEAT); 
    fillPaint.setShader(gradient); 

    shapePath = getParallelogrammPath(width, height, sidesGap); 
    shapeBorderPath = getParallelogrammPath(width, height, sidesGap); 
} 

Uso il percorso a causa delle viste di parallelogrammi, è possibile utilizzare qualsiasi cosa si desideri. Nell'attuare disegno, si dovrebbe notare 2 cose: è necessario translate() intero canvas su offset di corrente e offset() la forma di riempimento:

@Override 
protected void onDraw(Canvas canvas) { 
    canvas.save(); 
    canvas.translate(-gradientOffset, 0); 
    shapePath.offset(gradientOffset, 0f, tempPath); 
    canvas.drawPath(tempPath, fillPaint); 
    canvas.restore(); 

    canvas.drawPath(shapeBorderPath, borderPaint); 

    super.onDraw(canvas); // my View is FrameLayout, so need to call it after 
} 

Inoltre si dovrebbe utilizzare canvas.save() & canvas.restore(). Salva la matrice interna della tela per impilarla e ripristinarla in modo corrispondente.

Quindi l'ultimo cosa che devi fare è animare gradientOffset. Puoi utilizzare tutto ciò che desideri come ObjectAnimator (Property Animation). Ho usato TimeAnimator, perché avevo bisogno di controllare updateTick e iniziare lo spostamento direttamente. Qui è la mia realizzazione (un po 'difficile e dura):

static public final int LIFETIME_DEAFULT = 2300; 
private long lifetime = LIFETIME_DEAFULT, updateTickMs = 25, timeElapsed = 0; 
private long accumulatorMs = 0; 
private float gradientOffset = 0f; 

public void startGradientAnimation() { 
    stopGradientAnimation(); 
    resolveTimeElapsed(); 

    final float gradientOffsetCoef = (float) (updateTickMs)/lifetime; 
    final int colorsCount = this.colors.length - 1; 
    gradientAnimation.setTimeListener(new TimeAnimator.TimeListener() { 
     @Override 
     public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { 
      final long gradientWidth = width * colorsCount; 
      if (totalTime > (lifetime - timeElapsed)) { 
       animation.cancel(); 
       gradientOffset = gradientWidth; 
       invalidate(); 
      } else { 
       accumulatorMs += deltaTime; 

       final long gradientOffsetsCount = accumulatorMs/updateTickMs; 
       gradientOffset += (gradientOffsetsCount * gradientWidth) * gradientOffsetCoef; 
       accumulatorMs %= updateTickMs; 

       boolean gradientOffsetChanged = (gradientOffsetsCount > 0) ? true : false; 
       if (gradientOffsetChanged) { 
        invalidate(); 
       } 
      } 
     } 
    }); 

    gradientAnimation.start(); 
} 

Il codice completo View è possibile trovare here

+0

Non capisco ... lei ha chiesto la domanda e ha risposto allo stesso tempo su lo stesso giorno? Questa non è mai stata una domanda. –

+4

@ Chris-Jr, ho cercato molto e non ho trovato una risposta che volevo. Così ho fatto una sorta di ricerca e finalmente l'ho preso. Poi ho pensato "hm, forse qualcun altro lo cercherà in futuro e resterà bloccato come faccio io?" - Così ho creato la domanda con la risposta. Inoltre, c'è una funzione integrata per farlo. Prova a fare clic su 'Ask Question'. C'è un assegno 'Rispondi alla tua stessa domanda - condividi le tue conoscenze, stile Q & A' – Nexen

+0

Ah, va bene, sono stato solo confuso dai tempi. Grazie per questo, e grazie per aver condiviso la tua soluzione. –