Wednesday, April 18, 2012

How to add a button to a SurfaceView in Android

Today I am going to give a rough tutorial on a somewhat tricky task of adding a button on top of a SurfaceView in Android. This tutorial assumes that you already have a basic understanding of implementing the GameView and a GameLoopThread and that all works, you just want to add some clickable buttons over it to use in the game. So here is how I do it using code and not XML.

Preconditions: You have a GameView that extends SurfaceView and runs with a thread.
Post-conditions: You will have a standard button draw on top of the GameView that can be clicked.

Because I do most of the work using Java and not in the XML the code will go in to the Activity that you are wanting to play the game in. So set up your Activity with these three things:

1:  public class MainActivity extends Activity {  
2:       GameView gameView;//extends SurfaceView   
3:       FrameLayout game;// Sort of "holder" for everything we are placing  
4:       RelativeLayout GameButtons;//Holder for the buttons  

These three things are the different views that will be used and placed on the screen. The FrameLayout "game" is sort of the holder for the two other views.

Next in the onCreate method of the activity we need to initialize our views. *Note the constructor of your GameView may not be exactly like the one I show so use the appropriate constructor*

1:  @Override  
2:       public void onCreate(Bundle savedInstanceState) {  
3:            super.onCreate(savedInstanceState);  
4:            gameView = new GameView(this);  
5:            game = new FrameLayout(this);  
6:            GameButtons = new RelativeLayout(this);  

Now we will set up just one single button. This should give you the idea of how to setup multiple buttons using the same methods.


1:  Button butOne = new Button(this);  
2:  butOne.setText("Button");  
3:  butOne.setId(123456); //good to set ID to some random number because defaults new button id's all to same number  

Now things get a little less pretty because you have to programmatically define the layouts you want to use.
First the parameters for the button itself:
1:  //Define the layout parameter for the button to wrap the content for both width and height  
2:            RelativeLayout.LayoutParams b1 = new LayoutParams(  
3:                      RelativeLayout.LayoutParams.WRAP_CONTENT,  
4:                      RelativeLayout.LayoutParams.WRAP_CONTENT);  

Next we define and then set the parameters for the GameButtons holder. I know this seems like overkill but when you are using multiple buttons this is very useful to add this extra step.

1:       RelativeLayout.LayoutParams params = new LayoutParams(  
2:                      RelativeLayout.LayoutParams.FILL_PARENT,  
3:                      RelativeLayout.LayoutParams.FILL_PARENT);  
4:            GameButtons.setLayoutParams(params);  

Then we add the button we created as a child of the GameButtons holder and add a rule that will align it to the bottom and right of the GameButtons holder. Then set these layout parameters to our button.

1:  GameButtons.addView(butOne);       
2:  b1.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);  
3:  b1.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
4:  butOne.setLayoutParams(b1); 

Here is where you can set the onclickListener for the button and use it like you would any other button. There are many resources out there that explain how to get the functionality out of a button that you would like so I will not try to encompass all of that.

Now we are at the final step which is pretty easy and self explanatory. All you need to do is add the GameView and GameButtons to our FrameLayout that we titled "game" and set the content of our activity to the game.

1:  game.addView(gameView);  
2:  game.addView(GameButtons);  
3:  setContentView(game);  

This is my first little tutorial over the concepts of a problem that I had of programmatically placing a button on top of a SurfaceView. If you have any questions or there is something I did not explain clearly please just leave a comment or email and I will get back to you.
Hope this helps!
~Justin

10 comments:

  1. Thank you. Really helped me with a school project. Much appreciated !

    ReplyDelete
    Replies
    1. Glad I could help. If there are any more things you would like to see as a tutorial please let me know!
      Have a great day!
      ~Justin

      Delete
  2. thnx for the great tutorial.
    was looking exactly for this.

    i have got a question though.
    i am trying to code a game in which the background is a nintendo gam*boy like image. so i require the width of the buttons u have just helped me adding in. how can i do that??

    ReplyDelete
    Replies
    1. You can actually use the same paradigm we used to place the buttons. You could define a layout parameter for the button to explicitly set the width/height and so on.
      Hope this helps.

      Delete
  3. Have you seen/made a tutorial for doing this thing with XML? I'm not opposed to doing it in Java, but I like to know both sides. :)

    ReplyDelete
    Replies
    1. Wanting to add an XML? try the following

      1. game = new FrameLayout(this);

      2. LayoutInflater layOutInflater = (LayoutInflater) getSystemService (LAYOUT_INFLATER_SERVICE);

      3. viewGameControls = new View(this);

      4. viewGameControls = layOutInflater.inflate (R.layout.ID_OF_YOUR_XML, null);

      5. game.addView(gameView);

      6. game.addView(viewGameControls);

      7. setContentView(game);

      Of course, no need to declare any layout Params because the XML has it all!

      Delete
  4. This comment has been removed by the author.

    ReplyDelete
  5. Hi,

    Please provide me download link for source code.

    Thanks
    Vaibhav

    ReplyDelete
  6. Change your Background.. Its irritating and annoying..

    ReplyDelete