ルートレイアウトを基準にしたビューの座標の取得


回答:


138

これは1つの解決策ですが、APIは時間とともに変化し、それを行う他の方法がある可能性があるため、他の回答を確認してください。1つはより速く、もう1つはより簡単であると主張しています。

private int getRelativeLeft(View myView) {
    if (myView.getParent() == myView.getRootView())
        return myView.getLeft();
    else
        return myView.getLeft() + getRelativeLeft((View) myView.getParent());
}

private int getRelativeTop(View myView) {
    if (myView.getParent() == myView.getRootView())
        return myView.getTop();
    else
        return myView.getTop() + getRelativeTop((View) myView.getParent());
}

うまくいくかどうか教えてください。

各親コンテナの上部と左側の位置を再帰的に追加するだけです。Point必要に応じて、それを実装することもできます。


getRelativeLeft()これはキャストを追加する必要がありますが、(View)または(button)((Object)myView.getParent())。getRelativeTop()を
追加すると正しく

私は非常に似たようなことをしましたが、ルートビューをgetId == R.id.myRootViewでチェックしました。
fhucho

1
Log.i( "RelativeLeft"、 "" + getRelativeLeft(findViewById(R.id.tv))); Log.i( "RelativeTop"、 "" + getRelativeTop(findViewById(R.id.tv))); 私はすべて0を取得します。レイアウトのtextViewは次のとおりです<TextView android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "@ string / hello" android:id = "@ + id / tv" android:layout_marginBottom = "69dip" android:layout_marginLeft = "69dip" />
pengwang

このような簡単なアプローチ(手動で計算)がうまく機能したので、この答えを受け入れました。
fhucho

3
Android APIはすでにルートへの相対座標を提供しています。こちらをご覧くださいstackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

Android APIには、そのための方法がすでに用意されています。これを試して:

Rect offsetViewBounds = new Rect();
//returns the visible bounds
childView.getDrawingRect(offsetViewBounds);
// calculates the relative coordinates to the parent
parentViewGroup.offsetDescendantRectToMyCoords(childView, offsetViewBounds); 

int relativeTop = offsetViewBounds.top;
int relativeLeft = offsetViewBounds.left;

ここにドキュメントがあります


16
これは受け入れられる答えになるはずです。スタックオーバーフローの可能性、および数学エラーの可能性はありません。ありがとう!
GLee

私は同意します、これは受け入れられた答えであるべきです-行くための92の賛成票のみ。
2017

ツールバーでビューの座標を見つけたかった。これは、android:fitsSystemWindowsと、19から27までのさまざまなAPIバージョンに対応するために一貫して機能する1つの方法です。ありがとうございます。これが正解です。
デビッドフェランド

完璧に働きました
Rawa

非常にうまくparentViewGroup機能しました。それはビュー階層の任意の親になることができるので、ScrollViewでも完全に機能します。
Sira Lam

93

使用してくださいview.getLocationOnScreen(int[] location);Javadocsを参照)。答えは整数配列(x = location[0]およびy = location[1])にあります。


13
これは、アクティビティのルートレイアウトではなく、画面に対する相対位置を返します。
fhucho

10
ウィンドウに対するビューの位置を返すView.getLocationInWindow(int [])もあります。
ルビコン

この方法がどのように機能するか正確に教えてください。画面上のビューの出力またはx、y値を取得する方法をvoidで返します
user1106888

6
ルートレイアウトに対する相対的な位置を取得するには、ルートレイアウトと要素に対してgetLocationInWindowを呼び出し、減算のパワーを使用します。これは、受け入れられた回答よりもはるかに単純で、おそらく高速です。
Blake Miller

1
これは単に画面に関連する場所です。ルートではありません。ルートを基準にしてこちらをお読みください:stackoverflow.com/a/36740277/2008214
carlo.marinangeli

36
View rootLayout = view.getRootView().findViewById(android.R.id.content);

int[] viewLocation = new int[2]; 
view.getLocationInWindow(viewLocation);

int[] rootLocation = new int[2];
rootLayout.getLocationInWindow(rootLocation);

int relativeLeft = viewLocation[0] - rootLocation[0];
int relativeTop  = viewLocation[1] - rootLocation[1];

最初にルートレイアウトを取得し、次にビューとの座標差を計算します。
getLocationOnScreen()代わりにを使用することもできますgetLocationInWindow()


3
ビューのスケーリングと回転は何ですか?
DKV 2017年

これは私のために働いている唯一の答えです。これは受け入れられるべき答えです
ネオエキスパート

36

手動で計算する必要はありません。

