26

I'm drawing some graphics and i would like to add a couple of buttons to it. But with the surface view how do we add these buttons programatically ?

m4n07
  • 2,267
  • 12
  • 50
  • 65

4 Answers4

45

Enclose your surfaceView with a FrameLayout in your xml Layout. Then add your buttons to the same FrameLayout. Make sure they are placed below the surface view so they get drawn on top of it. (Might be a good idea to bundle them in another Layout and add that to the FrameLayout.)

<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
    <SurfaceView android:id="@+id/surfaceView1" android:layout_width="wrap_content" android:layout_height="wrap_content"></SurfaceView>
    <LinearLayout android:id="@+id/linearLayout1" android:layout_width="wrap_content" android:layout_height="wrap_content">
        <Button android:text="Button" android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
        <Button android:text="Button" android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
    </LinearLayout>
</FrameLayout>
pumpkee
  • 3,357
  • 3
  • 27
  • 34
  • 1
    I have created the surfaceView programatically, But how to link with the one in XML. – m4n07 Apr 26 '11 at 05:00
  • 2
    I had to add something like this in the xml – m4n07 May 02 '11 at 09:17
  • i am using this xml for my activity, in which i want to initialize surfaceview when the user tap on imageview which is customized TouchImageView having zoom and pinch fuctionality to ImageView. What i am trying to do is - (1) it shows image from webservices, that i have done with AQuery. (2)when user select on EDIT option of CAB's it enables surfaceview with a draggable edit text over the image. @androidika can you help me with this. – Sunishtha Singh Jul 07 '15 at 12:31
34

Thank you so much Androidica..

Your xml has helped me to figure out the following solution programatically without using any xml..

public class LudoActivity extends Activity implements OnClickListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        FrameLayout game = new FrameLayout(this);
        GameView gameView = new GameView (this);
        LinearLayout gameWidgets = new LinearLayout (this);

        Button endGameButton = new Button(this);
        TextView myText = new TextView(this);

        endGameButton.setWidth(300);
        endGameButton.setText("Start Game");
        myText.setText("rIZ..i");

        gameWidgets.addView(myText);
        gameWidgets.addView(endGameButton);       

        game.addView(gameView);
        game.addView(gameWidgets);

        setContentView(game);
        endGameButton.setOnClickListener(this);
    }

    public void onClick(View v) {
         Intent intent = new Intent(this, LudoActivity.class);
         startActivity(intent);
         // re-starts this activity from game-view. add this.finish(); to remove from stack
    }
}

while GameView is;

public class GameView extends SurfaceView {

    public GameView(Context context) {
        super(context);

        /*
         * your code
         */
    }
}
Guerneen4
  • 708
  • 8
  • 17
Rizwan Sohaib
  • 1,240
  • 17
  • 27
8

Make your own button:

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;

    public class GButton
    {
        public Matrix btn_matrix = new Matrix();

        public RectF btn_rect;

        float width;
        float height;   
        Bitmap bg;

        public GButton(float width, float height, Bitmap bg)
        {
            this.width = width;
            this.height = height;
            this.bg = bg;

            btn_rect = new RectF(0, 0, width, height);
        }

        public void setPosition(float x, float y)
        {
            btn_matrix.setTranslate(x, y);
            btn_matrix.mapRect(btn_rect);
        }

        public void draw(Canvas canvas)
        {
            canvas.drawBitmap(bg, btn_matrix, null);
        }
    }

on touch event:

float x = ev.getX();
float y = ev.getY();
if (my_button.btn_rect.contains(x, y))
{
    // handle on touch here
}

alternatively, even better, if you want to also rotate the button it will not be axis-aligned, then use the invert matrix, instead of mapRect map the touch points x,y:

