Android:How to add a button in surface view

2020-01-30 03:46发布

问题:

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 ?

回答1:

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>


回答2:

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
         */
    }
}


回答3:

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
}


回答4:

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);
}


   }