Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
c8057bc5
Unverified
Commit
c8057bc5
authored
Apr 13, 2022
by
chunhtai
Committed by
GitHub
Apr 13, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add default selection style (#100719)
parent
4aa843a6
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
358 additions
and
56 deletions
+358
-56
app.dart
packages/flutter/lib/src/cupertino/app.dart
+14
-4
text_field.dart
packages/flutter/lib/src/cupertino/text_field.dart
+11
-3
app.dart
packages/flutter/lib/src/material/app.dart
+34
-20
selectable_text.dart
packages/flutter/lib/src/material/selectable_text.dart
+17
-13
text_field.dart
packages/flutter/lib/src/material/text_field.dart
+13
-14
text_selection_theme.dart
packages/flutter/lib/src/material/text_selection_theme.dart
+28
-1
default_selection_style.dart
...ages/flutter/lib/src/widgets/default_selection_style.dart
+94
-0
editable_text.dart
packages/flutter/lib/src/widgets/editable_text.dart
+7
-1
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
text_field_test.dart
packages/flutter/test/cupertino/text_field_test.dart
+27
-0
debug_test.dart
packages/flutter/test/material/debug_test.dart
+1
-0
text_field_test.dart
packages/flutter/test/material/text_field_test.dart
+21
-0
text_selection_theme_test.dart
...ages/flutter/test/material/text_selection_theme_test.dart
+39
-0
editable_text_test.dart
packages/flutter/test/widgets/editable_text_test.dart
+30
-0
selectable_text_test.dart
packages/flutter/test/widgets/selectable_text_test.dart
+21
-0
No files found.
packages/flutter/lib/src/cupertino/app.dart
View file @
c8057bc5
...
...
@@ -43,6 +43,12 @@ import 'theme.dart';
/// widget, which the [CupertinoApp] composes. If you use Material widgets, a
/// [MaterialApp] also creates the needed dependencies for Cupertino widgets.
///
/// {@template flutter.cupertino.CupertinoApp.defaultSelectionStyle}
/// The [CupertinoApp] automatically creates a [DefaultSelectionStyle] with
/// selectionColor sets to [CupertinoThemeData.primaryColor] with 0.2 opacity
/// and cursorColor sets to [CupertinoThemeData.primaryColor].
/// {@endtemplate}
///
/// Use this widget with caution on Android since it may produce behaviors
/// Android users are not expecting such as:
///
...
...
@@ -586,10 +592,14 @@ class _CupertinoAppState extends State<CupertinoApp> {
data:
CupertinoUserInterfaceLevelData
.
base
,
child:
CupertinoTheme
(
data:
effectiveThemeData
,
child:
HeroControllerScope
(
controller:
_heroController
,
child:
Builder
(
builder:
_buildWidgetApp
,
child:
DefaultSelectionStyle
(
selectionColor:
effectiveThemeData
.
primaryColor
.
withOpacity
(
0.2
),
cursorColor:
effectiveThemeData
.
primaryColor
,
child:
HeroControllerScope
(
controller:
_heroController
,
child:
Builder
(
builder:
_buildWidgetApp
,
),
),
),
),
...
...
packages/flutter/lib/src/cupertino/text_field.dart
View file @
c8057bc5
...
...
@@ -712,7 +712,8 @@ class CupertinoTextField extends StatefulWidget {
/// The color to use when painting the cursor.
///
/// Defaults to the [CupertinoThemeData.primaryColor] of the ambient theme,
/// Defaults to the [DefaultSelectionStyle.cursorColor]. If that color is
/// null, it uses the [CupertinoThemeData.primaryColor] of the ambient theme,
/// which itself defaults to [CupertinoColors.activeBlue] in the light theme
/// and [CupertinoColors.activeOrange] in the dark theme.
final
Color
?
cursorColor
;
...
...
@@ -1180,7 +1181,11 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
final
TextStyle
placeholderStyle
=
textStyle
.
merge
(
resolvedPlaceholderStyle
);
final
Brightness
keyboardAppearance
=
widget
.
keyboardAppearance
??
CupertinoTheme
.
brightnessOf
(
context
);
final
Color
cursorColor
=
CupertinoDynamicColor
.
maybeResolve
(
widget
.
cursorColor
,
context
)
??
themeData
.
primaryColor
;
final
Color
cursorColor
=
CupertinoDynamicColor
.
maybeResolve
(
widget
.
cursorColor
??
DefaultSelectionStyle
.
of
(
context
).
cursorColor
,
context
,
)
??
themeData
.
primaryColor
;
final
Color
disabledColor
=
CupertinoDynamicColor
.
resolve
(
_kDisabledBackground
,
context
);
final
Color
?
decorationColor
=
CupertinoDynamicColor
.
maybeResolve
(
widget
.
decoration
?.
color
,
context
);
...
...
@@ -1208,7 +1213,10 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
color:
enabled
?
decorationColor
:
disabledColor
,
);
final
Color
selectionColor
=
CupertinoTheme
.
of
(
context
).
primaryColor
.
withOpacity
(
0.2
);
final
Color
selectionColor
=
CupertinoDynamicColor
.
maybeResolve
(
DefaultSelectionStyle
.
of
(
context
).
selectionColor
,
context
,
)
??
CupertinoTheme
.
of
(
context
).
primaryColor
.
withOpacity
(
0.2
);
final
Widget
paddedEditable
=
Padding
(
padding:
widget
.
padding
,
...
...
packages/flutter/lib/src/material/app.dart
View file @
c8057bc5
...
...
@@ -82,6 +82,14 @@ enum ThemeMode {
/// This widget also configures the observer of the top-level [Navigator] (if
/// any) to perform [Hero] animations.
///
/// {@template flutter.material.MaterialApp.defaultSelectionStyle}
/// The [MaterialApp] automatically creates a [DefaultSelectionStyle]. It uses
/// the colors in the [ThemeData.textSelectionTheme] if they are not null;
/// otherwise, the [MaterialApp] sets [DefaultSelectionStyle.selectionColor] to
/// [ColorScheme.primary] with 0.4 opacity and
/// [DefaultSelectionStyle.cursorColor] to [ColorScheme.primary].
/// {@endtemplate}
///
/// If [home], [routes], [onGenerateRoute], and [onUnknownRoute] are all null,
/// and [builder] is not null, then no [Navigator] is created.
///
...
...
@@ -874,29 +882,35 @@ class _MaterialAppState extends State<MaterialApp> {
theme
=
widget
.
highContrastTheme
;
}
theme
??=
widget
.
theme
??
ThemeData
.
light
();
final
Color
effectiveSelectionColor
=
theme
.
textSelectionTheme
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
final
Color
effectiveCursorColor
=
theme
.
textSelectionTheme
.
cursorColor
??
theme
.
colorScheme
.
primary
;
return
ScaffoldMessenger
(
key:
widget
.
scaffoldMessengerKey
,
child:
AnimatedTheme
(
data:
theme
,
child:
widget
.
builder
!=
null
?
Builder
(
builder:
(
BuildContext
context
)
{
// Why are we surrounding a builder with a builder?
//
// The widget.builder may contain code that invokes
// Theme.of(), which should return the theme we selected
// above in AnimatedTheme. However, if we invoke
// widget.builder() directly as the child of AnimatedTheme
// then there is no Context separating them, and the
// widget.builder() will not find the theme. Therefore, we
// surround widget.builder with yet another builder so that
// a context separates them and Theme.of() correctly
// resolves to the theme we passed to AnimatedTheme.
return
widget
.
builder
!(
context
,
child
);
},
)
:
child
??
const
SizedBox
.
shrink
(),
child:
DefaultSelectionStyle
(
selectionColor:
effectiveSelectionColor
,
cursorColor:
effectiveCursorColor
,
child:
AnimatedTheme
(
data:
theme
,
child:
widget
.
builder
!=
null
?
Builder
(
builder:
(
BuildContext
context
)
{
// Why are we surrounding a builder with a builder?
//
// The widget.builder may contain code that invokes
// Theme.of(), which should return the theme we selected
// above in AnimatedTheme. However, if we invoke
// widget.builder() directly as the child of AnimatedTheme
// then there is no Context separating them, and the
// widget.builder() will not find the theme. Therefore, we
// surround widget.builder with yet another builder so that
// a context separates them and Theme.of() correctly
// resolves to the theme we passed to AnimatedTheme.
return
widget
.
builder
!(
context
,
child
);
},
)
:
child
??
const
SizedBox
.
shrink
(),
),
),
);
}
...
...
packages/flutter/lib/src/material/selectable_text.dart
View file @
c8057bc5
...
...
@@ -12,7 +12,6 @@ import 'package:flutter/rendering.dart';
import
'desktop_text_selection.dart'
;
import
'feedback.dart'
;
import
'text_selection.dart'
;
import
'text_selection_theme.dart'
;
import
'theme.dart'
;
/// An eyeballed value that moves the cursor slightly left of where it is
...
...
@@ -359,9 +358,14 @@ class SelectableText extends StatefulWidget {
/// {@macro flutter.widgets.editableText.cursorRadius}
final
Radius
?
cursorRadius
;
/// The color
to use when painting
the cursor.
/// The color
of
the cursor.
///
/// Defaults to the theme's `cursorColor` when null.
/// The cursor indicates the current text insertion point.
///
/// If null then [DefaultSelectionStyle.cursorColor] is used. If that is also
/// null and [ThemeData.platform] is [TargetPlatform.iOS] or
/// [TargetPlatform.macOS], then [CupertinoThemeData.primaryColor] is used.
/// Otherwise [ColorScheme.primary] of [ThemeData.colorScheme] is used.
final
Color
?
cursorColor
;
/// Controls how tall the selection highlight boxes are computed to be.
...
...
@@ -597,14 +601,14 @@ class _SelectableTextState extends State<SelectableText> implements TextSelectio
);
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
TextSelectionThemeData
selectionTheme
=
TextSelectionThem
e
.
of
(
context
);
final
DefaultSelectionStyle
selectionStyle
=
DefaultSelectionStyl
e
.
of
(
context
);
final
FocusNode
focusNode
=
_effectiveFocusNode
;
TextSelectionControls
?
textSelectionControls
=
widget
.
selectionControls
;
final
bool
paintCursorAboveText
;
final
bool
cursorOpacityAnimates
;
Offset
?
cursorOffset
;
Color
?
cursorColor
=
widget
.
cursorColor
;
final
Color
cursorColor
;
final
Color
selectionColor
;
Radius
?
cursorRadius
=
widget
.
cursorRadius
;
...
...
@@ -615,8 +619,8 @@ class _SelectableTextState extends State<SelectableText> implements TextSelectio
textSelectionControls
??=
cupertinoTextSelectionControls
;
paintCursorAboveText
=
true
;
cursorOpacityAnimates
=
true
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Them
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorRadius
??=
const
Radius
.
circular
(
2.0
);
cursorOffset
=
Offset
(
iOSHorizontalOffset
/
MediaQuery
.
of
(
context
).
devicePixelRatio
,
0
);
break
;
...
...
@@ -627,8 +631,8 @@ class _SelectableTextState extends State<SelectableText> implements TextSelectio
textSelectionControls
??=
cupertinoDesktopTextSelectionControls
;
paintCursorAboveText
=
true
;
cursorOpacityAnimates
=
true
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Them
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorRadius
??=
const
Radius
.
circular
(
2.0
);
cursorOffset
=
Offset
(
iOSHorizontalOffset
/
MediaQuery
.
of
(
context
).
devicePixelRatio
,
0
);
break
;
...
...
@@ -639,8 +643,8 @@ class _SelectableTextState extends State<SelectableText> implements TextSelectio
textSelectionControls
??=
materialTextSelectionControls
;
paintCursorAboveText
=
false
;
cursorOpacityAnimates
=
false
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Them
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
break
;
case
TargetPlatform
.
linux
:
...
...
@@ -649,8 +653,8 @@ class _SelectableTextState extends State<SelectableText> implements TextSelectio
textSelectionControls
??=
desktopTextSelectionControls
;
paintCursorAboveText
=
false
;
cursorOpacityAnimates
=
false
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Them
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
break
;
}
...
...
packages/flutter/lib/src/material/text_field.dart
View file @
c8057bc5
...
...
@@ -19,7 +19,6 @@ import 'material_localizations.dart';
import
'material_state.dart'
;
import
'selectable_text.dart'
show
iOSHorizontalOffset
;
import
'text_selection.dart'
;
import
'text_selection_theme.dart'
;
import
'theme.dart'
;
export
'package:flutter/services.dart'
show
TextInputType
,
TextInputAction
,
TextCapitalization
,
SmartQuotesType
,
SmartDashesType
;
...
...
@@ -615,7 +614,7 @@ class TextField extends StatefulWidget {
/// the field.
///
/// If this is null it will default to the ambient
/// [
TextSelectionThemeData
.cursorColor]. If that is null, and the
/// [
DefaultSelectionStyle
.cursorColor]. If that is null, and the
/// [ThemeData.platform] is [TargetPlatform.iOS] or [TargetPlatform.macOS]
/// it will use [CupertinoThemeData.primaryColor]. Otherwise it will use
/// the value of [ColorScheme.primary] of [ThemeData.colorScheme].
...
...
@@ -1117,7 +1116,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
);
final
ThemeData
theme
=
Theme
.
of
(
context
);
final
TextSelectionThemeData
selectionTheme
=
TextSelectionThem
e
.
of
(
context
);
final
DefaultSelectionStyle
selectionStyle
=
DefaultSelectionStyl
e
.
of
(
context
);
final
TextStyle
style
=
theme
.
textTheme
.
subtitle1
!.
merge
(
widget
.
style
);
final
Brightness
keyboardAppearance
=
widget
.
keyboardAppearance
??
theme
.
brightness
;
final
TextEditingController
controller
=
_effectiveController
;
...
...
@@ -1135,7 +1134,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
final
bool
paintCursorAboveText
;
final
bool
cursorOpacityAnimates
;
Offset
?
cursorOffset
;
Color
?
cursorColor
=
widget
.
cursorColor
;
final
Color
cursorColor
;
final
Color
selectionColor
;
Color
?
autocorrectionTextRectColor
;
Radius
?
cursorRadius
=
widget
.
cursorRadius
;
...
...
@@ -1148,8 +1147,8 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
textSelectionControls
??=
cupertinoTextSelectionControls
;
paintCursorAboveText
=
true
;
cursorOpacityAnimates
=
true
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Them
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorRadius
??=
const
Radius
.
circular
(
2.0
);
cursorOffset
=
Offset
(
iOSHorizontalOffset
/
MediaQuery
.
of
(
context
).
devicePixelRatio
,
0
);
autocorrectionTextRectColor
=
selectionColor
;
...
...
@@ -1161,8 +1160,8 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
textSelectionControls
??=
cupertinoDesktopTextSelectionControls
;
paintCursorAboveText
=
true
;
cursorOpacityAnimates
=
true
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Them
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
cupertinoTheme
.
primaryColor
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
cupertinoTheme
.
primaryColor
.
withOpacity
(
0.40
);
cursorRadius
??=
const
Radius
.
circular
(
2.0
);
cursorOffset
=
Offset
(
iOSHorizontalOffset
/
MediaQuery
.
of
(
context
).
devicePixelRatio
,
0
);
handleDidGainAccessibilityFocus
=
()
{
...
...
@@ -1179,8 +1178,8 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
textSelectionControls
??=
materialTextSelectionControls
;
paintCursorAboveText
=
false
;
cursorOpacityAnimates
=
false
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Them
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
break
;
case
TargetPlatform
.
linux
:
...
...
@@ -1188,8 +1187,8 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
textSelectionControls
??=
desktopTextSelectionControls
;
paintCursorAboveText
=
false
;
cursorOpacityAnimates
=
false
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Them
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
break
;
case
TargetPlatform
.
windows
:
...
...
@@ -1197,8 +1196,8 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
textSelectionControls
??=
desktopTextSelectionControls
;
paintCursorAboveText
=
false
;
cursorOpacityAnimates
=
false
;
cursorColor
??=
selectionThem
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Them
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
cursorColor
=
widget
.
cursorColor
??
selectionStyl
e
.
cursorColor
??
theme
.
colorScheme
.
primary
;
selectionColor
=
selection
Styl
e
.
selectionColor
??
theme
.
colorScheme
.
primary
.
withOpacity
(
0.40
);
handleDidGainAccessibilityFocus
=
()
{
// Automatically activate the TextField when it receives accessibility focus.
if
(!
_effectiveFocusNode
.
hasFocus
&&
_effectiveFocusNode
.
canRequestFocus
)
{
...
...
packages/flutter/lib/src/material/text_selection_theme.dart
View file @
c8057bc5
...
...
@@ -129,6 +129,9 @@ class TextSelectionThemeData with Diagnosticable {
/// )
/// ```
/// {@end-tool}
///
/// This widget also creates a [DefaultSelectionStyle] for its subtree with
/// [data].
class
TextSelectionTheme
extends
InheritedTheme
{
/// Creates a text selection theme widget that specifies the text
/// selection properties for all widgets below it in the widget tree.
...
...
@@ -138,11 +141,28 @@ class TextSelectionTheme extends InheritedTheme {
Key
?
key
,
required
this
.
data
,
required
Widget
child
,
})
:
assert
(
data
!=
null
),
super
(
key:
key
,
child:
child
);
})
:
assert
(
data
!=
null
),
_child
=
child
,
// See `get child` override below.
super
(
key:
key
,
child:
const
_NullWidget
());
/// The properties for descendant [TextField] and [SelectableText] widgets.
final
TextSelectionThemeData
data
;
// Overriding the getter to insert `DefaultSelectionStyle` into the subtree
// without breaking API. In general, this approach should be avoided
// because it relies on an implementation detail of ProxyWidget. This
// workaround is necessary because TextSelectionTheme is const.
@override
Widget
get
child
{
return
DefaultSelectionStyle
(
selectionColor:
data
.
selectionColor
,
cursorColor:
data
.
cursorColor
,
child:
_child
,
);
}
final
Widget
_child
;
/// Returns the [data] from the closest [TextSelectionTheme] ancestor. If
/// there is no ancestor, it returns [ThemeData.textSelectionTheme].
/// Applications can assume that the returned value will not be null.
...
...
@@ -165,3 +185,10 @@ class TextSelectionTheme extends InheritedTheme {
@override
bool
updateShouldNotify
(
TextSelectionTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
class
_NullWidget
extends
Widget
{
const
_NullWidget
();
@override
Element
createElement
()
=>
throw
UnimplementedError
();
}
packages/flutter/lib/src/widgets/default_selection_style.dart
0 → 100644
View file @
c8057bc5
// 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
'dart:ui'
;
import
'framework.dart'
;
import
'inherited_theme.dart'
;
/// The selection style to apply to descendant [EditableText] widgets which
/// don't have an explicit style.
///
/// {@macro flutter.cupertino.CupertinoApp.defaultSelectionStyle}
///
/// {@macro flutter.material.MaterialApp.defaultSelectionStyle}
///
/// See also:
/// * [TextSelectionTheme]: which also creates a [DefaultSelectionStyle] for
/// the subtree.
class
DefaultSelectionStyle
extends
InheritedTheme
{
/// Creates a default selection style widget that specifies the selection
/// properties for all widgets below it in the widget tree.
const
DefaultSelectionStyle
({
Key
?
key
,
this
.
cursorColor
,
this
.
selectionColor
,
required
Widget
child
,
})
:
super
(
key:
key
,
child:
child
);
/// A const-constructable default selection style that provides fallback
/// values.
///
/// Returned from [of] when the given [BuildContext] doesn't have an enclosing
/// default selection style.
///
/// This constructor creates a [DefaultTextStyle] with an invalid [child],
/// which means the constructed value cannot be incorporated into the tree.
const
DefaultSelectionStyle
.
fallback
({
Key
?
key
})
:
cursorColor
=
null
,
selectionColor
=
null
,
super
(
key:
key
,
child:
const
_NullWidget
());
/// The color of the text field's cursor.
///
/// The cursor indicates the current location of the text insertion point in
/// the field.
final
Color
?
cursorColor
;
/// The background color of selected text.
final
Color
?
selectionColor
;
/// The closest instance of this class that encloses the given context.
///
/// If no such instance exists, returns an instance created by
/// [DefaultSelectionStyle.fallback], which contains fallback values.
///
/// Typical usage is as follows:
///
/// ```dart
/// DefaultSelectionStyle style = DefaultSelectionStyle.of(context);
/// ```
static
DefaultSelectionStyle
of
(
BuildContext
context
)
{
return
context
.
dependOnInheritedWidgetOfExactType
<
DefaultSelectionStyle
>()
??
const
DefaultSelectionStyle
.
fallback
();
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
return
DefaultSelectionStyle
(
cursorColor:
cursorColor
,
selectionColor:
selectionColor
,
child:
child
);
}
@override
bool
updateShouldNotify
(
DefaultSelectionStyle
oldWidget
)
{
return
cursorColor
!=
oldWidget
.
cursorColor
||
selectionColor
!=
oldWidget
.
selectionColor
;
}
}
class
_NullWidget
extends
StatelessWidget
{
const
_NullWidget
();
@override
Widget
build
(
BuildContext
context
)
{
throw
FlutterError
(
'A DefaultTextStyle constructed with DefaultTextStyle.fallback cannot be incorporated into the widget tree, '
'it is meant only to provide a fallback value returned by DefaultTextStyle.of() '
'when no enclosing default text style is present in a BuildContext.'
,
);
}
}
packages/flutter/lib/src/widgets/editable_text.dart
View file @
c8057bc5
...
...
@@ -20,6 +20,7 @@ import 'basic.dart';
import
'binding.dart'
;
import
'constants.dart'
;
import
'debug.dart'
;
import
'default_selection_style.dart'
;
import
'focus_manager.dart'
;
import
'focus_scope.dart'
;
import
'focus_traversal.dart'
;
...
...
@@ -961,6 +962,9 @@ class EditableText extends StatefulWidget {
/// The color to use when painting the selection.
///
/// If this property is null, this widget gets the selection color from the
/// [DefaultSelectionStyle].
///
/// For [CupertinoTextField]s, the value is set to the ambient
/// [CupertinoThemeData.primaryColor] with 20% opacity. For [TextField]s, the
/// value is set to the ambient [TextSelectionThemeData.selectionColor].
...
...
@@ -3250,6 +3254,8 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
assert
(
debugCheckHasMediaQuery
(
context
));
super
.
build
(
context
);
// See AutomaticKeepAliveClientMixin.
final
Color
?
effectiveSelectionColor
=
widget
.
selectionColor
??
DefaultSelectionStyle
.
of
(
context
).
selectionColor
;
final
TextSelectionControls
?
controls
=
widget
.
selectionControls
;
return
MouseRegion
(
cursor:
widget
.
mouseCursor
??
SystemMouseCursors
.
text
,
...
...
@@ -3311,7 +3317,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
minLines:
widget
.
minLines
,
expands:
widget
.
expands
,
strutStyle:
widget
.
strutStyle
,
selectionColor:
widget
.
s
electionColor
,
selectionColor:
effectiveS
electionColor
,
textScaleFactor:
widget
.
textScaleFactor
??
MediaQuery
.
textScaleFactorOf
(
context
),
textAlign:
widget
.
textAlign
,
textDirection:
_textDirection
,
...
...
packages/flutter/lib/widgets.dart
View file @
c8057bc5
...
...
@@ -34,6 +34,7 @@ export 'src/widgets/bottom_navigation_bar_item.dart';
export
'src/widgets/color_filter.dart'
;
export
'src/widgets/container.dart'
;
export
'src/widgets/debug.dart'
;
export
'src/widgets/default_selection_style.dart'
;
export
'src/widgets/default_text_editing_shortcuts.dart'
;
export
'src/widgets/desktop_text_selection_toolbar_layout_delegate.dart'
;
export
'src/widgets/dismissible.dart'
;
...
...
packages/flutter/test/cupertino/text_field_test.dart
View file @
c8057bc5
...
...
@@ -17,6 +17,7 @@ import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle, Color;
import
'package:flutter/cupertino.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
show
DragStartBehavior
,
PointerDeviceKind
,
kSecondaryMouseButton
,
kDoubleTapTimeout
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
...
...
@@ -406,6 +407,32 @@ void main() {
},
);
testWidgets
(
'uses DefaultSelectionStyle for selection and cursor colors if provided'
,
(
WidgetTester
tester
)
async
{
const
Color
selectionColor
=
Colors
.
black
;
const
Color
cursorColor
=
Colors
.
white
;
await
tester
.
pumpWidget
(
const
CupertinoApp
(
home:
Center
(
child:
DefaultSelectionStyle
(
selectionColor:
selectionColor
,
cursorColor:
cursorColor
,
child:
CupertinoTextField
(
autofocus:
true
,
)
),
),
),
);
await
tester
.
pump
();
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
expect
(
state
.
widget
.
selectionColor
,
selectionColor
);
expect
(
state
.
widget
.
cursorColor
,
cursorColor
);
},
);
testWidgets
(
'multi-lined text fields are intrinsically taller no-strut'
,
(
WidgetTester
tester
)
async
{
...
...
packages/flutter/test/material/debug_test.dart
View file @
c8057bc5
...
...
@@ -172,6 +172,7 @@ void main() {
' _InheritedTheme
\n
'
' Theme
\n
'
' AnimatedTheme
\n
'
' DefaultSelectionStyle
\n
'
' _ScaffoldMessengerScope
\n
'
' ScaffoldMessenger
\n
'
' Builder
\n
'
...
...
packages/flutter/test/material/text_field_test.dart
View file @
c8057bc5
...
...
@@ -286,6 +286,27 @@ void main() {
skip:
isContextMenuProvidedByPlatform
,
// [intended] only applies to platforms where we supply the context menu.
);
testWidgets
(
'uses DefaultSelectionStyle for selection and cursor colors if provided'
,
(
WidgetTester
tester
)
async
{
const
Color
selectionColor
=
Colors
.
orange
;
const
Color
cursorColor
=
Colors
.
red
;
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
Material
(
child:
DefaultSelectionStyle
(
selectionColor:
selectionColor
,
cursorColor:
cursorColor
,
child:
TextField
(
autofocus:
true
),
),
),
),
);
await
tester
.
pump
();
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
expect
(
state
.
widget
.
selectionColor
,
selectionColor
);
expect
(
state
.
widget
.
cursorColor
,
cursorColor
);
});
testWidgets
(
'Activates the text field when receives semantics focus on Mac, Windows'
,
(
WidgetTester
tester
)
async
{
final
SemanticsTester
semantics
=
SemanticsTester
(
tester
);
final
SemanticsOwner
semanticsOwner
=
tester
.
binding
.
pipelineOwner
.
semanticsOwner
!;
...
...
packages/flutter/test/material/text_selection_theme_test.dart
View file @
c8057bc5
...
...
@@ -262,4 +262,43 @@ void main() {
final
RenderEditable
renderSelectable
=
selectableTextState
.
renderEditable
;
expect
(
renderSelectable
.
cursorColor
,
cursorColor
.
withAlpha
(
0
));
});
testWidgets
(
'TextSelectionThem overrides DefaultSelectionStyle'
,
(
WidgetTester
tester
)
async
{
const
Color
themeSelectionColor
=
Color
(
0xffaabbcc
);
const
Color
themeCursorColor
=
Color
(
0x00ccbbaa
);
const
Color
defaultSelectionColor
=
Color
(
0xffaa1111
);
const
Color
defaultCursorColor
=
Color
(
0x00cc2222
);
final
Key
defaultSelectionStyle
=
UniqueKey
();
final
Key
themeStyle
=
UniqueKey
();
// Test TextField's cursor color.
await
tester
.
pumpWidget
(
MaterialApp
(
home:
DefaultSelectionStyle
(
selectionColor:
defaultSelectionColor
,
cursorColor:
defaultCursorColor
,
child:
Container
(
key:
defaultSelectionStyle
,
child:
TextSelectionTheme
(
data:
const
TextSelectionThemeData
(
selectionColor:
themeSelectionColor
,
cursorColor:
themeCursorColor
,
),
child:
Placeholder
(
key:
themeStyle
,
),
),
)
),
),
);
final
BuildContext
defaultSelectionStyleContext
=
tester
.
element
(
find
.
byKey
(
defaultSelectionStyle
));
DefaultSelectionStyle
style
=
DefaultSelectionStyle
.
of
(
defaultSelectionStyleContext
);
expect
(
style
.
selectionColor
,
defaultSelectionColor
);
expect
(
style
.
cursorColor
,
defaultCursorColor
);
final
BuildContext
themeStyleContext
=
tester
.
element
(
find
.
byKey
(
themeStyle
));
style
=
DefaultSelectionStyle
.
of
(
themeStyleContext
);
expect
(
style
.
selectionColor
,
themeSelectionColor
);
expect
(
style
.
cursorColor
,
themeCursorColor
);
});
}
packages/flutter/test/widgets/editable_text_test.dart
View file @
c8057bc5
...
...
@@ -660,6 +660,36 @@ void main() {
expect
(
focusNode
.
hasFocus
,
isFalse
);
});
testWidgets
(
'use DefaultSelectionStyle for selection color'
,
(
WidgetTester
tester
)
async
{
const
TextEditingValue
value
=
TextEditingValue
(
text:
'test test'
,
selection:
TextSelection
(
affinity:
TextAffinity
.
upstream
,
baseOffset:
5
,
extentOffset:
7
),
);
const
Color
selectionColor
=
Colors
.
orange
;
controller
.
value
=
value
;
await
tester
.
pumpWidget
(
DefaultSelectionStyle
(
selectionColor:
selectionColor
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
EditableText
(
controller:
controller
,
backgroundCursorColor:
Colors
.
grey
,
focusNode:
focusNode
,
keyboardType:
TextInputType
.
multiline
,
style:
textStyle
,
cursorColor:
cursorColor
,
),
),
)
),
);
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
expect
(
state
.
renderEditable
.
selectionColor
,
selectionColor
);
});
testWidgets
(
'visiblePassword keyboard is requested when set explicitly'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
MediaQuery
(
...
...
packages/flutter/test/widgets/selectable_text_test.dart
View file @
c8057bc5
...
...
@@ -297,6 +297,27 @@ void main() {
expect
(
tester
.
testTextInput
.
hasAnyClients
,
false
);
});
testWidgets
(
'uses DefaultSelectionStyle for selection and cursor colors if provided'
,
(
WidgetTester
tester
)
async
{
const
Color
selectionColor
=
Colors
.
orange
;
const
Color
cursorColor
=
Colors
.
red
;
await
tester
.
pumpWidget
(
const
MaterialApp
(
home:
Material
(
child:
DefaultSelectionStyle
(
selectionColor:
selectionColor
,
cursorColor:
cursorColor
,
child:
SelectableText
(
'text'
),
),
),
),
);
await
tester
.
pump
();
final
EditableTextState
state
=
tester
.
state
<
EditableTextState
>(
find
.
byType
(
EditableText
));
expect
(
state
.
widget
.
selectionColor
,
selectionColor
);
expect
(
state
.
widget
.
cursorColor
,
cursorColor
);
});
testWidgets
(
'Selectable Text has adaptive size'
,
(
WidgetTester
tester
)
async
{
await
tester
.
pumpWidget
(
boilerplate
(
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment