I'm trying to create a TableLayout programmatically, in order to make a grid-like layout with a configurable row and column count. This would likely be trivial to do in a layout file, but because each child element will be nearly identical and I want the row and column count to be configurable, I would like to do it programmatically if possible.
So far this is what I have.
MainActivity.java
private void displayBoard() {
TableLayout l = (TableLayout) findViewById(R.id.GameGrid);
l.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
for (int y = 0; y < b.height(); y++) {
TableRow r = new TableRow(this);
r.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, 15));
for (int x = 0; x < b.width(); x++) {
r.addView(b.getSpaceAt(x, y));
}
l.addView(r);
}
}
Board.java
for (int y = 0; y < spaces.length; y++) {
for (int x = 0; x < spaces[0].length; x++) {
spaces[y][x] = new BoardSpace(context, x, y);
}
}
BoardSpace.java
public class BoardSpace extends Button {
private ReversiPiece piece;
protected int x, y;
private BoardSpace(Context c) {
super(c);
}
public BoardSpace(Context c, int x, int y) {
super(c);
// this.setWidth(25); // Doesn't make a difference, either
// this.setHeight(15); // Doesn't make a difference, either
piece = null;
this.x = x;
this.y = y;
}
public ReversiPiece piece() {
return piece;
}
public void setPiece(ReversiPiece p) {
piece = p;
}
}
I'm basically trying to create a grid of buttons, but so far I cannot get the size of the buttons to change so I can make sure they all fit on the screen. At the moment they appear at a standard size, and any changes I make to the LayoutParams definitions do not make a difference.
I suspect this issue has to do with my usage of LayoutParams. There are a lot of LayoutParams classes associated with each View type, so perhaps I'm not using the right one? Any help would be appreciated.
EDIT: Now creating a new TableLayout.LayoutParams object for each TableRow based on cyanide's recommendation, but the buttons are still displaying at default size.
You are right, that's about LayoutParams, which must not be shared between views: each view should have its own copy of LayoutParams.
In other words, this is what you need:
r.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, 15));
About getSpaceAt (there is not code for it). Does it create a view programmatically? Remember to set LayoutParams and again it should be separate for each view.
Hopefully it will help.
Got it! I was trying to manipulate the LayoutParams of my TableLayout and TableRows when in reality I needed to set TableRow.LayoutParams on the buttons themselves, when I add them to TableRow. This involves specifying the weight of each child element (Button) as well.
private void displayBoard() {
TableLayout l = (TableLayout) findViewById(R.id.GameGrid);
l.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
for (int y = 0; y < b.height(); y++) {
TableRow r = new TableRow(this);
r.setWeightSum(b.width());
for (int x = 0; x < b.width(); x++) {
BoardSpace s = b.getSpaceAt(x, y);
s.setLayoutParams(new TableRow.LayoutParams(
TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.MATCH_PARENT, 1.0f));
r.addView(s);
}
l.addView(r);
}
}
TableRow.setWeightSum() is used to set the weight sum of the row to the number of elements in the row, then passing a weight of 1 to the LayoutParams for the button causes the buttons to adjust in size to fit on the screen, as intended.
Surprisingly this answer was for a more generic question but this is what led me to the solution:
How to set layout_weight attribute dynamically from code?
Related
I have a TableLayout with cells, populated like this:
TableLayout tableLayout = (TableLayout) getActivity().findViewById(R.id.button_table);
for (int y = 0; y < 4; y++) {
TableRow row = new TableRow(getActivity());
row.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
for (int x = 0; x < 3; x++) {
Button button = new Button(getActivity());
button.setText("Button");
button.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mainPresenter.processAction(((Button)v).getText().toString());
}
});
buttons.add(button);
row.addView(button);
}
tableLayout.addView(row, new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT));
}
This works nicely to start with, however sometimes the buttons have their text set to something that is too large for the allocated width. This results in the button expanding to accommodate the text.
I would like it to work the other way around - the buttons maintain their assigned width, and instead the font that is used shrinks to make sure that the text fits into the button. How can I do this?
when you add the button into a table row, instead of using buttons.add(button);, use buttons.add(button, new TableRow.LayoutParams(100, 100)); which would make the button be 100x100 large.
the actual wondering is the following : I have a full-screen GridLayout which has half of it visible. To see the second part we have to scroll.
I tried some ways and looked around for answers but none of whichs I found gave me what I need. In my grid there are square cells and each one contains a view, and I need to get the x and the y of these views.
Problem is that I could get the coordinates of the views that were put into the visible cells, the views that are not displayed have a x and a y set to 0... Whereas they were drawn..
Here it is, hope some of you guys could help! :)
private void createGrid(){
//I call the function several times
int gridsLength = 19*48*grids;
for(int i = 0; i < 19; i++) {
for (int j = 0; j < 48; j++) {
GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
layoutParams.width = 40;
layoutParams.height = 40;
View view = new View(this);
view.setLayoutParams(layoutParams);
Util.setDrawableBackground(view, R.drawable.border_black, this);
view.setOnTouchListener(newViewListener());
gridViews.add(view);
//glMain is my gridLayout that i put into global variable
glMain.addView(view, i + j + gridsLength);
}
}
grids++;
}
EDIT : I finally found out that I was not always accessing the views AFTER the grid were drawn so I changed that and it's working... Figured out that I was just a fool ^^
I'm trying to learn how to write Android programs, and I'm having trouble figuring out how padding works, in particular in a FrameLayout within a TableLayout.
private void fillTable(int nrows, int ncols) {
final int CENTER = 0x11; // used for "gravity" parameters
TableLayout table = (TableLayout) this.findViewById(R.id.tablelayout);
int counter = 1;
TextView text;
for (int i = 0; i < nrows; i++) {
TableRow row = new TableRow(this);
table.addView(row);
for (int j = 0; j < ncols; j++) {
View cell;
text = new TextView(this);
text.setTextColor(Color.BLUE);
text.setText(Integer.toString(counter++));
text.setGravity(CENTER);
if (i == 2 && j == 2) {
FrameLayout frame = new FrameLayout(this);
text.setLayoutParams(new FrameLayout.LayoutParams(90, 45, CENTER));
frame.setPadding(0, 0, 0, 0);
frame.addView(text);
cell = frame;
} else {
cell = text;
}
cell.setBackgroundColor((i + j) % 2 == 0 ? Color.YELLOW : Color.WHITE);
row.addView(cell);
cell.setLayoutParams(new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1F/ncols));
}
row.setLayoutParams(new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1F/nrows));
}
}
tablelayout just looks like this:
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tablelayout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</TableLayout>
I'm calling this with nrows=12 and ncols=5. I'm running on an emulator whose width is 720 pixels. If I change if (i==2&&j==2) to if (false), so that only an array of TextView is displayed, the columns are even, as I expect. However, with the code as written, the middle column is wider than the others.
I've also tried this adding android:stretchColumns="*" to the tablelayout definition and removing the weight parameter from cell.setLayoutParams, and the results are the same.
Assuming I have a reason to want to specify pixels for text.setLayoutParams (because of what I plan to do later), how would I get the column widths to be the same? Since 90*5 is well under 720, I don't understand why, or where, the extra width is being added.
Whenever you are dealing with weights, you must let the option take care of the remaining space. In this case width. Just set the width of each element to 0:
cell.setLayoutParams(new TableRow.LayoutParams(0, LayoutParams.MATCH_PARENT, 1F/ncols));
I am creating a Android app. This Android App will have objects that are dynamic. These objects are Places with a Address or Lat/Long, and distance from current location, and a ETA. What I would like to do is add with objects on a TableLayout with borders, but I need to be able to dynamically add rows as the number of places increase.
I understand somewhat how to do this for a fixed hardcoded number of items on the xml, but what would be the best way when the number of objects is coming from the Activity.java file?
Below is a screenshot of the TableLayout I would like:
So the object would be a place with a address, distance and direction.
but I need to be able to dynamically add rows as the number of places increase.
This isn't difficult, when you have a new object append a TableRow with the data to the TableLayout.
I understand somewhat how to do this for a fixed hardcoded number of items on the xml, but what would be the best way when the number of objects is coming from the Activity.java file?
I don't think there is a best way (or what you consider best way). You either:
Insert fake views to act as dividers. This would be easier to implement visually but it will also increase the memory consumption of your app, with bad consequences if the number of rows is big. (1)
Or use drawables for the backgrounds to simulate the borders (like nine-patch images). This would be simpler then inserting additional views but you need a bit more talent to make it look well. (2)
Some examples for your image:
(1)
private static final int DIVIDER_SIZE = 2;
// rowsCount the number of rows to add to the TableLayout
private void buildOldSchool(TableLayout table, int rowsCount) {
View divider;
for (int i = 0; i < rowsCount; i++) {
TableRow row = new TableRow(this);
for (int j = 0; j < 7; j++) {
if (j % 2 == 0) {
divider = new View(this);
divider.setLayoutParams(new TableLayout.LayoutParams(
DIVIDER_SIZE, TableLayout.LayoutParams.MATCH_PARENT));
divider.setBackgroundColor(Color.GREEN);
row.addView(divider, new TableRow.LayoutParams(
DIVIDER_SIZE, TableRow.LayoutParams.MATCH_PARENT));
continue;
}
TextView tv = new TextView(this);
tv.setText("DX"); // dummy data
row.addView(tv, new TableRow.LayoutParams(
TableRow.LayoutParams.MATCH_PARENT,
TableRow.LayoutParams.WRAP_CONTENT));
}
divider = new View(this);
divider.setLayoutParams(new TableLayout.LayoutParams(
TableLayout.LayoutParams.MATCH_PARENT, DIVIDER_SIZE));
divider.setBackgroundColor(Color.GREEN);
if (i == 0) {
table.addView(divider);
divider = new View(this);
divider.setLayoutParams(new TableLayout.LayoutParams(
TableLayout.LayoutParams.MATCH_PARENT, DIVIDER_SIZE));
divider.setBackgroundColor(Color.GREEN);
}
table.addView(row);
table.addView(divider);
}
}
(2) or with images:
private void buildWithDrawables(TableLayout table, int rowsCount) {
for (int i = 0; i < rowsCount; i++) {
TableRow row = new TableRow(this);
row.setBackgroundResource(i == 0 ? R.drawable.firstrow
: R.drawable.normalrow);
for (int j = 0; j < 3; j++) {
TextView tv = new TextView(this);
tv.setBackgroundResource(j == 2 ? R.drawable.extra
: R.drawable.cell);
tv.setText("DX");
row.addView(tv, new TableRow.LayoutParams(
TableRow.LayoutParams.MATCH_PARENT,
TableRow.LayoutParams.WRAP_CONTENT));
}
table.addView(row);
}
}
Where the images are:
R.drawable.cell:
R.drawable.extra (a visually transparent drawable which replicates the nine-patch above):
R.drawable.normalrow:
R.drawable.firstrow:
Ignore my design skills.
If your foresee a large number of rows I would advise you to use a ListView, which you could pretty easy make it to look like a table with borders.
Couldn't figure out the vertical line, but something you can build upon
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ScrollView sv = new ScrollView(this);
TableLayout ll=new TableLayout(this);
HorizontalScrollView hsv = new HorizontalScrollView(this);
for(int i=1;i<5;i++) {
TableRow tbrow=new TableRow(this);
for(int j=1;j<=3;j++) {
TextView tv1=new TextView(this);
tv1.setText("Element :"+ i + "" + j);
tbrow.addView(tv1);
}
ll.addView(tbrow);
View v = new View(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 5);
v.setLayoutParams(params);
v.setBackgroundColor(getResources().getColor(android.R.color.white));
ll.addView(v);
}
hsv.addView(ll);
sv.addView(hsv);
setContentView(sv);
}
I am using a TableLayout to print nine pictures. For some reason, I am getting a big gap between rows as shown in the image below. I set the background to green so the gaps are easy to see. My TableLayout is created programmatically. How do I fix this problem so that the gap between rows is not so big?
I have already tried tableRowParams.setMargins(0,0,0,0).
BTW: No I don't want to use ListView, etc.
I have been messing around with the code a lot trying to fix the problem. Below is simply the current state of the code:
EDIT: CORRECT IMAGE:
EDIT: the code now will work fine (thanks to #Guian):
public class FacialExpressionImagesTable extends TableLayout {
public FacialExpressionImagesTable(Context context, List<Bitmap> imageList, int sideDimension, int tableWidth, int tableHeight) {
super(context);
setLayoutParams(new TableLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
setBackgroundColor(Color.BLUE);
setContent(imageList, context, sideDimension);
}
private void setContent(List<Bitmap> imageList, Context context, final int sideDimension) {
final int iHeight = imageList.get(0).getHeight();
final int iWidth = imageList.get(0).getWidth();
int ndx = 0;
for (int r = 0; r < sideDimension; r++) {
TableRow tableRow = new TableRow(context);
TableLayout.LayoutParams forRow = new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
tableRow.setLayoutParams(forRow);
tableRow.setBackgroundColor(Color.RED);
TableRow.LayoutParams elementLayout = new TableRow.LayoutParams(iWidth, LayoutParams.WRAP_CONTENT, 1);
tableRow.requestLayout();
for (int c = 0; c < sideDimension; c++) {
ImageView element = new ImageView(context);
element.setLayoutParams(elementLayout);
element.setAdjustViewBounds(true);
element.setPadding(0, 0, 3, 3);
element.setBackgroundColor(Color.GREEN);
element.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
element.setImageBitmap(imageList.get(ndx++));
element.requestLayout();
tableRow.addView(element);
}
addView(tableRow);
}
}
}
first : be aware that you exchange width and height in :
new TableRow.LayoutParams(iHeight, iWidth);
But anyway, you can't give your table itesm the size of the bitmap's getHeight and getWidth since they will be resized ( depending on the screen size, screen density etc ... you would have to compute the new size according to density... )
here I think they are reduced. that's why the height of the row is too big.
set your layout params so the element take wrap_content in height and 0dip with a layout_weight to 1 in width;
TableRow.LayoutParams elementLayout = new TableRow.LayoutParams(0, LayoutParams.WRAP_CONTENT, 1 );
then the table row take wrap content as height :
TableLayout.LayoutParams forRow = new TableLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
if image are not scaled as needed, you'll may have to set a scale type to your ImageViews : ( using setScaleType )
elementLayout.setScaleType(ScaleType.CENTER_INSIDE); // or
FIT_CENTER... not quite sure
It should be good, tell if its not.
hope that helps.
Also try setting padding to 0 so that there is no padding inside each row of your table