Apa cara yang benar untuk mengganti onMeasure ()? Saya telah melihat berbagai pendekatan. Misalnya, Professional Android Development menggunakan MeasureSpec untuk menghitung dimensi, lalu diakhiri dengan panggilan ke setMeasuredDimension (). Sebagai contoh:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
}
Di sisi lain, sesuai postingan ini , cara yang "benar" adalah menggunakan MeasureSpec, panggil setMeasuredDimensions (), diikuti dengan panggilan ke setLayoutParams (), dan diakhiri dengan panggilan ke super.onMeasure (). Sebagai contoh:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Jadi jalan mana yang benar? Tidak ada pendekatan yang berhasil 100% untuk saya.
Saya rasa apa yang saya tanyakan adalah apakah ada yang tahu tentang tutorial yang menjelaskan onMeasure (), layout, dimensi tampilan anak, dll.?
android
android-layout
U Avalos
sumber
sumber
Jawaban:
Solusi lainnya tidak komprehensif. Mereka mungkin berhasil dalam beberapa kasus, dan merupakan tempat yang baik untuk memulai, tetapi mereka mungkin tidak dijamin berhasil.
Saat onMeasure dipanggil, Anda mungkin atau mungkin tidak memiliki hak untuk mengubah ukuran. Nilai yang diteruskan ke onMeasure (
widthMeasureSpec
,heightMeasureSpec
) Anda berisi informasi tentang apa yang boleh dilakukan oleh tampilan anak Anda. Saat ini ada tiga nilai:MeasureSpec.UNSPECIFIED
- Kamu bisa menjadi sebesar yang kamu mauMeasureSpec.AT_MOST
- Sebesar yang Anda inginkan (hingga ukuran spesifikasi), Ini adaparentWidth
di contoh Anda.MeasureSpec.EXACTLY
- Tidak ada pilihan. Orang tua telah memilih.Ini dilakukan agar Android dapat membuat beberapa lintasan guna menemukan ukuran yang tepat untuk setiap item, lihat di sini untuk detail selengkapnya.
Jika Anda tidak mengikuti aturan ini, pendekatan Anda tidak dijamin berhasil.
Misalnya jika Anda ingin memeriksa apakah Anda diizinkan untuk mengubah ukuran sama sekali, Anda dapat melakukan hal berikut:
final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY; boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
Dengan menggunakan informasi ini, Anda akan mengetahui apakah Anda dapat mengubah nilai-nilai seperti pada kode Anda. Atau jika Anda diminta untuk melakukan sesuatu yang berbeda. Cara cepat dan mudah untuk menyelesaikan ukuran yang Anda inginkan adalah dengan menggunakan salah satu metode berikut:
int ResolveSizeAndState (int size, int measureSpec, int childMeasuredState)
int resolutionSize (int size, int measureSpec)
Sementara yang pertama hanya tersedia di Honeycomb, yang kedua tersedia di semua versi.
Catatan: Anda mungkin menemukan itu
resizeWidth
atauresizeHeight
selalu salah. Saya menemukan ini menjadi kasus jika saya memintaMATCH_PARENT
. Saya dapat memperbaikinya dengan memintaWRAP_CONTENT
pada tata letak induk saya dan kemudian selama fase UNSPECIFIED meminta ukuranInteger.MAX_VALUE
. Melakukannya akan memberi Anda ukuran maksimal yang diizinkan orang tua Anda pada lintasan berikutnya melalui onMeasure.sumber
Dokumentasi adalah otoritas dalam masalah ini: http://developer.android.com/guide/topics/ui/how-android-draws.html dan http://developer.android.com/guide/topics/ui/custom -components.html
Untuk meringkas: di akhir
onMeasure
metode yang diganti, Anda harus memanggilsetMeasuredDimension
.Anda tidak boleh menelepon
super.onMeasure
setelah meneleponsetMeasuredDimension
, itu hanya akan menghapus apa pun yang Anda atur. Dalam beberapa situasi Anda mungkin ingin memanggil yangsuper.onMeasure
pertama dan kemudian mengubah hasilnya dengan memanggilsetMeasuredDimension
.Jangan panggil
setLayoutParams
dionMeasure
. Tata letak terjadi dalam hitungan detik setelah pengukuran.sumber
Saya pikir itu tergantung pada orang tua yang Anda timpa.
Misalnya, jika Anda memperluas ViewGroup (seperti FrameLayout), ketika Anda telah mengukur ukurannya, Anda harus memanggil seperti di bawah ini
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
karena Anda mungkin ingin ViewGroup untuk melakukan pekerjaan istirahat (melakukan beberapa hal pada tampilan anak)
Jika Anda memperluas Tampilan (seperti ImageView), Anda dapat memanggilnya
this.setMeasuredDimension(width, height);
, karena kelas induk akan melakukan sesuatu seperti yang biasa Anda lakukan.Singkatnya, jika Anda menginginkan beberapa fitur yang ditawarkan kelas induk Anda secara gratis, Anda harus memanggil
super.onMeasure()
(berikan spesifikasi pengukuran mode MeasureSpec.EXACTLY biasanya), jika tidak, panggilanthis.setMeasuredDimension(width, height);
sudah cukup.sumber
berikut adalah cara saya memecahkan masalah:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { .... setMeasuredDimension( measuredWidth, measuredHeight ); widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY ); heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
Selain itu, diperlukan untuk komponen ViewPager
sumber
super.onMeasure
akan menghapus set dimensi menggunakansetMeasuredDimension
.Jika mengubah ukuran tampilan di dalam
onMeasure
semua yang Anda butuhkan adalahsetMeasuredDimension
panggilan. Jika Anda mengubah ukuran di luaronMeasure
Anda perlu meneleponsetLayoutParams
. Misalnya mengubah ukuran tampilan teks saat teks diubah.sumber
Tergantung pada kontrol yang Anda gunakan. Instruksi dalam dokumentasi berfungsi untuk beberapa kontrol (TextView, Button, ...), tetapi tidak untuk yang lain (LinearLayout, ...). Cara yang bekerja sangat baik bagi saya adalah memanggil super setelah saya selesai. Berdasarkan artikel di tautan di bawah ini.
http://humptydevelopers.blogspot.in/2013/05/android-view-overriding-onmeasure.html
sumber
Saya kira, setLayoutParams dan menghitung ulang pengukuran adalah solusi untuk mengubah ukuran tampilan anak dengan benar, karena hal ini biasanya dilakukan di onMeasure kelas turunan.
Namun, ini jarang berfungsi dengan benar (untuk alasan apa pun ...), lebih baik panggil measureChildren (saat mendapatkan ViewGroup) atau coba sesuatu yang serupa bila perlu.
sumber
Anda bisa mengambil potongan kode ini sebagai contoh onMeasure () ::
public class MyLayerLayout extends RelativeLayout { public MyLayerLayout(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int parentWidth = MeasureSpec.getSize(widthMeasureSpec); int parentHeight = MeasureSpec.getSize(heightMeasureSpec); int currentChildCount = getChildCount(); for (int i = 0; i < currentChildCount; i++) { View currentChild = getChildAt(i); //code to find information int widthPercent = currentChildInfo.getWidth(); int heightPercent = currentChildInfo.getHeight(); //considering we will pass height & width as percentage int myWidth = (int) Math.round(parentWidth * (widthPercent / 100.0)); int myHeight = (int) Math.round(parentHeight * (heightPercent / 100.0)); //Considering we need to set horizontal & vertical position of the view in parent AlignmentTraitValue vAlign = currentChildInfo.getVerticalLocation() != null ? currentChildlayerInfo.getVerticalLocation() : currentChildAlignmentTraitValue.TOP; AlignmentTraitValue hAlign = currentChildInfo.getHorizontalLocation() != null ? currentChildlayerInfo.getHorizontalLocation() : currentChildAlignmentTraitValue.LEFT; int topPadding = 0; int leftPadding = 0; if (vAlign.equals(currentChildAlignmentTraitValue.CENTER)) { topPadding = (parentHeight - myHeight) / 2; } else if (vAlign.equals(currentChildAlignmentTraitValue.BOTTOM)) { topPadding = parentHeight - myHeight; } if (hAlign.equals(currentChildAlignmentTraitValue.CENTER)) { leftPadding = (parentWidth - myWidth) / 2; } else if (hAlign.equals(currentChildAlignmentTraitValue.RIGHT)) { leftPadding = parentWidth - myWidth; } LayoutParams myLayoutParams = new LayoutParams(myWidth, myHeight); currentChildLayoutParams.setMargins(leftPadding, topPadding, 0, 0); currentChild.setLayoutParams(myLayoutParams); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
sumber