mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
TextSelectionTheme support (step 2 of 3) (#65044)
This commit is contained in:
parent
277a87fd6e
commit
cb92ffc7fa
@ -1098,11 +1098,6 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
|
||||
}
|
||||
}
|
||||
|
||||
Color _defaultSelectionColor(BuildContext context, Color primary) {
|
||||
final bool isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
return primary.withOpacity(isDark ? 0.40 : 0.12);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
assert(debugCheckHasMaterial(context));
|
||||
@ -1136,13 +1131,14 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
|
||||
switch (theme.platform) {
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
final CupertinoThemeData cupertinoTheme = CupertinoTheme.of(context);
|
||||
forcePressEnabled = true;
|
||||
textSelectionControls = cupertinoTextSelectionControls;
|
||||
paintCursorAboveText = true;
|
||||
cursorOpacityAnimates = true;
|
||||
if (theme.useTextSelectionTheme) {
|
||||
cursorColor ??= selectionTheme.cursorColor ?? CupertinoTheme.of(context).primaryColor;
|
||||
selectionColor = selectionTheme.selectionColor ?? _defaultSelectionColor(context, CupertinoTheme.of(context).primaryColor);
|
||||
cursorColor ??= selectionTheme.cursorColor ?? cupertinoTheme.primaryColor;
|
||||
selectionColor = selectionTheme.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40);
|
||||
} else {
|
||||
cursorColor ??= CupertinoTheme.of(context).primaryColor;
|
||||
selectionColor = theme.textSelectionColor;
|
||||
@ -1162,7 +1158,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
|
||||
cursorOpacityAnimates = false;
|
||||
if (theme.useTextSelectionTheme) {
|
||||
cursorColor ??= selectionTheme.cursorColor ?? theme.colorScheme.primary;
|
||||
selectionColor = selectionTheme.selectionColor ?? _defaultSelectionColor(context, theme.colorScheme.primary);
|
||||
selectionColor = selectionTheme.selectionColor ?? theme.colorScheme.primary.withOpacity(0.40);
|
||||
} else {
|
||||
cursorColor ??= theme.cursorColor;
|
||||
selectionColor = theme.textSelectionColor;
|
||||
|
||||
@ -405,7 +405,7 @@ class ThemeData with Diagnosticable {
|
||||
dataTableTheme ??= const DataTableThemeData();
|
||||
|
||||
fixTextFieldOutlineLabel ??= false;
|
||||
useTextSelectionTheme ??= false;
|
||||
useTextSelectionTheme ??= true;
|
||||
|
||||
return ThemeData.raw(
|
||||
visualDensity: visualDensity,
|
||||
@ -883,12 +883,21 @@ class ThemeData with Diagnosticable {
|
||||
final Color secondaryHeaderColor;
|
||||
|
||||
/// The color of text selections in text fields, such as [TextField].
|
||||
///
|
||||
/// By default this property is no longer used. It has been replaced with
|
||||
/// [TextSelectionThemeData.selectionColor] and will soon be deprecated.
|
||||
final Color textSelectionColor;
|
||||
|
||||
/// The color of cursors in Material-style text fields, such as [TextField].
|
||||
///
|
||||
/// By default this property is no longer used. It has been replaced with
|
||||
/// [TextSelectionThemeData.cursorColor] and will soon be deprecated.
|
||||
final Color cursorColor;
|
||||
|
||||
/// The color of the handles used to adjust what part of the text is currently selected.
|
||||
///
|
||||
/// By default this property is no longer used. It has been replaced with
|
||||
/// [TextSelectionThemeData.selectionHandleColor] and will soon be deprecated.
|
||||
final Color textSelectionHandleColor;
|
||||
|
||||
/// A color that contrasts with the [primaryColor], e.g. used as the
|
||||
|
||||
@ -554,7 +554,9 @@ void main() {
|
||||
await tester.pumpWidget(RepaintBoundary(
|
||||
child: Theme(
|
||||
data: ThemeData(
|
||||
textSelectionHandleColor: const Color(0x550000AA),
|
||||
textSelectionTheme: const TextSelectionThemeData(
|
||||
selectionHandleColor: Color(0x550000AA),
|
||||
),
|
||||
),
|
||||
isMaterialAppTheme: true,
|
||||
child: Builder(
|
||||
|
||||
@ -58,6 +58,10 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('Empty textSelectionTheme will use defaults', (WidgetTester tester) async {
|
||||
const Color defaultCursorColor = Color(0x002196f3);
|
||||
const Color defaultSelectionColor = Color(0x662196f3);
|
||||
const Color defaultSelectionHandleColor = Color(0xff2196f3);
|
||||
|
||||
// Test TextField's cursor & selection color.
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
@ -69,52 +73,12 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
final EditableTextState editableTextState = tester.firstState(find.byType(EditableText));
|
||||
final RenderEditable renderEditable = editableTextState.renderEditable;
|
||||
expect(renderEditable.cursorColor, const Color(0x004285f4));
|
||||
expect(renderEditable.selectionColor, const Color(0xFF90CAF9));
|
||||
expect(renderEditable.cursorColor, defaultCursorColor);
|
||||
expect(Color(renderEditable.selectionColor.value), defaultSelectionColor);
|
||||
|
||||
// Test the selection handle color.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return materialTextSelectionControls.buildHandle(
|
||||
context, TextSelectionHandleType.left, 10.0
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final RenderBox handle = tester.firstRenderObject<RenderBox>(find.byType(CustomPaint));
|
||||
expect(handle, paints..path(color: Colors.blue[300]));
|
||||
|
||||
});
|
||||
|
||||
testWidgets('Empty textSelectionTheme with useTextSelectionTheme set will use new defaults', (WidgetTester tester) async {
|
||||
final ThemeData theme = ThemeData.fallback().copyWith(useTextSelectionTheme: true);
|
||||
final Color primaryColor = Color(theme.colorScheme.primary.value);
|
||||
|
||||
// Test TextField's cursor & selection color.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: const Material(
|
||||
child: TextField(),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final EditableTextState editableTextState = tester.firstState(find.byType(EditableText));
|
||||
final RenderEditable renderEditable = editableTextState.renderEditable;
|
||||
expect(renderEditable.cursorColor, primaryColor.withAlpha(0));
|
||||
expect(Color(renderEditable.selectionColor.value), primaryColor.withOpacity(0.12));
|
||||
|
||||
// Test the selection handle color.
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: theme,
|
||||
home: Material(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
@ -128,7 +92,7 @@ void main() {
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
final RenderBox handle = tester.firstRenderObject<RenderBox>(find.byType(CustomPaint));
|
||||
expect(handle, paints..path(color: primaryColor));
|
||||
expect(handle, paints..path(color: defaultSelectionHandleColor));
|
||||
});
|
||||
|
||||
testWidgets('ThemeDate.textSelectionTheme will be used if provided', (WidgetTester tester) async {
|
||||
@ -138,7 +102,6 @@ void main() {
|
||||
selectionHandleColor: Color(0x00ccbbaa),
|
||||
);
|
||||
final ThemeData theme = ThemeData.fallback().copyWith(
|
||||
useTextSelectionTheme: true,
|
||||
textSelectionTheme: textSelectionTheme,
|
||||
);
|
||||
|
||||
@ -184,7 +147,6 @@ void main() {
|
||||
selectionHandleColor: Color(0x00ccbbaa),
|
||||
);
|
||||
final ThemeData theme = ThemeData.fallback().copyWith(
|
||||
useTextSelectionTheme: true,
|
||||
textSelectionTheme: defaultTextSelectionTheme,
|
||||
);
|
||||
const TextSelectionThemeData widgetTextSelectionTheme = TextSelectionThemeData(
|
||||
@ -240,7 +202,6 @@ void main() {
|
||||
selectionHandleColor: Color(0x00ccbbaa),
|
||||
);
|
||||
final ThemeData theme = ThemeData.fallback().copyWith(
|
||||
useTextSelectionTheme: true,
|
||||
textSelectionTheme: defaultTextSelectionTheme,
|
||||
);
|
||||
const TextSelectionThemeData widgetTextSelectionTheme = TextSelectionThemeData(
|
||||
|
||||
@ -208,6 +208,7 @@ void main() {
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||
|
||||
testWidgets('Cursor does not animate on Android', (WidgetTester tester) async {
|
||||
final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value);
|
||||
const Widget widget = MaterialApp(
|
||||
home: Material(
|
||||
child: TextField(
|
||||
@ -225,12 +226,12 @@ void main() {
|
||||
|
||||
await tester.pump();
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
// Android cursor goes from exactly on to exactly off on the 500ms dot.
|
||||
await tester.pump(const Duration(milliseconds: 499));
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 1));
|
||||
expect(renderEditable.cursorColor.alpha, 0);
|
||||
@ -239,7 +240,7 @@ void main() {
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
expect(renderEditable.cursorColor.alpha, 0);
|
||||
@ -248,6 +249,7 @@ void main() {
|
||||
|
||||
testWidgets('Cursor does not animates when debugDeterministicCursor is set', (WidgetTester tester) async {
|
||||
EditableText.debugDeterministicCursor = true;
|
||||
final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value);
|
||||
const Widget widget = MaterialApp(
|
||||
home: Material(
|
||||
child: TextField(
|
||||
@ -268,24 +270,24 @@ void main() {
|
||||
await tester.pump();
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
|
||||
expect(renderEditable, paints..rrect(color: defaultCursorColor));
|
||||
|
||||
// Cursor draw never changes.
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
|
||||
expect(renderEditable, paints..rrect(color: defaultCursorColor));
|
||||
|
||||
// No more transient calls.
|
||||
await tester.pumpAndSettle();
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
|
||||
expect(renderEditable, paints..rrect(color: defaultCursorColor));
|
||||
|
||||
EditableText.debugDeterministicCursor = false;
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
|
||||
|
||||
testWidgets('Cursor does not animate on Android when debugDeterministicCursor is set', (WidgetTester tester) async {
|
||||
final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value);
|
||||
EditableText.debugDeterministicCursor = true;
|
||||
|
||||
const Widget widget = MaterialApp(
|
||||
home: Material(
|
||||
child: TextField(
|
||||
@ -303,21 +305,21 @@ void main() {
|
||||
|
||||
await tester.pump();
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
// Cursor draw never changes.
|
||||
await tester.pump(const Duration(milliseconds: 500));
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
// No more transient calls.
|
||||
await tester.pumpAndSettle();
|
||||
expect(renderEditable.cursorColor.alpha, 255);
|
||||
expect(renderEditable, paints..rect(color: const Color(0xff4285f4)));
|
||||
expect(renderEditable, paints..rect(color: defaultCursorColor));
|
||||
|
||||
EditableText.debugDeterministicCursor = false;
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user