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.
Related
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.
Can anyone tell me why this is happening, please?
What I'm trying to do is get them to all align centered, regardless of how many there are. It works lovely for quite a few, and even works with only 1 more, but 4 seems to do this. I'm adding them in code, here:
LinearLayout guessHolders = (LinearLayout)findViewById(R.id.guessHolders);
guessHolders.removeAllViews();
currentLetterPosition = 0;
final Bitmap emptyLetterHolder = BitmapFactory.decodeResource(getResources(), R.drawable.letter_holder);
for(int i=0; i<Globals.mUser.getLevel().getSolution().length(); i++)
{
final EmptyLetter tmp = new EmptyLetter(this, i);
tmp.setImageBitmap(emptyLetterHolder);
LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(Globals.defaultLetterSizes[mBlockSize],
Globals.defaultLetterSizes[mBlockSize], 1);
parms.weight = 1;
parms.gravity = Gravity.CENTER_HORIZONTAL;
tmp.setLayoutParams(parms);
tmp.setAdjustViewBounds(false);
tmp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("PP2", tmp.getId() + " << the clicked empty letter holder id");
currentLetterPosition = tmp.getId();
tmp.setImageBitmap(emptyLetterHolder);
setChosenLetter(tmp.getId(), '\u0000');
}
});
currentEmpties.add(tmp);
guessHolders.addView(tmp);
}
I've tried setting gravity, weightsum, width and height of the box views as well as the parent container LinearLayout, but nothing seems to shift them.
Any help is greatly appreciated!
Fixed it. With the following:
LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(Globals.defaultLetterSizes[mBlockSize],
Globals.defaultLetterSizes[mBlockSize], 0);
parms.gravity = Gravity.CENTER_HORIZONTAL;
tmp.setLayoutParams(parms);
So, I set the weighting to zero and leave the rest to the OS. Works for all of them now. Marvelous.
Cheers
I'm trying to make a dynamic grid layout, it being API 10+ is the part that's been making it slow going. I tried to make it wrap automatically.. but in the end found it easier just to try to force it into a grid pattern using coordinates. This script was working by itself when I did the positioning at time of creation, but now I am trying to loop through each item as a sort. So if one item is deleted, they all float back into a grid without a hole in the middle.
Problem is, it seems the layout parameters are only applying to the last object.
Here's some base variables and onCreate setup:
int screenWidth;
int screenHeight;
int distStep = 130;
int leftPad = 20;
int numCols;
int baseID = 0;
android.util.DisplayMetrics metrics = this.getResources().getDisplayMetrics();
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
numCols = (int) (screenWidth - leftPad) / distStep;
int scrRemain = screenWidth - ((numCols * distStep) + leftPad);
distStep += (int) scrRemain / numCols;
Then on to the main function for adding:
public void addObjToLayout() {
RelativeLayout relLay = (RelativeLayout) this.findViewById(R.id.mainWindow);
for(int i = 1; i <= currQuantity; i++){
TextView tv=new TextView(this);
tv.setTextSize(40);
tv.setId(baseID + i);
tv.setPadding(24, 4, 24, 4);
tv.setBackgroundColor(0x110000FF);
tv.setText(String.valueOf(baseID + i)); //Val for debugging
tv.setTextColor(0xFFFFFFFF);
relLay.addView(tv);
}
baseID += currQuantity;
sortLayout();
}
Then the sorting:
public void sortLayout() {
int leftNum = 20;
int topNum = 0;
for(int i = 1; i <= baseID; i++){
TextView tv= (TextView) this.findViewById(baseID);
MarginLayoutParams mp = new MarginLayoutParams(tv.getLayoutParams());
mp.setMargins(leftNum, topNum, 0, 0);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(mp);
tv.setLayoutParams(lp);
leftNum += distStep;
if(leftNum >= distStep * numCols){
leftNum = leftPad;
topNum += distStep;
}
}
}
What I am getting is all the textViews pile up in the top left corner, except the last one which is positioned exactly where it should be. So it seems in my head, the params object isn't applying until the loop ends or something.. but logically I don't see why.
As I said, this worked when I set the params at the get go, problem is mass updating them all at once. I am pretty new to android, so I hope I'm not just doing something stupid.
Thanks for your time
Margin means it will set a gap between the previous view and current view.
When you add view1, view2 and view3 to grid layout and if you remove view2 at some point of time, then the margin for view3 is set according to view1. So, it won't leave empty space in place of view2. Instead of removing view2 at run time, set the background for view2 as null and set the text as empty as below.
textView.setBackground(null);
textView.setText("");
So that the view is still available but looks as deleted.
Started looking into GridView using an extended baseAdapter. Looks promising:
For more (see #2):
http://www.mkyong.com/android/android-gridview-example/
I was wondering how I could "randomly" place an array of Buttons in a RelativeLayout?
Is it possible to space the buttons around the entire view?
Thanks for your help! I tried using setX() and setY() but they are float numbers and I'm unsure how they place the buttons in proportion to the size of the screen.
You can add layout margins to your buttons. As margins will be interpreted not relative to each other but to the frame, it will in fact position your buttons.
To set the margins you have to set the view's layout params:
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
Random random = new Random();
params.leftMargin = random.nextInt(100);
params.topMargin = random.nextInt(100);
button.setLayoutParams(params);
However this may cause your buttons to overlap, or be outside the Activity, so it's best not to use entirely random values for positions but to perform checks for overlapping and set random ranges according to the device resolution and button size.
To get device display size:
Display display= activity.getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int Height = display.getHeight();
instead do something like this first create a button array and find the respective id...
LayoutParams lp = new LinearLayout.LayoutParams(widthOfButtons,LayoutParams.WRAP_CONTENT);
Button[] buttons;
for(int i=0; i<4; i++) { //suppose you have four buttons
{
String buttonID = "button" + (i+1);
int resID = getResources().getIdentifier(buttonID, "id", getPackageName());
buttons[i] = ((Button) findViewById(resID));
buttons[i].setHeight(yourvalue);
buttons[i].setWidth(yourvalue);
buttons[i].setLayoutParams(lp);
}
hope it works for your
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