Как обрабатывать нулевые значения ширин детей при распределении
Что проверяют
Это задача про собственный алгоритм раскладки, чаще всего кастомный ViewGroup или аналог LinearLayout с весами: свободная ширина делится между детьми пропорционально их долям. Проверяют граничные случаи: нулевая ширина, нулевой вес, сумма весов равна нулю. Следом просят разобрать округление пикселей.
Как отвечать
Сначала договоритесь о смысле нуля. В LinearLayout значение layout_width="0dp" вместе с layout_weight означает «ширину определит вес», это не ошибка и не отсутствие значения. Незаданную ширину обозначают константы WRAP_CONTENT и MATCH_PARENT, у них отрицательные значения.
Алгоритм в onMeasure():
- первый проход: измерить детей с фиксированной шириной и без веса, сложить их ширину и отступы,
View.GONEпропустить целиком; - остаток:
remaining = available - used. Если он отрицательный, растягивать нечего, и нужно заранее решить, сжимаются дети или обрезаются; - сумма весов: если она равна нулю, делить на неё нельзя. Остаток отдают поровну, оставляют пустым или отдают последнему ребёнку, по требованиям;
- нулевой вес и нулевая ширина: ребёнок получает 0 и не должен ломать расчёт соседей;
- второй проход: ширина ребёнка
remaining * weight / totalWeight, затемmeasure()сMeasureSpec.EXACTLY; - округление: считать накопленные границы во
floatи брать ширину как разность округлённых границ. Тогда сумма точно совпадёт с шириной родителя.
Если родитель получил MeasureSpec.UNSPECIFIED, например внутри HorizontalScrollView, свободной ширины нет, и распределять веса не из чего. В Compose тот же вопрос решает Modifier.weight() в Row, но вес там обязан быть больше нуля, иначе будет IllegalArgumentException. Свой алгоритм пишется через Layout.
Где спотыкаются
Делят на сумму весов без проверки. Для целых это ArithmeticException, для float получаются NaN или бесконечность, и ребёнок исчезает или становится огромным.
Путают 0 с «не задано» и подменяют нулевую ширину значением по умолчанию. Весовая раскладка после этого ломается.
Округляют каждого ребёнка отдельно. На трёх детях по 33,33 пикселя теряется пиксель, и справа остаётся полоска.