Из этого ясно, что размеры виджета заранее не известны полностью. Горизонтальная планировка требует, чтобы каждый ребенок занимал минимально возможное пространство по горизонтали. С другой стороны, размеры корневого макета (который заполняет окно приложения) известны, поэтому, если бы горизонтальный макет был корневым макетом, мы бы знали высоту каждого дочернего элемента.
Поэтому я придумал следующий интерфейс функции верстки:
Код: Выделить всё
Dimensions layout(Dimensions minDimensions, Dimensions maxDimensions);
Код: Выделить всё
child->layout(Dimensions(0, parentMinDimensions.height), parentMaxDimensions);
Давайте попробуем реализовать функцию макета для горизонтального макета:
Код: Выделить всё
Dimensions layout(Dimensions minDimensions, Dimensions maxDimensions) {
int remainingWidth = maxDimensions.width;
for (Widget *child : children) {
Dimensions childDimensions = child->layout(
Dimensions(0, minDimensions.height),
Dimensions(remainingWidth, maxDimensions.height)
);
remainingWidth -= childDimensions.width;
minDimensions.height = max(minDimensions.height, childDimensions.height);
}
return Dimensions(maxDimensions.width-remainingWidth, minDimensions.height);
}
Код: Выделить всё
Dimensions layout(Dimensions minDimensions, Dimensions maxDimensions) {
// First pass - determine height
int height = minDimensions.height;
int remainingWidth = maxDimensions.width;
for (Widget *child : children) {
Dimensions childDimensions = child->layout(
Dimensions(0, minDimensions.height),
Dimensions(remainingWidth, maxDimensions.height)
);
remainingWidth -= childDimensions.width;
height = max(height, childDimensions.height);
}
// Second pass - apply height
remainingWidth = maxDimensions.width;
for (Widget *child : children) {
Dimensions childDimensions = child->layout(
Dimensions(0, height),
Dimensions(remainingWidth, height)
);
remainingWidth -= childDimensions.width;
}
return Dimensions(maxDimensions.width-remainingWidth, height);
}
Поскольку инфраструктуры графического интерфейса с этой парадигмой чрезвычайно распространено, мне было интересно, есть ли у них такая же проблема, но, возможно, на практике иерархии недостаточно глубоки, чтобы это стало серьезной проблемой, или действительно есть какой-то способ гарантировать лучше, чем экспоненциальное время выполнения даже в худшем случае (и без ущерба для гибкости макетов).
Сноска
Я осознавая, что вместо того, чтобы дважды вызывать макет, я могу использовать две функции, например
Код: Выделить всё
Dimensions measure(Dimensions minDimensions, Dimensions maxDimensions);
void layout(Dimensions exactDimensions);
Я да. Также известно, что кэширование промежуточных результатов может помочь, но существует ли на самом деле стратегия, которая может окончательно изменить сложность наихудшего случая во всех возможных сценариях? Меня интересует экспоненциальная сложность «большого О», а не оптимизация с постоянным коэффициентом.
Подробнее здесь: https://stackoverflow.com/questions/790 ... complexity