Как получить абсолютные координаты вида - PullRequest
363 голосов
/ 09 февраля 2010

Я пытаюсь получить абсолютные пиксельные координаты экрана в верхнем левом углу вида. Тем не менее, все методы, которые я могу найти, такие как getLeft() и getRight(), не работают, так как все они кажутся относительными к родителю представления, что дает мне 0. Как правильно это сделать?

Если это поможет, это для игры «верни картинку в порядок». Я хочу, чтобы пользователь мог нарисовать прямоугольник, чтобы выбрать несколько частей. Я предполагаю, что самый простой способ сделать это - getRawX() и getRawY() из MotionEvent, а затем сравнить эти значения с верхним левым углом макета, содержащего фрагменты. Зная размер кусочков, я могу определить, сколько кусочков было выбрано. Я понимаю, что могу использовать getX() и getY() на MotionEvent, но так как это возвращает относительную позицию, которая затрудняет определение, какие части были выбраны. (Знаю, не невозможно, но это кажется излишне сложным).

Редактировать: это код, который я использовал, чтобы попытаться получить размер контейнера для хранения, согласно одному из вопросов. TableLayout - это стол, в котором хранятся все кусочки головоломки.

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
Log.d(LOG_TAG, "Values " + tableLayout.getTop() + tableLayout.getLeft());

Редактировать 2: Вот код, который я пробовал, следуя другим предложенным ответам.

public int[] tableLayoutCorners = new int[2];
(...)

TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
tableLayout.requestLayout();
Rect corners = new Rect();
tableLayout.getLocalVisibleRect(corners);
Log.d(LOG_TAG, "Top left " + corners.top + ", " + corners.left + ", " + corners.right
            + ", " + corners.bottom);

cells[4].getLocationOnScreen(tableLayoutCorners);
Log.d(LOG_TAG, "Values " + tableLayoutCorners[0] + ", " + tableLayoutCorners[1]);

Этот код был добавлен после завершения инициализации. Изображение было разделено на массив ImageViews (массив cell []), содержащийся в TableLayout. Ячейки [0] - это верхний левый ImageView, и я выбрал ячейки [4], так как они где-то посередине и, безусловно, не должны иметь координат (0,0).

Код, показанный выше, все еще дает мне все 0 в журналах, которые я действительно не понимаю, потому что различные части головоломки отображаются правильно. (Я попробовал public int для tableLayoutCorners и видимости по умолчанию, оба дали одинаковый результат.)

Не знаю, значимо ли это, но ImageView изначально не имеют размера. Размер ImageView s определяется во время инициализации автоматически при просмотре, когда я даю ему изображение для отображения. Может ли это способствовать тому, что их значения будут равны 0, даже если этот код регистрации будет после того, как они получили изображение и автоматически изменили размеры сами? Чтобы потенциально противостоять этому, я добавил код tableLayout.requestLayout(), как показано выше, но это не помогло.

Ответы [ 8 ]

583 голосов
/ 09 февраля 2010

Используйте View.getLocationOnScreen() и / или getLocationInWindow().

95 голосов
/ 14 января 2017

Принятый ответ на самом деле не говорит, как получить местоположение, поэтому здесь немного подробнее. Вы передаете массив int длины 2, и значения заменяются координатами представления (x, y) (верхнего левого угла).

int[] location = new int[2];
myView.getLocationOnScreen(location);
int x = location[0];
int y = location[1];

Примечания

  • Замена getLocationOnScreen на getLocationInWindow должна давать в большинстве случаев те же результаты (см. этот ответ ). Однако, если вы находитесь в меньшем окне, например, в диалоговом окне или на пользовательской клавиатуре, вам нужно будет выбрать, какое из них лучше соответствует вашим потребностям.
  • Вы получите (0,0), если вы вызовете этот метод в onCreate, потому что представление еще не было размечено. Вы можете использовать ViewTreeObserver для прослушивания, когда макет сделан, и вы можете получить измеренные координаты. (См. этот ответ .)
69 голосов
/ 09 февраля 2010

Сначала вы должны получить локально видимый прямоугольник вида

Например:

Rect rectf = new Rect();

//For coordinates location relative to the parent
anyView.getLocalVisibleRect(rectf);

//For coordinates location relative to the screen/display
anyView.getGlobalVisibleRect(rectf);

Log.d("WIDTH        :", String.valueOf(rectf.width()));
Log.d("HEIGHT       :", String.valueOf(rectf.height()));
Log.d("left         :", String.valueOf(rectf.left));
Log.d("right        :", String.valueOf(rectf.right));
Log.d("top          :", String.valueOf(rectf.top));
Log.d("bottom       :", String.valueOf(rectf.bottom));

Надеюсь, это поможет

45 голосов
/ 07 ноября 2012

Использование слушателя с глобальным макетом всегда работало хорошо для меня. Преимущество состоит в том, что он может перезаписывать вещи при изменении макета, например, если что-то установлено в View.GONE или добавлены / удалены дочерние представления.

public void onCreate(Bundle savedInstanceState)
{
     super.onCreate(savedInstanceState);

     // inflate your main layout here (use RelativeLayout or whatever your root ViewGroup type is
     LinearLayout mainLayout = (LinearLayout ) this.getLayoutInflater().inflate(R.layout.main, null); 

     // set a global layout listener which will be called when the layout pass is completed and the view is drawn
     mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(
       new ViewTreeObserver.OnGlobalLayoutListener() {
          public void onGlobalLayout() {
               //Remove the listener before proceeding
               if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                    mainLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
               } else {
                    mainLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
               }

               // measure your views here
          }
       }
     );

     setContentView(mainLayout);
 }
17 голосов
/ 10 февраля 2010

После комментария Ромена Гая вот как я это исправил. Надеюсь, это поможет всем, у кого тоже была эта проблема.

Я действительно пытался выяснить положение представлений до того, как они были выложены на экран, но это было совсем не очевидно, что происходило. Эти строки были размещены после запуска кода инициализации, поэтому я предположил, что все было готово. Тем не менее, этот код все еще был в onCreate (); Поэкспериментировав с Thread.sleep (), я обнаружил, что макет на самом деле не завершен до тех пор, пока onCreate () полностью не завершит выполнение onResume (). И действительно, код пытался выполнить до того, как макет был размещен на экране. При добавлении кода в OnClickListener (или некоторый другой Listener) были получены правильные значения, потому что он мог быть запущен только после завершения макета.


Строка ниже была предложена как правка сообщества:

пожалуйста, используйте onWindowfocuschanged(boolean hasFocus)

5 голосов
/ 12 октября 2017

Моя функция утилит для определения местоположения, она возвращает объект Point с x value и y value

public static Point getLocationOnScreen(View view){
    int[] location = new int[2];
    view.getLocationOnScreen(location);
    return new Point(location[0], location[1]);
}

Использование

Point viewALocation = getLocationOnScreen(viewA);
3 голосов
/ 04 марта 2019

Первый путь:

В Kotlin мы можем создать простое расширение для просмотра:

fun View.getLocationOnScreen(): Point
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return Point(location[0],location[1])
}

И просто получите координаты:

val location = yourView.getLocationOnScreen()
val absX = location.x
val absY = location.y

Второй путь:

Второй способ более прост:

fun View.absX(): Int
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return location[0]
}

fun View.absY(): Int
{
    val location = IntArray(2)
    this.getLocationOnScreen(location)
    return location[1]
}

и просто получите абсолютный X на view.absX() и Y на view.absY()

0 голосов
/ 01 марта 2016

Используйте этот код, чтобы найти точные значения X и Y:

int[] array = new int[2];
ViewForWhichLocationIsToBeFound.getLocationOnScreen(array);
if (AppConstants.DEBUG)
    Log.d(AppConstants.TAG, "array  X = " + array[0] + ", Y = " + array[1]);
ViewWhichToBeMovedOnFoundLocation.setTranslationX(array[0] + 21);
ViewWhichToBeMovedOnFoundLocation.setTranslationY(array[1] - 165);

Я добавил / вычел некоторые значения, чтобы скорректировать мой взгляд. Пожалуйста, делайте эти строки только после того, как весь вид будет раздут.

...