รับพิกัดของ View ที่สัมพันธ์กับเค้าโครงรูท


142

ฉันจะได้ตำแหน่ง x และ y ของ View ที่สัมพันธ์กับเค้าโครงรูทของกิจกรรมของฉันใน Android หรือไม่

คำตอบ:


138

นี่เป็นวิธีแก้ไขปัญหาหนึ่งแม้ว่า API จะเปลี่ยนแปลงตลอดเวลาและอาจมีวิธีอื่นในการดำเนินการตรวจสอบให้แน่ใจว่าได้ตรวจสอบคำตอบอื่น ๆ หนึ่งอ้างว่าเป็นเร็วกว่าและอีกอ้างว่าง่ายขึ้น

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

แจ้งให้เราทราบหากใช้งานได้

มันควรจะวนซ้ำเพิ่มตำแหน่งบนสุดและซ้ายจากแต่ละคอนเทนเนอร์หลัก คุณสามารถนำไปใช้กับ a Pointถ้าคุณต้องการ


getRelativeLeft () นี่คือต้องการเพิ่ม cast แต่เมื่อฉันเพิ่ม (ดู) หรือ (ปุ่ม) ((วัตถุ) myView.getParent ()) getRelativeTop () มันยังไม่ถูกต้อง
pengwang

ฉันทำสิ่งที่คล้ายกันมาก แต่ฉันตรวจสอบมุมมองรูตโดย 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 คะแนนขึ้นไป
งงงวย

ฉันต้องการค้นหาพิกัดของมุมมองในแถบเครื่องมือ นี่เป็นวิธีหนึ่งที่ทำงานอย่างต่อเนื่องเพื่อบัญชีสำหรับ Android: FitsSystemWindows และ API รุ่นต่างๆตั้งแต่ 19 ถึง 27 ดังนั้นขอขอบคุณ! นี่คือคำตอบที่ถูกต้อง
David Ferrand

ทำงานได้อย่างไร้ที่ติ
Rawa

ทำงานได้ดีมากเพียงต้องการพูดถึงว่าparentViewGroupสามารถเป็นพาเรนต์ใด ๆ ในลำดับชั้นการดูดังนั้นจึงทำงานได้อย่างสมบูรณ์แบบสำหรับ ScrollView เช่นกัน
ศิระลำ

93

กรุณาใช้view.getLocationOnScreen(int[] location);(ดูJavadocs ) คำตอบอยู่ในอาร์เรย์จำนวนเต็ม (x = location[0]และ y = location[1])


13
สิ่งนี้จะส่งคืนตำแหน่ง rlative ไปที่หน้าจอไม่ใช่ไปที่เค้าโครงรูทของกิจกรรม
fhucho

10
นอกจากนี้ยังมี View.getLocationInWindow (int []) ซึ่งส่งคืนตำแหน่งมุมมองที่สัมพันธ์กับหน้าต่าง
Rubicon

คุณช่วยกรุณาบอกฉันว่าวิธีนี้ทำงานอย่างไร มันกลับเป็นโมฆะวิธีที่เราจะได้รับเอาท์พุทหรือค่า x, y ของมุมมองบนหน้าจอ
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

นี่เป็นคำตอบเดียวที่ใช้ได้สำหรับฉัน คำตอบนี้ควรได้รับการยอมรับ
neoexpert

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ถ้าคุณเพียงแค่ต้องญาติ coodinates
Xander

2
คำตอบนี้ควรได้รับการยอมรับ getLocationOnScreen ทำงานเช่นเดียวกับ getGlobalVisibleRect แต่ getGlobalVisibleRect ให้ข้อมูลเพิ่มเติมอีกเล็กน้อยและไม่จำเป็นต้องทำงานกับอาร์เรย์แบบดิบ ฉันจะไปกับ getGlobalVisibleRect การใช้งานง่าย Rect positionRect = new Rect (); view.getGlobablVisibleRect (positionRect); // x = positionRect.left // y = positionRect.top ไชโย
JacksOnF1re

หากเด็กบางส่วนอยู่ข้างนอกซึ่งจะไม่นำมาพิจารณาในกรณีนี้ วิธีแก้ปัญหากรณีดังกล่าว
DKV

คำตอบที่ดี! ขอบคุณมาก!
Rohit Kumar

8

คุณสามารถใช้ `

view.getLocationOnScreen (int [] ตำแหน่ง)

; `เพื่อให้ได้ตำแหน่งมุมมองของคุณอย่างถูกต้อง

แต่มีการจับถ้าคุณใช้มันก่อนที่จะขยายรูปแบบที่สูงเกินจริงคุณจะผิด

ทางออกสำหรับปัญหานี้คือการเพิ่ม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

ฉันเขียนตัวเองสองวิธีอรรถประโยชน์ที่ดูเหมือนจะทำงานในเงื่อนไขส่วนใหญ่จัดการเลื่อนแปลและปรับ แต่ไม่หมุน ฉันทำสิ่งนี้หลังจากพยายามใช้ offsetDescendantRectToMyCoords () ในกรอบซึ่งมีความแม่นยำที่ไม่สอดคล้องกัน มันทำงานได้ในบางกรณี แต่ให้ผลลัพธ์ที่ผิดในคนอื่น ๆ

"point" เป็นอาร์เรย์ลอยที่มีสององค์ประกอบ (พิกัด x & y) "บรรพบุรุษ" เป็นกลุ่มดูที่ใดที่หนึ่งเหนือ "ลูกหลาน" ในลำดับชั้นต้นไม้

วิธีแรกที่เปลี่ยนจากพิกัดผู้สืบทอดไปยังบรรพบุรุษ:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.