Bắt tọa độ của View so với bố cục gốc


142

Tôi có thể có được vị trí x và y của Chế độ xem so với bố cục gốc của Hoạt động trong Android không?

Câu trả lời:


138

Đây là một giải pháp, mặc dù các API thay đổi theo thời gian và có thể có các cách khác để thực hiện, hãy đảm bảo kiểm tra các câu trả lời khác. Một tuyên bố là nhanh hơn, và một tuyên bố khác là dễ dàng hơn.

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

Cho tôi biết nếu nó hiệu quả.

Nó nên đệ quy chỉ cần thêm các vị trí trên cùng và bên trái từ mỗi container cha. Bạn cũng có thể thực hiện nó với Pointnếu bạn muốn.


getRelativeLeft () cái này cần thêm cast, nhưng khi tôi thêm (View) hoặc (nút) ((Object) myView.getParent ()). getRelativeTop (), nó cũng không đúng
pengwang

Tôi đã làm một cái gì đó rất giống nhau nhưng tôi đã kiểm tra xem gốc bằng getId == R.id.myRootView.
fhucho

1
Log.i ("RelativeLeft", "" + getRelativeLeft (findViewById (R.id.tv))); Log.i ("RelativeTop", "" + getRelativeTop (findViewById (R.id.tv))); tôi nhận được tất cả là 0; textView trong layout là như sau android: layout_marginLeft = "69dip" />
pengwang

Cách tiếp cận quen thuộc như thế này (tính toán bằng tay) đã làm việc cho tôi vì vậy tôi đã chấp nhận câu trả lời này.
fhucho

3
api android đã cung cấp tọa độ tương đối cho root. nhìn vào đây stackoverflow.com/a/36740277/2008214
carlo.marinangeli

155

API Android đã cung cấp một phương pháp để đạt được điều đó. Thử cái này:

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;

Đây là tài liệu


16
Đây phải là câu trả lời được chấp nhận. Không có khả năng tràn ngăn xếp và không có khả năng xảy ra lỗi toán học. Cảm ơn!
GLee

Tôi đồng ý, đây phải là câu trả lời được chấp nhận - chỉ có 92 phiếu bầu tăng.
bàng hoàng

Tôi muốn tìm tọa độ của một khung nhìn trên thanh công cụ. Đây là một phương pháp hoạt động ổn định cho tài khoản Android: fitSystemWindows và các phiên bản API khác nhau từ 19 đến 27. Xin cảm ơn! Đây là câu trả lời đúng.
David Ferrand

Làm việc hoàn hảo
Rawa

Hoạt động rất tốt, chỉ muốn đề cập rằng parentViewGroupcó thể là bất kỳ cha mẹ nào trong hệ thống phân cấp chế độ xem, vì vậy nó cũng hoạt động hoàn hảo cho ScrollView.
Sira Lam

93

Vui lòng sử dụng view.getLocationOnScreen(int[] location);(xem Javadocs ). Câu trả lời là trong mảng số nguyên (x = location[0]và y = location[1]).


13
Điều này trả về vị trí rlative cho màn hình chứ không phải bố trí gốc của Activity.
fhucho

10
Ngoài ra còn có View.getLocationInWindow (int []) trả về vị trí của khung nhìn so với cửa sổ.
Rubicon

Bạn có thể vui lòng cho tôi biết chính xác làm thế nào phương pháp này hoạt động. Nó trả về một khoảng trống làm thế nào để chúng ta có được các giá trị đầu ra hoặc x, y của một chế độ xem trên màn hình
user1106888

6
Để có được vị trí liên quan đến bố cục gốc, chỉ cần gọi getLocationInWindow cho bố cục gốc và phần tử và sử dụng sức mạnh của phép trừ. Nó đơn giản hơn nhiều và có khả năng nhanh hơn câu trả lời được chấp nhận.
Blake Miller

1
đây chỉ là vị trí liên quan đến màn hình. không phải là gốc. đọc ở đây để liên quan đến root: 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];

Đầu tiên tôi lấy bố cục gốc sau đó tính toán sự khác biệt tọa độ với khung nhìn.
Bạn cũng có thể sử dụng getLocationOnScreen()thay thế getLocationInWindow().


3
cái nhìn được thu nhỏ và xoay là gì?
DKV

