Skip to content

Commit 358d79c

Browse files
Renzo-OlivaresRenzo Olivares
andauthored
TextField should support disabled input text style (flutter#119216)
Co-authored-by: Renzo Olivares <[email protected]>
1 parent bcdab11 commit 358d79c

File tree

3 files changed

+90
-7
lines changed

3 files changed

+90
-7
lines changed

dev/tools/gen_defaults/lib/text_field_template.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ class TextFieldTemplate extends TokenTemplate {
99

1010
@override
1111
String generate() => '''
12+
TextStyle? _m3StateInputStyle(BuildContext context) => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
13+
if (states.contains(MaterialState.disabled)) {
14+
return TextStyle(color: ${textStyle("md.comp.filled-text-field.label-text")}!.color?.withOpacity(0.38));
15+
}
16+
return TextStyle(color: ${textStyle("md.comp.filled-text-field.label-text")}!.color);
17+
});
18+
1219
TextStyle _m3InputStyle(BuildContext context) => ${textStyle("md.comp.filled-text-field.label-text")}!;
1320
1421
TextStyle _m3CounterErrorStyle(BuildContext context) =>

packages/flutter/lib/src/material/text_field.dart

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import 'package:flutter/rendering.dart';
1111
import 'package:flutter/services.dart';
1212

1313
import 'adaptive_text_selection_toolbar.dart';
14+
import 'color_scheme.dart';
1415
import 'colors.dart';
1516
import 'debug.dart';
1617
import 'desktop_text_selection.dart';
@@ -1191,6 +1192,22 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
11911192
}
11921193
// AutofillClient implementation end.
11931194

1195+
Set<MaterialState> get _materialState {
1196+
return <MaterialState>{
1197+
if (!_isEnabled) MaterialState.disabled,
1198+
if (_isHovering) MaterialState.hovered,
1199+
if (_effectiveFocusNode.hasFocus) MaterialState.focused,
1200+
if (_hasError) MaterialState.error,
1201+
};
1202+
}
1203+
1204+
TextStyle _getInputStyleForState(TextStyle style) {
1205+
final ThemeData theme = Theme.of(context);
1206+
final TextStyle stateStyle = MaterialStateProperty.resolveAs(theme.useMaterial3 ? _m3StateInputStyle(context)! : _m2StateInputStyle(context)!, _materialState);
1207+
final TextStyle providedStyle = MaterialStateProperty.resolveAs(style, _materialState);
1208+
return providedStyle.merge(stateStyle);
1209+
}
1210+
11941211
@override
11951212
Widget build(BuildContext context) {
11961213
assert(debugCheckHasMaterial(context));
@@ -1204,7 +1221,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
12041221

12051222
final ThemeData theme = Theme.of(context);
12061223
final DefaultSelectionStyle selectionStyle = DefaultSelectionStyle.of(context);
1207-
final TextStyle style = (theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.titleMedium!).merge(widget.style);
1224+
final TextStyle style = _getInputStyleForState(theme.useMaterial3 ? _m3InputStyle(context) : theme.textTheme.titleMedium!).merge(widget.style);
12081225
final Brightness keyboardAppearance = widget.keyboardAppearance ?? theme.brightness;
12091226
final TextEditingController controller = _effectiveController;
12101227
final FocusNode focusNode = _effectiveFocusNode;
@@ -1402,12 +1419,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
14021419
}
14031420
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
14041421
widget.mouseCursor ?? MaterialStateMouseCursor.textable,
1405-
<MaterialState>{
1406-
if (!_isEnabled) MaterialState.disabled,
1407-
if (_isHovering) MaterialState.hovered,
1408-
if (focusNode.hasFocus) MaterialState.focused,
1409-
if (_hasError) MaterialState.error,
1410-
},
1422+
_materialState,
14111423
);
14121424

14131425
final int? semanticsMaxValueLength;
@@ -1453,6 +1465,14 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
14531465
}
14541466
}
14551467

1468+
TextStyle? _m2StateInputStyle(BuildContext context) => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
1469+
final ThemeData theme = Theme.of(context);
1470+
if (states.contains(MaterialState.disabled)) {
1471+
return TextStyle(color: theme.disabledColor);
1472+
}
1473+
return TextStyle(color: theme.textTheme.titleMedium?.color);
1474+
});
1475+
14561476
TextStyle _m2CounterErrorStyle(BuildContext context) =>
14571477
Theme.of(context).textTheme.bodySmall!.copyWith(color: Theme.of(context).colorScheme.error);
14581478

@@ -1465,6 +1485,13 @@ TextStyle _m2CounterErrorStyle(BuildContext context) =>
14651485

14661486
// Token database version: v0_162
14671487

1488+
TextStyle? _m3StateInputStyle(BuildContext context) => MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {
1489+
if (states.contains(MaterialState.disabled)) {
1490+
return TextStyle(color: Theme.of(context).textTheme.bodyLarge!.color?.withOpacity(0.38));
1491+
}
1492+
return TextStyle(color: Theme.of(context).textTheme.bodyLarge!.color);
1493+
});
1494+
14681495
TextStyle _m3InputStyle(BuildContext context) => Theme.of(context).textTheme.bodyLarge!;
14691496

14701497
TextStyle _m3CounterErrorStyle(BuildContext context) =>

packages/flutter/test/material/text_field_test.dart

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6071,6 +6071,51 @@ void main() {
60716071
expect(errorWidget.style!.color, equals(Colors.transparent));
60726072
});
60736073

6074+
testWidgets('Disabled text field has default M2 disabled text style for the input text', (WidgetTester tester) async {
6075+
final TextEditingController controller = TextEditingController(
6076+
text: 'Atwater Peel Sherbrooke Bonaventure',
6077+
);
6078+
6079+
await tester.pumpWidget(
6080+
MaterialApp(
6081+
home: Material(
6082+
child: Center(
6083+
child: TextField(
6084+
controller: controller,
6085+
enabled: false,
6086+
),
6087+
),
6088+
),
6089+
),
6090+
);
6091+
final EditableText editableText = tester.widget(find.byType(EditableText));
6092+
expect(editableText.style.color, Colors.black38); // Colors.black38 is the default disabled color for ThemeData.light().
6093+
});
6094+
6095+
testWidgets('Disabled text field has default M3 disabled text style for the input text', (WidgetTester tester) async {
6096+
final TextEditingController controller = TextEditingController(
6097+
text: 'Atwater Peel Sherbrooke Bonaventure',
6098+
);
6099+
6100+
final ThemeData theme = ThemeData.light(useMaterial3: true);
6101+
6102+
await tester.pumpWidget(
6103+
MaterialApp(
6104+
theme: theme,
6105+
home: Material(
6106+
child: Center(
6107+
child: TextField(
6108+
controller: controller,
6109+
enabled: false,
6110+
),
6111+
),
6112+
),
6113+
),
6114+
);
6115+
final EditableText editableText = tester.widget(find.byType(EditableText));
6116+
expect(editableText.style.color, theme.textTheme.bodyLarge!.color!.withOpacity(0.38));
6117+
});
6118+
60746119
testWidgets('currentValueLength/maxValueLength are in the tree', (WidgetTester tester) async {
60756120
final SemanticsTester semantics = SemanticsTester(tester);
60766121
final TextEditingController controller = TextEditingController();
@@ -8355,7 +8400,11 @@ void main() {
83558400
// Empty TextStyle is overridden by theme
83568401
await tester.pumpWidget(buildFrame(const TextStyle()));
83578402
EditableText editableText = tester.widget(find.byType(EditableText));
8403+
8404+
// According to material 3 spec, the input text should be the color of onSurface.
8405+
// https://github.com/flutter/flutter/issues/107686 is tracking this issue.
83588406
expect(editableText.style.color, themeData.textTheme.bodyLarge!.color);
8407+
83598408
expect(editableText.style.background, themeData.textTheme.bodyLarge!.background);
83608409
expect(editableText.style.shadows, themeData.textTheme.bodyLarge!.shadows);
83618410
expect(editableText.style.decoration, themeData.textTheme.bodyLarge!.decoration);

0 commit comments

Comments
 (0)