Search code examples
flutterdart

Theme color not updated properly inside a ListView in Flutter


Recently I faced the following issue: I have a Card inside a ListView, I wanted to theme the card by setting the color to Theme.of(context).colorScheme.surfaceContainer but the issue now is that when I switch the theme, the color doesn't refresh.

I created a minimal reproducible example of this issue here

import 'package:flutter/material.dart';

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

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

  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  ThemeMode _themeMode = ThemeMode.light;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(),
      darkTheme: ThemeData(brightness: Brightness.dark),
      themeMode: _themeMode,
      home: Scaffold(
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Center(
              child: Column(
            spacing: 8,
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                  onPressed: () {
                    setState(() {
                      _themeMode = _themeMode == ThemeMode.light
                          ? ThemeMode.dark
                          : ThemeMode.light;
                    });
                  },
                  child: Text("Change Theme")),
              Expanded(child: MyList())
            ],
          )),
        ),
      ),
    );
  }
}

class MyList extends StatelessWidget {
  const MyList({super.key});

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: 10,
        itemBuilder: (context, index) {
          return Card(
            color: Theme.of(context).colorScheme.surfaceContainer,
            child: ListTile(
              title: Text('Item $index'),
            ),
          );
        });
  }
}

As I open the app, everything looks as expected:

Initial view

Now I click on the "Change Theme" button, and this happens:

After switching theme

Not sure if it is something I'm missing or an issue with the Flutter framework (unlikely).

I tried to remove the ListView, and just having one Card inside the widget fixes the issue, but of course, for my real app I need the cards to be in a ListView.

Also note that when scrolling, if the card goes out of screen, and then scroll it back to screen, it refetches the color and displays correctly.

I thought I'll ask here before raising an issue on the Flutter GitHub repo.


Solution

  • Rename context parameter inside the ListView.builder itemBuilder to avoid conflicts with the context of the build method.

    class MyList extends StatelessWidget {
      const MyList({super.key});
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          itemCount: 10,
          itemBuilder: (listViewContext, index) { // Renamed context to listViewContext
            return Card(
              color: Theme.of(context).colorScheme.surfaceContainer, // Uses build context
              child: ListTile(
                title: Text('Item $index'),
              ),
            );
          },
        );
      }
    }