nha*_*man 12 android surfaceview ondraw
我试图在一个屏幕上使用3个SurfaceViews,一个在上半部分(BoardView),一个在下半部分(StatusView),最后一个作为上半部分之上的额外层(TileView)(参见main.xml) .
我创建了一个MySurfaceView类,它由BoardView,StatusView和TileView扩展.
我有很多问题.
我先给出代码.
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>
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这三个类扩展了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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
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++;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我的问题是什么?
首先,你可以在MySurfaceView中看到我得到了这个:
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
postInvalidate();
}
}
Run Code Online (Sandbox Code Playgroud)
当我只使用onDraw(c)时,只绘制BoardView,不会绘制StatusView,但是正在执行StatusView的onDraw中的tmp增量.当我只使用postInvalidate(),相同的故事,但只有StatusView被绘制,BoardView没有.这就是为什么我使用这两种方法,并且两个视图都被绘制出来.
然后是TileView,System.out(2)显示在logcat中,但视图没有被绘制.这是一个黑色方块,而不是我要求它在onDraw方法中的红色方块.
当我关闭屏幕然后再打开时,TileView会被绘制,并显示tmp增量.
谁能帮我?
为清楚起见,我是根据本教程创建的.
fad*_*den 54
您可以SurfaceViews在一个布局中使用多个.格拉菲卡的"多表面测试"活动有三个.
在@nonsleepr的回答中引用的第一篇文章在9个月之后被同一作者的帖子跟进,后者提到了SurfaceView#setZOrderMediaOverlay()的存在.
要理解的关键SurfaceView是不是常规视图.当您的应用程序到达前台时,它会获得一个可以绘制的表面.应用程序UI中的所有内容都由应用程序呈现在应用程序的表面上,然后系统合成器将该表面与其他表面(如状态栏和导航栏)合成.当你创建一个时SurfaceView,它实际上创建了一个由系统合成的全新表面,而不是你的应用程序.
您可以SurfaceView非常松散地控制表面的Z排序(即"深度").从上到下有四个位置:
SurfaceView + ZOrderOnTopSurfaceView + ZOrderMediaOverlaySurfaceView (默认)如果你有两个相同深度的SurfaceView,并且它们重叠,结果是未定义的 - 一个将"赢",但你无法控制哪个.
当你有N个表面时,现代设备上的系统合成器非常有效.在N + 1个表面,你会遇到性能悬崖.所以虽然你可以有三个SurfaceViews,但你最好还是保持这个数字.N的值因设备而异.
更新:如果您真的想了解SurfaceView的工作原理,请参阅Android系统级图形文档.
non*_*epr 11
看起来您不应该在一个Layout上创建多个SurfaceView.根据Android框架工程师编写的这两篇 帖子:
实现曲面视图的方法是创建一个单独的曲面,并在其包含窗口后面进行Z排序,并将透明像素绘制到SurfaceView所在的矩形中,以便您可以看到背后的曲面.我们从未打算允许多个表面视图.
和
您应该有效地将SurfaceView视为嵌入窗口内的叠加层,为您提供一个区域,您可以在该区域中独立于普通视图更新系统进行绘制.
因此,您可以使用一个SurfaceView绘制所需的所有图形.