| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- import 'package:flutter/foundation.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- class CustomTextEdit extends StatefulWidget {
- CustomTextEdit({
- Key? key,
- required this.child,
- required this.onInsert,
- required this.onDelete,
- required this.onComposing,
- required this.onAction,
- required this.onKey,
- required this.focusNode,
- this.autofocus = false,
- this.readOnly = false,
- // this.initEditingState = TextEditingValue.empty,
- this.inputType = TextInputType.text,
- this.inputAction = TextInputAction.newline,
- this.keyboardAppearance = Brightness.light,
- this.deleteDetection = false,
- }) : super(key: key);
- final Widget child;
- final void Function(String) onInsert;
- final void Function() onDelete;
- final void Function(String?) onComposing;
- final void Function(TextInputAction) onAction;
- final KeyEventResult Function(RawKeyEvent) onKey;
- final FocusNode focusNode;
- final bool autofocus;
- final bool readOnly;
- final TextInputType inputType;
- final TextInputAction inputAction;
- final Brightness keyboardAppearance;
- final bool deleteDetection;
- @override
- CustomTextEditState createState() => CustomTextEditState();
- }
- class CustomTextEditState extends State<CustomTextEdit>
- implements TextInputClient {
- TextInputConnection? _connection;
- @override
- void initState() {
- widget.focusNode.addListener(_onFocusChange);
- super.initState();
- }
- @override
- void didUpdateWidget(CustomTextEdit oldWidget) {
- super.didUpdateWidget(oldWidget);
- if (widget.focusNode != oldWidget.focusNode) {
- oldWidget.focusNode.removeListener(_onFocusChange);
- widget.focusNode.addListener(_onFocusChange);
- }
- if (!_shouldCreateInputConnection) {
- _closeInputConnectionIfNeeded();
- } else {
- if (oldWidget.readOnly && widget.focusNode.hasFocus) {
- _openInputConnection();
- }
- }
- }
- @override
- Widget build(BuildContext context) {
- return Focus(
- focusNode: widget.focusNode,
- autofocus: widget.autofocus,
- onKey: _onKey,
- child: widget.child,
- );
- }
- bool get hasInputConnection => _connection != null && _connection!.attached;
- void requestKeyboard() {
- if (widget.focusNode.hasFocus) {
- _openInputConnection();
- } else {
- widget.focusNode.requestFocus();
- }
- }
- void closeKeyboard() {
- if (hasInputConnection) {
- _connection?.close();
- }
- }
- void setEditingState(TextEditingValue value) {
- _currentEditingState = value;
- _connection?.setEditingState(value);
- }
- void setEditableRect(Rect rect, Rect caretRect) {
- if (!hasInputConnection) {
- return;
- }
- _connection?.setEditableSizeAndTransform(
- rect.size,
- Matrix4.translationValues(0, 0, 0),
- );
- _connection?.setCaretRect(caretRect);
- }
- void _onFocusChange() {
- _openOrCloseInputConnectionIfNeeded();
- }
- KeyEventResult _onKey(FocusNode focusNode, RawKeyEvent event) {
- if (_currentEditingState.composing.isCollapsed) {
- return widget.onKey(event);
- }
- return KeyEventResult.skipRemainingHandlers;
- }
- void _openOrCloseInputConnectionIfNeeded() {
- if (widget.focusNode.hasFocus && widget.focusNode.consumeKeyboardToken()) {
- _openInputConnection();
- } else if (!widget.focusNode.hasFocus) {
- _closeInputConnectionIfNeeded();
- }
- }
- bool get _shouldCreateInputConnection => kIsWeb || !widget.readOnly;
- void _openInputConnection() {
- if (!_shouldCreateInputConnection) {
- return;
- }
- if (hasInputConnection) {
- _connection!.show();
- } else {
- final config = TextInputConfiguration(
- inputType: widget.inputType,
- inputAction: widget.inputAction,
- keyboardAppearance: widget.keyboardAppearance,
- autocorrect: false,
- enableSuggestions: false,
- enableIMEPersonalizedLearning: false,
- );
- _connection = TextInput.attach(this, config);
- _connection!.show();
- // setEditableRect(Rect.zero, Rect.zero);
- _connection!.setEditingState(_initEditingState);
- }
- }
- void _closeInputConnectionIfNeeded() {
- if (_connection != null && _connection!.attached) {
- _connection!.close();
- _connection = null;
- }
- }
- TextEditingValue get _initEditingState => widget.deleteDetection
- ? const TextEditingValue(
- text: ' ',
- selection: TextSelection.collapsed(offset: 2),
- )
- : const TextEditingValue(
- text: '',
- selection: TextSelection.collapsed(offset: 0),
- );
- late var _currentEditingState = _initEditingState.copyWith();
- @override
- TextEditingValue? get currentTextEditingValue {
- return _currentEditingState;
- }
- @override
- AutofillScope? get currentAutofillScope {
- return null;
- }
- @override
- void updateEditingValue(TextEditingValue value) {
- _currentEditingState = value;
- // Get input after composing is done
- if (!_currentEditingState.composing.isCollapsed) {
- final text = _currentEditingState.text;
- final composingText = _currentEditingState.composing.textInside(text);
- widget.onComposing(composingText);
- return;
- }
- widget.onComposing(null);
- if (_currentEditingState.text.length < _initEditingState.text.length) {
- widget.onDelete();
- } else {
- final textDelta = _currentEditingState.text.substring(
- _initEditingState.text.length,
- );
- widget.onInsert(textDelta);
- }
- // Reset editing state if composing is done
- if (_currentEditingState.composing.isCollapsed &&
- _currentEditingState.text != _initEditingState.text) {
- _connection!.setEditingState(_initEditingState);
- }
- }
- @override
- void performAction(TextInputAction action) {
- // print('performAction $action');
- widget.onAction(action);
- }
- @override
- void updateFloatingCursor(RawFloatingCursorPoint point) {
- // print('updateFloatingCursor $point');
- }
- @override
- void showAutocorrectionPromptRect(int start, int end) {
- // print('showAutocorrectionPromptRect');
- }
- @override
- void connectionClosed() {
- // print('connectionClosed');
- }
- @override
- void performPrivateCommand(String action, Map<String, dynamic> data) {
- // print('performPrivateCommand $action');
- }
- @override
- void insertTextPlaceholder(Size size) {
- // print('insertTextPlaceholder');
- }
- @override
- void removeTextPlaceholder() {
- // print('removeTextPlaceholder');
- }
- @override
- void showToolbar() {
- // print('showToolbar');
- }
- }
|