Animation at a specified rate using canvas / Ondra

2019-08-04 15:34发布

问题:

In my Android app, I am trying to show letters one by one with a short delay between each, while also playing a sound for each letter. I have everything working, and the sounds play with the correct delay, but the text always prints to the screen far too fast. The canvas seems to be updated even when i am not specifically invalidating the view.

Here is what I have so far - I also tried a variant of this based on the "snake" example and had the same results... any help would be appreciated!

public class SpellingView extends View {
private static final String WORD = "TRUCK";
int width;
int height;
String textToPrint;
float textspace;
int j=0;

private final Path arc;
private final Paint tPaint;

//constructor for SpellingView
public SpellingView(Context context) {
    super(context);
    arc = new Path();
    tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    displayLetterLoop();
}

public void displayLetterLoop(){

    for (int i = 0; i < WORD.length(); i++){
        final Runnable mUpdateUITimerTask = new Runnable() {
            public void run() { 
                Spelling.mp.start();    
            }
        };
        final Handler mHandler = new Handler();
        mHandler.postDelayed(mUpdateUITimerTask, i*1500);
    }
}

@Override
protected void onDraw(Canvas canvas) {
    int k;
    // Drawing commands go here
    width = canvas.getWidth();
    height = canvas.getHeight();

    arc.addArc(new RectF((width*.15f), (height*.15f), (width*.85f), (height*.4f)), 180,180);

    tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
    tPaint.setColor(Color.RED);
    tPaint.setTextSize(height * 0.1f);
    tPaint.setTextAlign(Paint.Align.LEFT);

    setBackgroundColor(Color.BLACK);

    for (k = 0; k < j; k++){
        char c = WORD.charAt(k);        
        String cs = Character.toString(c);
        textToPrint+= cs;
        textspace =(float) (k*(width/WORD.length())*.9);

        canvas.drawTextOnPath(cs, arc, textspace , 0, tPaint);
    }
    if(j<WORD.length()){
        j++;
    }
}

}

回答1:

Custom view will invalidate itself when is a part of a layout which for some reason redraw itself. Therefore you could envelop your code in onDraw() with a condition and a flag so that it draws your stuff only when the timer sets the flag and calls invalidate. After one letter is drawn then the flag shoud be set on false like:

if (drawLetter){
  drawLetter = false;

  /code...

}

However this also may need to be a sychronized block.



回答2:

OnDraw should happen 60 times a second and not only when you are invalidating. So maybe you need to update some class variables (when you are invalidating) and use those for your draw logic @ OnDraw.