← Назад к вопросам

Что такое RepaintBoundary и когда его использовать?

2.7 Senior🔥 72 комментариев
#Flutter виджеты#Архитектура Flutter

Комментарии (2)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

RepaintBoundary — оптимизация отрисовки

RepaintBoundary — это специальный виджет, который создаёт новый слой рисования (paint layer) и изолирует процесс перерисовки его содержимого от остальной части дерева виджетов.

Как работает визуализация в Flutter?

Флаттер проходит по дереву виджетов и отрисовывает всё на экран через несколько фаз:

  1. Build — создание дерева виджетов
  2. Layout — расчёт размеров и позиций
  3. Paint — отрисовка на Canvas
  4. Composite — композиция слоёв

По умолчанию, если переживает один виджет — всё дерево может быть перерисовано (repaint). Это расточительно для сложных интерфейсов.

Что делает RepaintBoundary?

RepaintBoundary отсекает цепочку перерисовки. Если виджет внутри RepaintBoundary изменился:

  • Перерисовывается только содержимое внутри границы
  • Родительские виджеты не перерисовываются
  • Создаётся отдельный слой (layer) в GPU

Практический пример

class CounterApp extends StatefulWidget {
  @override
  State<CounterApp> createState() => _CounterAppState();
}

class _CounterAppState extends State<CounterApp> {
  int counter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          // Сложный виджет, который НЕ зависит от counter
          ExpensiveWidget(),
          
          // Обновляется часто
          Text(Counter: $counter),
          
          ElevatedButton(
            onPressed: () => setState(() => counter++),
            child: Text(Increment),
          ),
        ],
      ),
    );
  }
}

Проблема: При каждом нажатии на кнопку весь Column перерисовывается, включая ExpensiveWidget.

Решение с RepaintBoundary:

class _CounterAppState extends State<CounterApp> {
  int counter = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          // Изолируем дорогой виджет
          RepaintBoundary(
            child: ExpensiveWidget(),
          ),
          
          // Этот часто обновляется
          Text(Counter: $counter),
          
          ElevatedButton(
            onPressed: () => setState(() => counter++),
            child: Text(Increment),
          ),
        ],
      ),
    );
  }
}

Теперь ExpensiveWidget перерисовываться не будет при изменении counter.

Когда использовать RepaintBoundary?

Используй, если:

  1. Есть дорогой виджет, который редко меняется

    RepaintBoundary(
      child: ComplexAnimation(),
    )
    
  2. Внутри анимация или частое обновление

    RepaintBoundary(
      child: AnimatedContainer(),
    )
    
  3. Список с тысячами элементов

    ListView.builder(
      itemBuilder: (context, index) {
        return RepaintBoundary(
          child: ExpensiveListTile(),
        );
      },
    )
    
  4. Видео или камера поверх UI

    Stack(
      children: [
        RepaintBoundary(
          child: CameraPreview(),
        ),
        Text(Overlay),
      ],
    )
    

Когда НЕ использовать?

Не используй, если:

  • Элемент редко обновляется и его маленькие
  • Виджет содержит текст или иконки (маленькая стоимость отрисовки)
  • Нет заметных проблем с производительностью

Продвинутый пример: Списки и анимации

ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) {
    // Каждый элемент в отдельном слое
    return RepaintBoundary(
      child: AnimatedListTile(
        index: index,
        animate: animationController,
      ),
    );
  },
)

Без RepaintBoundary — при анимации все 1000 элементов пересчитывались. С ним — только видимые.

Измерение эффекта с DevTools

Флаттер DevTools показывает рамку вокруг перерисовываемых областей:

// В main.dart при разработке
runApp(
  MyApp(
    showSemanticsDebugger: true,
  ),
);
// Или в DevTools: Performance → "Show repaint rainbow"

Сравнение: с и без RepaintBoundary

МетрикаБез RepaintBoundaryС RepaintBoundary
Отрисовка дорогого виджетаКаждый разТолько если изменился
GPU памятьМеньшеБольше (за счёт слоёв)
CPU нагрузкаВышеНиже
FPS при анимацииМожет упастьСтабильнее

Помните!

RepaintBoundary — это инструмент оптимизации, не решение. Используй его когда:

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

Вывод: RepaintBoundary изолирует отрисовку и улучшает FPS в сложных интерфейсах. Используй с умом — где есть вещи редко меняющиеся, но заключённые в часто обновляемых контейнерах.

Что такое RepaintBoundary и когда его использовать? | PrepBro