Skip to content

Changing app background color requires deprecated attribute background #149158

Closed

Description

@Mr-Pepe

Steps to reproduce

  1. Run the example code

Expected results

Setting the surface attribute of the color scheme to Colors.white makes the whole app have a white background.

Actual results

Only the app bar turns white. To make the whole app have a white background, background has to be set as well. However, that has been deprecated and the proposed migration path is to use surface instead.

Code sample

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

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

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple,
          surface: Colors.white,
        ),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Screenshots or Video

No response

Logs

No response

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.22.1, on Arch Linux 6.9.1-arch1-2, locale en_US.UTF-8)
    • Flutter version 3.22.1 on channel stable at /home/felipe/snap/flutter/common/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision a14f74ff3a (6 days ago), 2024-05-22 11:08:21 -0500
    • Engine revision 55eae6864b
    • Dart version 3.4.1
    • DevTools version 2.34.3

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /home/felipe/Android/Sdk/
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /home/felipe/Applications/android-studio/jbr/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • CHROME_EXECUTABLE = chromium

[✓] Linux toolchain - develop for Linux desktop
    • clang version 10.0.0-4ubuntu1
    • cmake version 3.16.3
    • ninja version 1.10.0
    • pkg-config version 0.29.1

[✓] Android Studio (version 2022.2)
    • Android Studio at /home/felipe/Applications/android-studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[✓] Connected device (3 available)
    • Pixel 8 (mobile) • 3A101FDJH00722 • android-arm64  • Android 14 (API 34)
    • Linux (desktop)  • linux          • linux-x64      • Arch Linux 6.9.1-arch1-2
    • Chrome (web)     • chrome         • web-javascript • Chromium 125.0.6422.112 Arch Linux

[✓] Network resources
    • All expected network resources are available.

• No issues found!