次のようにgetGlobalVisibleRectを使用するだけです。

Rect myViewRect = new Rect();
myView.getGlobalVisibleRect(myViewRect);
float x = myViewRect.left;
float y = myViewRect.top;

また、次のようなものではなく、中心座標についても注意してください。

...
float two = (float) 2
float cx = myViewRect.left + myView.getWidth() / two;
float cy = myViewRect.top + myView.getHeight() / two;

あなたはただ行うことができます:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();

すべてのAndroidのソースを見てgetGlobalVisibleRect行うことはある globalOffset.set(-mScrollX, -mScrollY);あなただけでそれらの値を得ることができるので、getScollX/Yあなただけの相対による座標が必要な場合。
Xander

2
これは受け入れられるべき答えです。getLocationOnScreenは、getGlobalVisibleRectと同様に機能します。しかし、getGlobalVisibleRectはもう少し多くの情報を提供し、生の配列を処理する必要はありません。したがって、私はgetGlobalVisibleRectを使用します。使い方は簡単です。Rect positionRect = new Rect(); view.getGlobablVisibleRect(positionRect); // x = positionRect.left // y = positionRect.top。歓声
JacksOnF1re

子供の一部が外にいる場合、この場合は考慮されません。そのような場合を解決する方法?
DKV 2017年

正解です。どうもありがとうございます!
Rohit Kumar

8

あなたは `を使うことができます

view.getLocationOnScreen(int [] location)

; `ビューの位置を正しく取得します。

しかし、落とし穴がありますレイアウトが間違った位置を取得します膨らませてきた前にあなたがそれを使用する場合。

この問題の解決策は ViewTreeObserverようにです:-

ビューのxy位置を格納する配列をグローバルに宣言します

 int[] img_coordinates = new int[2];

次に追加します ViewTreeObserver親レイアウトをして、レイアウトインフレーションのコールバックを取得し、ビューの位置をフェッチするだけです。そうしないと、間違ったxy座標が取得されます。

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

                            // measure your views here
                            fab.getLocationOnScreen(img_coordinates);
                        }
                    }
            );

そしてそれをこのように使います

xposition = img_coordinates[0];
yposition =  img_coordinates[1];

3

私は、ほとんどの状況で動作するように見える2つのユーティリティメソッドを記述しました。スクロール、変換、スケーリングは処理しますが、回転は処理しません。フレームワークでoffsetDescendantRectToMyCoords()を使用しようとした後、これに一貫性のない精度がありました。それはいくつかのケースで機能しましたが、他のケースでは間違った結果を与えました。

"point"は2つの要素(x座標とy座標)を持つfloat配列で、 "ancestor"はツリー階層の "子孫"の上にあるビューグループです。

最初に、子孫座標から祖先に移動するメソッド:

public static void transformToAncestor(float[] point, final View ancestor, final View descendant) {
    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = left + px + (point[0] - px) * sx + tx - scrollX;
    point[1] = top + py + (point[1] - py) * sy + ty - scrollY;

    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToAncestor(point, ancestor, (View) parent);
    }
}

次に、祖先から子孫への逆:

public static void transformToDescendant(float[] point, final View ancestor, final View descendant) {
    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToDescendant(point, ancestor, (View) parent);
    }

    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = px + (point[0] + scrollX - left - tx - px) / sx;
    point[1] = py + (point[1] + scrollY - top - ty - py) / sy;
}

2

誰かがまだこれを理解しようとしている場合。これは、の中心XおよびYを取得する方法ですview

    int pos[] = new int[2];
    view.getLocationOnScreen(pos);
    int centerX = pos[0] + view.getMeasuredWidth() / 2;
    int centerY = pos[1] + view.getMeasuredHeight() / 2;

1

私はここで答えを見つけました

それは言う:メソッドgetLeft()とgetTop()を呼び出すことによってビューの場所を取得することが可能です。前者は、ビューを表す長方形の左またはX座標を返します。後者は、ビューを表す長方形の上部またはY座標を返します。これらのメソッドはどちらも、親を基準にしたビューの位置を返します。たとえば、getLeft()が20を返す場合、ビューはその直接の親の左端から20ピクセル右に配置されていることを意味します。

だから使う:

view.getLeft(); // to get the location of X from left to right
view.getRight()+; // to get the location of Y from right to left

1
これにより、ルートビューではなく、ビューの直接の親に相対的な位置が得られます。ルートビューは、親の親などになる可能性があります...
Rupert Rawnsley

ビューのスケーリングと回転は何ですか?
DKV 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.