3

I'm trying to create an Activity that contains 10 buttons that are generated programmatically and are positioned in random places on the screen but without exceed the screen size.

I tried doing so but most of the buttons exceeded from the screen size (I couldn't see it).

    LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linear);
    Random rnd = new Random();

    DisplayMetrics displaymetrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
    int height = displaymetrics.heightPixels;
    int width = displaymetrics.widthPixels;

    for(int x = 0;x<10;x++) {

        Button btn = new Button(this);

        int Xpoistion = rnd.nextInt(width - 100) + 100;
        int Yposition = rnd.nextInt(height - 100) + 100;

        btn.setX(Xpoistion);
        btn.setY(Yposition);

        btn.setText(x +")"+width + "," + height + " | " + Xpoistion + "," + Yposition);

        linearLayout.addView(btn);

    }

So i'm trying to create the "limits of the screen" from height and width but for some reason I can't figure it out.

I played with Xposition and Yposition a lot but nothing seems to work for me.

Thank for very much for your help.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Aviv
  • 193
  • 2
  • 11
  • Why are you adding 100 to the random values? this will give you a left/top position of the buttons between 100 and displayWidth resp. 100 and displayHeight. And the button placed there will go off screen to right/bottom. – Ridcully Dec 30 '17 at 09:02
  • @Ridcully I just played with it, I tried a lot of options, nothing seems to work – Aviv Dec 30 '17 at 09:10

2 Answers2

1

You need to use RelativeLayout instead of LinearLayout to place your buttons with absolute values.

Edit: I just looked for a reference, you can find it here.

Yuliwee
  • 327
  • 1
  • 11
1

You should use the RelativeLayout as said already. But your logic is a bit flawed, you should set variables to garantee your buttons don't go of screen. I added a bit of code to yours already

    int height = displaymetrics.heightPixels;
    int width = displaymetrics.widthPixels;
    int buttonWidth = 150;
    int buttonHeigh = 40;
    int max_x_val = width - buttonWidth;
    int max_y_val = heigth - buttonHeigh; // Edited here

    for(int x = 0;x<10;x++) {

        Button btn = new Button(this);

        int Xpoistion = rnd.nextInt(max_x_val - buttonWidth) + buttonWidth;
        int Yposition = rnd.nextInt(max_y_val - buttonHeigh) + buttonHeigh;

        btn.setX(Xpoistion);
        btn.setY(Yposition);
        btn.setWidth(buttonWidth);
        btn.setHeight(buttonHeigh);
        btn.setText(x +")"+width + "," + height + " | " + Xpoistion + "," + Yposition);

        relativeLayout.addView(btn);
        Log.d("Debug","Xpos =" + Xpoistion);
        Log.d("Debug","Ypos =" + Yposition);
    }

This still is not the solution because the buttons might end up overlapped

Last edit

There are still some buttons that get a bit cut.This happens because we have the whole dimensions of the screen, and what we needed was the dimensions of only our Relative Layout .. That blue bar on top is also being included in the measure when it shouldn't. But this error is a bit more tricky to fix but not impossible, just google a bit and you will find enough help

EDIT: My initial thought was that btn.setX() and setY() would center the Button on those pixels, but no it marks the start of the button in those same pixels, so I had to change the randomize function to simply:

int Xposition = rnd.nextInt(width - buttonWidth);
int Yposition = rnd.nextInt(height - buttonHeight);

Next, to work around overlapping I wrote the following sample

// Create dummy class for holding coordinates
public class ButtonCordinates{

 public int x;
 public int y;

 public ButtonCordinates(int x, int y) {
     this.x = x;
     this.y = y;
 }
}

//In MainActivity class create a array for holding coordinates
ButtonCoordinates [] buttonsCoordinates = new ButtonCoordinates [10];    

int x = 0;
while(x < 10) {

  int Xposition = rnd.nextInt(width - buttonWidth);
  int Yposition = rnd.nextInt(height - buttonHeight);

  ButtonCoordinates buttonCoords = new ButtonCoordinates (Xposition,Yposition);

  if(!coordinatesFree(buttonCoords,buttonHeight,buttonWidth)){
    // Get another chance
    continue;
  }

  Button btn = new Button(this);
  btn.setX(Xposition);
  btn.setY(Yposition);

  btn.setWidth(buttonWidth);
  btn.setHeight(buttonHeight);
  btn.setText(Xposition+";"+Yposition);

  buttonsCoordinatesArray[x++] = buttonCoords;

  linearLayout.addView(btn);
  Log.d("Debug","Xpos =" + Xposition);
  Log.d("Debug","Ypos =" + Yposition);
}

// Method that prevents overlapping
private boolean coordinatesFree(ButtonCoordinates newButton, int buttonHeight, int buttonWidth){

     for(ButtonCoordinates existingButton : buttonsCoordinatesArray){
        if(existingButton == null){
            // First button ever
            return true;
        }

        boolean f1 = existingButton.x + buttonWidth <= newButton.x;
        boolean f2 = existingButton.y + buttonHeight <= newButton.y;
        boolean f3 = existingButton.x - buttonWidth >= newButton.x;
        boolean f4 = existingButton.y - buttonHeight >= newButton.y;

        if(!f1 && !f2 && !f3 && !f4){
            return false;
        }

    }
    return true;
}
Greggz
  • 1,873
  • 1
  • 12
  • 31
  • Thanks! I will figure the overlapped thing out now! You are awesome :) – Aviv Dec 30 '17 at 09:16
  • 1
    @user2561521 max_y_val variable updated. I was using `width` on her. Please update in yours aswell – Greggz Dec 30 '17 at 09:21
  • Where does buttonsCoordinatesArray comes from? – Aviv Dec 30 '17 at 14:58
  • @user2561521 Just use it as a field in `MainActivity` – Greggz Dec 30 '17 at 15:32
  • 1
    @user2561521 Check my last edit. It's important for you to fix it eventually and it shouldn't take much of your time – Greggz Dec 30 '17 at 16:16
  • You are a true king. – Aviv Dec 30 '17 at 16:32
  • 1
    @user2561521 It has been fun! GL – Greggz Dec 30 '17 at 16:36
  • Hi, I tried your sample for several times and there are still some overlapping, can you please help me figure it out? I followed your instructions step by step and everything is working except for the overlapping in two / three buttons everytime I run the application. – Aviv Jan 05 '18 at 11:24
  • 1
    I believe its about the styling of the button. Show me a picture where it happens and with the logs of the distances between them. I ll assume that the width and height of the button are still 150 and 40 respectively. – Greggz Jan 05 '18 at 13:04
  • You can also debug the method that deals with the overlapping and check where is it failing. – Greggz Jan 05 '18 at 13:10
  • Ok, so this is the picture where it happens: https://imgur.com/a/FStem In the part where I create each button I give each button (as you wrote in the sample code) a width and height attribute from the vars (150 x 40). And that is why I can't understand why there are still overlapping left.. Thank you so much for your help!! – Aviv Jan 06 '18 at 07:14
  • @user2561521 That's why I said there must be something wrong with the button styling, cause the pixel difference is 913 - 829 = **84** . There's more than enough room for not overlapping ( about 4 pixels ), because it's 40 height for 1st button + 40 for the 2nd button + 4 of distance between them. I can't really explain what's happening – Greggz Jan 06 '18 at 10:00
  • @user2561521 As a test, make 2 buttons with 80 pixel difference in Y coordinate, print me the results also. Give them different colors aswell – Greggz Jan 06 '18 at 10:08