Android - Dynamically created View's unexplained top margin - android

The idea is to create TextViews for programs in nice little 200x200 squares in the shape of your favourite tetris squares. These views then move on to their own course relevant to themselves.
Problem im facing is this:
The first two views have this step difference from the top that comes from nowhere. Need to align them side by side instead.
I've checked their margins when debugging, and it was the same, as well as the layout they are in and well, the code below.
Relevant code below:
for (int i = 0; i < 2; i++) {
TableRow tr = new TableRow(this);
tr.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
// within each tablerow, we then create the tablecolumns
// assuming we want two columns only. Change 2 otherwise.
for (int j = 0; j < 2; j++) {
try {
TextView nyan = new TextView(this);
nyan.setText(pail.get(count).getProgramName());
nyan.setClickable(true);
nyan.setLayoutParams(new LayoutParams(200, 200));
nyan.setGravity(Gravity.CENTER);
//nyan.setPadding(10, 50, 10, 50);
nyan.setBackgroundColor(R.drawable.programlistback);
nyan.setSingleLine(false);
nyan.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(v.getContext(),
CourseList.class);
i.putExtra("selectedProgram", pail.get(count)
.getProgramID());
startActivity(i);
}
});
tr.addView(nyan);
// when done with textview creation, update tick for nyan
count++;
} catch (IndexOutOfBoundsException e) {
Log.i("expect", "tableOrigin - hit " + count + "th index");
}
}
tabLayout.addView(tr, new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}

Related

How can I create a button with scaling text

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.

How do I randomly place/set/allocate items within a 2D Array?

I’ve been trying to create a minesweeper game in android, and so far, all has gone accordingly. However, I’m currently stuck on the part where I have to randomly place the mines within the game board.
I’ve tried a few things that I could think of, but none of which worked, except one. However, it doesn’t give me the results that I want. Here is how I am drawing the game board (using a 2D array of buttons).
final Button currentButton = new Button(this);
final int bombState = R.drawable.bomb_state;
final Button[][] buttonArray = new Button[6][6];
final int mine = R.drawable.bomb;
final Random rand = new Random();
final int number = 36;
int button;
int row;
//create new Linear Layout
RelativeLayout linearLayout = new RelativeLayout(this);
//creating the layout Params
LayoutParams linLayoutParam = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
//set layout background
linearLayout.setBackgroundDrawable(getWallpaper());
//set LinearLayout as a root element of the screen
setContentView(linearLayout, linLayoutParam);
//create a new Table Layout for the game grid
TableLayout mineGrid = new TableLayout(this);
/*
* creates TableRows and Buttons using the for loop
* then add the buttons into the rows and the rows
* into the TableLayout
*/
for(row = 0; row < 6; row++){
//create new Table Row
TableRow currentRow = new TableRow(this);
for(button = 0; button < 6; button++){
//create new Button
for(int id = 0; id < number; id++){
currentButton.setId(id);
}
currentButton.setText(" ");
//storing the buttons into the array of Buttons
buttonArray[row][button] = currentButton;
if(currentButton.isClickable()){
currentButton.setOnClickListener(new OnClickListener() {
/*
* (non-Javadoc)
* #see android.view.View.OnClickListener#onClick(android.view.View)
*/
public void onClick(View v) {
try
{
for(int i = 0; i < 10; i++){
if(rand.nextInt(10) == i){
currentButton.setBackgroundResource(mine);
restart.setBackgroundResource(bombState);
}
}
} catch(Exception e)
{
Toast.makeText(Game.this,e.getMessage() + "Error : ",
Toast.LENGTH_SHORT).show();
}
}
});
}
//store the button into the Table Row
currentRow.addView(currentButton);
}
//add the newly created row into the table
mineGrid.addView(currentRow);
}
linearLayout.addView(score, params3);
linearLayout.addView(mineGrid, params);
}
What the above code gives me, is a 6x6 grid made up of buttons.
And the following is where I’m trying to randomly place n amount of mines within the board.
try
{
for(int i = 0; i < 10; i++){
if(rand.nextInt(10) == i){
currentButton.setBackgroundResource(mine);
restart.setBackgroundResource(bombState);
}
}
}
Unfortunately, this fills the whole board with mines, instead of only placing n amount of mine on the board. I know am missing something when I try to randomly set the mines! Can anyone advise me as to where I’m going wrong and help point me in the right direction?
Please ask me anything for clarification.
Thanks in advance.
You basically, on every click of a button try to place a mine instead placing them when you create buttons. Maybe You could add to a list, id of a buttons which are mines and only check if user has clicked on one of those buttons.
ArrayList<Integer> mines = new ArrayList<Integer>();
.
.
.
currentButton.setText(" ");
if(rand.nextInt(2)==1)
mines.add(currentButton.id);
and in onClick() You check if currentButton.id is in mines list and if it is, display appropriate image.

Adding a dynamic TableLayout with borders in a Android App

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);
}

Android change visibility doesn't work

Simple card game setup creating rows and columns number of cards:
TableLayout tableCards = new TableLayout(this);
RelativeLayout.LayoutParams relLayParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
relLayParams.addRule(RelativeLayout.CENTER_IN_PARENT);
tableCards.setLayoutParams(relLayParams);
int i = 0;
StringBuilder sbCardsDebug = new StringBuilder('\n');
for (int r = 0; r < rows; r++) {
// create a new row
TableRow tr = new TableRow(this);
tr.setLayoutParams(new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT, TableLayout.LayoutParams.WRAP_CONTENT));
for (int c = 0; c < columns; c++) {
ImageView card = new ImageView(this);
card.setTag("" + i);
card.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT));
card.setImageDrawable(bitmapCardBackScaled);
tr.addView(card);
card.setOnClickListener(cardClickListener);
i++;
}
// add the row:
tableCards.addView(tr);
}
relativeLayoutCardsHolder.addView(tableCards);
Somewhere in the listener I have a code part like this:
imageView.setVisibility(View.INVISIBLE);
Where the imageView is a card ( I have breakpoint set up also log and it shows the correct card.
The problem: it doesn't become invisible.
I am thinking maybe I am not in a good Thread or should I need something to do it after setting the invisible?
I have tried with :
imageView.post(new Runnable() {
public void run() {
imageView.setVisibility(View.INVISIBLE);
}
});
and
TableLayout parent = (TableLayout) imageView.getParent().getParent();
parent.invalidate();
parent.requestLayout();
and no success. Pls make any suggestion, I am out of ideas, thanks.
Edit1:
As suggestion I have tried with postDelayed too:
imageView.postDelayed(new Runnable() {
public void run() {
imageView.setVisibility(View.INVISIBLE);
}
}, 600);
Listener body is from line 353 to 424 calling several classes with animations, passing references and it will reveal my dirty work, also will show the business logic too (NDA agrement), which part are you interested? - min 1000 lines are executed.
If it's a correct ImageView, its must work.
imageView.setAlpha(0);
Hope it's help.

Android Creating button dynamically and fill layout

I'm creating a button dynamically. The number of button is depend on the size of arraylist. the problem is, after creating the button I will add to the layout using addview method. The problem is I'm using linear layout, as by default orientation for linear layout is horizontal, so the button will fill the layout horizontally. Because of that some of the button is not visible. What I'm trying to achieve is something look like this
My code is like below:
Button[] tv = new Button[arraylist.size()];
for(int i=0;i<arraylist.size();i++){
tv[i] = new Button(getApplicationContext());
tv[i].setText(arraylist.get(i).toString());
tv[i].setTextColor(Color.parseColor("#000000"));
tv[i].setTextSize(20);
tv[i].setPadding(15, 5, 15, 5);
linearlayout.addView(tv[i]);
}
If I set the orientation of linear layout to vertical the button will fill vertically. So if there any solution to create the button dynamically and fill the layout both horizontal and vertical as shown by image.
There is not a canned layout in the SDK that does exactly what you are aiming for (i.e. lay out as many children horizontally as will fit, then flow to the next line to lay out some more), so you will need to create a custom ViewGroup that accomplishes this purpose. Luckily for you, Romain Guy created one live on-screen during a presentation at Devoxx.
Here is a link to that presentation video.
Here is a link to the sample code and slides.
HTH
After 2 days struggling thinking bout this problem finally I've found the solution. I've try put all my contact list, store it in arraylist and create button for each element and I'm quite satisfy with the result after display on the screen. Here is how I do the trick. I really appreciate for any comment from others.
variable declaration;
int currWidth;
int currCounter;
boolean isNewLine;
LinkedList<HashMap<String,Object>> button;
ArrayList<String> nameNumber = new ArrayList<String>();
contactWrapper = (LinearLayout) findViewById(R.id.multiple_selection);
create button onClick event;
for(int i=0;i<nameNumber.size();i++){
tv[i] = new Button(getApplicationContext());
String[] namePhone = nameNumber.get(i).toString().split("##");
phoneNumber.add(namePhone[1]);
tv[i].setText(namePhone[0]);
tv[i].setTag(namePhone[1]);
tv[i].setTextColor(Color.parseColor("#000000"));
tv[i].setTextSize(20);
tv[i].setPadding(15, 5, 15, 5);
tv[i].measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
HashMap<String, Object> map = new HashMap<String,Object>();
map.put("button", tv[i]);
map.put("width", tv[i].getMeasuredWidth());
button.add(map);
}
drawLayout();
drawlayout method is where I add button and arrange accordingly to fit the layout;
public void drawLayout(){
int counter=0;
contactWrapper.setOrientation(LinearLayout.VERTICAL);
currCounter=0;
currWidth=0;
isNewLine=false;
LinearLayout[] row = new LinearLayout[nameNumber.size()];
row[currCounter] = new LinearLayout(getApplicationContext());
#SuppressWarnings("rawtypes")
Iterator it = button.iterator();
for(int i = 0; i<button.size(); i++){
it.next();
row[currCounter].setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
currWidth += Integer.parseInt(button.get(i).get("width").toString());
if(isNewLine){
if(currWidth < contactWrapper.getWidth()){
row[currCounter].addView((View) button.get(i).get("button"));
if(!it.hasNext()){
contactWrapper.addView(row[currCounter]);
}else{
if(contactWrapper.getWidth()<(currWidth+Integer.parseInt(button.get(i+1).get("width").toString()))){
isNewLine=true;
contactWrapper.addView(row[currCounter]);
currCounter+=1;
row[currCounter] = new LinearLayout(getApplicationContext());
currWidth=0;
}else{
isNewLine=false;
}
}
}else{
isNewLine=true;
contactWrapper.addView(row[currCounter]);
currCounter+=1;
row[currCounter] = new LinearLayout(getApplicationContext());
currWidth=0;
}
}else{
if(currWidth < contactWrapper.getWidth()){
if(!it.hasNext()){
row[currCounter].addView((View) button.get(i).get("button"));
contactWrapper.addView(row[currCounter]);
}else{
row[currCounter].addView((View) button.get(i).get("button"));
if(contactWrapper.getWidth()<(currWidth+Integer.parseInt(button.get(i+1).get("width").toString()))){
isNewLine=true;
contactWrapper.addView(row[currCounter]);
currCounter+=1;
row[currCounter] = new LinearLayout(getApplicationContext());
currWidth=0;
}else{
isNewLine=false;
}
}
}else{
isNewLine=true;
contactWrapper.addView(row[currCounter]);
currCounter+=1;
row[currCounter] = new LinearLayout(getApplicationContext());
currWidth=0;
}
}
counter++;
}
}
this code quite messy + I'm not fully utilize the size of array for
LinearLayout[] row = new LinearLayout[nameNumber.size()];
but it work for me.
use TableLayout instead of LinearLayout this is tutorial hope this will help you to get the idea
Does you set android:layout_width="fill_parent"?
Do this if you don't.
Well, you can try using more sophisticated way. You can create horizontal linear layout, and add buttons to it. Every time you're attempting to add new button, you check if there is place for it, by finding difference between layout's and buttons widths.
Each time your horizontal layout is filled, you add it to another vertical layout, and create another horizontal layout to store buttons left.
I used that trick in my apps.
try this its working fine
this.row = (LinearLayout)findViewById(R.id.tags);
this.row.setOrientation(LinearLayout.VERTICAL);
LinearLayout one = new LinearLayout(this);
//get the size of the screen
Display display = getWindowManager().getDefaultDisplay();
this.screenWidth = display.getWidth(); // deprecated
this.screenHeight = display.getHeight();// depreceted
for(int i=0; i<6; i++) {
one.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
this.button = new Button(this);
button.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
if(i==0) {
this.button.setText("Muhammad Aamir");
} else if(i==1) {
this.button.setText("Ahsan");
} else if(i==2) {
this.button.setText("Mujahid");
} else if(i==3) {
this.button.setText("Waqas");
} else if(i==4) {
this.button.setText("Ali");
} else {
this.button.setText("Ahmer");
}
//get the size of the button text
Paint mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setTextSize(button.getTextSize());
mPaint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.NORMAL));
float size = mPaint.measureText(button.getText().toString(), 0, button.getText().toString().length());
size = size+14;
this.totalTextWidth += size;
if(totalTextWidth < screenWidth) {
one.addView(button);
} else {
this.row.addView(one);
one = new LinearLayout(this);
one.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
one.addView(button);
this.totalTextWidth = size;
}
}
this.row.addView(one);
}

Categories

Resources