Android:如何在SurfaceView中添加按钮

26

我正在绘制一些图形,并希望在其上面添加几个按钮。但是使用SurfaceView,我们如何编程添加这些按钮?

我正在绘制一些图形,并希望在其上添加几个按钮。但是,在使用 SurfaceView 时,我们该如何通过编程方式添加这些按钮呢?
4个回答

45

在你的xml布局中使用FrameLayout将SurfaceView包围起来,然后将按钮添加到同一个FrameLayout中。确保它们位于SurfaceView下方,这样它们就会覆盖在其上面。(最好将它们打包在另一个布局中,然后将该布局添加到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>

1
我已经通过编程方式创建了SurfaceView,但是如何与XML中的SurfaceView链接起来呢? - m4n07
2
<com.androidsurfaceview.test.MySurfaceView android:layout_width="fill_parent" android:layout_height="fill_parent"/> 我必须在xml中添加类似这样的内容。 - m4n07
我正在使用这个XML文件来初始化我的活动,在其中我想要在用户点击自定义的TouchImageView上的ImageView时初始化SurfaceView,该ImageView具有缩放和捏合功能。我想要做的是 - (1)它从Web服务显示图像,我已经用AQuery完成了这个过程。(2)当用户选择CAB的EDIT选项时,它会启用SurfaceView,并在图像上拖动可编辑文本。@androidika你能帮我吗? - Sunishtha Singh

34

非常感谢Androidica。

您的XML文件帮助我找到了以下解决方案,且该方案是通过编程实现而不需要使用任何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
    }
}

当GameView存在时;

public class GameView extends SurfaceView {

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

        /*
         * your code
         */
    }
}

非常感谢您提供的这个代码版本,另一个答案中发布的XML让我感到困惑。 - James Andrew

8

制作自己的按钮:

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

关于触摸事件:

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

或者更好的选择是,如果您想要旋转按钮并且它不是轴对齐的,则可以使用反转矩阵,而不是映射矩形来映射触摸点的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
}

我想在某个地方看到一篇文章,比较使用这种方式制作SurfaceView的自定义按钮与使用ButtonWidget中的Button对象(如gruemeen4的答案)之间的优势。最近,我将游戏代码中所有自定义按钮都更改为Button对象,但似乎点击性能不如以前。 - Androidcoder
如果您正在使用SurfaceView,则应该在其上绘制您的内容,包括按钮。这意味着您没有使用标准布局和小部件。 - alex

5
我们可以很容易地使用帧布局来进行SurfaceView绘制,就像这样:
<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>

主要活动是

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

绘图表面类是

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


   }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接