SurfaceView in Layout

2019-02-09 14:37发布

问题:

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

}

}

回答1:

I am just putting down the changes.

  1. Replace surface view in the xml with LinearLayout.

        <LinearLayout 
           android:id="@+id/middleSurface"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
        />
    
  2. Get an instance of linear layout

    LinearLayout surface = (LinearLayout)findViewById(R.id.surface);

  3. Add the surface view's instance to LinearLayout

    surface.addView(new MagnetView(this));

2,3 steps should be performed after setContentView(R.layout.main);



回答2:

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.



回答3:

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



回答4:

  1. Remove the surface view from the xml and place a linearlayout in place of that and associate an id with it.
  2. Get an instance of linearlayout.
  3. add child view i.e., magnet view in this case to the linearlayout using

    addView()

This solved the problem.



回答5:

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.



回答6:

You could try this other way, move setContentView(R.layout.main); after super.onCreate(savedInstanceState);

super.onCreate(savedInstanceState);
setContentView(R.layout.main);
midSurf = new MagnetView(this);
LinearLayout midLL = new LinearLayout(this);

midLL.findViewById(R.id.middlesurface);
midLL.addView(midSurf);