float pts[] = {x, y};            
my_button.invert_matrix.mapPoints(pts);           
if (my_button.btn_rect.contains(pts[0], pts[1])
{
    // handle on touch here
}
alex
  • 301
  • 3
  • 13
  • I'd like to a see post somewhere comparing the advantages of making one's own buttons in this way for a surfaceview vs using the Button object from the buttonwidget as in gruemeen4's answer. I recently changed all my own custom buttons in my game code to Button objects, and it seems like it doesn't perform as well for clicks. – Androidcoder Oct 16 '17 at 20:50
  • If you are using surfaceview, you are supposedly drawing your stuff on it, including buttons.Means you are not using standard layouts and widgets. – alex Mar 24 '18 at 23:26
5

We can use frame layout for surface view drawing very easily . like this

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
<FrameLayout
     android:id="@+id/frameLayout"
     android:layout_width="fill_parent"
     android:layout_height="430dp"/>
   <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="50dp"
        android:gravity="center_horizontal"
        android:layout_gravity="bottom"
        android:background="#c2300f">

        <Button
            android:id="@+id/buttonColor"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Color" />
    </LinearLayout>     
</LinearLayout>

And Main activity is

package com.example.surfacetuto;


 import android.app.Activity;
 import android.graphics.Paint;
 import android.graphics.Point;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 import android.widget.Toast;

 public class MainActivity extends Activity implements OnClickListener{
    DrawingSurface ds;
    FrameLayout frm;
    Button btnC;
    int color=0xfff00000;
    @Override
   public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ds=new DrawingSurface(this);
    setContentView(R.layout.activity_main);


    frm=(FrameLayout)findViewById(R.id.frameLayout);
    frm.addView(ds);

    btnC=(Button)findViewById(R.id.buttonColor);

    btnC.setOnClickListener(this);
}
@Override
public void onClick(View v) {
    // TODO Auto-generated method stub
    switch (v.getId()) {

    case R.id.buttonColor:
        Toast.makeText(getApplicationContext(), "Color", 2).show();
        ds.colorNew();

        break;

    default:
        break;
    }
}   
    }

And Drawing Surface class is

package com.example.surfacetuto;

 import android.app.Activity;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Paint.Cap;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.Toast;

   public class DrawingSurface extends SurfaceView implements SurfaceHolder.Callback {

      Canvas cacheCanvas;
      Bitmap backBuffer;
      int width, height, clientHeight;
      Paint paint;
      Context context;
      SurfaceHolder mHolder;


public DrawingSurface(Context context) {
    super(context);
    this.context = context;
    init();
}
public DrawingSurface(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;      
    init();
}

private void init() {
    mHolder = getHolder();
    mHolder.addCallback(this);

}

int lastX, lastY, currX, currY;
boolean isDeleting;
@Override
public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);
    int action = event.getAction();
    switch(action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        lastX = (int) event.getX();
        lastY = (int) event.getY();
        break;
    case MotionEvent.ACTION_MOVE:
        if(isDeleting) break;

        currX = (int) event.getX();
        currY = (int) event.getY();
        cacheCanvas.drawLine(lastX, lastY, currX, currY, paint);
        lastX = currX;
        lastY = currY;

        break;
    case MotionEvent.ACTION_UP:
        if(isDeleting) isDeleting = false;
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        cacheCanvas.drawColor(Color.WHITE);
        isDeleting = true;
        break;
    case MotionEvent.ACTION_POINTER_UP:
        break;
    }
    draw(); 
    return true;
}

protected void draw() {

    if(clientHeight==0) {
        clientHeight = getClientHeight();
        height = clientHeight;
        backBuffer = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888);
        cacheCanvas.setBitmap(backBuffer);
        cacheCanvas.drawColor(Color.WHITE);
    }
    Canvas canvas = null;
    try{
        canvas = mHolder.lockCanvas(null);

        canvas.drawBitmap(backBuffer, 0,0, paint);
    }catch(Exception ex){
        ex.printStackTrace();
    }finally{
        if(mHolder!=null)  mHolder.unlockCanvasAndPost(canvas);
    }
}

private int getClientHeight() {
    Rect rect= new Rect();    
    Window window = ((Activity)context).getWindow();     
    window.getDecorView().getWindowVisibleDisplayFrame(rect);     
    int statusBarHeight= rect.top;    
    int contentViewTop= window.findViewById(Window.ID_ANDROID_CONTENT).getTop();     
    int titleBarHeight= contentViewTop - statusBarHeight;
    return ((Activity)context).getWindowManager().getDefaultDisplay().
            getHeight() - statusBarHeight - titleBarHeight;
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
}

public void surfaceCreated(SurfaceHolder holder) {

    width = getWidth();
    height = getHeight();
    cacheCanvas = new Canvas();
    backBuffer = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888); 
    cacheCanvas.setBitmap(backBuffer);
    cacheCanvas.drawColor(Color.WHITE);
    paint = new Paint();
    paint.setColor(Color.BLUE);
    paint.setStrokeWidth(10);
    paint.setStrokeCap(Paint.Cap.ROUND);
    paint.setStrokeJoin(Paint.Join.ROUND);
    draw();

}

public void surfaceDestroyed(SurfaceHolder holder) {
     boolean retry = true;
        thread.setRunning(false);
        while (retry) {
            try {
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                // we will try it again and again...
            }
        }
}

public void colorNew() {
    // TODO Auto-generated method stub
    paint.setColor(Color.GRAY);
}


   }
Android Help
  • 261
  • 4
  • 19