11

In android version, Flutter TextEditingController does not scroll above keyboard like default text fields do when you start typing in field. I tried to look in sample apps provided in flutter example directory, but even there are no example of TextEditController with such behaviour.

Is there any way to implement this.

Thanks in advance.

Ganapat
  • 6,984
  • 3
  • 24
  • 38

6 Answers6

21

so simple

if your textfields is between 5-10 fields

 SingleChildScrollView(
     reverse: true,  // add this line in scroll view
     child:  ...
)
Rahman Rezaee
  • 1,943
  • 16
  • 24
6

I think my answer might be the cleanest solution for this problem:

@override
Widget build(BuildContext context) {
  /// Get the [BuildContext] of the currently-focused
  /// input field anywhere in the entire widget tree.
  final focusedCtx = FocusManager.instance.primaryFocus!.context;

  /// If u call [ensureVisible] while the keyboard is moving up
  /// (the keyboard's display animation does not yet finish), this
  /// will not work. U have to wait for the keyboard to be fully visible
  Future.delayed(const Duration(milliseconds: 400))
      .then((_) => Scrollable.ensureVisible(
            focusedCtx!,
            duration: const Duration(milliseconds: 200),
            curve: Curves.easeIn,
          ));
  /// [return] a [Column] of [TextField]s here...
}

Every time the keyboard kicks in or disappears, the Flutter framework will automatically call the build() method for u. U can try to place a breakpoint in the IDE to figure out this behavior yourself.

Future.delayed() will first immediately return a pending Future that will complete successfully after 400 milliseconds. Whenever the Dart runtime see a Future, it will enter a non-blocking I/O time (= inactive time = async time = pending time, meaning that the CPU is idle waiting for something to complete). While Dart runtime is waiting for this Future to complete, it will proceed to the lines of code below to build a column of text fields. And when the Future is complete, it will immediately jump back to the line of code of this Future and execute .then() method.

More about asynchronous programming from this simple visualization about non-blocking I/O and from the Flutter team.

Son Nguyen
  • 2,991
  • 2
  • 19
  • 21
4

Flutter does not have such thing by default.

Add your TextField in a ListView. create ScrollController and assign it to the ListView's controller.

When you select the TextField, scroll the ListView using:

controller.jumpTo(value);

or if you wish to to have scrolling animation:

controller.animateTo(offset, duration: null, curve: null);

EDIT: Of course the duration and curve won't be null. I just copied and pasted it here.

Arnold Parge
  • 6,684
  • 2
  • 30
  • 34
4

Thank you all for the helpful answers @user2785693 pointed in the right direction.
I found complete working solution here: here

Issue with just using scroll or focusNode.listner is, it was working only if I focus on textbox for the first time, but if I minimize the keyboard and again click on same text box which already had focus, the listner callback was not firing, so the auto scroll code was not running. Solution was to add "WidgetsBindingObserver" to state class and override "didChangeMetrics" function.

Hope this helps others to make Flutter forms more user friendly.

Ganapat
  • 6,984
  • 3
  • 24
  • 38
1

This is an attempt to provide a complete answer which combines information on how to detect the focus from this StackOverflow post with information on how to scroll from Arnold Parge.

I have only been using Flutter for a couple days so this might not be the best example of how to create a page or the input widget.

The link to the gist provided in the other post also looks like a more robust solution but I haven't tried it yet. The code below definitely works in my small test project.

import 'package:flutter/material.dart';

class MyPage extends StatefulWidget {
  @override createState() => new MyPageState();
}

class MyPageState extends State<MyPage> {
  ScrollController _scroll;
  FocusNode _focus = new FocusNode();

  @override void initState() {
    super.initState();
    _scroll = new ScrollController();
    _focus.addListener(() {
      _scroll.jumpTo(-1.0);
    });
  }

  @override Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Some Page Title'),
      ),
      body: new DropdownButtonHideUnderline(
        child: new SafeArea(
          top: false,
          bottom: false,
          child: new ListView(
            controller: _scroll,
            padding: const EdgeInsets.all(16.0),
            children: <Widget>[

              // ... several other input widgets which force the TextField lower down the page ...

              new TextField(
                decoration: const InputDecoration(labelText: 'The label'),
                focusNode: _focus,
              ),
            ],
          ),
        ),
      ),
    );
  }
}
user2785693
  • 935
  • 1
  • 8
  • 7
0

I have also encountered the same problem. Setting MaterialApp as parent and main widget solved this problem for me.

VolcanoCoder
  • 423
  • 5
  • 7