Просмотреть getX() и getY() вернуть 0.0 после того, как они были добавлены в Activity

в ManActivity onCreate() Я создал новый вид и добавил его через layout.addView для этой активности. Если я пытаюсь getX() или getY() для этого представления, я всегда получаю 0.0.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    RelativeLayout main = (RelativeLayout)findViewById(R.id.main);

    RelativeLayout.LayoutParams squarePosition = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    GameToken square1 = new GameToken(this,GameToken.SQUARE, fieldHeight,fieldWidth);
    squarePosition.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
    squarePosition.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
    main.addView(square1, squarePosition);
    System.out.println(square1.getX()); //Prints '0.0'
    System.out.println(square1.getY()); //Prints '0.0'

Ответ 1

ViewGroup, такие как RelativeLayout, не размещают своих детей немедленно, и, таким образом, ваш вид еще не знает, где он будет лежать на экране. Вам нужно подождать, пока RelativeLayout завершит макет, прежде чем это произойдет.

Вы можете прослушивать глобальные события компоновки следующим образом:

view.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Layout has happened here.

            // Don't forget to remove your listener when you are done with it.
            view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

Ответ 2

Другим вариантом является использование метода post(Runnable action):

view.post(new Runnable() {
    @Override
    public void run() {
        System.out.println(view.getX());
        System.out.println(view.getY());
    }
});

Это приведет к тому, что Runnable будет выполнен после завершения остальных ожидающих задачи (например, выкладки).

Ответ 3

Переместите вызовы на getX() и getY() в onWindowFocusChanged() обратный вызов. Как говорится в официальном руководстве, лучший способ узнать, является ли действие видимым для пользователя. Рассматривая свой код, вы можете поместить свой квадрат в переменные-члены, чтобы иметь возможность использовать его с двумя обратными вызовами.

Попробуйте следующее:

    GameToken mSquare1 = new GameToken(this,GameToken.SQUARE, fieldHeight,fieldWidth);

    ...
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {

          super.onWindowFocusChanged(hasFocus);

          if(hasFocus) {
             System.out.println(mSquare1.getX());
             System.out.println(mSquare1.getY());
          }
    } 

Общее правило заключается в том, что вы не можете получать информацию о местоположении из своего макета внутри onCreate(), потому что вы просто создаете его, и андроид все еще должен их разрабатывать.

Вы также можете дать возможность обратного вызова onResume(), но для меня это не сработало.