I'm trying to work with 3 SurfaceViews on one screen, one on top half (BoardView), one on bottom half (StatusView), and the last one as an extra layer above the top half (TileView) (see main.xml).
I created a class MySurfaceView, which is extended by BoardView, StatusView and TileView.
I've got multiple problems with this.
Let me first give the code.
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/main_background">
<com.niek.test.BoardView
android:id="@+id/boardview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/boardview">
<com.niek.test.StatusView
android:id="@+id/statusview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#F0931E"
android:layout_below="@+id/boardview" />
<com.niek.test.TileView
android:id="@+id/tileview"
android:layout_width="180dip"
android:layout_height="60dip"
android:layout_gravity="bottom"/>
</FrameLayout>
</RelativeLayout>
MainActivity.java:
package com.niek.test;
public class MainActivity extends Activity {
private Board board;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
board = new Board();
BoardView boardView = (BoardView) findViewById(R.id.boardview);
boardView.setBoard(board);
StatusView statusView = (StatusView) findViewById(R.id.statusview);
statusView.setBoard(board);
}
}
MySurfaceView.java
package com.niek.test;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
protected DrawThread drawThread;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(this);
setFocusable(true);
drawThread = new DrawThread(getHolder());
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
drawThread.setRunning(true);
drawThread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// we have to tell thread to shut down & wait for it to finish, or else
// it might touch the Surface after we return and explode
boolean retry = true;
drawThread.setRunning(false);
while (retry) {
try {
drawThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
protected class DrawThread extends Thread {
private SurfaceHolder surfaceHolder;
private boolean isRunning;
public DrawThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
isRunning = false;
}
public void setRunning(boolean run) {
isRunning = run;
}
public void run() {
Canvas c;
while (isRunning) {
try {
Thread.sleep(100);
} catch (Exception e) {
// TODO: handle exception
}
c = null;
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
postInvalidate();
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
These three classes extend MySurfaceView:
BoardView.java
package com.niek.test;
public class BoardView extends MySurfaceView {
private int squareSize, marginX, marginY;
private Board board;
Paint boardBorder;
public BoardView(Context context, AttributeSet attrs) {
super(context, attrs);
board = null;
}
public void setBoard(Board board) {
this.board = board;
}
private void init(SurfaceHolder holder) {
Canvas canvas = null;
try {
canvas = holder.lockCanvas();
/* Initialize the board */
squareSize = canvas.getWidth() / Board.GRIDSIZE;
/* Size the view */
LayoutParams lp = getLayoutParams();
lp.height = (squareSize * Board.GRIDSIZE) + 4;
setLayoutParams(lp);
/* Place the board neatly in the center */
marginX = (canvas.getWidth() - (squareSize * Board.GRIDSIZE)) / 2;
marginY = 1;
} finally {
holder.unlockCanvasAndPost(canvas);
}
boardBorder = new Paint();
boardBorder.setColor(Color.RED);
boardBorder.setStyle(Style.STROKE);
}
@Override
public void onDraw(Canvas canvas) {
drawBoard(board, canvas);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
init(holder);
super.surfaceCreated(holder);
}
private void drawBoard(Board board, Canvas canvas) {
synchronized (board) {
if (board != null) {
for (Square[] ys : board.getSquares()) {
for (Square xs : ys) {
xs.onDraw(canvas, squareSize, squareSize, marginX, marginY);
}
}
}
canvas.drawRect(marginX - 1, marginY - 1, marginX + squareSize * Board.GRIDSIZE + 1, marginY + squareSize * Board.GRIDSIZE + 1, boardBorder);
}
}
}
StatusView.java
package com.niek.test;
public class StatusView extends MySurfaceView {
private Board board;
private Paint textPaint;
public StatusView(Context context, AttributeSet attrs) {
super(context, attrs);
board = null;
textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(20);
textPaint.setTypeface(Typeface.DEFAULT_BOLD);
}
public void setBoard(Board board) {
this.board = board;
}
int tmp=0;
@Override
public void onDraw(Canvas c) {
if (board != null) {
c.drawText(tmp+"", 10, 20, textPaint);
tmp++;
System.out.println(tmp);
}
}
}
TileView.java
package com.niek.test;
public class TileView extends MySurfaceView {
public TileView(Context context, AttributeSet attrs) {
super(context, attrs);
System.out.println(0);
}
int tmp =0;
@Override
public void onDraw(Canvas c) {
System.out.println(2);
Paint p= new Paint();
p.setColor(Color.RED);
c.drawColor(Color.RED);
c.drawText(tmp+"",10,10,p);
tmp++;
}
}
Now what are my problems?
First off, as you can see in MySurfaceView I've got this:
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
postInvalidate();
}
}
When I only use onDraw(c), only the BoardView gets drawn, the StatusView doesn't get drawn, but the tmp increments in the onDraw of StatusView are being executed. When I only use postInvalidate(), same story, but only StatusView gets drawn, BoardView doesn't. So that's why I use both methods, and both Views get drawn.
Then there's TileView, the System.out(2) is being shown in logcat, but the view doesn't get drawn. It is a black square instead of the red square I ask it to be in the onDraw method.
When I turn the screen off and then on again, the TileView does get drawn, and the tmp increments are shown.
Who can help me?
For clarity, I've created this based on this tutorial.