Basically the ability to manipulate complex, hierarchical transformation is achieved by an(?) internal matrix stack with the top matrix being the current one in effect and the one that you are manipulating. All the transformations you are making on the current matrix are cumulative; so if you were just to manipulate the current matrix, it’s going to be a big pain to draw something like a car or a human figure which conceptually is assembled by different parts. Canvas.save()/Camera.save() is to push a matrix into the stack; the result is the transformation you’ve made is saved into the stack. Canvas.restore()/Camera.restore() is to discard the current transformation and go back to the last saved one and continue on it. So if you want to continue with some transformation you made a while ago, you should first save/push it into the stack first so that you can go back to it by restoring/popping it out from the stack. See the following pseudo code for how we go about drawing a drag race car with huge wheels:
To summarize (applying to android.graphics.Camera as well), you repeatedly do the following cycles:
Note that in android, #2 transformation should be coded before #3 drawing to make the drawing stick to the transformation. If you reverse 2/3, your drawing won’t be affected by the transformations that come after it. This is kinda “counter-intuitive” at least for me since you have always need to set your canvas in position before you paint but not the other way around.
package com.mh.android.test;
import android.app.Activity;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.View;
public class HelloAndroidAgain extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new MyTestView(this));
}
private static class MyTestView extends View {
public MyTestView(Context context) {
super(context);
setMinimumWidth(200);
setMinimumHeight(200);
//camera = new Camera();
}
private Camera camera = new Camera();
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
camera.save();
camera.rotateY(60f);
camera.applyToCanvas(canvas);
canvas.drawColor(Color.DKGRAY);
Paint paint = new Paint();
paint.setTextSize(24);
//front left wheel
canvas.save();
canvas.translate(50f, 50f);//xCtr, yCtr
paint.setColor(Color.GREEN);
canvas.drawCircle(0, 0, 30, paint);
paint.setColor(Color.WHITE);
canvas.drawText(“FL”, -10, 10, paint);//string
canvas.restore();
//front right wheel
canvas.save();
canvas.translate(150f, 50f);
paint.setColor(Color.GREEN);
canvas.drawCircle(0, 0, 30, paint);
paint.setColor(Color.WHITE);
canvas.drawText(“FR”, -10, 10, paint);
canvas.restore();
//rear left wheel
canvas.save();
canvas.translate(50f, 150f);
paint.setColor(Color.GREEN);
canvas.drawCircle(0, 0, 30, paint);
paint.setColor(Color.WHITE);
canvas.drawText(“BL”, -10, 10, paint);
canvas.restore();
//rear right wheel
canvas.save();
canvas.translate(150f, 150f);
paint.setColor(Color.GREEN);
canvas.drawCircle(0, 0, 30, paint);
paint.setColor(Color.WHITE);
canvas.drawText(“BR”, -10, 10, paint);
canvas.restore();
//body
canvas.save();
canvas.translate(100f, 100f);
paint.setColor(Color.RED);
canvas.drawRect(-50, -50, 50, 50, paint);
canvas.restore();
camera.restore();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(getSuggestedMinimumWidth(), getSuggestedMinimumHeight());
}
}
}