Mendapatkan koordinat Tampilan relatif terhadap tata letak root

142

Bisakah saya mendapatkan posisi tampilan x dan y relatif terhadap tata letak root dari Aktivitas saya di Android?

fhucho
sumber

Jawaban:

138

Ini adalah salah satu solusi, meskipun karena API berubah dari waktu ke waktu dan mungkin ada cara lain untuk melakukannya, pastikan untuk memeriksa jawaban lainnya. Satu mengklaim lebih cepat, dan lainnya mengklaim lebih mudah.

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());
}

Beri tahu saya jika itu berhasil.

Seharusnya secara rekursif tambahkan saja posisi atas dan kiri dari setiap wadah induk. Anda juga bisa menerapkannya dengan Pointjika Anda mau.

ramblinjan
sumber
getRelativeLeft () ini perlu add cast, tetapi ketika saya menambahkan (View) atau (tombol) ((Object) myView.getParent ()). getRelativeTop (), itu juga tidak benar
pengwang
Saya melakukan sesuatu yang sangat mirip tetapi saya memeriksa tampilan root dengan getId == R.id.myRootView.
fhucho
1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv)))); saya mendapatkan semua adalah 0; textView dalam tata letak adalah sebagai berikut <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
Pendekatan smiliar seperti ini (menghitungnya secara manual) bekerja untuk saya jadi saya menerima jawaban ini.
fhucho
3
api android sudah menyediakan koordinat relatif ke root. lihat di sini stackoverflow.com/a/36740277/2008214
carlo.marinangeli
155

API Android sudah menyediakan metode untuk mencapainya. Coba ini:

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;

Ini dok

carlo.marinangeli
sumber
16
Ini harus menjadi jawaban yang diterima. Tidak ada kemungkinan stack overflow, dan tidak ada kemungkinan kesalahan matematika. Terima kasih!
GLee
Saya setuju, ini harus menjadi jawaban yang diterima - hanya 92 suara yang tersisa.
Bingung
Saya ingin menemukan koordinat tampilan di bilah alat. Ini adalah salah satu metode yang bekerja secara konsisten untuk memperhitungkan Android: cocokSystemWindows dan berbagai versi API dari 19 hingga 27. Jadi terima kasih! Ini adalah jawaban yang benar.
David Ferrand
Bekerja dengan sempurna
Rawa
Bekerja dengan sangat baik, hanya ingin menyebutkan bahwa parentViewGroupdapat berupa orang tua mana pun dalam hierarki tampilan, sehingga berfungsi dengan baik untuk ScrollView juga.
Sira Lam
93

Silakan gunakan view.getLocationOnScreen(int[] location);(lihat Javadocs ). Jawabannya ada dalam array integer (x = location[0]dan y = location[1]).

BinaryTofu
sumber
13
Ini mengembalikan posisi ke layar tidak ke tata letak root Aktivitas.
fhucho
10
Ada juga View.getLocationInWindow (int []) yang mengembalikan posisi tampilan relatif ke jendela.
Rubicon
Bisakah Anda jelaskan bagaimana cara kerja metode ini. Ini mengembalikan kekosongan bagaimana kita mendapatkan nilai output atau x, y dari tampilan di layar
user1106888
6
Untuk mendapatkan posisi relatif terhadap tata letak root, cukup panggil getLocationInWindow untuk tata letak root dan elemen, dan gunakan kekuatan pengurangan. Jauh lebih sederhana dan kemungkinan lebih cepat dari jawaban yang diterima.
Blake Miller
1
ini hanya lokasi yang terkait dengan layar. bukan akarnya. baca di sini untuk
mengetahui
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];

Pertama saya mendapatkan tata letak root lalu menghitung selisih koordinat dengan tampilan.
Anda juga dapat menggunakan getLocationOnScreen()bukan getLocationInWindow().

Kerrmiter
sumber
3
apa tampilan yang diskalakan dan diputar?
DKV
Ini adalah satu-satunya jawaban yang berfungsi untuk saya. Ini harus diterima jawaban
neoexpert
36

Tidak perlu menghitungnya secara manual.

Cukup gunakan getGlobalVisibleRect seperti:

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

