Skip to content

Commit

Permalink
Add more documentation for TextEditingController default constructor …
Browse files Browse the repository at this point in the history
…(#143452)

## Description

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

flutter/flutter#96245 was a first improvement to the documentation.
flutter/flutter#79495 tried to hide the cursor when an invalid selection is set but it was reverted.
flutter/flutter#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 flutter/flutter#95978

## Tests

Adds 1 test for the new example.
  • Loading branch information
bleroux authored Feb 14, 2024
1 parent c61dc2a commit 5c88fbf
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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),
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -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));
});
}
19 changes: 19 additions & 0 deletions packages/flutter/lib/src/widgets/editable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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));

Expand Down

0 comments on commit 5c88fbf

Please sign in to comment.