Я немного запутался в ролях методов forceLayout()
, requestLayout()
и invalidate()
класса View
.
Когда они будут называться?
Я немного запутался в ролях методов forceLayout()
, requestLayout()
и invalidate()
класса View
.
Когда они будут называться?
Чтобы лучше понять ответы, предоставленные François BOURLIEUX и Dalvik Я предлагаю вам взглянуть на этот удивительный просмотреть диаграмму жизненного цикла Arpit Mathur:
invalidate()
Вызов invalidate()
выполняется, если вы хотите запланировать перерисовку представления. Это приведет к тому, что onDraw
будет вызван в конце (скоро, но не сразу). Примером того, когда пользовательское представление вызывается, является изменение свойства текста или фона.
Вид будет перерисован, но размер не изменится.
requestLayout()
Если что-то изменится в вашем представлении, что повлияет на размер, вы должны позвонить requestLayout()
. Это приведет к срабатыванию onMeasure
и onLayout
не только для этого представления, но и по всей линии для родительских представлений.
Вызов requestLayout()
не гарантирует результат onDraw
(вопреки тому, что подразумевает диаграмма в принятом ответе), поэтому он обычно сочетается с invalidate()
.
invalidate();
requestLayout();
Примером этого является, когда пользовательский ярлык изменил его текстовое свойство. Метка изменит размер и, следовательно, его нужно переоценить и перерисовать.
forceLayout()
Когда есть requestLayout()
, который вызывается в родительской группе представлений, нет необходимости переделывать и ретранслировать его дочерние представления. Однако, если ребенок должен быть включен в ремикс и ретрансляцию, вы можете вызывать forceLayout()
для ребенка. forceLayout()
работает только с дочерним элементом, если он встречается в сочетании с requestLayout()
в его прямом родителе. Вызов forceLayout()
сам по себе не будет иметь никакого эффекта, поскольку он не вызывает requestLayout()
до дерева представлений.
Прочтите этот Q & A для более подробного описания forceLayout()
.
Здесь вы можете найти ответ: 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()
), и вы никогда не должны использовать эту функцию в своем коде.