Android多个SurfaceView
我尝试在一个屏幕上使用3个SurfaceView,一个在上半部分(BoardView),一个在下半部分(StatusView),最后一个作为上半部分(TileView)上方的额外层(请参见main.xml) 我创建了一个类MySurfaceView,它由BoardView、StatusView和TileView扩展 我有很多问题 让我先给出代码 main.xml:Android多个SurfaceView,android,surfaceview,ondraw,Android,Surfaceview,Ondraw,我尝试在一个屏幕上使用3个SurfaceView,一个在上半部分(BoardView),一个在下半部分(StatusView),最后一个作为上半部分(TileView)上方的额外层(请参见main.xml) 我创建了一个类MySurfaceView,它由BoardView、StatusView和TileView扩展 我有很多问题 让我先给出代码 main.xml: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout
<?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>
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);
}
}
}
}
}
}
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++;
}
}
这三个类扩展了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 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);
}
}
}
}
}
}
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++;
}
}
现在我的问题是什么
首先,正如您在MySurfaceView中看到的,我有以下内容:
try {
c = surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
onDraw(c);
postInvalidate();
}
}
当我只使用onDraw(c)时,只绘制BoardView,不绘制StatusView,但正在执行StatusView onDraw中的tmp增量。
当我只使用postInvalidate()时,会绘制相同的故事,但只绘制StatusView,而BoardView不会。
这就是为什么我使用这两种方法,两种视图都被绘制出来
然后是TileView,System.out(2)显示在logcat中,但视图没有绘制出来。它是一个黑色的正方形,而不是红色的正方形,我要求它是在onDraw方法中
当我关闭屏幕然后再次打开时,会绘制TileView,并显示tmp增量
谁能帮我
为清楚起见,我根据教程创建了此视图。看起来您不应该在一个布局上创建多个SurfaceView。 根据Android框架工程师撰写的这篇文章: 曲面视图的实现方式是在其包含窗口后面创建一个单独的曲面并按Z顺序排列,并将透明像素绘制到曲面视图所在的矩形中,以便可以看到后面的曲面。我们从未打算允许多个曲面视图 及 您应该有效地将SurfaceView视为嵌入窗口中的覆盖层, 为您提供一个区域,在该区域中,您可以独立于法线视图更新系统直接绘制 因此,您可以使用一个SurfaceView来绘制所需的所有图形。在一个布局中可以有多个
SurfaceView
。中的“多表面测试”活动有三个方面
@nonsleepr的回答中引用的第一篇帖子在9个月后被同一作者跟进,该作者提到了
要理解的关键是SurfaceView
不是常规视图。当你的应用程序出现在前台时,它会得到一个可以绘制的表面。应用程序UI中的所有内容都由应用程序渲染到应用程序的曲面上,然后由系统合成器将该曲面与其他曲面(如状态栏和导航栏)合成。当您创建一个SurfaceView
时,它实际上是在创建一个由系统而不是应用程序合成的全新曲面
您可以非常松散地控制SurfaceView
曲面的Z顺序(即“深度”)。从上到下有四个位置:
+ZOrderOnTopSurfaceView
- (应用程序界面在这里)
+ZOrderMediaOverlaySurfaceView
(默认)SurfaceView
SurfaceViews
,但一般来说,您最好将数字保持在较低的水平。N的值因设备而异
更新:如果您真的想了解SurfaceView是如何工作的,请参阅。听起来好像正在绘制SurfaceView,但顶部的任何一个都不启用透明度。在surfaceCreated()方法的MySurfaceView类中,确保调用的是
holder.setFormat(PixelFormat.TRANSPARENT)代码>那么我可以在不同的家长中添加两个surfaceview吗?这个答案有误导性。从fadden的回答中,在该工程师的帖子链接后,我们读到:“在2.0之前,不支持多个相互重叠的曲面……从2.0开始,有一个黑客可以用来至少控制两个曲面视图的Z顺序”。关键短语相互重叠。即使在2.0之前,非重叠曲面也没有问题。(参见fadden的答案,链接到Grafika source,它演示了这一点。)2.0之后,即使是重叠的表面也可以处理,只需一点努力。这应该被标记为答案。谢谢你@fadden@fadden:嗨,首先,谢谢你的回答!如果有两个SurfaceView,而其中一个总是隐藏的(View.INVISIBLE)?对于那些来到这里但正在使用GLSurfaceView
的读者来说:但是,如果您试图有两个GLSurfaceView
,而不仅仅是两个surfaceView
,那就行不通了。(关于锁定GL线程的内容)因此Grafika使用的方法是创建自己的GL线程,并管理对该线程上不同SurfaceView
的访问。这应该被标记为答案。多谢各位@fadden@ToolmakerSteve嘿,你能告诉我你在格拉菲卡密码里到底指的是什么吗?我需要同时使用GLSURFACHEVIEW和SURFACHEVIEW,并面临类似的问题。