Set cursor position anywhere in TextFormField and add/remove text there Flutter

Viewed 24

I am trying to add a TextFormField in which while typing text if user want to edit previous typed text he can do so. I want to move the cursor to anywhere position in the typed text and add/remove text. This is Flutter desktop application currently, for which I am asking this question.

Column(children: [
Container(
margin: EdgeInsets.only(top: 10),
                          height: 140,
                          child: TextFormField(
                            controller: footer,
                            keyboardType: TextInputType.multiline,
                            cursorColor: Colors.grey[700],
                            validator: (value) {
                              if (value!.isEmpty)
                                return 'Please fill this field';
                              else
                                return null;
                            },
                            maxLines: 5,
                            onChanged: (value)
                            {
                              initText = footer.text;
                              globalKey.currentState!
                                  .clearPreviousText(initText);
                            },
                            decoration: InputDecoration(
                              labelText: 'Footer Text',
                              labelStyle: TextStyle(color: Colors.grey[700]),
                              contentPadding: EdgeInsets.symmetric(
                                  horizontal: 12, vertical: 15),
                              border: OutlineInputBorder(
                                  borderSide: BorderSide(
                                      color: Theme.of(context)
                                          .focusColor
                                          .withOpacity(0.2))),
                              focusedBorder: OutlineInputBorder(
                                  borderSide: BorderSide(
                                      color: Theme.of(context)
                                          .focusColor
                                          .withOpacity(0.5))),
                              enabledBorder: OutlineInputBorder(
                                  borderSide: BorderSide(
                                      color: Theme.of(context)
                                          .focusColor
                                          .withOpacity(0.2))),
                            ),
                            onTap: () {
                              
                            },
                          ),
                        ),
                        Container(
            child: KeyboardWidget(
              globalKey,
              addLine: () {
              },
              keyboardText: (text) {
                print('TEXT TYPED: $text');
                setState(
                  () {
                   
                      footer.text = text;
                      footer.selection = TextSelection.collapsed(
                          offset: footer.text.length);
                    
                  },
                );
              },
              bottomPadding: 10.0,
              keyboardType: 'alphanumeric',
              initialText: initText,
              hide: false,
            ),
          ),
       ],
      )

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:virtual_keyboard_multi_language/virtual_keyboard_multi_language.dart';

class KeyboardWidget extends StatefulWidget {
  Function(String) keyboardText;
  double bottomPadding;
  String keyboardType;
  String initialText;
  bool hide;
  VoidCallback addLine;

  KeyboardWidget(
    Key? key, {
    required this.keyboardText,
    required this.bottomPadding,
    required this.keyboardType,
    required this.initialText,
    required this.hide,
    required this.addLine,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return KeyboardWidgetState();
  }
}

class KeyboardWidgetState extends State<KeyboardWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<Offset> _offsetAnimation;
  late String instructions;
  bool shiftEnabled = false;
  bool isNumericMode = true;
  late bool showKeyboard;
  bool capsLockOn = false;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    instructions = widget.initialText;
    showKeyboard = false;
    _controller = AnimationController(
      duration: const Duration(milliseconds: 350),
      vsync: this,
    );
    _offsetAnimation = Tween<Offset>(
      begin: const Offset(0.0, 1.5),
      end: const Offset(0.0, 0.0),
    ).animate(CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOut,
    ));
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.dismissed) {
        setState(() {
          showKeyboard = false;
        });
      }
    });
    if (!widget.hide) {
      showKeyboard = true;
      _controller.forward();
    }
  }

  void dispose() {
    // TODO: implement dispose
    _controller.dispose();
    super.dispose();
  }

  _onKeyPress(VirtualKeyboardKey key) {
    if (key.keyType == VirtualKeyboardKeyType.String) {
      if (capsLockOn) {
        instructions = instructions + (key.text!.toUpperCase());
      } else {
        instructions = instructions + (key.text ?? '');
      }
      widget.keyboardText(instructions);
    } else if (key.keyType == VirtualKeyboardKeyType.Action) {

      switch (key.action) {
        case VirtualKeyboardKeyAction.Backspace:
          if (instructions.isEmpty) break;
          instructions = instructions.substring(0, instructions.length - 1);
          widget.keyboardText(instructions);
          break;

        case VirtualKeyboardKeyAction.Space:
          instructions = instructions + (key.text ?? '');
          widget.keyboardText(instructions);

          break;
        case VirtualKeyboardKeyAction.Shift:
          capsLockOn = !capsLockOn;

          break;
        case VirtualKeyboardKeyAction.Return:
          instructions = instructions + '\n';
          widget.keyboardText(instructions);

          break;
        default:
      }
      print('TEXT: $instructions');
    }
  }

  clearPreviousText(String text) {
    instructions = text;
  }

  animateKeyboard(value) async {
    if (value) {
      if (!showKeyboard) {
        setState(() {
          showKeyboard = value;
        });
        _controller.forward();
      }
    } else {
      setState(() {
        showKeyboard = value;
      });
      _controller.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return showKeyboard
        ? SlideTransition(
            position: _offsetAnimation,
            child: Container(
              width: double.infinity,
              margin: EdgeInsets.only(top: 10),
              decoration: BoxDecoration(
                color: Color(0XFFffffff),
                borderRadius: BorderRadius.all(Radius.circular(10)),
                boxShadow: [
                  BoxShadow(
                      color: Theme.of(context).focusColor.withOpacity(0.1),
                      blurRadius: 6,
                      offset: Offset(0, -5)),
                ],
              ),
              child: Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  Container(
                    padding: EdgeInsets.only(top: 5),
                    child: ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        shape: CircleBorder(side: BorderSide.none),
                        padding:
                            EdgeInsets.symmetric(vertical: 5, horizontal: 5),
                        primary: Colors.grey[300],
                      ),
                      onPressed: () async {
                        _controller.reverse();
                        showKeyboard = false;
                      },
                      child: FittedBox(
                        fit: BoxFit.fill,
                        child: Icon(
                          Icons.keyboard_arrow_down,
                          color: Colors.grey[800],
                          size: 30,
                        ),
                      ),
                    ),
                  ),
                  Container(
                    child: VirtualKeyboard(
                      width: 600,
                      textColor: Colors.grey[800]!,
                      fontSize: 20,
                      type: widget.keyboardType == 'numeric'
                          ? VirtualKeyboardType.Numeric
                          : VirtualKeyboardType.Alphanumeric,
                      onKeyPress: _onKeyPress,
                    ),
                  ),
                ],
              ),
            ),
          )
        : SizedBox();
  }
}

enter image description here

This is my text field and I want to edit the text where cursor is placed right now.

header.selection = TextSelection.collapsed(offset: header.text.length); This piece of code is only adding text at the end of line no matter where the cursor is placed.

Anyone help me please with this issue.

Thanks

0 Answers
Related