mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add static of accessor methods to ColorScheme and TextTheme (#154073)
The most common use case to lookup a `ThemeData` instance using `Theme.of(context)` is to access either the `ColorScheme`, the `TextTheme`, or both.
Before this change:
```dart
final colors = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
final primaryTextTheme = Theme.of(context).primaryTextTheme;
```
or
```dart
final ThemeData(
:colorScheme,
:textTheme,
:primaryTextTheme,
) = Theme.of(context);
```
After this change:
```dart
final colors = ColorScheme.of(context);
final textTheme = TextTheme.of(context);
final primaryTextTheme = TextTheme.primaryOf(context);
```
### Primary Changes
This PR adds static `of` convenience methods to `ColorScheme` and `TextTheme` that delegate to the `ThemeData`'s respective properties. The methods added are:
* `ColorScheme.of(context)` that returns `Theme.of(context).colorScheme`.
* `TextTheme.of(context)` that returns `Theme.of(context).textTheme`.
* `TextTheme.primaryOf(context)` that returns `Theme.of(context).primaryTextTheme`.
### Side-effects
To allow the above changes to function, this PR adds:
* A `theme.dart` import to `color_scheme.dart` to access to `Theme`.
* A `theme.dart` import to `text_theme.dart` to access to `Theme`.
* A `package:flutter/widgets.dart` import to `text_theme.dart` to access `BuildContext`.
* The above import allowed getting rid of the same `@docImport` from `text_theme.dart`.
### Documentation updates
This PR also updates the following documentation elements:
* Adds docs to the newly added members.
* Updates `TextTheme`'s docs to instruct using `TextTheme.of(context)` instead of `Theme.of(context).textTheme`.
* Updates `Theme.of` to add a "See also" section to `ColorScheme.of` and `TextTheme.of` since these use cases are among the most common ones for `Theme.of(context)`.
Fixes #72201.
This commit is contained in:
parent
a5ca16ea94
commit
4a54ca8285
@ -14,7 +14,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:material_color_utilities/material_color_utilities.dart';
|
||||
|
||||
import 'colors.dart';
|
||||
import 'theme_data.dart';
|
||||
import 'theme.dart';
|
||||
|
||||
/// The algorithm used to construct a [ColorScheme] in [ColorScheme.fromSeed].
|
||||
///
|
||||
@ -1920,4 +1920,9 @@ class ColorScheme with Diagnosticable {
|
||||
DynamicSchemeVariant.fruitSalad => SchemeFruitSalad(sourceColorHct: sourceColor, isDark: isDark, contrastLevel: contrastLevel),
|
||||
};
|
||||
}
|
||||
|
||||
/// The [ThemeData.colorScheme] of the ambient [Theme].
|
||||
///
|
||||
/// Equivalent to `Theme.of(context).colorScheme`.
|
||||
static ColorScheme of(BuildContext context) => Theme.of(context).colorScheme;
|
||||
}
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// @docImport 'package:flutter/widgets.dart';
|
||||
///
|
||||
/// @docImport 'elevated_button.dart';
|
||||
/// @docImport 'material.dart';
|
||||
/// @docImport 'outlined_button.dart';
|
||||
@ -13,8 +11,9 @@
|
||||
library;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'theme.dart';
|
||||
import 'typography.dart';
|
||||
|
||||
/// Material design text theme.
|
||||
@ -23,8 +22,9 @@ import 'typography.dart';
|
||||
/// (e.g., labelLarge, bodySmall). Rather than creating a [TextTheme] directly,
|
||||
/// you can obtain an instance as [Typography.black] or [Typography.white].
|
||||
///
|
||||
/// To obtain the current text theme, call [Theme.of] with the current
|
||||
/// [BuildContext] and read the [ThemeData.textTheme] property.
|
||||
/// To obtain the current text theme, call [TextTheme.of] with the current
|
||||
/// [BuildContext]. This is equivalent to calling [Theme.of] and reading
|
||||
/// the [ThemeData.textTheme] property.
|
||||
///
|
||||
/// The names of the TextTheme properties match this table from the
|
||||
/// [Material Design spec](https://m3.material.io/styles/typography/tokens).
|
||||
@ -597,6 +597,25 @@ class TextTheme with Diagnosticable {
|
||||
);
|
||||
}
|
||||
|
||||
/// The [ThemeData.textTheme] property of the ambient [Theme].
|
||||
///
|
||||
/// Equivalent to `Theme.of(context).textTheme`.
|
||||
///
|
||||
/// See also:
|
||||
/// * [TextTheme.primaryOf], which returns the [ThemeData.primaryTextTheme] property of
|
||||
/// the ambient [Theme] instead.
|
||||
static TextTheme of(BuildContext context) => Theme.of(context).textTheme;
|
||||
|
||||
/// The [ThemeData.primaryTextTheme] property of the ambient [Theme].
|
||||
///
|
||||
///
|
||||
/// Equivalent to `Theme.of(context).primaryTextTheme`.
|
||||
///
|
||||
/// See also:
|
||||
/// * [TextTheme.of], which returns the [ThemeData.textTheme] property of the ambient
|
||||
/// [Theme] instead.
|
||||
static TextTheme primaryOf(BuildContext context) => Theme.of(context).primaryTextTheme;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) {
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
/// @docImport 'app.dart';
|
||||
/// @docImport 'color_scheme.dart';
|
||||
/// @docImport 'text_theme.dart';
|
||||
library;
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
@ -104,6 +106,15 @@ class Theme extends StatelessWidget {
|
||||
/// );
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ColorScheme.of], a convenience method that returns [ThemeData.colorScheme]
|
||||
/// from the closest [Theme] ancestor. (equivalent to `Theme.of(context).colorScheme`).
|
||||
/// * [TextTheme.of], a convenience method that returns [ThemeData.textTheme]
|
||||
/// from the closest [Theme] ancestor. (equivalent to `Theme.of(context).textTheme`).
|
||||
/// * [IconTheme.of], that returns [ThemeData.iconTheme] from the closest [Theme] or
|
||||
/// [IconThemeData.fallback] if there is no [IconTheme] ancestor.
|
||||
static ThemeData of(BuildContext context) {
|
||||
final _InheritedTheme? inheritedTheme = context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
|
||||
final MaterialLocalizations? localizations = Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
|
||||
|
||||
@ -901,6 +901,25 @@ void main() {
|
||||
colorsMatchDynamicSchemeColors(schemeVariant, Brightness.dark, 0.5);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('ColorScheme.of(context) is equivalent to Theme.of(context).colorScheme', (WidgetTester tester) async {
|
||||
const Key sizedBoxKey = Key('sizedBox');
|
||||
final ColorScheme colorScheme = ColorScheme.fromSeed(seedColor: Colors.red);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData.from(colorScheme: colorScheme),
|
||||
home: const SizedBox(key: sizedBoxKey),
|
||||
),
|
||||
);
|
||||
|
||||
final BuildContext context = tester.element(find.byKey(sizedBoxKey));
|
||||
final ColorScheme colorSchemeOfTheme = Theme.of(context).colorScheme;
|
||||
final ColorScheme colorSchemeFromContext = ColorScheme.of(context);
|
||||
|
||||
expect(colorSchemeOfTheme, colorScheme);
|
||||
expect(colorSchemeFromContext, colorScheme);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _testFilledButtonColor(WidgetTester tester, ColorScheme scheme, Color expectation) async {
|
||||
|
||||
@ -246,4 +246,49 @@ void main() {
|
||||
expect(fullLerp.horizontal, 2.0);
|
||||
expect(fullLerp.vertical, 1.0);
|
||||
});
|
||||
|
||||
testWidgets('TextTheme.of(context) is equivalent to Theme.of(context).textTheme', (WidgetTester tester) async {
|
||||
const Key sizedBoxKey = Key('sizedBox');
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
textTheme: const TextTheme(
|
||||
displayLarge: TextStyle(color: Colors.blue, fontSize: 30.0),
|
||||
),
|
||||
),
|
||||
home: const SizedBox(key: sizedBoxKey),
|
||||
),
|
||||
);
|
||||
final BuildContext context = tester.element(find.byKey(sizedBoxKey));
|
||||
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final TextTheme expectedTextTheme = themeData.textTheme;
|
||||
final TextTheme actualTextTheme = TextTheme.of(context);
|
||||
|
||||
expect(actualTextTheme, equals(expectedTextTheme));
|
||||
|
||||
});
|
||||
|
||||
testWidgets('TextTheme.primaryOf(context) is equivalent to Theme.of(context).primaryTextTheme', (WidgetTester tester) async {
|
||||
const Key sizedBoxKey = Key('sizedBox');
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeData(
|
||||
primaryTextTheme: const TextTheme(
|
||||
displayLarge: TextStyle(backgroundColor: Colors.green, fontStyle: FontStyle.italic),
|
||||
),
|
||||
),
|
||||
home: const SizedBox(key: sizedBoxKey),
|
||||
),
|
||||
);
|
||||
|
||||
final BuildContext context = tester.element(find.byKey(sizedBoxKey));
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final TextTheme expectedTextTheme = themeData.primaryTextTheme;
|
||||
final TextTheme actualTextTheme = TextTheme.primaryOf(context);
|
||||
|
||||
expect(actualTextTheme, equals(expectedTextTheme));
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user