Đây là câu trả lời duy nhất đang làm việc cho tôi. Điều này nên được chấp nhận câu trả lời
neoexpert

36

Không cần phải tính toán bằng tay.

Chỉ cần sử dụng getGlobalVisibleRect như vậy:

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

Cũng lưu ý rằng đối với tọa độ trung tâm, chứ không phải là:

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

Bạn chỉ có thể làm:

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

Nhìn vào nguồn android tất cả getGlobalVisibleRectglobalOffset.set(-mScrollX, -mScrollY);vì vậy bạn chỉ có thể nhận được các giá trị đó getScollX/Ynếu bạn chỉ cần các điều phối tương đối.
Xander

2
Điều này nên được chấp nhận câu trả lời. getLocationOnScreen hoạt động cũng như getGlobalVisibleRect. Nhưng getGlobalVisibleRect cung cấp thêm một chút thông tin và không cần phải làm việc với các mảng thô. Do đó tôi sẽ đi với getGlobalVisibleRect. Cách sử dụng rất đơn giản. Vị trí RectRect = new Rect (); view.getGlobablVisibleRect (vị tríRect); // x = locationRect.left // y = locationRect.top. chúc mừng
JacksOnF1re

nếu một phần của đứa trẻ ở bên ngoài sẽ không được xem xét trong trường hợp này. Làm thế nào để giải quyết trường hợp như vậy?
DKV

Câu trả lời chính xác! Cảm ơn bạn rất nhiều!
Rohit Kumar

8

Bạn có thể sử dụng `

view.getLocationOnScreen (int [] location)

; `để có được vị trí của quan điểm của bạn một cách chính xác.

Nhưng có một nhược điểm nếu bạn sử dụng nó trước khi bố trí bị thổi phồng bạn sẽ nhận được vị trí sai.

Giải pháp cho vấn đề này là thêm ViewTreeObservernhư thế này: -

Khai báo toàn cầu mảng để lưu trữ vị trí xy của chế độ xem của bạn

 int[] img_coordinates = new int[2];

và sau đó thêm ViewTreeObservervào bố cục cha mẹ của bạn để có được cuộc gọi lại cho lạm phát bố cục và chỉ sau đó tìm nạp vị trí của chế độ xem nếu không bạn sẽ nhận được tọa độ xy sai

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

và sau đó sử dụng nó như thế này

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

3

Tôi đã tự viết cho mình hai phương pháp tiện ích dường như hoạt động trong hầu hết các điều kiện, xử lý cuộn, dịch và chia tỷ lệ, nhưng không xoay vòng. Tôi đã làm điều này sau khi thử sử dụng offsetDescendantRectToMyCoords () trong khung, có độ chính xác không nhất quán. Nó đã làm việc trong một số trường hợp nhưng cho kết quả sai ở những người khác.

"điểm" là một mảng nổi có hai phần tử (tọa độ x & y), "tổ tiên" là một nhóm xem ở đâu đó phía trên "hậu duệ" trong hệ thống phân cấp cây.

Đầu tiên một phương thức đi từ tọa độ con cháu đến tổ tiên:

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

Tiếp theo nghịch đảo, từ tổ tiên đến hậu duệ:

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

Trong trường hợp ai đó vẫn đang cố gắng để tìm ra điều này. Đây là cách bạn có được trung tâm X và Y của view.

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

1

Tôi chỉ tìm thấy câu trả lời ở đây

Nó nói: Có thể truy xuất vị trí của một khung nhìn bằng cách gọi các phương thức getLeft () và getTop (). Cái trước trả về tọa độ bên trái, hoặc X, của hình chữ nhật đại diện cho khung nhìn. Cái sau trả về đỉnh, hoặc Y, tọa độ của hình chữ nhật đại diện cho khung nhìn. Các phương thức này đều trả về vị trí của khung nhìn so với cha của nó. Chẳng hạn, khi getLeft () trả về 20, điều đó có nghĩa là chế độ xem được đặt 20 pixel ở bên phải cạnh trái của cha mẹ trực tiếp.

nên sử dụng:

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
Điều này cung cấp vị trí liên quan đến cha mẹ trực tiếp của chế độ xem, không phải là chế độ xem gốc, có thể là cha mẹ của phụ huynh, v.v ...
Rupert Rawnsley

cái nhìn được thu nhỏ và xoay là gì?
DKV
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.