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
Related
I am creating a Table of buttons, to control a LED Matrix via Bluetooth.
I have found on the web Brian's Video Tutorials and followed his Dynamic Buttons and Images video to implement this.
Here is the code:
public class DrawerMode extends Activity {
private static final int NUMOFCOL = 15;
private static final int NUMOFROW = 8;
Button buttons[][] = new Button[NUMOFROW][NUMOFCOL];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Assign content
setContentView(R.layout.activity_draw_mod);
fillTable();
}
private void fillTable() {
TableLayout tableLayout = (TableLayout) findViewById(R.id.drawer_table);
for( int iter_R = 0; iter_R!= NUMOFROW; iter_R++){
TableRow tableRow = new TableRow(this);
tableRow.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT,TableLayout.LayoutParams.WRAP_CONTENT,1.0f));
tableLayout.addView(tableRow);
for(int iter_C = 0; iter_C != NUMOFCOL; iter_C++){
final int FINAL_COL = iter_C;
final int FINAL_ROW = iter_R;
Button button = new Button(this);
button.setLayoutParams(new TableRow.LayoutParams( TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.MATCH_PARENT, 1.0f));
button.setText("" + iter_C + "," + iter_R);
button.setPadding(0, 0, 0, 0);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
whenBtnClicked(FINAL_COL, FINAL_ROW);
}
});
tableRow.addView(button);
buttons[iter_R][iter_C] = button;
}
}
}
private void whenBtnClicked(int col, int row) {
//Toast.makeText(this, "Button clicked: " + FINAL_COL + "," + FINAL_ROW, Toast.LENGTH_SHORT).show();
Button button = buttons[row][col];
// Lock Button Sizes:
lockButtonSizes();
int newWidth = button.getWidth();
int newHeight = button.getHeight();
Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_dark_blue);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true);
Resources resource = getResources();
button.setBackground(new BitmapDrawable(resource, scaledBitmap)); // Change text on button:
button.setText(" ");
}
private void lockButtonSizes(){
for (int row = 0; row < NUMOFROW; row++){
for (int col = 0; col < NUMOFCOL; col++){
Button button = buttons[row][col];
int width = button.getWidth();
button.setMinWidth(width);
button.setMaxWidth(width);
int height = button.getHeight();
button.setMinHeight(height);
button.setMaxHeight(height);
}
}
}
}
It works great, but while testing I have found the following issue.
When I click random buttons it works great:
[img]http://i.imgur.com/OYFJ6zJ.png?1[/img]
But when I complete a row (all elements on row are clicked), and I mean any row it starts to rescale the buttons in the whole table:
[img]http://i.imgur.com/ttAz4U0.png?1[/img]
I was thinking that maybe the LayoutParams of the TableRow should be changed, but not sure about that. What am I missing here?
I think you're right about the layout parameters needing to change. This line
tableRow.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT,TableLayout.LayoutParams.WRAP_CONTENT,1.0f));
would cause the row's height to shrink in size if no button had displayed text, which seems to be what's happening. The TableLayout.LayoutParams does support setting fixed width/height, which you could sensibly calculate by first getting the device's screen width/height and dividing accordingly.
Or, if that gets to cumbersome, you could set -- though this may be too much of a hack -- the default text in the TextViews in the "unset" buttons with some transparent text (e.g., "1,1") so that the height is the same as a set button. This SO answer answer shows how to make transparent text.
I am certain that this is not a good solution for all cases. But just as I thought, the problem was with
button.setLayoutParams(new TableRow.LayoutParams( TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.MATCH_PARENT, 1.0f));
If I understand correctly after the entire row was clicked, since the LayoutParams change according to the MATCH_PARENT value, the TableRow rescales the whole row to meet this criteria,since the height of the entire row is the same now. Not sure if it happens exactly this way, but I think this is the case because of my solution.
My work around is to add specific values for the LayoutParams, instead of leaving it the system to figure it out:
button.setLayoutParams(new TableRow.LayoutParams( 75, 50, 1.0f));
I am aware this is not how it should be done. But since I have a deadline to met soon, I can't spend any more time with it. Most likely the correct way to do this is Jason's suggestion to get the screen size and calculate it. You can do this with:
Display display = getWindowManager().getDefaultDisplay(); Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
The problem is to come up with a correct formula to calculate this values you can pass to the LayoutParam. If anyone can figure this out please do post your solution and I will accept that answer. At this point I accept Jason's suggestion.
Hey I have a grid of ImageButtons that is being scaled by display width and contains a PNG file as image. I add the whole thing to the linear layout like this:
public void createButtons(){
int buttonX = 9;
int buttonY = 9;
int size = 80;
int tag = 0;
TableLayout layout = new TableLayout (this);
layout.setLayoutParams( new TableLayout.LayoutParams(900,900) );
layout.setPadding(1,1,1,1);
layout.setBackgroundColor(0xff00af00); //green
RelativeLayout ll = (RelativeLayout)findViewById(R.id.rel);
ll.addView(layout);
for(int x=0;x<buttonX;x++) {
TableRow tr = new TableRow(this);
for(int y=0;y<buttonY;y++) {
but[x][y] = new ImageButton(this);
but[x][y].setBackgroundColor(0xff0000af); //blue
but[x][y].setImageResource(R.drawable.buttonmask3);
but[x][y].setScaleType(ImageButton.ScaleType.CENTER_INSIDE);
tr.addView(but[x][y], height/10,height/10);
}
layout.addView(tr);
}
}
The problem is, that the layout now looks like the following:
whereas it is supposed to look like:
(this one was a quick photoshop but you get the idea, that the scale is supposed to fill the button completely)
What can I do about these tiny images? I tried CENTER_INSIDE, FITXY and all the other ScaleTypes but I haven't been lucky so far :/
The width is taken from the screen width (or height in landscape)
the buttonmask3.png is about 170*170 px.
The problem is the padding that the ImageButton comes with naturally.
adding
but[x][y].setPadding(0, 0, 0, 0);
along with
but[x][y].setScaleType(ImageButton.ScaleType.CENTER_CROP);
Solved it for me.
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 have a TableLayout with multiple TableRow views inside it. I wish to specify the height of the row programatically. E.g.
int rowHeight = calculateRowHeight();
TableLayout tableLayout = new TableLayout(activity);
TableRow tableRow = buildTableRow();
TableLayout.LayoutParams rowLp = new TableLayout.LayoutParams(
LayoutParams.FILL_PARENT, rowHeight);
tableLayout.addView(tableRow, rowLp);
But this isn't working and is defaulting to WRAP_CONTENT. Digging around in the Android source code, I see this in TableLayout (triggered by the onMeasure() method):
private void findLargestCells(int widthMeasureSpec) {
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child instanceof TableRow) {
final TableRow row = (TableRow) child;
// forces the row's height
final ViewGroup.LayoutParams layoutParams = row.getLayoutParams();
layoutParams.height = LayoutParams.WRAP_CONTENT;
Seems like any attempt to set the row height will be overridden by the TableLayout. Anyone know a way around this?
OK, I think I've got the hang of this now. The way to set the height of the row is not to fiddle with the TableLayout.LayoutParams attached to the TableRow, but the TableRow.LayoutParams attached to any of the cells. Simply make one cell the desired height and (assuming its the tallest cell) the entire row will be that height. In my case, I added an extra 1 pixel wide column set to the desired height which did the trick:
View spacerColumn = new View(activity);
//add the new column with a width of 1 pixel and the desired height
tableRow.addView(spacerColumn, new TableRow.LayoutParams(1, rowHeight));
First of all, You should convert it from dps to pixels using the display factor formula.
final float scale = getContext().getResources().getDisplayMetrics().density;
int trHeight = (int) (30 * scale + 0.5f);
int trWidth = (int) (67 * scale + 0.5f);
ViewGroup.LayoutParams layoutpParams = new ViewGroup.LayoutParams(trWidth, trHeight);
tableRow.setLayoutParams(layoutpParams);
I'm trying to create a chess game board with 8x8 buttons. I'm using nested LinearLayouts. The problem is that there's a padding between each row of ImageViews that I can't get rid of. This is what I have sofar, the board should be square, but isn't:
public class BoardLayout extends LinearLayout {
public BoardLayout(Context context) {
super(context);
LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f);
setLayoutParams(parms);
setOrientation(LinearLayout.VERTICAL);
setPadding(0, 0, 0, 0);
for (int i = 0; i < 8; i++) {
LinearLayout row = new LinearLayout(context);
row.setLayoutParams(parms);
row.setOrientation(LinearLayout.HORIZONTAL);
row.setPadding(0, 0, 0, 0);
for (int j = 0; j < 8; j++) {
ImageView button = new ImageView(context);
button.setLayoutParams(parms);
button.setImageResource(R.drawable.icon);
button.setAdjustViewBounds(true);
button.setPadding(0, 0, 0, 0);
row.addView(button);
}
addView(row);
}
setSquare();
}
public void setSquare() {
int size = Math.min(getWidth(), getHeight());
// setHeight(size); // Not Function, but this is what I need
// setWidth(size); // Not Function, but this is what I need
// also doesn't work
setLayoutParams(new LinearLayout.LayoutParams(size, size, 1.0f));
}
}
Solution:
As suggested TableLayout is better for what I'm trying to do. So the main class should be changed to a TableLayout and the nested LinearLayouts to TableRows.
But that alone didn't fix it, I also had to call the following in TableLayout:
setShrinkAllColumns(true);
setStretchAllColumns(true);
and for each item inserted, I had to also call:
setAdjustViewBounds(true);
TableLayout
Class Overview
A layout that arranges its children
into rows and columns. A TableLayout
consists of a number of TableRow
objects, each defining a row
(actually, you can have other
children, which will be explained
below). TableLayout containers do not
display border lines for their rows,
columns, or cells.
You are better off using a GridView or TableLayout instead of nested LinearLayouts, since that's what they're designed for.