Search code examples
fluttertextfield

Flutter readonly Textfield set caret to end


I have a TextField that I set to readonly, and it contains a TextEditingController. When I set the text on the controller through code, I want the text field to jump all the way to the back.

enter image description here

TextField(
  readOnly: true,
  controller: _dialogStore.exportFolderPathController,
),

The store in this case is part of mobx, which I use instead of stateful widgets. But that doesn't matter for the question here.

I have a rather small text box. So when the text is long I want the text field to scroll all the way to the end. When I set the text on the scroll controller via exportFolderPathController.selection = TextSelection.collapsed(offset: exportFolderPathController.text.length);, it doesn't want to update, but when I set readonly to false, it does work.

I have been digging through the code and found hints of if(readonly), for showing the selection handlers.

Eventually I got it to work with a dirty bool and a Future.delayed solution like so:

Future<void> setFilePath(String filePath) async {
  _readonly = false;
  exportFolderPathController.text = filePath;
  exportFolderPathController.selection =
      TextSelection.collapsed(offset: exportFolderPathController.text.length);
  // wait for the scroll animation to finish
  await Future.delayed(const Duration(milliseconds: 300));
  _readonly = true;
}

I really don't like the Future.delayed here, since it's an assumtion that it will take a while for the animation to finish. What are my alternatives?

I saw that there is also the possibility to add a ScrollController, but I couldn't get that to work.


Solution

  • The quickest and easiest solution is below

    Initialize a scrollController

    final ScrollController _scrollController = ScrollController();
    

    Then assign that controller in TextField

    TextField(
      readOnly: true,
      controller: _dialogStore.exportFolderPathController,
      scrollController: _scrollController,
    )
    

    Last step is to add 2 lines in your setFilePath() method

    Future<void> setFilePath(String filePath) async {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        final scrollOffset = _scrollController.position.maxScrollExtent;
        _scrollController.jumpTo(scrollOffset);
      });
    }
    

    call above method in initState.

    And you're done. You'll achieve what you want.