Відповіді:
Щоб краще зрозуміти відповіді , надані Франсуа BOURLIEUX і Dalvik я пропоную вам поглянути на цей дивовижний вид діаграми життєвого циклу по Arpit Матура :
TextView
. Я подумав, що, можливо, вони хочуть зробити View
останній раз перед тим, як змінити параметри, пов’язані з компонуванням, але це насправді не має сенсу, якщо ми подумаємо про те, що виклики викликаються в іншому порядку (і вони дзвонять invalidate()
відразу після requestLayout()
в TextView
також). Може бути, це заслуговує на інше питання щодо StackOverflow :)?
invalidate()
і requestLayout()
) належним чином. Мета цих методів полягає в тому, щоб розповісти, View
яка інвалідність (як ви її назвали) сталася. Це не так, як View
вирішувати, який шлях слід пройти після виклику одного з цих методів. Логіка вибору шляху View
-lifecycle - вибір правильного методу для виклику себе. Якщо є щось, що стосується зміни розміру - requestLayout()
слід викликати, якщо є лише візуальна зміна без зміни розміру - вам слід зателефонувати invalidate()
.
View
певним чином зміните розмір свого , наприклад, ви отримуєте струмLayoutParams
a View
і змінюєте їх, але НЕ дзвоните requestLayout
або setLayoutParams
( або дзвінки requestLayout
внутрішньо), ви можете дзвонити invalidate()
скільки завгодно, і View
не буде проходити через процес вимірювання верстки, тому не буде змінювати його розмір. Якщо ви не говорите ваш , View
що його розмір змінився (з requestLayout
викликом методу), то View
будемо вважати , що не зробив, а onMeasure
й onLayout
не називатиме.
invalidate()
Виклик invalidate()
проводиться, коли ви хочете запланувати перемальовування перегляду. Це призведе до виклику в onDraw
кінцевому підсумку (незабаром, але не відразу). Прикладом того, коли користувацький перегляд називав би це, коли властивість тексту або кольору фону змінилася.
Вид буде перероблений, але розмір не зміниться.
requestLayout()
Якщо щось у вашому перегляді зміниться, що вплине на розмір, то вам слід зателефонувати requestLayout()
. Це викличе onMeasure
і onLayout
не тільки для цієї точки зору , але все шляху вгору по лінії поглядів батьківських.
Виклик requestLayout()
буде не гарантовано результат вonDraw
(попри те , що передбачає діаграма в загальноприйнятому відповіді), так що, як правило , в поєднанні з invalidate()
.
invalidate();
requestLayout();
Прикладом цього є те, коли власна мітка змінила властивість тексту. Етикетка змінила б розмір і, таким чином, потрібно буде переосмислити та переробити.
forceLayout()
Коли requestLayout()
в батьківській групі перегляду є те, що викликається, йому не потрібно переоцінювати та ретрансляцію своїх дочірніх поглядів. Однак, якщо дитину слід включити до переоцінки та ретрансляції, то можна зателефонувати forceLayout()
на дитину. forceLayout()
працює на дитину, лише якщо це відбувається спільно з requestLayout()
прямим батьком. Виклик forceLayout()
сам по собі не матиме ефекту, оскільки він не запускає requestLayout()
дерево перегляду.
Прочитайте цю запитання для більш детального опису forceLayout()
.
requestLayout()
раніше, invalidate()
якщо захочете. Ні один не робить макет або малювати негайно. Швидше, вони встановлюють прапори, що в підсумку призведе до ретрансляції та перемальовки.
Тут ви можете знайти відповідь: http://developer.android.com/guide/topics/ui/how-android-draws.html
Для мене дзвінок invalidate()
лише оновлює подання, а виклик - для requestLayout()
оновлення подання та обчислення розміру перегляду на екрані.
ви використовуєте Invalidate () для подання, яке ви хочете перемалювати, воно зробить його onDraw (Canvas c) для виклику, а requestLayout () призведе до повторного запуску всього макета (фаза вимірювання та фаза позиціонування). Ви повинні використовувати його, якщо ви змінюєте розмір дитячого подання під час виконання, але лише в окремих випадках, наприклад, обмеження батьківського перегляду (маючи на увазі, що висота або ширина батьків є WRAP_CONTENT, і тому відповідайте вимірюванню дітей, перш ніж вони зможуть їх завернути)
Ця відповідь не є правильноюforceLayout()
.
Як ви бачите в кодіforceLayout()
він просто позначає представлення як "потребує ретрансляції", але він не ані графік, ані запуск цього ретрансляції. Передача не відбудеться до тих пір, поки в якийсь момент батьківський погляд не буде викладений з якоїсь іншої причини.
Існує також набагато більша проблема при використанні forceLayout()
та requestLayout()
:
Скажімо, ви зателефонували forceLayout()
на перегляд. Тепер, коли закликає requestLayout()
нащадка цього погляду, Android буде рекурсивно закликати requestLayout()
предків цього нащадка. Проблема полягає в тому, що вона зупинить рекурсію при погляді, на який ви дзвонили forceLayout()
. Таким чином, requestLayout()
виклик ніколи не дійде до кореня перегляду і, таким чином, ніколи не планує пропуск макета. Ціле піддерево ієрархії перегляду чекає макета, і виклик requestLayout()
будь-якого виду цього піддерева не спричинить макет. Лише заклик requestLayout()
до будь-якого виду поза цим піддеревом порушить заклинання.
Я б розглядав реалізацію forceLayout()
(і як це впливає requestLayout()
на порушення функції, і ви ніколи не повинні використовувати цю функцію у своєму коді.
View
і запускаючи проблему сам і налагоджуючи її.
forceLayout()
API: він насправді не примушує пропускати макет, він просто змінює прапор, який спостерігаєтьсяonMeasure()
, але onMeasure()
не буде викликаний, якщо не буде викликано requestLayout()
явний або явний View#measure()
. Це означає, що з цим forceLayout()
слід поєднуватися requestLayout()
. З іншого боку, навіщо тоді виконувати, forceLayout()
якщо мені все одно потрібно виступати requestLayout()
?
requestLayout()
робить все, що forceLayout()
також робить.
forceLayout
має сенс. Отже, врешті-решт, це дуже погано названо та задокументовано.
invalidate()
---> onDraw()
з потоку інтерфейсу користувача
postInvalidate()
---> onDraw()
з фонової нитки
requestLayout()
---> onMeasure()
і onLayout()
І НЕ обов'язково onDraw()
forceLayout()
---> onMeasure()
і onLayout()
ТІЛЬКИ ЯКЩО прямий батько називається requestLayout()
.