Masalah dasarnya adalah, Anda harus menunggu fase menggambar untuk pengukuran aktual (terutama dengan nilai dinamis seperti wrap_content
atau match_parent
), tetapi biasanya fase ini belum selesai onResume()
. Jadi Anda perlu solusi untuk menunggu fase ini. Ada beberapa solusi yang mungkin untuk ini:
1. Dengarkan Draw / Layout Events: ViewTreeObserver
ViewTreeObserver dipecat untuk berbagai peristiwa menggambar. Biasanya OnGlobalLayoutListener
adalah apa yang Anda inginkan untuk mendapatkan pengukuran, sehingga kode di pendengar akan dipanggil setelah fase tata letak, sehingga pengukuran siap:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Catatan: Pendengar akan segera dihapus karena jika tidak maka akan menyala pada setiap acara tata letak. Jika Anda harus mendukung aplikasi SDK Lvl <16 gunakan ini untuk membatalkan pendaftaran pendengar:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. Tambahkan runnable ke antrian tata letak: View.post ()
Tidak terlalu terkenal dan solusi favorit saya. Pada dasarnya cukup gunakan metode posting View dengan runnable Anda sendiri. Ini pada dasarnya mengantri kode Anda setelah ukuran tampilan, tata letak, dll. Seperti yang dinyatakan oleh Romain Guy :
Antrian acara UI akan memproses acara secara berurutan. Setelah setContentView () dipanggil, antrian acara akan berisi pesan yang meminta relai, sehingga apa pun yang Anda poskan ke antrian akan terjadi setelah tata letak berlalu
Contoh:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
Keuntungan lebih dari ViewTreeObserver
:
- kode Anda hanya dieksekusi sekali dan Anda tidak perlu menonaktifkan Observer setelah eksekusi yang dapat merepotkan
- kurang sintaksis verbose
Referensi:
3. Timpa Metode onLayout Views
Ini hanya praktis dalam situasi tertentu ketika logika dapat diringkas dalam pandangan itu sendiri, jika tidak, ini adalah sintaksis yang sangat verbose dan rumit.
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
}
};
Selain itu, onLayout akan dipanggil berkali-kali, jadi pertimbangkan apa yang Anda lakukan dalam metode ini, atau nonaktifkan kode Anda setelah pertama kali
4. Periksa apakah telah melalui fase tata letak
Jika Anda memiliki kode yang menjalankan beberapa kali saat membuat ui Anda bisa menggunakan metode lib dukungan v4 berikut:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
Mengembalikan nilai true jika tampilan telah melalui setidaknya satu tata letak sejak terakhir kali dilampirkan atau dilepaskan dari jendela.
Tambahan: Mendapatkan pengukuran yang ditentukan secara statis
Jika cukup untuk mendapatkan tinggi / lebar yang ditentukan secara statis, Anda bisa melakukan ini dengan:
Tapi ingat, ini mungkin berbeda dengan lebar / tinggi sebenarnya setelah menggambar. Javadoc menjelaskan perbedaan dengan sempurna:
Ukuran tampilan dinyatakan dengan lebar dan tinggi. Tampilan sebenarnya memiliki dua pasang nilai lebar dan tinggi.
Pasangan pertama dikenal sebagai lebar terukur dan tinggi terukur. Dimensi ini menentukan seberapa besar tampilan ingin berada di dalam induknya (lihat Layout untuk detail lebih lanjut.) Dimensi yang diukur dapat diperoleh dengan memanggil getMeasuredWidth () dan getMeasuredHeight ().
Pasangan kedua hanya dikenal sebagai lebar dan tinggi, atau kadang-kadang menggambar lebar dan tinggi menggambar. Dimensi ini menentukan ukuran sebenarnya dari tampilan di layar, pada waktu menggambar dan setelah tata letak. Nilai-nilai ini mungkin, tetapi tidak harus, berbeda dari lebar dan tinggi yang diukur. Lebar dan tinggi dapat diperoleh dengan memanggil getWidth () dan getHeight ().