I need to place a dinamic number of buttons in some rows. The number of buttons per row and the size should fit to any screen width.
LinearLayout llh = new LinearLayout(this);
llh.setOrientation(LinearLayout.HORIZONTAL);
for(int i=1; i<=nl; ++i) {
Button b = new Button(this);
b.setText(String.valueOf(i));
if(i>ul) {
b.setFocusable(false);
b.setEnabled(false);
}
llh.addView(b);
}
The problem with this piece of code is that for example, my nl test value is 10, and this only displays 6 buttons, all in the same row, and the last one is smaller than the others.
I need them to stack vertically, like, when there's no space for another button, a new row is created and the rest of the buttons go in there.
Thanks in advance.
Sounds like you are talking about a vertical FlowLayout, where newly added views are stacked vertically until there is no more room, then a new column is started.
Unfortunately Android does not already have a FlowLayout, but you can make your own. Check out this answer by Romain Guy "How can I do something like a FlowLayout in Android?", and watch the video of his talk where he describes how to create one. I learnt a great deal about creating custom layouts by watching this several times until I understood it.
If the width of the screen is less than a certain value, set the weight property to 1 for all buttons. And if the screen width is large enough to fit all your buttons properly, go with the default.
I cannot post the code now as I am far away from my PC.
This is what I came up with. It's not as pretty as I tought but it gets the job done.
Buttons will have fixed size, but that shouldn't be much of a problem.
Thanks for all your help :)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="top|center_horizontal"
android:orientation="vertical"></LinearLayout>
Display display = getWindowManager().getDefaultDisplay();
Point p = new Point();
display.getSize(p);
int buttonSize = 120;
int n = p.x/buttonSize-1;
LinearLayout llv = (LinearLayout)findViewById(R.id.container);
LinearLayout llh = null;
for(int i=0; i<nl; ++i) {
Button b = new Button(this);
if(i%n==0 || i==0) {
llh = new LinearLayout(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llh.setLayoutParams(params);
llh.setOrientation(LinearLayout.HORIZONTAL);
llv.addView(llh);
}
b.setText(String.valueOf(i+1));
b.setWidth(buttonSize);
if(i>ul) {
b.setFocusable(false);
b.setEnabled(false);
}
llh.addView(b);
}
Related
I am trying to add buttons to a GridView for each string from textArray.
void addButtons() {
GridView gridView = (GridView) findViewById(R.id.gridView);
List<Button> buttons = new ArrayList<Button>();
for (int i = 0; i < textArray.length; i++) {
Button newButton = new Button(this);
newButton.setText(textArray[i]);
newButton.setId(i);
newButton.setOnClickListener(onClickListener);
buttons.add(newButton);
}
ArrayAdapter<Button> arrayAdapter = new ArrayAdapter<Button>
(this, android.R.layout.simple_list_item_1, buttons);
gridView.setAdapter(arrayAdapter);
}
But in result, I get this: Virtual Device screen
What can be wrong? Or maybe there is a better way to do the same thing? I've tried LinearLayout and everything was ok, but I was not able to scroll down.
how to add button in gridview dynamically might have a solution, but, to be honest, it is too hard for me at the moment.
Try this out, it shows how to create buttons during runtime https://forums.xamarin.com/discussion/49225/dynamic-buttons-in-gridview
So the initial problem was to get a view with programmatically generated buttons. The first solution was a LinearLayout, but I found out that I was not able to scroll it down, so the number of buttons was limited. On the internet, I found that GridView also can do such a task and it would be scrollable. Well, it is true, but I have stuck upon the problem mentioned in this thread.
After a few days of googling I found that LinearLayout inside ScrollView is what I need. So here is both my xml and java code for someone who stumbles up on the same problem:
<ScrollView
<LinearLayout
android:id="#+id/cityLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<!-- Content here -->
</LinearLayout>
</ScrollView>
void addButtons() {
LinearLayout linearLayout = findViewById(R.id.cityLayout);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams
(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for (int i = 0; i < cityArray.length; i++) {
Button newButton = new Button(this);
newButton.setText(cityArray[i]);
newButton.setId(i);
newButton.setOnClickListener(onClickListener);
linearLayout.addView(newButton, layoutParams);
}
}
Anyway, thanks to everyone for help!
I have a header layout that programmatically needs to be divided into 3 equally sized layouts. I tried weights, but nothing showed up, so I hardcoded the height in there and the root layout (extra header) becomes bigger. So they are working but the background color I have assigned them to doesn't show up, the button that is supposed to show inside the right layout doesn't show up and when I use weights instead of hardcoded numbers, the layouts are also not visible. Am I missing something?
private void SetHeader(LinearLayout extraHeader)
{
ImageView btnSettings = new ImageView(this);
btnSettings.SetBackgroundResource(Resource.Drawable.general_btn_dots_horizontal);
btnSettings.LayoutParameters = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WrapContent, LinearLayout.LayoutParams.WrapContent);
LinearLayout lnLeft = new LinearLayout(this);
LinearLayout lnCenter = new LinearLayout(this);
LinearLayout lnRight = new LinearLayout(this);
extraHeader.Orientation = Orientation.Horizontal;
LinearLayout.LayoutParams lpWeights = new LinearLayout.LayoutParams(200, 500);
//lpWeights.Weight = 33;
lnLeft.SetGravity(GravityFlags.Center);
lnCenter.SetGravity(GravityFlags.Center);
lnRight.SetGravity(GravityFlags.Center);
lnLeft.SetBackgroundColor(Android.Graphics.Color.ParseColor("#222222"));
lnCenter.SetBackgroundColor(Android.Graphics.Color.ParseColor("#333333"));
lnRight.SetBackgroundColor(Android.Graphics.Color.ParseColor("#444444"));
lnLeft.LayoutParameters = lpWeights;
lnCenter.LayoutParameters = lpWeights;
lnRight.LayoutParameters = lpWeights;
lnRight.AddView(btnSettings);
extraHeader.AddView(lnLeft);
extraHeader.AddView(lnCenter);
extraHeader.AddView(lnRight);
}
Also: Making the extra header orientation vertical shows my layouts right... only on top of one another and not side by side...
Remember folks: If the layout already has children (i.e.: from the xml) REMOVEALLVIEWS()
I want to add multiple buttons to a layout programmatically.
However, count of buttons is different every time and I just want them to placed next to each other with a wrap content width. After a line is filled, it should go to next line and continue that way.
What is the cleanest way to achieve that?
Thanks.
LinearLayout verticalLayout = new LinearLayout(context);
verticalLayout.setOrientation(LinearLayout.VERTICAL);
while(isActive) {
LinearLayout horziontalLayout = new LinearLayout(context);
horziontalLayout.setOrientation(LinearLayout.HORIZONTAL);
add buttons here..
//Example Button button = new Button(context);
//horziontalLayout.addView(button);
verticalLayout.addView(horziontalLayout);
isActive = false // when youe done filling up buttons..
}
easiest way should be having a vertical LinearLayout in wich you add multiple horizontal LinearLayout
//vertical one
LinearLayout vlinear = new LinearLayout(this);
vlinear.setOrientation(LinearLayout.VERTICAL);
LayoutParams vlinearParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
vlinear.setLayoutParams(vlinearParams);
parentgroup.addView(vlinear);
//horizontal lines
for (int i=0;i<numlines){
LinearLayout hlinear = new LinearLayout(this);
hlinear.setOrientation(LinearLayout.HORIZONTAL);
LayoutParams vlinearParams = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);
hlinear.setLayoutParams(hlinearParams);
vlinear.addView(hlinear);
///add the loop for adding cells
for...
hlinear.addView(cell);
}
I'm trying to create Buttons in LinearLayout dynamically, and I want to add those in vertical and horizontal way.
At first, add a button A in the layout, and if there's enough space between button A and screen edge, add button B to the right of button A (horizontally). Otherwise, add button B below button A (vertically).
My current layout :
<LinearLayout
android:id="#+id/btn_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
in class :
LinearLayout btnLayout = (LinearLayout) findViewById(R.id.btn_layout);
btnLayout.removeAllViewsInLayout();
for(Tag tag : tagList.getChildTags()) {
Button button = new Button(this);
button.setId(tag.getId());
button.setText(tag.getName());
btnLayout.addView(button);
}
In this case, if I set orientation as horizontal, then some of buttons are not showing (cut-off by screen), and if I set as vertical, it looks pretty bad.
Is there any way to solve this problem? Thanks everyone in advance!
You can achieve this but not in a trivial way. I'll explain how I do something similar (in my case, I add TextViews) to TableRows, if they fit.
With this approach you'll have to use a TableLayout and add TableRows to it with your Buttons. So you might replace your "#+id/btn_layout" LinearLayout to be a TableLayout instead.
Firstly, to get the screen's width, use something like this:
final Display display = getWindowManager().getDefaultDisplay();
final Point size = new Point();
display.getSize(size);
final WindowManager.LayoutParams params = getWindow().getAttributes();
// Your screen's width will be stored within your params.width value
You'll use this to know if the current Button still fits the screen's width within the current TableRow or it has to be added to a new one. So now, use something like this to create your buttons:
int currentRowsWidth = 0;
TableLayout tl = (TableLayout) findViewById(R.id.my_table_layout);
TableRow currentRow = new TableRow();
for (Tag tag : tagList.getChildTags()) {
Button button = new Button(this);
button.setId(tag.getId());
button.setText(tag.getName());
// There's where you check whether it still fits the current `TableRow` or not
if (currentRowsWidth + button.getWidth() < params.width) {
currentRowsWidth += button.getWidth();
currentRow.addView(button);
}
else {
// It doesn't fit, add the currentRow to the table and start a new one
tl.add(currentRow);
currentRow = new TableRow();
currentRow.addView(button);
currentRowsWidth = button.getWidth();
}
}
It might happen that once you get out of the loop there are still Buttons to add in the currentView, simply test it:
if (currentRow.getChildCound() > 0)
tl.add(currentRow);
I'm writing this from head, so some things might not compile at first time, but I hope you get the idea.
Im posting from my phone so please excuse stupid typos and formatting issues.
I have an activity which lists saved games that the player can load.
I created a simple layout xml file which defines a ScrollView. On load, I grab all the saved games and programatically add a view for each saved game to a vertically oriented LinearLayout child of the ScrollView.
The view for each game consists of a Horizontally oriented LinearLayout which in turn contains a Button and a vertically oriented LinearLayout. That LinearLayout in turn contains some TextViews and ImageViews (and one more LinearLayout which I'm ommitting here for the sake of clarity).
The hierarchy looks something like this (some details omitted).
ScrollView
LinearLayout - vertical
Each saved game:
LinearLayout - horizontal
Button - load game
LinearLayout - vertical
TextView - game name
TextView - date string
My problem:
I would like the top of the button and the "game name" texview to be vertically aligned but the TextView (or maybe it's LinearLayout parent) has some rogue padding on top that I can't get rid of. See screenshot for details.
LoadSaved class:
Note: mScrollView is badly named. It refers to the ScrollView's child LinearLayout.
public class LoadSaved extends Activity {
public LinearLayout mScrollView;
private MinerDb mDb;
public void onCreate(Bundle b) {
super.onCreate(b);
setContentView(R.layout.loadsaved);
mDb = new MinerDb(this);
mScrollView = (LinearLayout) findViewById(R.id.load_scroll_view);
Bundle[] savedGames = mDb.getSavedGames();
for (int i = 0; i < savedGames.length; i++) {
Bundle game = savedGames[i];
final int gameId = game.getInt("gameId");
String name = game.getString("name");
String date = game.getString("date");
Bundle player = game.getBundle("player");
int playerMoney = player.getInt("money");
int playerHealth = player.getInt("health");
LinearLayout gameContainer = new LinearLayout(getApplicationContext());
gameContainer.setPadding(5, 5, 5, 5);
gameContainer.setGravity(Gravity.TOP);
gameContainer.setOrientation(LinearLayout.HORIZONTAL);
gameContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
Button loadButton = new Button(getApplicationContext());
loadButton.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
loadButton.setText("Load");
LinearLayout gameInfo = new LinearLayout(getApplicationContext());
gameInfo.setOrientation(LinearLayout.VERTICAL);
gameInfo.setPadding(10,0,10,10);
gameInfo.setGravity(Gravity.TOP);
gameInfo.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
TextView nameView = new TextView(getApplicationContext());
nameView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
nameView.setGravity(Gravity.TOP);
nameView.setText(name);
TextView dateView = new TextView(getApplicationContext());
dateView.setPadding(5,0,0,0);
dateView.setGravity(Gravity.TOP);
dateView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
dateView.setText(date);
LinearLayout playerView = new LinearLayout(getApplicationContext());
playerView.setOrientation(LinearLayout.HORIZONTAL);
playerView.setPadding(5,0,0,0);
playerView.setGravity(Gravity.TOP);
playerView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
TextView playerMoneyView = new TextView(getApplicationContext());
playerMoneyView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
playerMoneyView.setPadding(0,0,10,0);
playerMoneyView.setTextColor(Color.GREEN);
playerMoneyView.setText("$" + playerMoney);
TextView playerHealthView = new TextView(getApplicationContext());
playerHealthView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
playerHealthView.setPadding(0,0,10,0);
playerHealthView.setTextColor(Color.RED);
playerHealthView.setText(playerHealth + "%");
playerView.addView(playerMoneyView);
playerView.addView(playerHealthView);
gameInfo.addView(nameView);
gameInfo.addView(dateView);
gameInfo.addView(playerView);
gameContainer.addView(loadButton);
gameContainer.addView(gameInfo);
mScrollView.addView(gameContainer);
loadButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Log.e("LoadSaved", "LoadSaved::onCreate: Clicking: " + gameId);
Intent loadGameIntent = new Intent(LoadSaved.this, Miner.class);
loadGameIntent.putExtra("load_game", gameId);
startActivity(loadGameIntent);
finish();
}
});
}
}
}
loadsaved.xml
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/load_scroll_view" />
</ScrollView>
</LinearLayout>
If you want any kind of alignment, why don't you use a RelativeLayout? That's basically designed to align one view with another. android:layout_alignTop sounds like something you want.
(And, of course, verify that the padding values are the same in all controls, but I'm sure you did that.)
Why don't you try using a ListView for that kind of gui.
You will still need to define a row xml.
+1 to the answers suggesting ListView and RelativeLayout. For this type of situation you probably want a ListView with an item layout using RelativeLayout. (ListView will scale much better if there are many items, and if this is for a list of saved games it seems like this could grow quite a bit.) For this type of UI it's recommended to have the whole row/list item clickable rather than use a small Load button, but that's a design issue and ultimately up to you.
Don't use getApplicationContext for creating your views. Activity is a Context, just pass this in your case.
By default LinearLayouts try to align child views by their text baseline if present. Note that the bottom of your button's Load text aligns perfectly with the CURRENT_GAME text in your screenshot. Try gameContainer.setBaselineAligned(false).
Normally your gameInfo layout would only report the baseline of one of its children if you set a baselineAlignedChildIndex, but it looks like this behavior changed between cupcake and eclair when creating LinearLayouts programmatically. (Link to the commit that changed it in AOSP here.)