fit_grid 1.0.0 copy "fit_grid: ^1.0.0" to clipboard
fit_grid: ^1.0.0 copied to clipboard

Сетка с автоподбором размера и количества плиток под доступное пространство

Fit Grid #

Сетка, которая сама подбирает размер и количество плиток под доступное пространство, минимизируя пустые зазоры.

Описание #

Пакет предоставляет виджет FitGrid, который сам подбирает количество столбцов и строк, размер плиток и их позиции — без ручного указания crossAxisCount, как в обычном GridView. Раскладка пересчитывается на layout-фазе (CustomMultiChildLayout + MultiChildLayoutDelegate), поэтому ресайз области не вызывает rebuild дерева виджетов — только relayout.

Основные возможности #

  • Автоматический подбор количества столбцов/строк и размера плиток под доступное пространство
  • Минимизация пустого пространства: если элементов меньше вместимости страницы — приоритет отдаётся заполнению области, если страница заполнена целиком — максимизации размера плитки
  • Расчёт раскладки на layout-фазе, без rebuild при ресайзе
  • Настраиваемое выравнивание сетки через AlignmentDirectional — учитывает направление текста (RTL/LTR)
  • Отдельное выравнивание неполной последней строки
  • Поддержка отступов между плитками (itemPadding) и от границ области (gridPadding)
  • Поддержка пропорций плиток (aspectRatio)
  • Настраиваемый список пресетов размеров плиток (presets) — свой набор форм-факторов вместо встроенного
  • Встроенная пагинация: maxItemsPerPage, currentPage и уведомления через pageInfoNotifier
  • Утилита расчёта maxItemsPerPage по ширине области с дефолтными брейкпоинтами под mobile/tablet и desktop/web
  • Без сторонних зависимостей — только Flutter SDK

Установка #

Пакет опубликован на pub.dev. Добавьте зависимость в pubspec.yaml:

dependencies:
  fit_grid: ^1.0.0

Затем выполните:

flutter pub get

Использование #

Базовый пример #

import 'package:fit_grid/fit_grid.dart';

FitGrid(
  children: [
    Card(child: Text('Карточка 1')),
    Card(child: Text('Карточка 2')),
    Card(child: Text('Карточка 3')),
    // ... больше карточек
  ],
  maxItemsPerPage: 9,
  alignment: AlignmentDirectional.center,
)

Расширенный пример с настройками #

FitGrid(
  children: _buildCards(),
  maxItemsPerPage: 12,
  alignment: AlignmentDirectional.topStart,
  itemPadding: Size(16, 16),  // Отступы между плитками
  gridPadding: EdgeInsets.all(24),  // Отступы от границ
  aspectRatio: 16 / 9,  // Пропорции плитки (опционально)
)

Выравнивание и RTL #

alignment типизирован как AlignmentDirectional, поэтому start/end автоматически зеркалятся под направление текста из ближайшего Directionality (например, для арабской/ивритской локали). Если нужно жёстко закрепить сторону независимо от locale — используйте AlignmentDirectional.topLeft/topRight и т.д. напрямую вместо topStart/topEnd.

Пример с пагинацией #

final ValueNotifier<FitGridPageInfo> pageInfoNotifier = ValueNotifier<FitGridPageInfo>(
  const FitGridPageInfo(currentPage: 1, totalPages: 1),
);

// Слушаем изменения информации о страницах
ValueListenableBuilder<FitGridPageInfo>(
  valueListenable: pageInfoNotifier,
  builder: (context, pageInfo, child) {
    return Text('Страница ${pageInfo.currentPage} из ${pageInfo.totalPages}');
  },
)

// Используем в FitGrid
FitGrid(
  children: _buildCards(),
  maxItemsPerPage: 12,
  alignment: AlignmentDirectional.center,
  pageInfoNotifier: pageInfoNotifier,  // Уведомления о страницах
  currentPage: 1,  // Текущая страница (опционально)
)

Расчёт maxItemsPerPage по ширине (брейкпоинты) #

Если вы хотите автоматически подбирать maxItemsPerPage в зависимости от ширины области, можно использовать дефолтные брейкпоинты пакета:

LayoutBuilder(
  builder: (context, constraints) {
    final FitGridPlatformGroup platformGroup = FitGridPlatformGroup.desktopAndWeb;
    final int maxItemsPerPage = FitGridItemsPerPageCalculator.calculateForPlatformGroup(
      width: constraints.maxWidth,
      platformGroup: platformGroup,
    );
    return FitGrid(
      children: _buildCards(),
      maxItemsPerPage: maxItemsPerPage,
      alignment: AlignmentDirectional.center,
    );
  },
)

FitGridItemsPerPageBreakpoint

FitGridItemsPerPageBreakpoint — правило вида «диапазон ширины → рекомендуемое maxItemsPerPage».

  • minWidth: минимальная ширина (включительно)
  • maxWidth: максимальная ширина (включительно), можно использовать double.infinity
  • maxItemsPerPage: рекомендуемое значение maxItemsPerPage для диапазона

Если дефолтные брейкпоинты вам не подходят, вы можете описать собственные:

LayoutBuilder(
  builder: (context, constraints) {
    final List<FitGridItemsPerPageBreakpoint> breakpoints =
        <FitGridItemsPerPageBreakpoint>[
      const FitGridItemsPerPageBreakpoint(
        minWidth: 0,
        maxWidth: 599,
        maxItemsPerPage: 8,
      ),
      const FitGridItemsPerPageBreakpoint(
        minWidth: 600,
        maxWidth: 1023,
        maxItemsPerPage: 12,
      ),
      const FitGridItemsPerPageBreakpoint(
        minWidth: 1024,
        maxWidth: double.infinity,
        maxItemsPerPage: 16,
      ),
    ];
    final int maxItemsPerPage = FitGridItemsPerPageCalculator.calculateForBreakpoints(
      width: constraints.maxWidth,
      breakpoints: breakpoints,
    );
    return FitGrid(
      children: _buildCards(),
      maxItemsPerPage: maxItemsPerPage,
      alignment: AlignmentDirectional.center,
    );
  },
)

Пресеты размеров плиток #

FitGrid перебирает список пресетов и выбирает тот, что даёт максимальное заполнение области (presets, по умолчанию — встроенный tileSizePresets). В debug-режиме выбранный пресет выводится в консоль.

Пресет — это не только пропорция, но и потолок абсолютного размера плитки: если элементов на странице ровно maxItemsPerPage (страница заполнена целиком), плитка не может превысить preset.size. Если встроенные пресеты вам не подходят (например, нужны более крупные плитки на широких экранах), передайте свой список:

FitGrid(
  children: _buildCards(),
  maxItemsPerPage: 9,
  alignment: AlignmentDirectional.center,
  presets: const [
    TileSizePreset('wide', Size(900, 400)),
    TileSizePreset('square', Size(500, 500)),
  ],
)

API #

FitGrid #

Основной виджет пакета.

Параметры

Параметр Тип Обязательный По умолчанию Описание
children List<Widget> ✅ - Список виджетов-карточек для отображения
maxItemsPerPage int ✅ - Максимальное количество элементов на странице
alignment AlignmentDirectional ✅ - Выравнивание сетки внутри области (учитывает RTL/LTR)
itemPadding Size ❌ Size(8, 8) Отступы между плитками (width = горизонтальный, height = вертикальный)
gridPadding EdgeInsets ❌ EdgeInsets.zero Внешние отступы сетки от границ области
aspectRatio double? ❌ null Пропорции плитки (width / height). Если null, используется 1:1
pageInfoNotifier ValueNotifier<FitGridPageInfo>? ❌ null ValueNotifier для уведомления о текущей странице и общем количестве страниц
currentPage int? ❌ null Текущая страница (начинается с 1). Если не указан, используется значение из pageInfoNotifier.value.currentPage, по умолчанию 1
presets List<TileSizePreset> ❌ tileSizePresets Список пресетов размеров плитки, из которых выбирается оптимальный

Выравнивание

Поддерживаются все стандартные варианты AlignmentDirectional:

  • AlignmentDirectional.topStart, topCenter, topEnd
  • AlignmentDirectional.centerStart, center, centerEnd
  • AlignmentDirectional.bottomStart, bottomCenter, bottomEnd

а также нейтральные к направлению варианты (topLeft/topRight и т.д.), если зеркалирование под RTL не нужно.

findOptimalPreset #

Функция для автоматического выбора оптимального пресета размера плиток.

