So I've done a lot of searching but still can't seem to find the exact reason as to why my SurfaceView won't display. Here's a little background as to what I'm doing:
I have a Linear Layout that is set Horizontally. It contains an ImageView, then a vertical Linear Layout, and finally another ImageView. In the vertical Linear Layout, there are essential three things: another ImageView at the top, an extended SurfaceView (called MagnetView) and an ImageView below that.
Here's the xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<!-- Left Magnetrak -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="@drawable/vectorparts_01"
android:adjustViewBounds="true" />
<!-- Middle Linear Layout -->
<LinearLayout
android:layout_width="0dip"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_weight="1">
<!-- Top Bar with Lifes and Score counter -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true">
<ImageView
android:adjustViewBounds="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/vectorparts_22"/>
<!-- Score counter -->
<TextView
android:id="@+id/myImageViewText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_marginTop="5dp"
android:gravity="center"
android:text="000000000000"
android:textColor="#000000" />
<!-- Life1 -->
<ImageView
android:id = "@+id/life1"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/vectorparts_13"
android:layout_alignParentLeft="true"
android:layout_marginLeft="5dp"
android:layout_marginTop="1dp"
android:gravity="center" />
<!-- Life2 -->
<ImageView
android:id = "@+id/life2"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/vectorparts_13"
android:layout_toRightOf="@id/life1"
android:layout_marginTop="1dp"
android:layout_marginLeft="1dp"
android:gravity="center" />
<!-- Life3 -->
<ImageView
android:id = "@+id/life3"
android:adjustViewBounds="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/vectorparts_13"
android:layout_toRightOf="@id/life2"
android:layout_marginTop="1dp"
android:layout_marginLeft="1dp"
android:gravity="center" />
</RelativeLayout>
<!-- SurfaceView -->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/middlesurface">
</LinearLayout>
<!-- Bottom Bar -->
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true">
<ImageView
android:adjustViewBounds="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/vectorparts_02"/>
</RelativeLayout>
</LinearLayout>
<!-- Right Magnetrak -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="@drawable/vectorparts_01"
android:adjustViewBounds="true" />
Essentially, I want the MagnetView to show through (or punch a hole) where I put it in the Layout. But it does not display. In fact, the only time my SurfaceView displays is when I set the activity's setContentView() to the SurfaceView explicitly, canceling out everything else.
Here is the actually Activity:
public class Magnetraks extends Activity {
MagnetView midSurf;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
midSurf = new MagnetView(this);
LinearLayout midLL = new LinearLayout(this);
midLL.findViewById(R.id.middlesurface);
midLL.addView(midSurf);
setContentView(R.layout.main);
//Debugging purposes: run to see if middleSurface view is showing up when on its own.
//setContentView(midSurf);
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
midSurf.resume();
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
midSurf.pause();
}
Should I place the SurfaceView at the top of my layout xml? Are there more attributes I must set? Can I just overlay the SurfaceView over everything else, make it translucent and draw what I need? Any help would be greatly appreciated, as I cannot seem to grasp how SurfaceViews work. It seems they are apart of my View hierarchy, but then documentation tells me they are something different entirely.
Thank you.
EDIT 04/17/2012
To offer a little more info: My xml UI Designer shows a big box in the middle for my extended SurfaceView class, called MagnetView. I've outlined it in red. (Stackoverflow won't allow me to post images yet)
UI Designer view(http://24.media.tumblr.com/tumblr_m2mmqvBNwW1qcreoco1_500.jpg) http://24.media.tumblr.com/tumblr_m2mmqvBNwW1qcreoco1_500.jpg
Here's the MagnetView (SurfaceView) class:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MagnetView extends SurfaceView implements Runnable, SurfaceHolder.Callback{
Thread mThread;
SurfaceHolder mSurfaceHolder;
volatile boolean running = false;
//Creates new surface view as well as a new surfaceholder, which allows access to the surface
public MagnetView (Context context){
super(context);
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
//this.setZOrderOnTop(true);
//getHolder().setFormat(PixelFormat.TRANSLUCENT);
}
public void resume(){
running = true;
mThread = new Thread(this);
mThread.start();
}
public void pause(){
boolean retry = true;
running = false;
while(retry){
try {
mThread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while(running){
if(mSurfaceHolder.getSurface().isValid()){
Canvas canvas = mSurfaceHolder.lockCanvas();
//... actual drawing on canvas
canvas.drawARGB(100, 255, 255, 80);
mSurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
@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
this.resume();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
}
I would examine the layout in the Eclipse UI designer to see if everything is placed as you want to. Surface Views are just ordinary views in regards to layout.
add child view i.e., magnet view in this case to the linearlayout using
addView()
This solved the problem.
If I am not wrong, the way I perceived your query is: You want something to be displayed/rendered on top of the surface view along with the other view elements as you mentioned in the xml.
If you want a view on top of surface view, you need to extend it(AFAIK there is no other way). Then you need to override the onDraw() method to display what all things you want on the surface view. You also need to get an object of SurfaceHolder which gets the canvas.
Here is a good link showing, putting an imageview on top of surface view: http://www.droidnova.com/playing-with-graphics-in-android-part-ii,160.html
Have you set the background of the SurfaceView? I found that if you set the background of the SurfaceView, it will not display what you draw on the secondary thread.
I am just putting down the changes.
Replace surface view in the xml with LinearLayout.
Get an instance of linear layout
LinearLayout surface = (LinearLayout)findViewById(R.id.surface);
Add the surface view's instance to LinearLayout
surface.addView(new MagnetView(this));
2,3 steps should be performed after setContentView(R.layout.main);
You could try this other way, move
setContentView(R.layout.main);
aftersuper.onCreate(savedInstanceState);