This reverts commit f8f5953d8002cb17b861486dff93e5456ca54efd.
This commit is contained in:
parent
f8f5953d80
commit
c5457068df
@ -92,8 +92,8 @@ class TextField extends StatefulWidget {
|
|||||||
/// switch to the [decoration.errorStyle] when the limit is exceeded.
|
/// switch to the [decoration.errorStyle] when the limit is exceeded.
|
||||||
///
|
///
|
||||||
/// The [textAlign], [autofocus], [obscureText], [autocorrect],
|
/// The [textAlign], [autofocus], [obscureText], [autocorrect],
|
||||||
/// [maxLengthEnforced], [scrollPadding], [maxLines], and [maxLength]
|
/// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength],
|
||||||
/// arguments must not be null.
|
/// and [enableInteractiveSelection] arguments must not be null.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
///
|
///
|
||||||
@ -126,7 +126,7 @@ class TextField extends StatefulWidget {
|
|||||||
this.cursorColor,
|
this.cursorColor,
|
||||||
this.keyboardAppearance,
|
this.keyboardAppearance,
|
||||||
this.scrollPadding = const EdgeInsets.all(20.0),
|
this.scrollPadding = const EdgeInsets.all(20.0),
|
||||||
this.enableInteractiveSelection,
|
this.enableInteractiveSelection = true,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
}) : assert(textAlign != null),
|
}) : assert(textAlign != null),
|
||||||
assert(autofocus != null),
|
assert(autofocus != null),
|
||||||
@ -137,6 +137,7 @@ class TextField extends StatefulWidget {
|
|||||||
assert(maxLines == null || maxLines > 0),
|
assert(maxLines == null || maxLines > 0),
|
||||||
assert(maxLength == null || maxLength > 0),
|
assert(maxLength == null || maxLength > 0),
|
||||||
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
|
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
|
||||||
|
assert(enableInteractiveSelection != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// Controls the text being edited.
|
/// Controls the text being edited.
|
||||||
@ -333,11 +334,6 @@ class TextField extends StatefulWidget {
|
|||||||
/// {@macro flutter.widgets.editableText.enableInteractiveSelection}
|
/// {@macro flutter.widgets.editableText.enableInteractiveSelection}
|
||||||
final bool enableInteractiveSelection;
|
final bool enableInteractiveSelection;
|
||||||
|
|
||||||
/// {@macro flutter.rendering.editable.selectionEnabled}
|
|
||||||
bool get selectionEnabled {
|
|
||||||
return enableInteractiveSelection ?? !obscureText;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Called when the user taps on this textfield.
|
/// Called when the user taps on this textfield.
|
||||||
///
|
///
|
||||||
/// The textfield builds a [GestureDetector] to handle input events like tap,
|
/// The textfield builds a [GestureDetector] to handle input events like tap,
|
||||||
@ -512,7 +508,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleTap() {
|
void _handleTap() {
|
||||||
if (widget.selectionEnabled)
|
if (widget.enableInteractiveSelection)
|
||||||
_renderEditable.handleTap();
|
_renderEditable.handleTap();
|
||||||
_requestKeyboard();
|
_requestKeyboard();
|
||||||
_confirmCurrentSplash();
|
_confirmCurrentSplash();
|
||||||
@ -525,7 +521,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _handleLongPress() {
|
void _handleLongPress() {
|
||||||
if (widget.selectionEnabled)
|
if (widget.enableInteractiveSelection)
|
||||||
_renderEditable.handleLongPress();
|
_renderEditable.handleLongPress();
|
||||||
_confirmCurrentSplash();
|
_confirmCurrentSplash();
|
||||||
}
|
}
|
||||||
@ -603,7 +599,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
|||||||
autocorrect: widget.autocorrect,
|
autocorrect: widget.autocorrect,
|
||||||
maxLines: widget.maxLines,
|
maxLines: widget.maxLines,
|
||||||
selectionColor: themeData.textSelectionColor,
|
selectionColor: themeData.textSelectionColor,
|
||||||
selectionControls: widget.selectionEnabled
|
selectionControls: widget.enableInteractiveSelection
|
||||||
? (themeData.platform == TargetPlatform.iOS
|
? (themeData.platform == TargetPlatform.iOS
|
||||||
? cupertinoTextSelectionControls
|
? cupertinoTextSelectionControls
|
||||||
: materialTextSelectionControls)
|
: materialTextSelectionControls)
|
||||||
|
@ -122,6 +122,8 @@ class RenderEditable extends RenderBox {
|
|||||||
///
|
///
|
||||||
/// The [offset] is required and must not be null. You can use [new
|
/// The [offset] is required and must not be null. You can use [new
|
||||||
/// ViewportOffset.zero] if you have no need for scrolling.
|
/// ViewportOffset.zero] if you have no need for scrolling.
|
||||||
|
///
|
||||||
|
/// The [enableInteractiveSelection] argument must not be null.
|
||||||
RenderEditable({
|
RenderEditable({
|
||||||
TextSpan text,
|
TextSpan text,
|
||||||
@required TextDirection textDirection,
|
@required TextDirection textDirection,
|
||||||
@ -141,7 +143,7 @@ class RenderEditable extends RenderBox {
|
|||||||
Locale locale,
|
Locale locale,
|
||||||
double cursorWidth = 1.0,
|
double cursorWidth = 1.0,
|
||||||
Radius cursorRadius,
|
Radius cursorRadius,
|
||||||
bool enableInteractiveSelection,
|
bool enableInteractiveSelection = true,
|
||||||
@required this.textSelectionDelegate,
|
@required this.textSelectionDelegate,
|
||||||
}) : assert(textAlign != null),
|
}) : assert(textAlign != null),
|
||||||
assert(textDirection != null, 'RenderEditable created without a textDirection.'),
|
assert(textDirection != null, 'RenderEditable created without a textDirection.'),
|
||||||
@ -150,6 +152,7 @@ class RenderEditable extends RenderBox {
|
|||||||
assert(offset != null),
|
assert(offset != null),
|
||||||
assert(ignorePointer != null),
|
assert(ignorePointer != null),
|
||||||
assert(obscureText != null),
|
assert(obscureText != null),
|
||||||
|
assert(enableInteractiveSelection != null),
|
||||||
assert(textSelectionDelegate != null),
|
assert(textSelectionDelegate != null),
|
||||||
_textPainter = TextPainter(
|
_textPainter = TextPainter(
|
||||||
text: text,
|
text: text,
|
||||||
@ -712,22 +715,6 @@ class RenderEditable extends RenderBox {
|
|||||||
markNeedsSemanticsUpdate();
|
markNeedsSemanticsUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// {@template flutter.rendering.editable.selectionEnabled}
|
|
||||||
/// True if interactive selection is enabled based on the values of
|
|
||||||
/// [enableInteractiveSelection] and [obscureText].
|
|
||||||
///
|
|
||||||
/// By default [enableInteractiveSelection] is null, obscureText is false,
|
|
||||||
/// and this method returns true.
|
|
||||||
/// If [enableInteractiveSelection] is null and obscureText is true, then this
|
|
||||||
/// method returns false. This is the common case for password fields.
|
|
||||||
/// If [enableInteractiveSelection] is non-null then its value is returned. An
|
|
||||||
/// app might set it to true to enable interactive selection for a password
|
|
||||||
/// field, or to false to unconditionally disable interactive selection.
|
|
||||||
/// {@endtemplate}
|
|
||||||
bool get selectionEnabled {
|
|
||||||
return enableInteractiveSelection ?? !obscureText;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
void describeSemanticsConfiguration(SemanticsConfiguration config) {
|
||||||
super.describeSemanticsConfiguration(config);
|
super.describeSemanticsConfiguration(config);
|
||||||
@ -741,10 +728,10 @@ class RenderEditable extends RenderBox {
|
|||||||
..isFocused = hasFocus
|
..isFocused = hasFocus
|
||||||
..isTextField = true;
|
..isTextField = true;
|
||||||
|
|
||||||
if (hasFocus && selectionEnabled)
|
if (hasFocus && enableInteractiveSelection)
|
||||||
config.onSetSelection = _handleSetSelection;
|
config.onSetSelection = _handleSetSelection;
|
||||||
|
|
||||||
if (selectionEnabled && _selection?.isValid == true) {
|
if (enableInteractiveSelection && _selection?.isValid == true) {
|
||||||
config.textSelection = _selection;
|
config.textSelection = _selection;
|
||||||
if (_textPainter.getOffsetBefore(_selection.extentOffset) != null) {
|
if (_textPainter.getOffsetBefore(_selection.extentOffset) != null) {
|
||||||
config
|
config
|
||||||
|
@ -183,7 +183,8 @@ class EditableText extends StatefulWidget {
|
|||||||
/// default to [TextInputType.multiline].
|
/// default to [TextInputType.multiline].
|
||||||
///
|
///
|
||||||
/// The [controller], [focusNode], [style], [cursorColor], [textAlign],
|
/// The [controller], [focusNode], [style], [cursorColor], [textAlign],
|
||||||
/// [rendererIgnoresPointer] arguments must not be null.
|
/// [rendererIgnoresPointer], and [enableInteractiveSelection] arguments must
|
||||||
|
/// not be null.
|
||||||
EditableText({
|
EditableText({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.controller,
|
@required this.controller,
|
||||||
@ -213,7 +214,7 @@ class EditableText extends StatefulWidget {
|
|||||||
this.cursorRadius,
|
this.cursorRadius,
|
||||||
this.scrollPadding = const EdgeInsets.all(20.0),
|
this.scrollPadding = const EdgeInsets.all(20.0),
|
||||||
this.keyboardAppearance = Brightness.light,
|
this.keyboardAppearance = Brightness.light,
|
||||||
this.enableInteractiveSelection,
|
this.enableInteractiveSelection = true,
|
||||||
}) : assert(controller != null),
|
}) : assert(controller != null),
|
||||||
assert(focusNode != null),
|
assert(focusNode != null),
|
||||||
assert(obscureText != null),
|
assert(obscureText != null),
|
||||||
@ -225,6 +226,7 @@ class EditableText extends StatefulWidget {
|
|||||||
assert(autofocus != null),
|
assert(autofocus != null),
|
||||||
assert(rendererIgnoresPointer != null),
|
assert(rendererIgnoresPointer != null),
|
||||||
assert(scrollPadding != null),
|
assert(scrollPadding != null),
|
||||||
|
assert(enableInteractiveSelection != null),
|
||||||
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
|
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
|
||||||
inputFormatters = maxLines == 1
|
inputFormatters = maxLines == 1
|
||||||
? (
|
? (
|
||||||
@ -467,11 +469,6 @@ class EditableText extends StatefulWidget {
|
|||||||
/// Defaults to false, resulting in a typical blinking cursor.
|
/// Defaults to false, resulting in a typical blinking cursor.
|
||||||
static bool debugDeterministicCursor = false;
|
static bool debugDeterministicCursor = false;
|
||||||
|
|
||||||
/// {@macro flutter.rendering.editable.selectionEnabled}
|
|
||||||
bool get selectionEnabled {
|
|
||||||
return enableInteractiveSelection ?? !obscureText;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
EditableTextState createState() => EditableTextState();
|
EditableTextState createState() => EditableTextState();
|
||||||
|
|
||||||
@ -932,19 +929,19 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
|
|||||||
}
|
}
|
||||||
|
|
||||||
VoidCallback _semanticsOnCopy(TextSelectionControls controls) {
|
VoidCallback _semanticsOnCopy(TextSelectionControls controls) {
|
||||||
return widget.selectionEnabled && _hasFocus && controls?.canCopy(this) == true
|
return widget.enableInteractiveSelection && _hasFocus && controls?.canCopy(this) == true
|
||||||
? () => controls.handleCopy(this)
|
? () => controls.handleCopy(this)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
VoidCallback _semanticsOnCut(TextSelectionControls controls) {
|
VoidCallback _semanticsOnCut(TextSelectionControls controls) {
|
||||||
return widget.selectionEnabled && _hasFocus && controls?.canCut(this) == true
|
return widget.enableInteractiveSelection && _hasFocus && controls?.canCut(this) == true
|
||||||
? () => controls.handleCut(this)
|
? () => controls.handleCut(this)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
VoidCallback _semanticsOnPaste(TextSelectionControls controls) {
|
VoidCallback _semanticsOnPaste(TextSelectionControls controls) {
|
||||||
return widget.selectionEnabled &&_hasFocus && controls?.canPaste(this) == true
|
return widget.enableInteractiveSelection &&_hasFocus && controls?.canPaste(this) == true
|
||||||
? () => controls.handlePaste(this)
|
? () => controls.handlePaste(this)
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
@ -1053,10 +1050,11 @@ class _Editable extends LeafRenderObjectWidget {
|
|||||||
this.rendererIgnoresPointer = false,
|
this.rendererIgnoresPointer = false,
|
||||||
this.cursorWidth,
|
this.cursorWidth,
|
||||||
this.cursorRadius,
|
this.cursorRadius,
|
||||||
this.enableInteractiveSelection,
|
this.enableInteractiveSelection = true,
|
||||||
this.textSelectionDelegate,
|
this.textSelectionDelegate,
|
||||||
}) : assert(textDirection != null),
|
}) : assert(textDirection != null),
|
||||||
assert(rendererIgnoresPointer != null),
|
assert(rendererIgnoresPointer != null),
|
||||||
|
assert(enableInteractiveSelection != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
final TextSpan textSpan;
|
final TextSpan textSpan;
|
||||||
|
@ -658,66 +658,6 @@ void main() {
|
|||||||
// End the test here to ensure the animation is properly disposed of.
|
// End the test here to ensure the animation is properly disposed of.
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('An obscured TextField is not selectable by default', (WidgetTester tester) async {
|
|
||||||
// This is a regression test for
|
|
||||||
// https://github.com/flutter/flutter/issues/24100
|
|
||||||
|
|
||||||
final TextEditingController controller = TextEditingController();
|
|
||||||
Widget buildFrame(bool obscureText, bool enableInteractiveSelection) {
|
|
||||||
return overlay(
|
|
||||||
child: TextField(
|
|
||||||
controller: controller,
|
|
||||||
obscureText: obscureText,
|
|
||||||
enableInteractiveSelection: enableInteractiveSelection,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obscure text and don't enable or disable selection
|
|
||||||
await tester.pumpWidget(buildFrame(true, null));
|
|
||||||
await tester.enterText(find.byType(TextField), 'abcdefghi');
|
|
||||||
await skipPastScrollingAnimation(tester);
|
|
||||||
expect(controller.selection.isCollapsed, true);
|
|
||||||
|
|
||||||
// Long press doesn't select anything
|
|
||||||
final Offset ePos = textOffsetToPosition(tester, 1);
|
|
||||||
final TestGesture gesture = await tester.startGesture(ePos, pointer: 7);
|
|
||||||
await tester.pump(const Duration(seconds: 2));
|
|
||||||
await gesture.up();
|
|
||||||
await tester.pump();
|
|
||||||
expect(controller.selection.isCollapsed, true);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('An obscured TextField is selectable when enabled', (WidgetTester tester) async {
|
|
||||||
// This is a regression test for
|
|
||||||
// https://github.com/flutter/flutter/issues/24100
|
|
||||||
|
|
||||||
final TextEditingController controller = TextEditingController();
|
|
||||||
Widget buildFrame(bool obscureText, bool enableInteractiveSelection) {
|
|
||||||
return overlay(
|
|
||||||
child: TextField(
|
|
||||||
controller: controller,
|
|
||||||
obscureText: obscureText,
|
|
||||||
enableInteractiveSelection: enableInteractiveSelection,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Explicitly allow selection on obscured text
|
|
||||||
await tester.pumpWidget(buildFrame(true, true));
|
|
||||||
await tester.enterText(find.byType(TextField), 'abcdefghi');
|
|
||||||
await skipPastScrollingAnimation(tester);
|
|
||||||
expect(controller.selection.isCollapsed, true);
|
|
||||||
|
|
||||||
// Long press does select text
|
|
||||||
final Offset ePos2 = textOffsetToPosition(tester, 1);
|
|
||||||
final TestGesture gesture2 = await tester.startGesture(ePos2, pointer: 7);
|
|
||||||
await tester.pump(const Duration(seconds: 2));
|
|
||||||
await gesture2.up();
|
|
||||||
await tester.pump();
|
|
||||||
expect(controller.selection.isCollapsed, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
testWidgets('Multiline text will wrap up to maxLines', (WidgetTester tester) async {
|
testWidgets('Multiline text will wrap up to maxLines', (WidgetTester tester) async {
|
||||||
final Key textFieldKey = UniqueKey();
|
final Key textFieldKey = UniqueKey();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user