Recently while working on an Android project I needed to add several buttons to a layout dynamically. I wanted to create them on the fly from an array. That way whenever I need to add another all I would have to do is add another element to the array. The code wasn’t that straightforward and after a while I was able to figure out what to do. Below is what I came up with.
ArrayList
int x=1;
int y =0;
for (NumQuestionsObj gt : gameTypes)
{
Button tempButton = new Button(this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (x==1)
{
y=R.id.tvHighScores;
}
else
{
y=x-1;
}
lp.setMargins(10, 10, 10, 0);
lp.addRule(RelativeLayout.BELOW, y);
lp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE );
tempButton.setLayoutParams(lp);
tempButton.setId(x);
tempButton.setBackgroundResource(R.drawable.custombutton);
tempButton.setText(gt.toString());
tempButton.setTextColor(getResources().getColor(R.color.WHITE));
highscoremenu.addView(tempButton);
final int gameType = gt.getID();
((Button) findViewById(x)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
Intent i = new Intent(mCTX, HighScoresLocal.class);
i.putExtra("gameType", gameType);
startActivity(i);
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
}
}
);
x++;
}
This first part sets up the array list from an object containing all the details. I could have put the data into a table and used a cursor instead. However, my list rarely changes and I wanted to save the overhead on the data access. It also declares and initiates my counter variables for the loop.
ArrayList
int x=1;
int y =0;
This next section starts the loop and declares a generic button. The next line starts the layout parameters for the button. This was the hardest thing I had trouble with as the Android docs are a little confusing here. Next is some logic for where the button will be. I wanted them to line up under a TextView already on the page. So the first element is placed under that element (R.id.tvHighScores). The following elements are placed under the previous view based on the view’s ID. These are assigned dynamically further down.
for (NumQuestionsObj gt : gameTypes)
{
Button tempButton = new Button(this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
if (x==1)
{
y=R.id.tvHighScores;
}
else
{
y=x-1;
}
Here’s where the magic happens. First you add your rules for layout. Next you set the ID. You can use any number here that you want. I recommend using the counter to make it really easy. Next I setup the graphic elements of the view and finally add it to the existing layout.
Last but not least you assign the “value” of the button from your array to a final variable. The reason for this is when you set up the View.OnClickListener() you have the have the variable finalized.
lp.setMargins(10, 10, 10, 0);
lp.addRule(RelativeLayout.BELOW, y);
lp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE );
tempButton.setLayoutParams(lp);
tempButton.setId(x);
tempButton.setBackgroundResource(R.drawable.custombutton);
tempButton.setText(gt.toString());
tempButton.setTextColor(getResources().getColor(R.color.WHITE));
highscoremenu.addView(tempButton);
final int gameType = gt.getID();
What is a button that doesn’t do anything? To solve that problem you also setup the click listener dynamically. After that you increment your counter and start all over again.
((Button) findViewById(x)).setOnClickListener(new View.OnClickListener()
{
public void onClick(View v) {
Intent i = new Intent(mCTX, HighScoresLocal.class);
i.putExtra("gameType", gameType);
startActivity(i);
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
}
}
);
x++;