Tuesday, August 21, 2012

Android: 2d drawing surface

To create a canvas for custom drawing, eg,: for 2d games without using opengl
Create a new class extending SurfaceView, add constructor with 2 arguments (so that it can be used in graphical editor in eclipse too), implement interface SurfaceHolder.Callback

import android.content.Context;
import android.util.AttributeSet;
import android.view.*;

public class MySurface extends SurfaceView implements SurfaceHolder.Callback{
SurfaceHolder holder;

public MySurface(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
holder = this.getHolder();
holder.addCallback(this);

}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
System.out.println("surface changed");
}

public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("surface created");
}

public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("surface destroyed");
}

}


This new custom UI will be available for the xml layout file in Eclipse

can create a draw() method to contain all drawing code in there. then call draw() when surfaceCreated(...)

void draw(){
canvas = holder.lockCanvas();
Paint paint = new Paint();
paint.setColor(0xFFFF0000); // ARGB, red
canvas.drawRect(new Rect(10, 20, 100, 50), paint);
holder.unlockCanvasAndPost(canvas);
}


Threading can be used if animation is needed, for example for games.

Sample code snippet:

public class MySurface extends SurfaceView implements SurfaceHolder.Callback, Runnable{
SurfaceHolder holder;
Canvas canvas;
MySprite s = new MySprite();
boolean isRunning = true;
long time = 0;

static final int DELAY = 10;

public MySurface(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
holder = this.getHolder();
holder.addCallback(this);

}

synchronized void draw(){
canvas = holder.lockCanvas();
canvas.drawColor(0xFFDDDDDD); // ARGB , fill whole canvas

// call draw in sprite
s.draw(canvas);

holder.unlockCanvasAndPost(canvas);
}

synchronized void update(){
s.update();
System.out.println((System.currentTimeMillis() - time) + " ms");
time = System.currentTimeMillis();
}

public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
System.out.println("surface changed");
}

public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("surface created");

isRunning = true;
Thread thread = new Thread(this);
thread.start();

time = System.currentTimeMillis();
}

public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
System.out.println("surface destroyed");
isRunning = false;
}

public void run() {
// TODO Auto-generated method stub
try{
while(isRunning){
update();
draw();
Thread.sleep(DELAY);
}
}
catch(Exception ex){
System.out.println(ex.getMessage());
}
}
}

MySprite is a custom class which contains x, y, width, height, its own draw(), update(), init(), cleanup() methods.


No comments: