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));
Related
I have created a TableLayout and then I created TableRow dynamically in my java code, and added some buttons in the form of an 8x8 grid. But I want to reduce the space between the buttons. I tried setting LayoutParam for the TableRow , but when I do this , the output shows just a blank screen. Here's my code:
LayoutParams param= new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
field=new Button[8][8];
tb=new TableLayout(this);
param.setMargins(10, 2, 10, 2);
for (int i = 0; i < field.length; i++) {
TableRow current=new TableRow(this);
for (int j = 0; j < field[i].length; j++) {
Button button=new Button(this);
field[i][j]=button;
button.setWidth(40);
button.setHeight(40);
button.setLayoutParams(param);
current.addView(button);
}
tb.addView(current);
}
t.addView(tb);
But when I don't write button.setLayoutParams(param)
I get an output like this:
which is the normal output except that I want the space between the buttons reduced.
The spacing you're seeing is padding built into the standard Android button background asset. You can see that your layout is correct by turning on "Show Layout Bounds" in Settings > Developer Options. You just need to make your own button asset, or if a simple color is all that is needed, then just set the button background to be a color.
In the param.setMargins() call, use negative values as necessary to get past what seems to be some natural spacing. You will also want to give the same layout margins to the table layout, and use WRAP_CONTENT for both the width and height. I am not sure if variable "t" is needed as I created the buttons without it using a TableLayout in an XML file. (I also did a 5x5 grid to fit onto my screen.)
LayoutParams param= new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
field=new Button[5][5];
tb=new TableLayout(this);
// these are the two important changes
param.setMargins(-5, -5, -5, -5);
tb.setLayoutParams(param);
for (int i = 0; i < field.length; i++) {
TableRow current=new TableRow(this);
for (int j = 0; j < field[i].length; j++) {
Button button=new Button(this);
field[i][j]=button;
button.setWidth(40);
button.setHeight(40);
button.setLayoutParams(param);
current.addView(button);
}
tb.addView(current);
}
t.addView(tb);
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
I'm trying to create a TableLayout in code. Each row in the table should have equally spaced columns. The content of each cell is the same and is just a square button (I'm trying to create a calendar).
How do I get each column to take up equal width and then take up the full width the table? Right now the columns are all the same width because they all have the same content, but columns are not expanding to fill the entire width of the table.
The following is what I have tried. I am extending the TableLayout class which is why I use "this" in the code. The lines commented out are things I tried that had no effect:
this.setStretchAllColumns(true);
TableRow row;
CalendarButton button;
for(int i = 0; i < 6; ++i)
{
row = createRow();
TableRow.LayoutParams params = new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
//params.span = 7;
row.setLayoutParams(params);
//row.setWeightSum(7);
for(int j = 0; j < 7; ++j)
{
button = createCalendarButton();
TableRow.LayoutParams params = new TableRow.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
params.span = 1;
row.addView(button, params);
}
this.addView(row);
}
I have a TableLayout in my app, which I need to define and add programmatically, as it builds upon the output of an SQL query. Basically, the result should look similar to a timetable (7 columns for each day in a week, multiple rows for different timeslots per day). For the cells/timeslots, I just need ordinary views with a certain background colour.
The problem is, that all views end up with a height and width of 0, although defined otherwise. What am I doing wrong?
Code:
RelativeLayout.LayoutParams tableLayout = new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
tableLayout.addRule(RelativeLayout.BELOW, R.id.myOtherLayout);
tableLayout.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
TableLayout table = new TableLayout(this);
table.setBackgroundColor(Color.WHITE);
table.setMinimumHeight(PixelConverter.pxToSp(this, 240));
// get availability table data
int[][] tableData = getTableData(...);
if (availability != null) {
// init array of tablerows, which represent one line each for every timeslot
for (int timeSlot = 0; timeSlot < 12; h++) {
// init row
TableRow newRow = new TableRow(this);
newRow.setLayoutParams(new LinearLayout.LayoutParams(
LayoutParams.FILL_PARENT, // width
10)); // height
newRow.setMinimumHeight(10);
// create 7 views in each row - one for each day in a week
for (int day = 0; day < 7; d++) {
View v = new View(this);
v.setLayoutParams(new LinearLayout.LayoutParams(
10, // TODO width
10)); // height
v.setMinimumWidth(10);
v.setMinimumHeight(10);
int cellHue = tableData[day][timeSlot];
if (cellHue >= 0) {
v.setBackgroundColor(Color.HSVToColor(new float[] { cellHue, 100, 100 }));
} else {
v.setBackgroundColor(Color.TRANSPARENT);
}
// add view to tablerow
newRow.addView(v, day);
}
table.addView(newRow, timeSlot);
}
}
table.setId(R.id.my_table_id);
mainLayout.addView(table, tableLayout);
I've encountered a similar issue - the problem appears to be with the choice of type of LayoutParams used after inflating your views. Particularly, the following is probably the root of your problem:
View v = new View(this);
v.setLayoutParams(new LinearLayout.LayoutParams(
10, // TODO width
10)); // height
I'd suggest that you try:
View v = new View(this);
v.setLayoutParams(new TableRow.LayoutParams(
10, // TODO width
10)); // height
The key is that you apparently should specify the type of the parent view when using LayoutParams, rather than the type of the view that you're setting them on. Note that in this case, you'll probably need to specify TableLayout.LayoutParams when calling setLayoutParams on your row, too.
I don't know how well documented this is - I noticed it mentioned on an arbitrary blog I'd found (lost the link now, alas) and I haven't had chance to go back to the official documention yet, but presumably it's there somewhere... :)
Hope this helps!