ForceLayout (), requestLayout () ve invalidate () kullanımı


185

Ben rolleri hakkında karıştı biraz değilim forceLayout(), requestLayout()ve invalidate()yöntemleri Viewsınıfının.

Ne zaman aranacaklar?

Yanıtlar:


357

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 : resim açıklamasını buraya girin


28
Çoğu zaman requestLayout'un geçersiz kılındıktan hemen sonra çağrıldığını görüyorum, hatta TextView gibi şeyler için Android kaynak kodunda gerçekleştiğini görüyorum, ancak bu şemaya göre gereksiz, değil mi? Bunu yapmanın bir amacı var mı?
tcox

5
Bu ilginç bir soru ve dürüst olmak gerekirse neden her iki yöntemi de çağırdıklarını bilmiyorum TextView. Onların çizmek istiyorum belki bu düşünce Viewonları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 TextViewde). Belki StackOverflow :) 'da başka bir soruyu hak ediyor?
Bartek Lipinski

14
(1/2) : Bu iki yöntemi ( invalidate()ve requestLayout()) düzgün bir şekilde anladığınızı sanmıyorum . Bu yöntemlerin amacı (sizin adınıza) Viewne tür bir geçersiz kılma olduğunu anlatmaktır. Bu Viewyö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().
Bartek Lipinski

11
(2/2): aşağıdaki konularda boyutunu değiştirirseniz Viewbir şekilde, örneğin size güncel olsunLayoutParams a Viewve bunları değiştirmek ancak DEĞİL ya çağrı requestLayoutveya setLayoutParams(çağıran requestLayouto zaman arayabilirsin, içten) invalidate()istediğiniz kadar kadar ve Viewdolayısıyla boyutunu değiştirmek olmaz, tedbir düzeni sürecinde gitmeyecek. ViewBoyutunuzun değiştiğini ( requestLayoutyöntem çağrısı ile) söylemezseniz, o zaman bunun değişmediğini Viewvarsayar onMeasureve onLayoutçağrılmaz.
Bartek Lipinski

2
@tcox burada daha fazlası -> stackoverflow.com/questions/35279374/…
Sotti

125

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 onMeasureveonLayout 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().

İlerideki çalışma


1
ancak ilk önce requestLayout () öğesini çağırıp daha sonra () geçersiz kılmak daha anlamlı olmaz mıydı?
scholt

2
@scholt, Bildiğim kadarıyla siparişin önemi yok, bu yüzden isterseniz daha requestLayout()ö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.
Suragch

27

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ı .


3
sonra forceLayout () ne dersin?
sdabet

@fiddler, bu yöntem sadece iki bayrak belirler: PFLAG_FORCE_LAYOUT ve PFLAG_INVALIDATED
suitianshi

7
@suitianshi Bayrakları ayarlamanın sonuçları nelerdir?
Sergey

1
@Sergey Sonuç, bu bayrağın önbelleği geçersiz kılmasıdır (görünümler, aynı MeasureSpec için gelecekte daha hızlı ölçmek için önbellek kullanır); View.java'nın 18783 numaralı satırına buradan bakın: github.com/android/platform_frameworks_base/blob/master/core/…
RhetoricalRuvim

3

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)


3

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.


1
Selam! Bu büyüyü nasıl buldun ? Bu bir yerde belgelendi mi?
azizbekian

1
Ne yazık ki belgelenmemiş ve muhtemelen tasarlanmamıştır. Bunu kodunu araştırarak Viewve konuyu kendim çalıştırarak ve hata ayıklayarak anladım.
fluidsonic

Sonra 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()
azizbekian

@azizbekyan hayır, zorunda değilsiniz. requestLayout()herşeyi forceLayout()de yapar.
fluidsonic

1
@ Suragch bunu kaçırdı, teşekkürler! Çok ilginç bir analiz. Amaçlanan kullanımı forceLayoutmantıklı. Sonunda sadece çok kötü bir şekilde adlandırılmış ve belgelenmiştir.
fluidsonic

0

invalidate()---> onDraw()UI iş parçacığından

postInvalidate()---> onDraw()arka plan iş parçacığından

requestLayout()---> onMeasure()ve onLayout()VE DEĞİL Mutlaka onDraw()

  • ÖNEMLİ : Bu yöntemin çağrılması, çağrılan sınıfın alt öğesini etkilemez.

forceLayout()---> onMeasure()ve onLayout() SADECE doğrudan ebeveyn çağırırsa requestLayout().

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.