Temel sorun, gerçek ölçümler için çizim aşamasını beklemeniz gerektiğidir (özellikle wrap_content
veya gibi dinamik değerlerle match_parent
), ancak genellikle bu aşama tamamlanmamıştır onResume()
. Bu nedenle bu aşamayı beklemek için bir geçici çözüme ihtiyacınız var. Bunun farklı olası çözümleri vardır:
1. Çizim / Mizanpaj Etkinliklerini Dinleyin: ViewTreeObserver
Farklı çizim etkinlikleri için bir ViewTreeObserver tetiklenir. Genellikle OnGlobalLayoutListener
ölçümü almak için istediğiniz şeydir, bu yüzden dinleyicideki kod düzen aşamasından sonra çağrılır, böylece ölçümler hazırdır:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Not: Dinleyici hemen kaldırılacaktır, aksi takdirde her düzen olayında tetiklenecektir. SDK Lvl <16 uygulamalarını desteklemeniz gerekiyorsa, dinleyicinin kaydını silmek için bunu kullanın:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Düzen kuyruğuna bir runnable ekleyin: View.post ()
Çok iyi bilinmeyen ve en sevdiğim çözüm. Temel olarak, Görünüm'ün yayın yöntemini kendi runnable'ınızla kullanın. Bu temelde kodunuzu kuyruklar sonra da belirttiği gibi vb görünümün ölçü, düzen, Romain Guy :
UI olay kuyruğu olayları sırayla işler. SetContentView () çağrıldıktan sonra, olay kuyruğunda geçiş izni isteyen bir ileti bulunur, bu nedenle kuyruğa gönderdiğiniz her şey mizanpaj geçişinden sonra gerçekleşir
Misal:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Avantajı ViewTreeObserver
:
- kodunuz yalnızca bir kez yürütülür ve bir güçlük olabilen yürütme işleminden sonra Gözlemciyi devre dışı bırakmanız gerekmez
- daha az ayrıntılı sözdizimi
Referanslar:
3. Görünümlerin onLayout Yönteminin Üzerine Yaz
Bu sadece mantığın görünümde kapsüllenebileceği belirli durumlarda pratiktir, aksi takdirde bu oldukça ayrıntılı ve hantal bir sözdizimidir.
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
Ayrıca, onLayout'un birçok kez çağrılacağını unutmayın, bu nedenle yöntemde ne yaptığınızı düşünün veya ilk kez kodunuzu devre dışı bırakın
4. Düzen aşamasından geçip geçmediğini kontrol edin
Kullanıcı arabirimini oluştururken birden çok kez yürütülen kodunuz varsa, aşağıdaki destek v4 lib yöntemini kullanabilirsiniz:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Görünüm, bir pencereye en son eklendiğinden veya pencereden ayrıldığından beri en az bir mizanpajdan geçtiğinde true değerini döndürür.
Ek: Statik olarak tanımlanmış ölçümler alma
Sadece statik olarak tanımlanmış yükseklik / genişlik elde etmek yeterliyse, bunu aşağıdakilerle yapabilirsiniz:
Ancak, bunun çizimden sonra gerçek genişlik / yükseklikten farklı olabileceğini unutmayın. Javadoc farkı mükemmel bir şekilde anlatıyor:
Bir görünümün boyutu, genişlik ve yükseklik ile ifade edilir. Bir görünüm aslında iki çift genişlik ve yükseklik değerine sahiptir.
İlk çift ölçülen genişlik ve ölçülen yükseklik olarak bilinir. Bu boyutlar, bir görünümün üst öğesi içinde ne kadar büyük olmasını istediğini tanımlar (daha fazla ayrıntı için Düzen'e bakın.) Ölçülen boyutlar, getMeasuredWidth () ve getMeasuredHeight () çağrılarak elde edilebilir.
İkinci çift basitçe genişlik ve yükseklik veya bazen çizim genişliği ve çizim yüksekliği olarak bilinir. Bu boyutlar ekrandaki görünümün, çizim zamanında ve mizanpajdan sonra gerçek boyutunu tanımlar. Bu değerler ölçülen genişlik ve yükseklikten farklı olabilir, ancak zorunlu değildir. Genişlik ve yükseklik getWidth () ve getHeight () çağrılarak elde edilebilir.