diff --git a/examples/api/lib/material/theme_data/theme_data.0.dart b/examples/api/lib/material/theme_data/theme_data.0.dart new file mode 100644 index 00000000000..ceec42105d3 --- /dev/null +++ b/examples/api/lib/material/theme_data/theme_data.0.dart @@ -0,0 +1,115 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; + +void main() { + runApp(const ThemeDataExampleApp()); +} + +// This app's theme specifies an overall ColorScheme as well as overrides +// for the default configuration of FloatingActionButtons. To customize +// the appearance of other components, add additional component specific +// themes, rather than tweaking the color scheme. +// +// Creating an entire color scheme from a single seed color is a good +// way to ensure a visually appealing color palette where the default +// component colors have sufficient contrast for accessibility. Another +// good way to create an app's color scheme is to use +// ColorScheme.fromImageProvider. +// +// The color scheme reflects the platform's light or dark setting +// which is retrieved with `MediaQuery.platformBrightnessOf`. The color +// scheme's colors will be different for light and dark settings although +// they'll all be related to the seed color in both cases. +// +// Color scheme colors have been used where component defaults have +// been overidden so that the app will look good and remain accessible +// in both light and dark modes. +// +// Text styles are derived from the theme's textTheme (not the obsolete +// primaryTextTheme property) and then customized using copyWith. +// Using the _on_ version of a color scheme color as the foreground, +// as in `tertiary` and `onTertiary`, guarantees sufficient contrast +// for readability/accessibility. + +class ThemeDataExampleApp extends StatelessWidget { + const ThemeDataExampleApp({ super.key }); + + @override + Widget build(BuildContext context) { + final ColorScheme colorScheme = ColorScheme.fromSeed( + brightness: MediaQuery.platformBrightnessOf(context), + seedColor: Colors.indigo, + ); + return MaterialApp( + title: 'ThemeData Demo', + theme: ThemeData( + colorScheme: colorScheme, + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: colorScheme.tertiary, + foregroundColor: colorScheme.onTertiary, + ), + ), + home: const Home(), + ); + } +} + +class Home extends StatefulWidget { + const Home({ super.key }); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + int buttonPressCount = 0; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final ColorScheme colorScheme = theme.colorScheme; + final double pointCount = 8 + (buttonPressCount % 6); + + return Scaffold( + appBar: AppBar( + title: const Text('Press the + Button'), + ), + // An AnimatedContainer makes the decoration changes entertaining. + body: AnimatedContainer( + duration: const Duration(milliseconds: 500), + margin: const EdgeInsets.all(32), + alignment: Alignment.center, + decoration: ShapeDecoration( + color: colorScheme.tertiaryContainer, + shape: StarBorder( + points: pointCount, + pointRounding: 0.4, + valleyRounding: 0.6, + side: BorderSide( + width: 9, + color: colorScheme.tertiary + ), + ), + ), + child: Text( + '${pointCount.toInt()} Points', + style: theme.textTheme.headlineMedium!.copyWith( + color: colorScheme.onPrimaryContainer, + ), + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () { + setState(() { + buttonPressCount += 1; + }); + }, + tooltip: "Change the shape's point count", + child: const Icon(Icons.add), + ), + ); + } +} diff --git a/examples/api/test/material/theme_data/theme_data.0_test.dart b/examples/api/test/material/theme_data/theme_data.0_test.dart new file mode 100644 index 00000000000..bb1de226387 --- /dev/null +++ b/examples/api/test/material/theme_data/theme_data.0_test.dart @@ -0,0 +1,36 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter_api_samples/material/theme_data/theme_data.0.dart' as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + + testWidgets('ThemeData basics', (WidgetTester tester) async { + await tester.pumpWidget(const example.ThemeDataExampleApp()); + + final ColorScheme colorScheme = ColorScheme.fromSeed( + seedColor: Colors.indigo, + ); + + final Material fabMaterial = tester.widget( + find.descendant(of: find.byType(FloatingActionButton), matching: find.byType(Material)), + ); + expect(fabMaterial.color, colorScheme.tertiary); + + final RichText iconRichText = tester.widget( + find.descendant(of: find.byIcon(Icons.add), matching: find.byType(RichText)), + ); + expect(iconRichText.text.style!.color, colorScheme.onTertiary); + + expect(find.text('8 Points'), isNotNull); + await tester.tap(find.byType(FloatingActionButton)); + await tester.pumpAndSettle(); + expect(find.text('9 Points'), isNotNull); + await tester.tap(find.byType(FloatingActionButton)); + await tester.pumpAndSettle(); + expect(find.text('10 Points'), isNotNull); + }); +} diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index f4c2f4209b5..518c389348c 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -179,68 +179,15 @@ enum MaterialTapTargetSize { /// for the subtree that appears below the new [Theme], or insert a widget /// that creates a new BuildContext, like [Builder]. /// -/// {@tool snippet} -/// In this example, the [Container] widget uses [Theme.of] to retrieve the -/// primary color from the theme's [colorScheme] to draw an amber square. -/// The [Builder] widget separates the parent theme's [BuildContext] from the -/// child's [BuildContext]. +/// {@tool dartpad} +/// This example demonstrates how a typical [MaterialApp] specifies +/// and uses a custom [Theme]. The theme's [ColorScheme] is based on a +/// single "seed" color and configures itself to match the platform's +/// current light or dark color configuration. The theme overrides the +/// default configuration of [FloatingActionButton] to show how to +/// customize the appearance a class of components. /// -/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/theme_data.png) -/// -/// ```dart -/// Theme( -/// data: ThemeData.from( -/// colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.amber), -/// ), -/// child: Builder( -/// builder: (BuildContext context) { -/// return Container( -/// width: 100, -/// height: 100, -/// color: Theme.of(context).colorScheme.primary, -/// ); -/// }, -/// ), -/// ) -/// ``` -/// {@end-tool} -/// -/// {@tool snippet} -/// -/// This sample creates a [MaterialApp] with a [Theme] whose -/// [ColorScheme] is based on [Colors.blue], but with the color -/// scheme's [ColorScheme.secondary] color overridden to be green. The -/// [AppBar] widget uses the color scheme's [ColorScheme.primary] as -/// its default background color and the [FloatingActionButton] widget -/// uses the color scheme's [ColorScheme.secondary] for its default -/// background. By default, the [Text] widget uses -/// [TextTheme.bodyMedium], and the color of that [TextStyle] has been -/// changed to purple. -/// -/// ![](https://flutter.github.io/assets-for-api-docs/assets/material/material_app_theme_data.png) -/// -/// ```dart -/// MaterialApp( -/// theme: ThemeData( -/// colorScheme: ColorScheme.fromSwatch().copyWith( -/// secondary: Colors.green, -/// ), -/// textTheme: const TextTheme(bodyMedium: TextStyle(color: Colors.purple)), -/// ), -/// home: Scaffold( -/// appBar: AppBar( -/// title: const Text('ThemeData Demo'), -/// ), -/// floatingActionButton: FloatingActionButton( -/// child: const Icon(Icons.add), -/// onPressed: () {}, -/// ), -/// body: const Center( -/// child: Text('Button pressed 0 times'), -/// ), -/// ), -/// ) -/// ``` +/// ** See code in examples/api/lib/material/theme_data/theme_data.0.dart ** /// {@end-tool} /// /// See for