android button.getWidth() returns value 0 - java

I'm dynamically creating buttons and I want to place them randomly on the screen.
In order to do that, I'm substracting the width of the button from the screen's width.
The thing is, the function button.getWidth() always return 0.
I saw in other posts that people recommended using
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
placeButtonsOnScreen();
}
But even when I'm using it, it doesn't work.
private void placeButtonsOnScreen() {
Random r = new Random();
LinearLayout layout = (LinearLayout) findViewById(R.id.ordered_buttons_layout);
for (int i = 0; i < NUMBER_OF_BUTTONS; i++) {
Button hiddenButton = buttonsArr[i];
// Get random horizontal margin for the button
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
horizontalMargin = r
.nextInt(SCREEN_WIDTH - hiddenButton.getWidth());
layoutParams.setMargins(horizontalMargin, 50, 0, 0);
// Add the button to the screen
layout.addView(hiddenButton, layoutParams);
Log.d("button width",String.valueOf(hiddenButton.getWidth()));
}
}
Any ideas how can I position the buttons on the screen minus their width? Cos right now they get cut off from intersection with the right side of the screen.

myView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
myView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
placeButtonsOnScreen();
}
});

You should use RelativeLayouts and make buttons position according to each other (Aligning of course the one closest to the right side of the screen as alignedToParentRight = true)

Related

Add plus/minus buttons to table cell LibGDX

I am looking for a way to add plus and minus buttons to table cells in LibGDX.
I'm trying to do something like this image:
I noticed that the uiskin files I'm using contain plus and minus buttons (right next to the checkbox) which will do just fine (uiskin.png).
Any tips on how I can add those to my table and make it so they increase/decrease the integer value in that table cell?
I've added a rudimentary sample code with an indication of what I want to do:
#Override
public void create() {
Stage stage = new Stage();
Skin skin = new Skin(Gdx.files.internal("skins/uiskin.json"));
Table table = new Table(skin);
table.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
for(int i = 0; i < 10; i++){
table.add(Integer.toString(i)); //Somehow add plus/minus buttons left
//and right that increase/decrease the integer value
table.row();
}
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
}
#Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
}
This is just some example code, but if it works here I will certainly be able to figure it out.
Thanks
First, you need an array to store your number values. It's not good practice to use your View (table cells) to store your Model (number values), and besides, Label cells store a String, not an integer, so it would be inconvenient.
private int[] tableData = new int[10];
Now you need a button that can be associated with a row in your data. Here's one way Create a subclass of ImageButton that can take a row number and mode (subtract or add).
public class IncrementButton extends ImageButton {
public final int rowNumber;
public final boolean decrement;
public IncrementButton (Skin skin, String styleName, int rowNumber, boolean decrement){
super(skin, styleName);
this.rowNumber = rowNumber;
this.decrement = decrement;
}
}
The plus and minus images in the uiskin atlas you're using are called "tree-minus" and "tree-plus". You need an ImageButton style for each of these that uses one of these as the imageUp property. (imageUp is used as a default if you don't define images for other states such as imageDown.) You can add these to uiskin.json:
com.badlogic.gdx.scenes.scene2d.ui.ImageButton$ImageButtonStyle: {
plus: { down: default-round-down, up: default-round, imageUp: tree-plus },
minus: { down: default-round-down, up: default-round, imageUp: tree-minus }
},
Now you can create a ChangeListener for these buttons that will modify the numbers in the data and update the table accordingly. And then set it all up:
Stage stage = new Stage();
Skin skin = new Skin(Gdx.files.internal("skins/uiskin.json"));
final Table table = new Table(skin);
final Label[] labels = new Label[tableData.length]; //keep references to the labels for updating them.
final ChangeListener incrementListner = new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
IncrementButton incrementButton = (IncrementButton)actor;
int row = incrementButton.rowNumber;
tableData[row] += incrementButton.decrement ? -1 : 1;
labels[row].setText(Integer.toString(tableData[row]));
}
};
table.setPosition(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
for(int i = 0; i < tableData.length; i++){
IncrementButton decrementButton = new IncrementButton(skin, "minus", i, true);
decrementButton.addListener(incrementListner);
IncrementButton incrementButton = new IncrementButton(skin, "plus", i, false);
incrementButton.addListener(incrementListner);
table.add(decrementButton);
labels[i] = table.add(Integer.toString(i)).getActor();//Add number label and keep reference to it in labels array for the change listener to look up
table.add(incrementButton);
table.row();
}
stage.addActor(table);
Gdx.input.setInputProcessor(stage);
If you want to set min and max values for the data, then you need some arrays for the plus buttons and minus buttons (similar to the labels array) so the change listener can look up and disable/enable the buttons accordingly when a limit is hit.

How to avoid items overlap together when set position random?

on xml layout, I have a FrameLayout with no child. Then I add a list buttons programatically into this framelayout by this code below:
private void addNumbers(){ // Numbers is set with random position
for (int i = 1; i < 20; i++) {
Button btn = new Button(this);
btn.setText("" + i);
btn.setId(i);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(50, 50);
int leftMargin = new Random().nextInt(widthScreen - btnSize );
int topMargin = new Random().nextInt(heightScreen - btnSize);
lp.leftMargin = leftMargin;
lp.topMargin = topMargin;
btn.setLayoutParams(lp);
framelayout1.addView(btn);
//framelayout2.addView(btn);
}
}
And some buttons overlap together, I do not want to happen this. How to avoid this problem ? Thanks in advance.
P/s: Sorry I can not upload image from my company, all upload > 4K is reject, please tell me if the question is not clear.

How to get the button's border size in Android

How can I get the border width of a stand Android button programmatically? I simply need to resize the text to fit to the gray area and need to position other objects inline with the buttons, but I cannot do that without knowing the size of the border. I need this to work in all API's 7+. The red arrows in the image below show what I am trying to get:
Here is the code I use for creating my button:
cmdView = new Button(this);
params = new RelativeLayout.LayoutParams(widthLblViewVerbs , (int) fieldHeight);
params.leftMargin = (int) (screenWidth - params.width);
params.topMargin = (int) yPos;
cmdView.setSingleLine();
cmdView.setText("View");
cmdView.setPadding(0, 0, 0, 0);
cmdView.setTextSize(TypedValue.COMPLEX_UNIT_PX, SetTextSize(cmdView.getText().toString(), params.width, params.height));
layout.addView(cmdView, params);
NB. I've had to ask this question again because someone downvoted my question last time and I am desperate for a solution. I have made absolutely no progress with my program in weeks because I have been stuck with this and another problem. If there is something unclear about my question, please let me know and I will edit it. Thank you
My initial code recommendation from the comments can be found here. The implementation done by Dan Bray is:
final Button button = new Button(this);
params = new RelativeLayout.LayoutParams(50, 50);
layout.addView(button, params);
button.post(new Runnable()
{
#Override
public void run()
{
button.buildDrawingCache();
Bitmap viewCopy = button.getDrawingCache();
boolean stillBorder = true;
PaddingLeft = 0;
PaddingTop = 0;
while (stillBorder)
{
int color = viewCopy.getPixel(PaddingLeft, button.getHeight() / 2);
if (color != Color.TRANSPARENT)
stillBorder = false;
else
PaddingLeft++;
}
stillBorder = true;
while (stillBorder)
{
int color = viewCopy.getPixel(button.getWidth() / 2, PaddingTop);
if (color != Color.TRANSPARENT)
stillBorder = false;
else
PaddingTop++;
}
}
});
Not really clear on the question - you want the margins of the underlying view and then the set the size of the button to match ? Then Have you tried
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
margins are accessible via
lp.leftMargin;
lp.rightMargin;
lp.topMargin;
lp.bottomMargin;
Details here:http://developer.android.com/reference/android/view/ViewGroup.MarginLayoutParams.html
This gets the width and height of the button's border:
final Button button = new Button(this);
params = new RelativeLayout.LayoutParams(50, 50);
layout.addView(button, params);
button.post(new Runnable()
{
#Override
public void run()
{
button.buildDrawingCache();
Bitmap viewCopy = button.getDrawingCache();
boolean stillBorder = true;
PaddingLeft = 0;
PaddingTop = 0;
while (stillBorder)
{
int color = viewCopy.getPixel(PaddingLeft, button.getHeight() / 2);
if (color != Color.TRANSPARENT)
stillBorder = false;
else
PaddingLeft++;
}
stillBorder = true;
while (stillBorder)
{
int color = viewCopy.getPixel(button.getWidth() / 2, PaddingTop);
if (color != Color.TRANSPARENT)
stillBorder = false;
else
PaddingTop++;
}
}
});
Assuming you are using a nine patch background image, there is a much easier way.
In the nine patch image, you can define a padding box. This padding box will automatically be applied to the contents you set. No need to recalculate the paddings manually in that case.
Note that you should not set a padding on views using a nine patch as a background as the padding from the nine patch will be ignored.

Set layout margine with float value in android

I want to set margin of Imageview. What I wanted to achieve is to move one image up to some distance. The content of screen is RelativeLayout, in that there is ImageView at left and button at right aligned. Now I want to move image from left to right within the gap between Image and Button in 100 click of button. The code I am following is as below:
private static int count= 1 ;
public void onClick(View view) {
RelativeLayout lay = (RelativeLayout)findViewById(R.id.layout1);
ImageView i1= (ImageView)findViewById(R.id.img1);
ImageButton btn= (ImageButton)findViewById(R.id.iBtn);
int i1Width = i1.getWidth();
int btnWidth = btn.getWidth();
int totalMragine = lay.getWidth() - i1Width - btnWidth ; //the total margine image will move.
int stepSize = (lay.getWidth() - i1Width - btnWidth ) / 100;
int step = stepSize * count++;
Log.i("i1Width ", ""+i1Width );
Log.i("btnWidth ", ""+btnWidth );
Log.i("lay.getWidth()", ""+lay.getWidth());
Log.i("stepSize", ""+stepSize);
Log.i("count", ""+count);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(step, 0, 0, 0);
i1.setLayoutParams(lp);
LinearLayout.LayoutParams lp1 = (LinearLayout.LayoutParams) horse.getLayoutParams();
Log.i("currentMargine", ""+lp1.leftMargin);
if(lp1.leftMargin >= totalMragine ){
Log.i("Result", "maringe over");
}
}
What I wanted to know that the margin I am setting is in Integer but the value for the step is in float. So How to set margin float in LayoutParams? or is there any other way to do this?
you can do one thing calculate distance to move every time as when going to move
distance to move = the rest of length/rest of clicks
of in final step (100th step) it will reach to end with error < . 5px and . 5px is too small )
like in
1st click distance_to_move = 370/100; as round off come 4
2nd click distance_to_move = 366/99; as round off come 4
3rd click distance_to_move = 362/98; as round off come 4
so movemnt will be as in px 44444...3444...3444..3444...

Android: Changing ImageView size is not working

I am trying to change my ImageView size, but I can't seem to change both - width and height. If I just change one of them, then all works correctly, but when I try to change both, only width is changed.
I have the size in dp: width 22 and height 38, and I convert them to px. Is there another way to do so? I have tried many other ways, but they don't seem to work either.
Could someone tell me, what I should do differently?
Here is my code:
public GridLayout gridLayout;
public GridLayout.Spec row = GridLayout.spec(0);
public GridLayout.Spec col = GridLayout.spec(3);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gridLayout = (GridLayout) findViewById(R.id.gameGrid);
createBlock();
}
public void createBlock() {
ImageView block = new ImageView(this);
block.setImageResource(R.drawable.red);
if (gridLayout != null) {
gridLayout.addView(block, new GridLayout.LayoutParams(row, col));
int width_in_dp = 22, height_in_dp = 38;
final float scale = getResources().getDisplayMetrics().density;
int width_in_px = (int) (width_in_dp * scale + 0.5f);
int height_in_px = (int) (height_in_dp * scale + 0.5f);
ViewGroup.LayoutParams layoutParams = block.getLayoutParams();
layoutParams.width = width_in_px;
layoutParams.height = height_in_px;
block.setLayoutParams(layoutParams);
}
}
Have you tried playing with the block's scaleType? The default is fitCenter but I usually choose centerCrop or fitXY. Here's a good webpage that describes the differences.
You can set the scaleType through ImageView's setScaleType method.

Categories

Resources