Yanıtlar:
Daha iyi tarafından verilen cevapları anlamak François BOURLIEUX ve Dalvik I Eğer bu müthiş görünüm yaşam döngüsü diyagramı bakmak önermek Arpit Mathur :
TextView
. Onların çizmek istiyorum belki bu düşünce View
onların düzen-ilişkili parametreleri değiştirmeden önce son kez, ama farklı sırayla çağrılan o aramalarla ilgili düşünüyorsanız gerçekten bir anlam ifade etmez (ve çağrı invalidate()
sonrasında sağ requestLayout()
içinde TextView
de). Belki StackOverflow :) 'da başka bir soruyu hak ediyor?
invalidate()
ve requestLayout()
) düzgün bir şekilde anladığınızı sanmıyorum . Bu yöntemlerin amacı (sizin adınıza) View
ne tür bir geçersiz kılma olduğunu anlatmaktır. Bu View
yöntemlerden birini çağırdıktan sonra hangi yolu izleyeceğinize karar vermek gibi değil . View
-Lifecycle-path seçiminin ardındaki mantık , kendisini çağırmak için uygun yöntemin seçilmesidir. Boyut değişikliği ile ilgili bir şey varsa - requestLayout()
çağrılmalı, sadece boyut değiştirmeden görsel bir değişiklik varsa - aramalısınız invalidate()
.
View
bir şekilde, örneğin size güncel olsunLayoutParams
a View
ve bunları değiştirmek ancak DEĞİL ya çağrı requestLayout
veya setLayoutParams
(çağıran requestLayout
o zaman arayabilirsin, içten) invalidate()
istediğiniz kadar kadar ve View
dolayısıyla boyutunu değiştirmek olmaz, tedbir düzeni sürecinde gitmeyecek. View
Boyutunuzun değiştiğini ( requestLayout
yöntem çağrısı ile) söylemezseniz, o zaman bunun değişmediğini View
varsayar onMeasure
ve onLayout
çağrılmaz.
invalidate()
Arama invalidate()
, görünümün yeniden çizilmesini planlamak istediğinizde yapılır. SonuçlanacakonDraw
(ama hemen değil, yakında) sonunda çağrılan. Özel görünümün ne zaman çağrılacağına örnek olarak, bir metin veya arka plan rengi özelliği değişmiştir.
Görünüm yeniden çizilecek, ancak boyut değişmeyecek.
requestLayout()
Görüşünüzle ilgili olarak boyutu etkileyecek bir şey değişirse, aramanız gerekir requestLayout()
. Bu tetikleyecek onMeasure
veonLayout
ebeveyn görünümleri için çizgi yukarı yol Bu görünüm için ama hepsi değil sadece.
Aramanın requestLayout()
, (kabul edilen cevaptaki şemanın ne anlama geldiğinin aksine) ile sonuçlanması garanti edilmezonDraw
, bu nedenle genellikle birleştirilir invalidate()
.
invalidate();
requestLayout();
Bunun bir örneği, özel bir etiketin text özelliği değiştiğinde verilebilir. Etiketin boyutu değişecek ve bu nedenle yeniden ölçülüp yeniden çizilmesi gerekiyor.
forceLayout()
Bir requestLayout()
üst görünüm grubunda çağrılan bir varsa, alt görünümlerini yeniden ölçmek ve yaymak gerekmez. Bununla birlikte, bir çocuğun yeniden ölçüme ve röleye dahil edilmesi gerekiyorsa forceLayout()
, çocuğu arayabilirsiniz . forceLayout()
yalnızca requestLayout()
doğrudan ebeveynindeki bir a ile birlikte ortaya çıkarsa çocuk üzerinde çalışır . Tek forceLayout()
başına arama yapmanın bir etkisi olmayacaktır, çünkü requestLayout()
görünüm ağacını tetiklemez .
İle ilgili daha ayrıntılı açıklama için bu Soru ve Cevapları okuyun forceLayout()
.
View
kaynak kodurequestLayout()
önce arayabilirsiniz invalidate()
. İkisi de hemen bir düzen veya çizim yapmaz. Aksine, sonunda bir geçiş ve yeniden çizim ile sonuçlanacak bayrakları ayarlarlar.
Burada bazı yanıtlar bulabilirsiniz: http://developer.android.com/guide/topics/ui/how-android-draws.html
Benim için invalidate()
yalnızca görünümü yenilerken, görünümü requestLayout()
yenileyip ekranda görünümün boyutunu hesaplamak için yapılan bir çağrı .
yeniden çizmek istediğiniz bir görünümde invalidate () yöntemini kullanırsanız, onDraw öğesinin (Canvas c) çağrılmasını sağlar ve requestLayout () tüm düzen oluşturmayı (ölçüm aşaması ve konumlandırma aşaması) yeniden çalıştırır. Çalışma zamanındaki çocuk görünümünün boyutunu değiştiriyorsanız, ancak yalnızca üst görünümdeki kısıtlamalar gibi belirli durumlarda kullanmalısınız (yani, ebeveyn yüksekliğinin veya genişliğinin WRAP_CONTENT olduğu anlamına gelir ve bu nedenle eşleşme, çocukları tekrar sarmadan önce ölçün)
Bu cevap hakkında doğru değilforceLayout()
.
Eğer görebileceğiniz gibi kodforceLayout()
"Bir relayout gerekiyor" ama ne zamanlamayı ne de tetiği o relayout yaptığı gibi bu sadece işaretleri görünümü. Geçiş, gelecekte bir noktada görünümün ebeveyninin başka bir nedenden ötürü ortaya konmasına kadar gerçekleşmeyecektir.
forceLayout()
Ve kullanırken çok daha büyük bir sorun var requestLayout()
:
Diyelim ki forceLayout()
bir görünümü çağırdınız . Şimdi requestLayout()
bu görünümün bir soyundan çağrı yaparken , Android requestLayout()
bu soyun atalarını tekrar tekrar çağırır . Sorun, aradığınız görünümde özyinelemeyi durduracağıdır forceLayout()
.Böylece requestLayout()
çağrı hiçbir zaman görünüm köküne ulaşmaz ve böylece bir düzen geçişi asla planlanmaz. Görünüm hiyerarşisinin tüm alt ağacı bir düzen bekliyor ve requestLayout()
bu alt ağacın herhangi bir görünümünü çağırmak bir düzene neden olmaz. Yalnızca requestLayout()
bu alt ağacın dışındaki herhangi bir görünümü çağırmak büyüyü bozar.
Ben uygulanmasını forceLayout()
(ve requestLayout()
kırılmasını nasıl etkilediğini düşünürdüm ve kodunuzda bu işlevi asla kullanmamalısınız.
View
ve konuyu kendim çalıştırarak ve hata ayıklayarak anladım.
forceLayout()
API'nin amacını merak ediyorum : aslında bir düzen geçişini zorlamıyor, sadece gözlemlenenonMeasure()
bir bayrağı değiştiriyor , ancak açık bir şekilde onMeasure()
çağrılmadığı sürece çağrılmayacak. Bu, bununla eşleştirilmesi gerektiği anlamına gelir . Öte yandan, hala yapmam gerekiyorsa neden performans göstermeliyim ? requestLayout()
View#measure()
forceLayout()
requestLayout()
forceLayout()
requestLayout()
requestLayout()
herşeyi forceLayout()
de yapar.
forceLayout
mantıklı. Sonunda sadece çok kötü bir şekilde adlandırılmış ve belgelenmiştir.
invalidate()
---> onDraw()
UI iş parçacığından
postInvalidate()
---> onDraw()
arka plan iş parçacığından
requestLayout()
---> onMeasure()
ve onLayout()
VE DEĞİL Mutlaka onDraw()
forceLayout()
---> onMeasure()
ve onLayout()
SADECE doğrudan ebeveyn çağırırsa requestLayout()
.