Ответы:
Чтобы лучше понять ответы Франсуа BOURLIEUX и Dalvik, я предлагаю вам взглянуть на эту удивительную диаграмму жизненного цикла представления от Arpit Mathur :
TextView
. Я подумал , что , может быть , они хотят , чтобы нарисовать View
в последний раз , прежде чем они изменить его расположение связанных параметров, но это на самом деле не имеет никакого смысла , если мы думаем о тех вызовах, вызываемых в другом порядке (и они называют invalidate()
сразу после requestLayout()
в TextView
также). Может быть, это заслуживает другого вопроса о StackOverflow :)?
invalidate()
и requestLayout()
) правильно. Цель этих методов - рассказать, View
что за недействительность (как вы ее назвали) произошла. Это не похоже на View
решение, по какому пути следовать после вызова одного из этих методов. Логика выбора View
-lifecycle-path - это выбор правильного метода для вызова самого себя. Если есть что-то, связанное с изменением размера - 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()
.