mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
168 lines
4.5 KiB
Dart
168 lines
4.5 KiB
Dart
// 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/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
|
|
/// Flutter code sample for [TextInputControl].
|
|
|
|
void main() => runApp(const TextInputControlExampleApp());
|
|
|
|
class TextInputControlExampleApp extends StatelessWidget {
|
|
const TextInputControlExampleApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const MaterialApp(
|
|
home: TextInputControlExample(),
|
|
);
|
|
}
|
|
}
|
|
|
|
class TextInputControlExample extends StatefulWidget {
|
|
const TextInputControlExample({super.key});
|
|
|
|
@override
|
|
MyStatefulWidgetState createState() => MyStatefulWidgetState();
|
|
}
|
|
|
|
class MyStatefulWidgetState extends State<TextInputControlExample> {
|
|
final TextEditingController _controller = TextEditingController();
|
|
final FocusNode _focusNode = FocusNode();
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
_controller.dispose();
|
|
_focusNode.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Center(
|
|
child: TextField(
|
|
autofocus: true,
|
|
controller: _controller,
|
|
focusNode: _focusNode,
|
|
decoration: InputDecoration(
|
|
suffix: IconButton(
|
|
icon: const Icon(Icons.clear),
|
|
tooltip: 'Clear and unfocus',
|
|
onPressed: () {
|
|
_controller.clear();
|
|
_focusNode.unfocus();
|
|
},
|
|
),
|
|
),
|
|
),
|
|
),
|
|
bottomSheet: const MyVirtualKeyboard(),
|
|
);
|
|
}
|
|
}
|
|
|
|
class MyVirtualKeyboard extends StatefulWidget {
|
|
const MyVirtualKeyboard({super.key});
|
|
|
|
@override
|
|
MyVirtualKeyboardState createState() => MyVirtualKeyboardState();
|
|
}
|
|
|
|
class MyVirtualKeyboardState extends State<MyVirtualKeyboard> {
|
|
final MyTextInputControl _inputControl = MyTextInputControl();
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_inputControl.register();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
_inputControl.unregister();
|
|
}
|
|
|
|
void _handleKeyPress(String key) {
|
|
_inputControl.processUserInput(key);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ValueListenableBuilder<bool>(
|
|
valueListenable: _inputControl.visible,
|
|
builder: (_, bool visible, __) {
|
|
return Visibility(
|
|
visible: visible,
|
|
child: FocusScope(
|
|
canRequestFocus: false,
|
|
child: TextFieldTapRegion(
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
for (final String key in <String>['A', 'B', 'C'])
|
|
ElevatedButton(
|
|
child: Text(key),
|
|
onPressed: () => _handleKeyPress(key),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class MyTextInputControl with TextInputControl {
|
|
TextEditingValue _editingState = TextEditingValue.empty;
|
|
final ValueNotifier<bool> _visible = ValueNotifier<bool>(false);
|
|
|
|
/// The input control's visibility state for updating the visual presentation.
|
|
ValueListenable<bool> get visible => _visible;
|
|
|
|
/// Register the input control.
|
|
void register() => TextInput.setInputControl(this);
|
|
|
|
/// Restore the original platform input control.
|
|
void unregister() => TextInput.restorePlatformInputControl();
|
|
|
|
@override
|
|
void show() => _visible.value = true;
|
|
|
|
@override
|
|
void hide() => _visible.value = false;
|
|
|
|
@override
|
|
void setEditingState(TextEditingValue value) => _editingState = value;
|
|
|
|
/// Process user input.
|
|
///
|
|
/// Updates the internal editing state by inserting the input text,
|
|
/// and by replacing the current selection if any.
|
|
void processUserInput(String input) {
|
|
_editingState = _editingState.copyWith(
|
|
text: _insertText(input),
|
|
selection: _replaceSelection(input),
|
|
);
|
|
|
|
// Request the attached client to update accordingly.
|
|
TextInput.updateEditingValue(_editingState);
|
|
}
|
|
|
|
String _insertText(String input) {
|
|
final String text = _editingState.text;
|
|
final TextSelection selection = _editingState.selection;
|
|
return text.replaceRange(selection.start, selection.end, input);
|
|
}
|
|
|
|
TextSelection _replaceSelection(String input) {
|
|
final TextSelection selection = _editingState.selection;
|
|
return TextSelection.collapsed(offset: selection.start + input.length);
|
|
}
|
|
}
|