Skip to content

[syncfusion_flutter_datepicker]: cellBuilder cache invalidate #2533

Description

@ziqq

Summary

When SfDateRangePicker uses cellBuilder, switching the app theme between light and dark does not fully refresh the month cells.

The picker itself receives the new theme, but the custom month cells appear to remain cached. As a result, the cells stay visually stale and only start behaving correctly again after an external rebuild such as:

  • parent setState
  • hot reload
  • any change that forces the picker to recreate month cells

In our case, explicitly changing monthViewSettings.specialDates on theme change works as a workaround, which suggests the issue is related to internal month-cell caching.

Package version

syncfusion_flutter_datepicker: 33.2.7

Question

Is this expected behavior?

If not, could SfDateRangePicker invalidate or rebuild cached month cells when inherited theme dependencies change, or provide an official way to force a rebuild of month cells without using unrelated inputs like specialDates as a cache-busting workaround?

Steps to reproduce

  1. Open a screen with SfDateRangePicker using cellBuilder.
  2. Switch the app theme from light to dark or back.
  3. Observe the month cells.

Expected behavior

The month cells created by cellBuilder should update immediately after a theme change, just like the rest of the widget tree.

Actual behavior

The month cells remain stale after a theme change and only refresh after an external rebuild, for example:

  • parent setState
  • hot reload
  • changing specialDates

Additional notes

In our implementation, the custom cells use CustomPaint and repaint correctly when a theme-related Listenable changes.

However, repaint alone is not enough here, because the month-cell widgets created by cellBuilder appear to remain cached internally. Once we force a cache invalidation by updating specialDates, the picker updates correctly again.

This workaround fixes the issue for us:

@override
void didChangeDependencies() {
  super.didChangeDependencies();

  final nextTheme = Theme.of(context);
  if (identical(_theme.value, nextTheme)) return;

  _theme.value = nextTheme;

  // Forces Syncfusion to recreate cached month cells.
  _cacheRevision += 1;
  _specialDates = _buildSpecialDates();
}

So the issue seems to be that a theme change does not invalidate the internal cache for month cells produced by cellBuilder.

Code sample

Code sample
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  ThemeMode _themeMode = ThemeMode.light;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      themeMode: _themeMode,
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('DatePicker cache issue'),
          actions: [
            IconButton(
              onPressed: () {
                setState(() {
                  _themeMode = _themeMode == ThemeMode.light
                      ? ThemeMode.dark
                      : ThemeMode.light;
                });
              },
              icon: const Icon(Icons.brightness_6),
            ),
          ],
        ),
        body: const _PickerBody(),
      ),
    );
  }
}

class _PickerBody extends StatefulWidget {
  const _PickerBody();

  @override
  State<_PickerBody> createState() => _PickerBodyState();
}

class _PickerBodyState extends State<_PickerBody> {
  final DateRangePickerController _controller = DateRangePickerController();
  int _cacheRevision = 0;

  List<DateTime> get _specialDates => [
        DateTime(9999, 1, 1).add(Duration(days: _cacheRevision)),
      ];

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();

    // Workaround:
    // Uncommenting this forces the picker to recreate month cells
    // after theme changes.
    //
    // _cacheRevision += 1;
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    return SfDateRangePicker(
      controller: _controller,
      navigationMode: DateRangePickerNavigationMode.scroll,
      navigationDirection: DateRangePickerNavigationDirection.vertical,
      enableMultiView: true,
      selectionMode: DateRangePickerSelectionMode.single,
      cellBuilder: (context, details) {
        final isDark = theme.brightness == Brightness.dark;

        return Container(
          alignment: Alignment.center,
          margin: const EdgeInsets.all(4),
          decoration: BoxDecoration(
            shape: BoxShape.circle,
            color: isDark ? Colors.blueGrey.shade700 : Colors.blue.shade50,
            border: Border.all(
              color: isDark ? Colors.white70 : Colors.black54,
            ),
          ),
          child: Text(
            '${details.date.day}',
            style: TextStyle(
              color: isDark ? Colors.white : Colors.black,
            ),
          ),
        );
      },
      monthViewSettings: DateRangePickerMonthViewSettings(
        specialDates: _specialDates,
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration Image

On which target platforms have you observed this bug?

iOS, Android

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions