Add more documentation for TextEditingController default constructor (#143452)

## Description

This PR adds more documentation for `TextEditingController(String text)` constructor and it adds one example.

https://github.com/flutter/flutter/pull/96245 was a first improvement to the documentation.
https://github.com/flutter/flutter/issues/79495 tried to hide the cursor when an invalid selection is set but it was reverted.
https://github.com/flutter/flutter/pull/123777 mitigated the issue of having a default invalid selection: it takes care of setting a proper selection when a text field is focused and its controller selection is not initialized.

I will try changing the initial selection in another PR, but It will probably break several existing tests.

## Related Issue

Fixes https://github.com/flutter/flutter/issues/95978

## Tests

Adds 1 test for the new example.
This commit is contained in:
Bruno Leroux 2024-02-14 21:10:18 +01:00 committed by GitHub
parent c61dc2a586
commit 5c88fbf0b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 101 additions and 0 deletions

View file

@ -0,0 +1,61 @@
// 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 'package:flutter/material.dart';
/// Flutter code sample for [TextEditingController].
void main() {
runApp(const TextEditingControllerExampleApp());
}
class TextEditingControllerExampleApp extends StatelessWidget {
const TextEditingControllerExampleApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: TextEditingControllerExample(),
);
}
}
class TextEditingControllerExample extends StatefulWidget {
const TextEditingControllerExample({super.key});
@override
State<TextEditingControllerExample> createState() => _TextEditingControllerExampleState();
}
class _TextEditingControllerExampleState extends State<TextEditingControllerExample> {
// Create a controller whose initial selection is empty (collapsed) and positioned
// before the text (offset is 0).
final TextEditingController _controller = TextEditingController.fromValue(
const TextEditingValue(
text: 'Flutter',
selection: TextSelection.collapsed(offset: 0),
),
);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
autofocus: true,
decoration: const InputDecoration(filled: true),
),
),
);
}
}

View file

@ -0,0 +1,21 @@
// 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 'package:flutter/material.dart';
import 'package:flutter_api_samples/widgets/editable_text/text_editing_controller.1.dart' as example;
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Initial selection is collasped at offset 0', (WidgetTester tester) async {
await tester.pumpWidget(
const example.TextEditingControllerExampleApp(),
);
final EditableText editableText = tester.widget(find.byType(EditableText));
final TextEditingController controller = editableText.controller;
expect(controller.text, 'Flutter');
expect(controller.selection, const TextSelection.collapsed(offset: 0));
});
}

View file

@ -178,6 +178,7 @@ class _RenderCompositionCallback extends RenderProxyBox {
///
/// Remember to [dispose] of the [TextEditingController] when it is no longer
/// needed. This will ensure we discard any resources used by the object.
///
/// {@tool dartpad}
/// This example creates a [TextField] with a [TextEditingController] whose
/// change listener forces the entered text to be lower case and keeps the
@ -198,6 +199,24 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
///
/// This constructor treats a null [text] argument as if it were the empty
/// string.
///
/// The initial selection is `TextSelection.collapsed(offset: -1)`.
/// This indicates that there is no selection at all ([TextSelection.isValid]
/// is false in this case). When a text field is built with a controller whose
/// selection is not valid, the text field will update the selection when it
/// is focused (the selection will be an empty selection positioned at the
/// end of the text).
//
/// Consider using [TextEditingController.fromValue] to initialize both the
/// text and the selection.
///
/// {@tool dartpad}
/// This example creates a [TextField] with a [TextEditingController] whose
/// initial selection is empty (collapsed) and positioned at the beginning
/// of the text (offset is 0).
///
/// ** See code in examples/api/lib/widgets/editable_text/text_editing_controller.1.dart **
/// {@end-tool}
TextEditingController({ String? text })
: super(text == null ? TextEditingValue.empty : TextEditingValue(text: text));