Bir görünümün mutlak koordinatlarını alma


390

Bir görünümün sol üst köşesinin mutlak ekran piksel koordinatlarını almaya çalışıyorum. Ancak, bulabildiğim getLeft()ve bulamadığım tüm yöntemler, hepsi getRight()görünümün ebeveynine göreli göründüğünden bana verir 0. Bunu yapmanın uygun yolu nedir?

Eğer yardımcı olursa, bu 'resmi tekrar sıraya koy' oyunu içindir. Kullanıcının birden fazla parça seçmek için bir kutu çizebilmesini istiyorum. Benim varsayım Bunu yapmanın en kolay yolu olmasıdır getRawX()ve getRawY()gelen MotionEventve daha sonra parçaları tutan düzen sol üst köşesine karşı bu değerleri karşılaştırın. Parçaların boyutunu bilerek, kaç parçanın seçildiğini belirleyebilirim. I kullanabilir gerçekleştirmek getX()ve getY()ilgili MotionEvent, ancak geri döner parçalar daha zor seçilen belirlenirken yapan bir göreli konum olarak. (İmkansız değil, biliyorum, ama gereksiz yere karmaşık görünüyor).

Düzenleme: Bu, soru konteyner birine göre tutma konteyner boyutunu almak için kullanılan kod. TableLayouttüm yapboz parçalarını tutan masadır.

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

Edit 2: Önerilen cevaplardan daha fazlasını izleyerek denediğim kod.

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

Bu kod, tüm başlatma işlemleri tamamlandıktan sonra eklenmiştir. Görüntü, içinde bulunan bir ImageViews dizisine (hücreleri [] dizisi) bölünmüştür TableLayout. Hücreler [0] sol ImageViewüsttedir ve hücreleri [4] ortada bir yerde olduğu için aldım ve (0,0) koordinatlarına kesinlikle sahip olmamalıydım.

Yukarıda gösterilen kod hala günlüklerdeki tüm 0'ları veriyor, ki gerçekten bilmiyorum çünkü çeşitli puzzle parçaları doğru bir şekilde gösteriliyor. (Her ikisi de aynı sonucu veren tableLayoutCorners ve varsayılan görünürlük için genel int denedim.)

Bunun önemli olup olmadığını bilmiyorum, ama ImageViews aslında bir boyut verilmiyor. ImageViewGörüntülenecek bir görüntü verdiğimde , s boyutu yeniden başlatma sırasında Görünüm tarafından otomatik olarak belirlenir. Günlük kaydı kodu bir resim verildikten ve otomatik olarak yeniden boyutlandırıldıktan sonra olsa da, bu değerlerin 0 olmasına katkıda bulunabilir mi? Potansiyel olarak buna karşı koymak için, tableLayout.requestLayout()yukarıda gösterildiği gibi kodu ekledim , ancak bu yardımcı olmadı.

Yanıtlar:


632

3
Şimdi bulmayı umduğum türden bir fonksiyon. Ne yazık ki, düzgün kullanmamalıyım. GetLocationOnScreen'in Android v1.5'te (kodladığım platform) boş bir işaretçi istisnası verdiği bilinen bir hata olduğunu fark ettim, ancak v2.1'de test daha iyi çalışmadı. Her iki yöntem de bana her şey için 0 saniye verdi. Yukarıda bir kod pasajı ekledim.
Steve Haley

76
Bunu ancak düzen gerçekleştikten sonra çağırabilirsiniz . Görünümler ekrana yerleştirilmeden önce yöntemi çağırıyorsunuz.
Romain Guy

5
Aha, haklısın, ama bunu yaptığım belli değildi. Teşekkürler! Daha fazla ayrıntı merak eden herkes için ne demek istediğimi açıklayan bir cevap ekledim.
Steve Haley

9
ViewTreeObserver ve OnGlobalLayoutListener gibi mi demek istediniz? Başlamak için View.getViewTreeObserver () öğesine bakın.
Romain Guy

8
@RomainGuy Evet, böyle bir şey, ancak kayıt olmaktan daha az kafa karıştırıcı (ve ardından kayıttan çıkar…). Bu, iOS'un SDK açısından Android'den daha iyi yaptığı bir alandır. Her ikisini de günlük olarak kullanarak, iOS'un çok can sıkıcı şeyleri olduğunu söyleyebilirim, ancak UIView kullanımı bunlardan biri değil. :)
Martin Marconcini

127

Kabul edilen cevap aslında konumu nasıl alacağını söylemedi, bu yüzden biraz daha detay. Bir intuzunluk 2 dizisini iletirsiniz ve değerler görünümün (x, y) koordinatlarıyla (üst sol köşenin) değiştirilir.

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

notlar

  • Değiştirme getLocationOnScreenile getLocationInWindowçoğu durumda aynı sonuçları vermelidir (bkz bu cevabı ). Ancak, bir İletişim Kutusu veya özel klavye gibi daha küçük bir penceredeyseniz, hangisinin ihtiyaçlarınıza daha uygun olduğunu seçmeniz gerekecektir.
  • Görünüm henüz düzenlenmediği için (0,0)bu yöntemi çağırırsanız alacaksınız onCreate. ViewTreeObserverDüzen bittiğinde dinlemek için a düğmesini kullanabilir ve ölçülen koordinatları alabilirsiniz. ( Bu cevaba bakınız .)

86

İlk önce görünümün yerelVisible dikdörtgenini almalısınız

Örneğin:

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

Umarım bu yardımcı olur


3
Bu da işe yaramış olmalı ... Ama bana 0 değeri de veriyor. Yanlış yaptığımı anlamanıza yardımcı olması durumunda yukarıdaki kod pasajını ekledim. Tekrar teşekkürler.
Steve Haley

1
Diğer yorumlarıma bakın; Görünümler kendilerini düzenlemeyi bitirmeden bunu yanlışlıkla çağırıyordum. Bu şimdi iyi çalışıyor teşekkürler.
Steve Haley

@Naveen Murthy belirli bir görünüm için koordinatlar verir, ben kök düzeninde tıklatılan görünüm koordinatlarına ihtiyacım var ..
Aniket

20
bu, üst öğeye göre konumu döndürür. getGlobalVisibleRect()mutlak kordlar için kullanın .
Jeffrey Blattman

3
@SteveHaley, seninle aynı sorunla karşı karşıya kaldım, nedense denediğim her yöntemde 0 veriyor. Görünüşe göre neden sıfır verdiğini anladınız. Düzen yüklendikten sonra görünüm koordinatlarını almaya çalışıyorum hala sıfır olsun neden bu kadar? Yardımınız için teşekkürler
Pankaj Nimgade

46

Global bir düzen dinleyici kullanmak benim için her zaman iyi çalıştı. Düzen değiştirilirse, örneğin View.GONE olarak ayarlanmışsa veya alt görünümler eklenir / kaldırılırsa, şeyleri yeniden ölçebilme avantajı vardır.

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

OnGlobalLayout () {...} içindeki (sonunda) OnGlobalLayoutListener'ı kaldırmayı unutmayın. Ayrıca, sadece emin olmak için, ne geçtiğini kontrol edin! = 0; dinleyici iki kez çağrılabilir, bir kez w = 0 / h = 0 değeri, ikinci kez gerçek, doğru değerler ile çağrılabilir.
MacD

Ana düzeni şişirmek ve daha sonra kullanmak için bu şekilde benim app setContentView()özel bir soruna neden oldu Activity! Bu bir iletişim etkinliğiydi ( windowFrame:@null, windowActionBar:false, windowIsFloating:true, windowNoTitle:true). Ana düzeni (a LinearLayout) kararlı olan herhangi bir doğrudan çocuğa sahip değildir layout_width(hepsi match_parentya da idi wrap_content).
Mir-Ismaili

17

Romain Guy'ın yorumundan sonra, bunu nasıl düzelttim. Umarım bu sorunu yaşayan herkese yardımcı olur.

Gerçekten onlar ekranda ortaya konmadan önce görüş pozisyonlarını almak için çalışıyordu ama bu hiç belli değildi. Bu satırlar başlatma kodu çalıştırıldıktan sonra yerleştirilmişti, bu yüzden her şeyin hazır olduğunu varsaydım. Ancak, bu kod hala onCreate (); Thread.sleep () ile deney yaparak, onCreate () 'e kadar onResume ()' e kadar işlemin tamamlanmasına kadar mizanpajın aslında sonlandırılmadığını keşfettim. Gerçekten de, kod mizanpaj ekranda konumlandırılmadan önce çalışmaya çalışıyordu. Kodu bir OnClickListener'a (veya başka bir Dinleyiciye) ekleyerek, yalnızca mizanpaj bittikten sonra tetiklenebildiğinden doğru değerler elde edildi.


Aşağıdaki satır bir topluluk düzenlemesi olarak önerildi:

lütfen kullan onWindowfocuschanged(boolean hasFocus)


Yani demek istediğim setContentView (my_layout); tüm görünümleri yerleştirmez. Tüm görünümler yalnızca onCreate () bittikten sonra mı yerleştirilecek?
Ashwin

5
Pek değil. Tüm görüşler sonradan var olur setContentView(R.layout.something), ancak görsel olarak yüklenmezler. Boyutları veya konumları yoktur. Gelecekte bir noktada (genellikle onResume () sonrasında) gerçekleşen ilk düzen geçişi bitene kadar bu olmaz.
Steve Haley

14

İlk Yol:

In KOTLIN biz görünüm için basit bir uzantısı oluşturabilirsiniz:

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

Ve sadece koordinatları alın:

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

İkinci Yol:

İkinci yol daha basit:

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]
}

ve sadece mutlak X'i view.absX()ve Y'yiview.absY()


6
İlk örneğiniz için daha kısa bir versiyon:val location = IntArray(2).apply(::getLocationOnScreen)
Tuan Chau

5

Benim utils benim görünüm konumu için işlev Point, x valueve ile bir nesne döndürüry value

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

kullanma

Point viewALocation = getLocationOnScreen(viewA);

5

Sen kullanarak Views'ın koordinatlarını alabilirsiniz getLocationOnScreen()veyagetLocationInWindow()

Daha sonra xve ybakış sol üst köşesi olmalıdır. Kök düzeniniz ekrandan daha küçükse (bir İletişim Kutusunda olduğu gibi), kullanımı getLocationInWindowekranın tamamına değil, kabına göre olur.

Java Çözümü

int[] point = new int[2];
view.getLocationOnScreen(point); // or getLocationInWindow(point)
int x = point[0];
int y = point[1];

NOT: Değer her zaman 0 ise, konum isteğinde bulunmadan hemen önce görünümü değiştiriyorsunuzdur.

Görünümün güncelleme şansına sahip olduğundan emin olmak için, Görünümün yeni düzeni hesaplandıktan sonra konum isteğinizi aşağıdakileri kullanarak çalıştırın view.post:

view.post(() -> {
    // Values should no longer be 0
    int[] point = new int[2];
    view.getLocationOnScreen(point); // or getLocationInWindow(point)
    int x = point[0];
    int y = point[1];
});

~~

Kotlin Çözümü

val point = IntArray(2)
view.getLocationOnScreen(point) // or getLocationInWindow(point)
val (x, y) = point

NOT: Değer her zaman 0 ise, konum isteğinde bulunmadan hemen önce görünümü değiştiriyorsunuzdur.

Görünümün güncelleme şansına sahip olduğundan emin olmak için, Görünümün yeni düzeni hesaplandıktan sonra konum isteğinizi aşağıdakileri kullanarak çalıştırın view.post:

view.post {
    // Values should no longer be 0
    val point = IntArray(2)
    view.getLocationOnScreen(point) // or getLocationInWindow(point)
    val (x, y) = point
}

Bunu işlemek için bir uzantı işlevi oluşturmanızı öneririz:

// To use, call:
val (x, y) = view.screenLocation

val View.screenLocation get(): IntArray {
    val point = IntArray(2)
    getLocationOnScreen(point)
    return point
}

Güvenilirliğe ihtiyacınız varsa şunları da ekleyin:

view.screenLocationSafe { x, y -> Log.d("", "Use $x and $y here") }

fun View.screenLocationSafe(callback: (Int, Int) -> Unit) {
    post {
        val (x, y) = screenLocation
        callback(x, y)
    }
}

0

Tam X ve Y kordinatlarını bulmak için bu kodu kullanın:

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

Görünümümü ayarlamak için bazı değerler ekledim / çıkardım. Lütfen bu çizgileri yalnızca tüm görünüm şişirildikten sonra yapın.


"Görünümümü ayarlamak için bazı değerler ekledim / çıkardım." Neden??
ToolmakerSteve

Gereksinimime göre (Görünüm yerleştirme), görünümümü ayarlamak için değerler ekledim ve çıkardım.
Tarun

0

Hem Görüntüleme Konumunu hem de Boyutunu ekrana getirin

val viewTreeObserver: ViewTreeObserver = videoView.viewTreeObserver;

    if (viewTreeObserver.isAlive) {
        viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                //Remove Listener
                videoView.viewTreeObserver.removeOnGlobalLayoutListener(this);

                //View Dimentions
                viewWidth = videoView.width;
                viewHeight = videoView.height;

                //View Location
                val point = IntArray(2)
                videoView.post {
                    videoView.getLocationOnScreen(point) // or getLocationInWindow(point)
                    viewPositionX = point[0]
                    viewPositionY = point[1]
                }

            }
        });
    }

0

Sadece yukarıdaki cevaplara ek olarak, nerede ve ne zaman arayacağınız sorusu için getLocationOnScreen?

Almak istediğiniz herhangi bir görünümle ilgili herhangi bir bilgide, yalnızca görünüm ekranda belirlendikten sonra kullanılabilir. Bunu, görünümün oluşturulmasına bağlı olan kodunuzu bunun içine yerleştirerek kolayca yapabilirsiniz (view.post (Runnable)):

view.post(new Runnable() {
            @Override
            public void run() {

               // This code will run view created and rendered on screen

               // So as the answer to this question, you can put
               int[] location = new int[2];
               myView.getLocationOnScreen(location);
               int x = location[0];
               int y = location[1];
            }
        });  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.