Perhatikan juga bahwa untuk koordinat pusat, bukan sesuatu seperti:

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

Anda bisa melakukannya:

float cx = myViewRect.exactCenterX();
float cy = myViewRect.exactCenterY();
Tinggi
sumber
Melihat sumber android semua getGlobalVisibleRectdilakukan globalOffset.set(-mScrollX, -mScrollY);sehingga Anda hanya bisa mendapatkan nilai-nilai itu dengan getScollX/Yjika Anda hanya membutuhkan koodinat relatif.
Xander
2
Ini harus diterima jawaban. getLocationOnScreen berfungsi serta getGlobalVisibleRect. Tetapi getGlobalVisibleRect memberikan sedikit lebih banyak informasi dan tidak perlu bekerja dengan array mentah. Karena itu saya akan menggunakan getGlobalVisibleRect. Penggunaannya sederhana. Rect positionRect = Rect baru (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top. cheers
JacksOnF1re
jika beberapa bagian anak berada di luar yang tidak akan dipertimbangkan dalam kasus ini. bagaimana menyelesaikan kasus seperti itu?
DKV
Jawaban bagus! Terima kasih banyak!
Rohit Kumar
8

Anda bisa menggunakan `

view.getLocationOnScreen (int [] lokasi)

; `untuk mendapatkan lokasi tampilan Anda dengan benar.

Tetapi ada tangkapan jika Anda menggunakannya sebelum tata letak telah meningkat Anda akan mendapatkan posisi yang salah.

Solusi untuk masalah ini adalah menambahkan ViewTreeObserverseperti ini: -

Deklarasikan secara global array untuk menyimpan posisi tampilan Anda

 int[] img_coordinates = new int[2];

dan kemudian menambahkan ViewTreeObserverpada tata letak induk Anda untuk mendapatkan panggilan balik untuk tata letak inflasi dan hanya kemudian mengambil posisi pandang jika tidak, Anda akan mendapatkan koordinat xy yang salah

  // 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);
                        }
                    }
            );

dan kemudian gunakan seperti ini

xposition = img_coordinates[0];
yposition =  img_coordinates[1];
Hitesh Sahu
sumber
3

Saya menulis sendiri dua metode utilitas yang tampaknya berfungsi di sebagian besar kondisi, menangani gulir, terjemahan, dan penskalaan, tetapi tidak rotasi. Saya melakukan ini setelah mencoba menggunakan offsetDescendantRectToMyCoords () dalam framework, yang memiliki akurasi tidak konsisten. Ini berhasil dalam beberapa kasus tetapi memberikan hasil yang salah pada yang lain.

"point" adalah array float dengan dua elemen (koordinat x & y), "leluhur" adalah viewgroup di suatu tempat di atas "keturunan" dalam hierarki pohon.

Pertama metode yang beralih dari koordinat turunan ke leluhur:

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);
    }
}

Berikutnya kebalikannya, dari leluhur ke keturunan:

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;
}
Alexander Hugestrand
sumber
2

Memetikan seseorang masih berusaha mencari tahu ini. Ini adalah bagaimana Anda mendapatkan pusat X dan Y dari view.

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

Saya baru saja menemukan jawabannya di sini

Bunyinya: Dimungkinkan untuk mengambil lokasi tampilan dengan memanggil metode getLeft () dan getTop (). Yang pertama mengembalikan koordinat kiri, atau X, dari persegi panjang yang mewakili tampilan. Yang terakhir mengembalikan bagian atas, atau Y, mengoordinasikan persegi panjang yang mewakili tampilan. Metode ini keduanya mengembalikan lokasi tampilan relatif ke induknya. Misalnya, ketika getLeft () mengembalikan 20, itu berarti tampilan terletak 20 piksel di sebelah kanan tepi kiri induk langsungnya.

jadi gunakan:

view.getLeft(); // to get the location of X from left to right
view.getRight()+; // to get the location of Y from right to left
donmj
sumber
1
Ini memberikan lokasi relatif terhadap tampilan langsung orang tua, bukan ke tampilan root, yang bisa menjadi orang tua dari orang tua dll ...
Rupert Rawnsley
apa tampilan yang diskalakan dan diputar?
DKV