Add cursorWidth and cursorRadius to TextField (Material) cursor (#19317)
* fixed segmented control golden test * fixed segmented control golden test * made the comments more explanatory * changed comment, wrapped tests with if statements so they only run on MacOS * changed formatting * added width and radius fields to TextField; to do: tests and Material defaults * weak warnings * added tests * added default cursor width; changed default EditableText width * only run golden file tests on linux * changed goldens version * actually changed goldens.version * style changes * small fixes * added default material cursor color * changed goldens.version * changed goldens version again * changed goldens.version again (3) * added todo * deleted whitespace
This commit is contained in:
parent
f44f625c06
commit
834fb7b9a8
@ -1 +1,2 @@
|
||||
4948d5d7c0e07d092bd38511e5e159007425ec48
|
||||
6b9d7eb922429f3f86afa4a6ed316e56640ce587
|
||||
|
||||
|
@ -117,6 +117,9 @@ class TextField extends StatefulWidget {
|
||||
this.onSubmitted,
|
||||
this.inputFormatters,
|
||||
this.enabled,
|
||||
this.cursorWidth = 2.0,
|
||||
this.cursorRadius,
|
||||
this.cursorColor,
|
||||
this.keyboardAppearance,
|
||||
this.scrollPadding = const EdgeInsets.all(20.0),
|
||||
}) : assert(keyboardType != null),
|
||||
@ -314,6 +317,18 @@ class TextField extends StatefulWidget {
|
||||
/// [Decoration.enabled] property.
|
||||
final bool enabled;
|
||||
|
||||
/// How thick the cursor will be.
|
||||
///
|
||||
/// Defaults to 2.0.
|
||||
final double cursorWidth;
|
||||
|
||||
/// How rounded the corners of the cursor should be.
|
||||
/// By default, the cursor has a null Radius
|
||||
final Radius cursorRadius;
|
||||
|
||||
/// The color to use when painting the cursor.
|
||||
final Color cursorColor;
|
||||
|
||||
/// The appearance of the keyboard.
|
||||
///
|
||||
/// This setting is only honored on iOS devices.
|
||||
@ -542,7 +557,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
obscureText: widget.obscureText,
|
||||
autocorrect: widget.autocorrect,
|
||||
maxLines: widget.maxLines,
|
||||
cursorColor: themeData.textSelectionColor,
|
||||
selectionColor: themeData.textSelectionColor,
|
||||
selectionControls: themeData.platform == TargetPlatform.iOS
|
||||
? cupertinoTextSelectionControls
|
||||
@ -553,6 +567,9 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
onSelectionChanged: _handleSelectionChanged,
|
||||
inputFormatters: formatters,
|
||||
rendererIgnoresPointer: true,
|
||||
cursorWidth: widget.cursorWidth,
|
||||
cursorRadius: widget.cursorRadius,
|
||||
cursorColor: widget.cursorColor ?? Theme.of(context).cursorColor,
|
||||
scrollPadding: widget.scrollPadding,
|
||||
keyboardAppearance: keyboardAppearance,
|
||||
),
|
||||
@ -595,4 +612,4 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -123,6 +123,7 @@ class ThemeData extends Diagnosticable {
|
||||
ButtonThemeData buttonTheme,
|
||||
Color secondaryHeaderColor,
|
||||
Color textSelectionColor,
|
||||
Color cursorColor,
|
||||
Color textSelectionHandleColor,
|
||||
Color backgroundColor,
|
||||
Color dialogBackgroundColor,
|
||||
@ -172,6 +173,8 @@ class ThemeData extends Diagnosticable {
|
||||
// Spec doesn't specify a dark theme secondaryHeaderColor, this is a guess.
|
||||
secondaryHeaderColor ??= isDark ? Colors.grey[700] : primarySwatch[50];
|
||||
textSelectionColor ??= isDark ? accentColor : primarySwatch[200];
|
||||
// todo (sandrasandeep): change to color provided by Material Design team
|
||||
cursorColor = const Color.fromRGBO(66, 133, 244, 1.0);
|
||||
textSelectionHandleColor ??= isDark ? Colors.tealAccent[400] : primarySwatch[300];
|
||||
backgroundColor ??= isDark ? Colors.grey[700] : primarySwatch[200];
|
||||
dialogBackgroundColor ??= isDark ? Colors.grey[800] : Colors.white;
|
||||
@ -230,6 +233,7 @@ class ThemeData extends Diagnosticable {
|
||||
buttonTheme: buttonTheme,
|
||||
secondaryHeaderColor: secondaryHeaderColor,
|
||||
textSelectionColor: textSelectionColor,
|
||||
cursorColor: cursorColor,
|
||||
textSelectionHandleColor: textSelectionHandleColor,
|
||||
backgroundColor: backgroundColor,
|
||||
dialogBackgroundColor: dialogBackgroundColor,
|
||||
@ -279,6 +283,7 @@ class ThemeData extends Diagnosticable {
|
||||
@required this.buttonTheme,
|
||||
@required this.secondaryHeaderColor,
|
||||
@required this.textSelectionColor,
|
||||
@required this.cursorColor,
|
||||
@required this.textSelectionHandleColor,
|
||||
@required this.backgroundColor,
|
||||
@required this.dialogBackgroundColor,
|
||||
@ -319,6 +324,7 @@ class ThemeData extends Diagnosticable {
|
||||
assert(buttonTheme != null),
|
||||
assert(secondaryHeaderColor != null),
|
||||
assert(textSelectionColor != null),
|
||||
assert(cursorColor != null),
|
||||
assert(textSelectionHandleColor != null),
|
||||
assert(backgroundColor != null),
|
||||
assert(dialogBackgroundColor != null),
|
||||
@ -465,6 +471,9 @@ class ThemeData extends Diagnosticable {
|
||||
/// The color of text selections in text fields, such as [TextField].
|
||||
final Color textSelectionColor;
|
||||
|
||||
/// The color of cursors in Material-style text fields, such as [TextField].
|
||||
final Color cursorColor;
|
||||
|
||||
/// The color of the handles used to adjust what part of the text is currently selected.
|
||||
final Color textSelectionHandleColor;
|
||||
|
||||
@ -551,6 +560,7 @@ class ThemeData extends Diagnosticable {
|
||||
ButtonThemeData buttonTheme,
|
||||
Color secondaryHeaderColor,
|
||||
Color textSelectionColor,
|
||||
Color cursorColor,
|
||||
Color textSelectionHandleColor,
|
||||
Color backgroundColor,
|
||||
Color dialogBackgroundColor,
|
||||
@ -593,6 +603,7 @@ class ThemeData extends Diagnosticable {
|
||||
buttonTheme: buttonTheme ?? this.buttonTheme,
|
||||
secondaryHeaderColor: secondaryHeaderColor ?? this.secondaryHeaderColor,
|
||||
textSelectionColor: textSelectionColor ?? this.textSelectionColor,
|
||||
cursorColor: cursorColor ?? this.cursorColor,
|
||||
textSelectionHandleColor: textSelectionHandleColor ?? this.textSelectionHandleColor,
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
dialogBackgroundColor: dialogBackgroundColor ?? this.dialogBackgroundColor,
|
||||
@ -719,6 +730,7 @@ class ThemeData extends Diagnosticable {
|
||||
buttonTheme: t < 0.5 ? a.buttonTheme : b.buttonTheme,
|
||||
secondaryHeaderColor: Color.lerp(a.secondaryHeaderColor, b.secondaryHeaderColor, t),
|
||||
textSelectionColor: Color.lerp(a.textSelectionColor, b.textSelectionColor, t),
|
||||
cursorColor: Color.lerp(a.cursorColor, b.cursorColor, t),
|
||||
textSelectionHandleColor: Color.lerp(a.textSelectionHandleColor, b.textSelectionHandleColor, t),
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
dialogBackgroundColor: Color.lerp(a.dialogBackgroundColor, b.dialogBackgroundColor, t),
|
||||
@ -766,6 +778,7 @@ class ThemeData extends Diagnosticable {
|
||||
(otherData.buttonTheme == buttonTheme) &&
|
||||
(otherData.secondaryHeaderColor == secondaryHeaderColor) &&
|
||||
(otherData.textSelectionColor == textSelectionColor) &&
|
||||
(otherData.cursorColor == cursorColor) &&
|
||||
(otherData.textSelectionHandleColor == textSelectionHandleColor) &&
|
||||
(otherData.backgroundColor == backgroundColor) &&
|
||||
(otherData.dialogBackgroundColor == dialogBackgroundColor) &&
|
||||
@ -828,7 +841,8 @@ class ThemeData extends Diagnosticable {
|
||||
sliderTheme,
|
||||
chipTheme,
|
||||
platform,
|
||||
materialTapTargetSize
|
||||
materialTapTargetSize,
|
||||
cursorColor
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -856,6 +870,7 @@ class ThemeData extends Diagnosticable {
|
||||
properties.add(new DiagnosticsProperty<Color>('buttonColor', buttonColor, defaultValue: defaultData.buttonColor));
|
||||
properties.add(new DiagnosticsProperty<Color>('secondaryHeaderColor', secondaryHeaderColor, defaultValue: defaultData.secondaryHeaderColor));
|
||||
properties.add(new DiagnosticsProperty<Color>('textSelectionColor', textSelectionColor, defaultValue: defaultData.textSelectionColor));
|
||||
properties.add(new DiagnosticsProperty<Color>('cursorColor', cursorColor, defaultValue: defaultData.cursorColor));
|
||||
properties.add(new DiagnosticsProperty<Color>('textSelectionHandleColor', textSelectionHandleColor, defaultValue: defaultData.textSelectionHandleColor));
|
||||
properties.add(new DiagnosticsProperty<Color>('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor));
|
||||
properties.add(new DiagnosticsProperty<Color>('dialogBackgroundColor', dialogBackgroundColor, defaultValue: defaultData.dialogBackgroundColor));
|
||||
|
@ -209,7 +209,7 @@ class EditableText extends StatefulWidget {
|
||||
this.onSelectionChanged,
|
||||
List<TextInputFormatter> inputFormatters,
|
||||
this.rendererIgnoresPointer = false,
|
||||
this.cursorWidth = 1.0,
|
||||
this.cursorWidth = 2.0,
|
||||
this.cursorRadius,
|
||||
this.scrollPadding = const EdgeInsets.all(20.0),
|
||||
this.keyboardAppearance = Brightness.light,
|
||||
@ -374,7 +374,7 @@ class EditableText extends StatefulWidget {
|
||||
|
||||
/// How thick the cursor will be.
|
||||
///
|
||||
/// Defaults to 1.0
|
||||
/// Defaults to 2.0
|
||||
final double cursorWidth;
|
||||
|
||||
/// How rounded the corners of the cursor should be.
|
||||
|
@ -270,6 +270,72 @@ void main() {
|
||||
await checkCursorToggle();
|
||||
});
|
||||
|
||||
testWidgets('cursor has expected defaults', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
child: const TextField(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final TextField textField = tester.firstWidget(find.byType(TextField));
|
||||
expect(textField.cursorWidth, 2.0);
|
||||
expect(textField.cursorRadius, null);
|
||||
});
|
||||
|
||||
testWidgets('cursor has expected radius value', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
child: const TextField(
|
||||
cursorRadius: Radius.circular(3.0),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
final TextField textField = tester.firstWidget(find.byType(TextField));
|
||||
expect(textField.cursorWidth, 2.0);
|
||||
expect(textField.cursorRadius, const Radius.circular(3.0));
|
||||
});
|
||||
|
||||
testWidgets('cursor layout has correct width', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
child: const RepaintBoundary(
|
||||
child: TextField(
|
||||
cursorWidth: 15.0,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.enterText(find.byType(TextField), ' ');
|
||||
await skipPastScrollingAnimation(tester);
|
||||
|
||||
await expectLater(
|
||||
find.byType(TextField),
|
||||
matchesGoldenFile('text_field_test.0.0.png'),
|
||||
);
|
||||
}, skip: !Platform.isLinux);
|
||||
|
||||
testWidgets('cursor layout has correct radius', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
child: const RepaintBoundary(
|
||||
child: TextField(
|
||||
cursorWidth: 15.0,
|
||||
cursorRadius: Radius.circular(3.0),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
await tester.enterText(find.byType(TextField), ' ');
|
||||
await skipPastScrollingAnimation(tester);
|
||||
|
||||
await expectLater(
|
||||
find.byType(TextField),
|
||||
matchesGoldenFile('text_field_test.1.0.png'),
|
||||
);
|
||||
}, skip: !Platform.isLinux);
|
||||
|
||||
testWidgets('obscureText control test', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
overlay(
|
||||
@ -1228,7 +1294,7 @@ void main() {
|
||||
editable.getLocalRectForCaret(const TextPosition(offset: 0)).topLeft,
|
||||
);
|
||||
|
||||
expect(topLeft.dx, equals(399));
|
||||
expect(topLeft.dx, equals(398.5));
|
||||
|
||||
await tester.enterText(find.byType(TextField), 'abcd');
|
||||
await tester.pump();
|
||||
@ -1237,7 +1303,7 @@ void main() {
|
||||
editable.getLocalRectForCaret(const TextPosition(offset: 2)).topLeft,
|
||||
);
|
||||
|
||||
expect(topLeft.dx, equals(399));
|
||||
expect(topLeft.dx, equals(398.5));
|
||||
});
|
||||
|
||||
testWidgets('Can align to center within center', (WidgetTester tester) async {
|
||||
@ -1260,7 +1326,7 @@ void main() {
|
||||
editable.getLocalRectForCaret(const TextPosition(offset: 0)).topLeft,
|
||||
);
|
||||
|
||||
expect(topLeft.dx, equals(399));
|
||||
expect(topLeft.dx, equals(398.5));
|
||||
|
||||
await tester.enterText(find.byType(TextField), 'abcd');
|
||||
await tester.pump();
|
||||
@ -1269,7 +1335,7 @@ void main() {
|
||||
editable.getLocalRectForCaret(const TextPosition(offset: 2)).topLeft,
|
||||
);
|
||||
|
||||
expect(topLeft.dx, equals(399));
|
||||
expect(topLeft.dx, equals(398.5));
|
||||
});
|
||||
|
||||
testWidgets('Controller can update server', (WidgetTester tester) async {
|
||||
|
@ -79,7 +79,7 @@ void main() {
|
||||
expect(editableText.maxLines, equals(1));
|
||||
expect(editableText.obscureText, isFalse);
|
||||
expect(editableText.autocorrect, isTrue);
|
||||
expect(editableText.cursorWidth, 1.0);
|
||||
expect(editableText.cursorWidth, 2.0);
|
||||
});
|
||||
|
||||
testWidgets('cursor has expected width and radius',
|
||||
|
Loading…
x
Reference in New Issue
Block a user