Оптимальный гибкий алгоритм расположения коробок - PullRequest
6 голосов
/ 02 августа 2011

Я реализую модуль гибкой коробки CSS3 , как это определено в W3C, который аналогичен блочной модели Mozilla для xul . Хотя эти стандарты определяют, как должна вести себя модель, они не дают никаких подробностей о том, как они должны быть реализованы.

Детали интересующей меня модели:

  1. Коробки имеют ширину и высоту.
  2. Ящики могут содержать другие ящики.
  3. Контейнерные ящики (родительские ящики) отвечают за определение размера и расположение ящиков, которые они содержат (дочерние ящики).
  4. Коробки имеют ориентацию, которая может быть горизонтальной или вертикальной. Ориентация определяет, как дочерние блоки позиционируются и изменяются в размерах.
  5. Дочерние ящики могут быть гибкими или негибкими. Если дочерний блок негибкий, он рисуется в размере, указанном в параметрах width и height. Если он гибкий, то его размер изменяется в соответствии с доступным пространством в родительском контейнере.
  6. Гибкость относительно других дочерних ящиков в том же контейнере, размеры ящиков с более высокой гибкостью больше, чем у ящиков с меньшей гибкостью.
  7. Дочерние ящики могут быть ограничены минимальным или максимальным размером. Если дочерний блок является гибким, родительский блок никогда не изменит его размер ниже минимального размера или выше максимального размера.

Возможности 1-5 могут быть реализованы довольно эффективно. Функция 6 проблематична, так как самый эффективный алгоритм, который я могу придумать, довольно наивен. Алгоритм работает следующим образом:

  1. Поместите все поля в список.
  2. Переберите каждый дочерний блок и измените его размер, используя гибкость, чтобы определить сумму для его изменения.
  3. Если размер превышает одно из ограничений, установите для размера ячейки ограничение, удалите его из списка и начните с начала списка.

Шаг 3, где эффективность падает. Например, если в списке десять элементов, а последний имеет ограничение, то алгоритм вычисляет размер для первых девяти элементов, а затем, когда он достигает десятого элемента, ему необходимо повторить все вычисления. Я рассмотрел сохранение списка отсортированным и сначала определил размеры всех ограниченных блоков, однако это связано с дополнительными сложностями и накладными расходами на сортировку списка.

Я ожидаю, что существует признанное оптимальное решение, учитывая, что это довольно распространенная функция в браузерах и средах (XUL, .Net, Flex и т. Д.).

1 Ответ

5 голосов
/ 02 августа 2011

Большинство алгоритмов компоновки ящиков / контейнеров используют алгоритм 2 прохода. В случае .NET (WPF) они называются «Измерить» и «Упорядочить». Каждый элемент управления может измерять свое содержимое и сообщать «желаемый размер» в проходе рекурсивной меры.

Во время второго прохода (упорядочить), если требуемые размеры дочерних элементов не будут помещаться в родительском элементе, родитель использует свой алгоритм компоновки, чтобы предоставить фактический размер каждому дочернему элементу, например, назначая фактический размер, взвешенный по требуемому размеру. Минимальные / максимальные размеры, гибкость коробки и т. Д. Могут быть здесь.

Дополнительная информация о системе макетов WPF http://msdn.microsoft.com/en-us/library/ms745058.aspx

макет Xul http://www -archive.mozilla.org / проекты / XUL / layout.html

...