Как переопределять методы onMeasure, onLayout и onDraw при создании кастомных View в Android
Что проверяют
Понимаете ли вы три фазы отрисовки и знаете ли главное правило: в onDraw нельзя выделять память.
Как отвечать
Разберите по ролям:
onMeasure отвечает на вопрос, какого размера должен быть элемент. На вход приходят спецификации от родителя (точный размер, ограничение сверху или свобода), и метод обязан завершиться вызовом setMeasuredDimension. Разбирать спецификацию удобно через resolveSize, учитывая желаемый размер по содержимому и минимальные размеры.
onLayout нужен только контейнерам: он расставляет дочерние элементы, вызывая у каждого layout с координатами. Для одиночного элемента без детей переопределять его не нужно.
onDraw рисует на переданном холсте. Здесь действует жёсткое правило: никаких выделений памяти, никаких создающих объекты вызовов. Кисти, пути и прямоугольники создаются заранее, в конструкторе или при изменении размера, потому что метод вызывается на каждом кадре, и мусор в нём даёт заметные подтормаживания.
Что ещё обязательно назвать:
invalidateпротивrequestLayout: первый просит перерисовать (запускаетonDraw), второй просит пересчитать размеры (запускает всю цепочку). Вызов не того метода это либо лишняя работа, либо неизменившийся размер;- отступы нужно учитывать самому, система за вас этого не сделает;
- сохранение состояния через
onSaveInstanceState, если у элемента есть собственное состояние; - доступность: описание содержимого и обработка событий, иначе элемент невидим для голосового доступа;
- касания обрабатываются в
onTouchEvent, часто вместе с распознавателем жестов.
Где спотыкаются
Создают кисть внутри onDraw и получают падение частоты кадров при прокрутке.
Забывают setMeasuredDimension и получают исключение при измерении.
Вызывают requestLayout на каждый кадр анимации вместо invalidate.