TileSizePreset findOptimalPreset({
  required Size layoutSize,
  required int itemCount,
  required int maxItems,
  required Size itemPadding,
  required Alignment alignment,
  required EdgeInsets gridPadding,
  double? aspectRatio,
  List<TileSizePreset> presets = tileSizePresets,
})

TileSizePreset #

Класс для представления предустановленного размера плитки.

class TileSizePreset {
  final String name;  // Название пресета
  final Size? size;   // Размер плитки (null означает максимальный размер)
  double? get aspectRatio;  // Соотношение сторон
}

tileSizePresets #

Константа со встроенным списком предустановленных размеров плиток (используется по умолчанию, если не передан свой presets):

  • 377x200
  • 332x266
  • 432x366
  • 409x234
  • 351x304
  • 604x351
  • 615x309

FitGridItemsPerPageCalculator #

Класс для расчёта количества элементов на странице по ширине области.

Методы

  • calculateForPlatformGroup - рассчитывает maxItemsPerPage по ширине области с использованием дефолтных брейкпоинтов для указанной группы платформ
  • calculateForBreakpoints - рассчитывает maxItemsPerPage по ширине области на основе произвольного списка брейкпоинтов

FitGridDefaultBreakpoints #

Класс с дефолтными правилами (брейкпоинтами) для расчёта количества элементов на странице.

Константы

  • mobileAndTabletBreakpoints - брейкпоинты для мобильных устройств и планшетов
  • desktopAndWebBreakpoints - брейкпоинты для десктопа и веба

FitGridItemsPerPageBreakpoint #

Класс для представления правила брейкпоинта.

class FitGridItemsPerPageBreakpoint {
  final double minWidth;  // Минимальная ширина (включительно)
  final double maxWidth;  // Максимальная ширина (включительно), можно использовать double.infinity
  final int maxItemsPerPage;  // Рекомендуемое значение maxItemsPerPage для диапазона
}

FitGridPageInfo #

Класс для хранения информации о текущей странице и общем количестве страниц.

class FitGridPageInfo {
  final int currentPage;  // Текущая страница (начинается с 1)
  final int totalPages;   // Общее количество страниц
}

FitGridLayoutDelegate #

MultiChildLayoutDelegate, на котором построен FitGrid. Экспортируется для случаев, когда нужно встроить ту же раскладку в свой CustomMultiChildLayout напрямую.

TileLayoutCalculator #

Калькулятор оптимальной сетки: перебирает варианты количества столбцов/строк, считает размер плитки с учётом пропорций, отступов и потолка пресета, а также смещение сетки для выравнивания. Экспортируется для кастомных сценариев расчёта вне FitGrid.

Примеры #

Полный рабочий пример доступен в папке example/. Запустите его командой:

cd example
flutter run

Как это работает #

  1. Расчёт оптимальной сетки: алгоритм перебирает все возможные комбинации строк и столбцов для заданного количества элементов. Если элементов меньше maxItemsPerPage, приоритет отдаётся заполнению области; если страница заполнена целиком — максимизируется площадь плитки (минимизируется пустое пространство).

  2. Выбор пресета: для каждого пресета из presets прогоняется расчёт сетки, и выбирается тот, что даёт наибольший коэффициент заполнения области. Пресет задаёт как пропорцию плитки, так и потолок её абсолютного размера.

  3. Расчёт размера плиток: для выбранной конфигурации сетки и пресета рассчитывается финальный размер плитки с учётом доступного пространства, отступов и заданных пропорций (aspectRatio переопределяет пропорцию пресета).

  4. Позиционирование: плитки размещаются с учётом выбранного AlignmentDirectional (резолвится в Alignment через Directionality контекста), включая отдельное выравнивание неполной последней строки.

  5. Пересчёт на layout-фазе: всё вышеперечисленное происходит в FitGridLayoutDelegate.performLayout, а не в build(), поэтому ресайз области не перестраивает дерево виджетов — только relayout.

Тесты #

Модульные и виджет-тесты покрывают алгоритм раскладки, брейкпоинты, подбор пресета, кастомные пресеты, RTL-выравнивание и пагинацию:

flutter test

Требования #

  • Flutter SDK: >=3.41.9
  • Dart SDK: >=3.6.0 <4.0.0

Лицензия #

MIT, см. LICENSE.

1
likes
130
points
28
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Сетка с автоподбором размера и количества плиток под доступное пространство

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on fit_grid