Activity

  1. darshankawar commented on May 28, 2024

    @darshankawar
    Member

    @Mr-Pepe
    Does passing backgroundColor in Scaffold help in your case ?

    Screenshot 2024-05-28 at 3 14 59 PM
  2. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 28, 2024
  3. Mr-Pepe commented on May 28, 2024

    @Mr-Pepe
    ContributorAuthor

    @darshankawar Thank you for the response.

    I use GoRouter with nested navigation as explained in https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/shell_route.dart, which requires nested scaffolds due to #122972. To get the white background everywhere, I would have to

    • Set surface in ThemeData,
    • Set backgroundColor of the root scaffold's bottom navigation bar, and
    • Set backgroundColor for each nested scaffold.

    That doesn't seem very ergonomic.

  4. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 28, 2024
  5. darshankawar commented on May 29, 2024

    @darshankawar
    Member

    Thanks for the feedback. Can you provide us the code sample involving go_router which shows current behavior ?

  6. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 29, 2024
  7. Keetz commented on May 30, 2024

    @Keetz

    Looking through the code, it looks like the ColorScheme indeed defaults to surface if background isn't set, as a middle way until background is completely removed.

    The problem seems to be that it always uses the one defined here so background is never not set:

    const ColorScheme _colorSchemeDarkM3 = ColorScheme(
        ...
        background: Color(0xFF141218),
        ...
    );
    

    I am not exactly sure if that is the problem, but it is the color I see as the background color even when trying to set the surface color.

    Setting the backgroundColor directly on the scaffold does work, or setting the scaffoldBackgroundColor on the ThemeData works, but that doesn't change that the current info about changing background to surface doesn't work as intended.

  8. Mr-Pepe commented on May 31, 2024

    @Mr-Pepe
    ContributorAuthor

    Here is a somewhat minimal example that illustrates the problem. It's a stripped-down version of the official example at: https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/shell_route.dart. Add GoRouter with flutter pub add go_router. Then run the below code sample as main.dart.

    There is one ShellRoute that contains a scaffold with a bottom navigation bar. The router inserts different routes as the body of this root scaffold. The routes have to be scaffolds themselves to prevent the page transition issue raised in #122972. The bottom navigation bar and each nested scaffold now need to have their background color set explicitly. The color of the nested scaffolds' app bar is retrieved from the theme's surface color.

    This means it's necessary to keep the background color in sync across many different places in the code base. Previously, setting the background color in the theme was enough.

    Code sample
    import 'package:flutter/material.dart';
    import 'package:go_router/go_router.dart';
    
    final GlobalKey<NavigatorState> _rootNavigatorKey =
        GlobalKey<NavigatorState>(debugLabel: 'root');
    final GlobalKey<NavigatorState> _shellNavigatorKey =
        GlobalKey<NavigatorState>(debugLabel: 'shell');
    
    void main() {
      runApp(ShellRouteExampleApp());
    }
    
    class ShellRouteExampleApp extends StatelessWidget {
      ShellRouteExampleApp({super.key});
    
      final GoRouter _router = GoRouter(
        navigatorKey: _rootNavigatorKey,
        initialLocation: '/a',
        debugLogDiagnostics: true,
        routes: <RouteBase>[
          ShellRoute(
            navigatorKey: _shellNavigatorKey,
            builder: (BuildContext context, GoRouterState state, Widget child) {
              return ScaffoldWithNavBar(child: child);
            },
            routes: <RouteBase>[
              GoRoute(
                path: '/a',
                builder: (BuildContext context, GoRouterState state) {
                  return const ScreenA();
                },
                routes: <RouteBase>[
                  GoRoute(
                    path: 'details',
                    builder: (BuildContext context, GoRouterState state) {
                      return const DetailsScreen(label: 'A');
                    },
                  ),
                ],
              ),
              GoRoute(
                path: '/b',
                builder: (BuildContext context, GoRouterState state) {
                  return const ScreenA();
                },
                routes: <RouteBase>[
                  GoRoute(
                    path: 'details',
                    builder: (BuildContext context, GoRouterState state) {
                      return const DetailsScreen(label: 'B');
                    },
                  ),
                ],
              ),
            ],
          ),
        ],
      );
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp.router(
          title: 'Flutter Demo',
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(
              seedColor: Colors.deepPurple,
              surface: Colors.green,
            ),
          ),
          routerConfig: _router,
        );
      }
    }
    
    class ScaffoldWithNavBar extends StatelessWidget {
      const ScaffoldWithNavBar({
        required this.child,
        super.key,
      });
    
      final Widget child;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: child,
          bottomNavigationBar: BottomNavigationBar(
            backgroundColor: Colors.red,
            items: const <BottomNavigationBarItem>[
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                label: 'A Screen',
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.business),
                label: 'B Screen',
              ),
            ],
            currentIndex: _calculateSelectedIndex(context),
            onTap: (int idx) => _onItemTapped(idx, context),
          ),
        );
      }
    
      static int _calculateSelectedIndex(BuildContext context) {
        final String location = GoRouterState.of(context).uri.path;
        if (location.startsWith('/a')) {
          return 0;
        }
        if (location.startsWith('/b')) {
          return 1;
        }
        return 0;
      }
    
      void _onItemTapped(int index, BuildContext context) {
        switch (index) {
          case 0:
            GoRouter.of(context).go('/a');
          case 1:
            GoRouter.of(context).go('/b');
        }
      }
    }
    
    class ScreenA extends StatelessWidget {
      const ScreenA({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.yellow,
          appBar: AppBar(),
          body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                const Text('Screen A'),
                TextButton(
                  onPressed: () {
                    GoRouter.of(context).go('/a/details');
                  },
                  child: const Text('View A details'),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    class DetailsScreen extends StatelessWidget {
      const DetailsScreen({
        required this.label,
        super.key,
      });
    
      final String label;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.blue,
          appBar: AppBar(
            title: const Text('Details Screen'),
          ),
          body: Center(
            child: Text(
              'Details for $label',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ),
        );
      }
    }
    
  9. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 31, 2024
  10. darshankawar commented on May 31, 2024

    @darshankawar
    Member

    Thanks for the update. Can you check if your case is similar to #131994 ?

  11. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 31, 2024
  12. Mr-Pepe commented on May 31, 2024

    @Mr-Pepe
    ContributorAuthor

    That issue seems to be unrelated and I also can't reproduce that issue anymore (I left a comment there).

    @darshankawar Could you maybe explain what the expected behavior is here? How were ColorScheme.background, ColorScheme.surface, ThemeData.scaffoldBackgroundColor, Scaffold.backgroundColor, and BottomNavigationBar.backgroundColor supposed to work together? And how does that change with the deprecation of ColorScheme.background? Should changing it to ColorScheme.surface preserve all behavior? In that case, the current behavior is clearly a bug.

  13. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on May 31, 2024
  14. darshankawar commented on May 31, 2024

    @darshankawar
    Member

    Thanks for the feedback. Please check this PR that seems to have made the said changes and see if any of the toned base surface colors helps further in your case or not.

  15. 8 remaining items

  16. Troyx21 commented on Jun 5, 2024

    @Troyx21

    I also agree that just replacing background property with surface will break many apps that rely on it to define the scaffold background. The solution is simple though - define ThemeData.scaffoldBackgroundColor instead. But this should have been somehow documented better.

  17. added
    triaged-designTriaged by Design Languages team
    P2Important issues not at the top of the work list
    on Jun 5, 2024
  18. self-assigned this
    on Jun 5, 2024
  19. added
    r: fixedIssue is closed as already fixed in a newer version
    on Jun 18, 2024
  20. github-actions commented on Jul 2, 2024

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  21. locked as resolved and limited conversation to collaborators on Jul 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listfound in release: 3.22Found to occur in 3.22found in release: 3.23Found to occur in 3.23frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagesr: fixedIssue is closed as already fixed in a newer versionteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions