36

When i select a Textfield, the keyboard is going to be shown but the keyboard hide my selected TextField. Does someone have a solution?

Roshin Raphel
  • 2,612
  • 4
  • 22
  • 40
Anton Schrage
  • 1,181
  • 2
  • 14
  • 23
  • 1
    you migth want to follow this issue https://github.com/flutter/flutter/issues/10826 – Tree Jun 07 '18 at 09:06
  • Check this out it worked out for me. No Animation required. https://stackoverflow.com/a/58209885/15035067 – joseph joe Mampilly Mar 10 '21 at 07:13
  • My solution [here at this thread](https://stackoverflow.com/a/68857184/8138591) solves this problem. It's very short and simple, no animation required. – Son Nguyen Aug 20 '21 at 05:08

17 Answers17

37
 Scaffold(
    resizeToAvoidBottomInset: true,
    body: SingleChildScrollView(
      child: Container(
        child: Column(
          children: <Widget>[
            TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            ),
            TextFormField(
              decoration: InputDecoration(
                labelText: 'Enter Text',
              ),
            )
          ],
        ),
      ),
    )
);

// resizeToAvoidBottomPadding: false isDeprecated

use resizeToAvoidBottomInset: true.

Ankush Modi
  • 446
  • 4
  • 6
  • 1
    @Watanabe.N I know it's too late to reply on your comment. I just want to ask you that you are still facing the same or now your issue has been fixed. If still facing the same then let me know so I can help you for the same. – Ankush Modi Jun 08 '21 at 07:03
  • @AnkushModi Thank you for your kindness. In my case, finally, `resizeToAvoidBottomInset` solved the problem! – Watanabe.N Jun 08 '21 at 08:01
31

Compose an animation and move your TextField container up when a TextField gets focus.

For learning about composing animations refer to: Composing Animations and Chaining Animations in Dart's Flutter Framework

Use Flutter's FocusNode to detect the focus on a TextField

Edit:

Here I've written an example that does exactly what you want:

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Animation Demo',
      theme: new ThemeData(
        primaryColor: new Color(0xFFFF0000),
      ),
      home: new FormDemo(),
    );
  }
}

class FormDemo extends StatefulWidget {
  @override
  _FormDemoState createState() => _FormDemoState();
}

class _FormDemoState extends State<FormDemo> with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation _animation;

  FocusNode _focusNode = FocusNode();

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 300));
    _animation = Tween(begin: 300.0, end: 50.0).animate(_controller)
    ..addListener(() {
      setState(() {});
    });

    _focusNode.addListener(() {
      if (_focusNode.hasFocus) {
        _controller.forward();
      } else {
        _controller.reverse();
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    _focusNode.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomPadding: false, // this avoids the overflow error
      appBar: AppBar(
        title: Text('TextField Animation Demo'),
      ),
      body: new InkWell( // to dismiss the keyboard when the user tabs out of the TextField
        splashColor: Colors.transparent,
        onTap: () {
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Container(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            children: <Widget>[
              SizedBox(height: _animation.value),
              TextFormField(
                decoration: InputDecoration(
                  labelText: 'I move!',
                ),
                focusNode: _focusNode,
              )
            ],
          ),
        ),
      ),
    );
  }
}

Javid Noutash
  • 2,142
  • 17
  • 19
  • Can u send me a Codesample pls? – Anton Schrage Jun 08 '18 at 07:41
  • Thanks, but i got a Problem with the animation. The valuetype of Tween cant be assigned to variable of type animation. – Anton Schrage Jun 08 '18 at 10:24
  • the error will go away when you add `.animate(_controller)` to the end of Tween – Javid Noutash Jun 08 '18 at 10:28
  • Sry i saw my mistake. Thanks for help! – Anton Schrage Jun 08 '18 at 10:34
  • 2
    You should use dispose when using animation: "Best practice is that any object with a dispose method should, in its dispose method, call the dispose method of all the objects it owns that also have dispose methods. In general, always call dispose on an object with such a method if you are done with that object." @Ian Hickson – speedyGonzales Jul 05 '18 at 07:31
  • I agree with you @speedyGonzales, I don't know how I missed it, but I've edited my answer :) – Javid Noutash Jul 05 '18 at 10:59
  • Its not working in `Flutter 2.2.3`. Please update the answer with Null safety. – Jay Tillu Jul 23 '21 at 12:29
  • If you have got it working with `Flutter 2.2.3`, can you please update the answer @JayTillu? – Javid Noutash Jul 25 '21 at 22:56
  • Use `Focus(onFocusChange: (hasFocus) {}, child: Widget())` instead so u don't have to manage the `FocusNode()` yourself. This is able to detect if any widget in the widget subtree is focused and unfocused. – Son Nguyen Aug 20 '21 at 03:36
21

A pretty short way to realize this is by simply using a MediaQuery for getting the bottom view insets. This would look as follows:

...
return Column(
  children: <Widget>[
    TextField(
      decoration: InputDecoration.collapsed(hintText: "Start typing ..."),
      controller: _chatController,
    ),
    SizedBox(
      height: MediaQuery.of(context).viewInsets.bottom,
    ),
  ],
);
...

Hope it helps!

Lucas Aschenbach
  • 862
  • 1
  • 11
  • 17
19

Just cut and paste your body code in this -

SingleChildScrollView(
            child: Stack(
              children: <Widget>[
                  // your body code 
               ],
             ),
           ),
Harsh Kashyap
  • 256
  • 2
  • 5
  • 2
    This doesnt work. This will make content scrollable with its content, the problem isn't inability to scroll but textfield not popping above keyboad. I have tried these. Still struggling. – Firaun Apr 28 '21 at 21:47
6

In my case I had to combine answer given by @Javid Noutash which uses AnimationController along with scrollPadding property of TextFormField. code:

Add this line in build method

double bottomInsets = MediaQuery.of(context).viewInsets.bottom;

Add scrollPadding property

return ListView(
children:[

...widgets,
Container(
margin:EdgeInsets.only(
   top:1.0,
   left:1.0,
   right:1.0,
   bottom:_focusNode.hasFocus && bottomInsets != 0?
          _animation.value : 1.0),
child:TextFormField(
   decoration: InputDecoration(
                  labelText: 'I move!',
               ),
   focusNode: _focusNode,
   scrollPadding: EdgeInsets.only(bottom:bottomInsets + 40.0),
  ),
 ),
]
);

Note: Combine this code with @Javid Noutash's code

Firosh Vasudevan
  • 671
  • 10
  • 11
5

I had the same problem where the parent widget is Material and the other widgets are inside a ListView. The problem was fixed when I changed the parent widget to Scaffold without any extra code and the TextField, TextFormField in my case, is being showed above the Keyboard automatically. So, if you encountered this problem just make sure to have Scaffold as the main widget. 1

3

The most simple way is to just wrap it with

SingleChildScrollView( ... )

When the textfield is on the page bottom and the keyboard appears, the textfield is automatically scrolled up. Then the text may be entered right above the keyboard.

3

Wrap your widget into Padding and set padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),

Kien Vu
  • 460
  • 4
  • 8
2

My way here

Scaffold(
    resizeToAvoidBottomInset: false,
    resizeToAvoidBottomPadding: false,
    body: Container(
      decoration: BoxDecoration(
          image: DecorationImage(
              image: AssetImage('images/Bg img.png'), fit: BoxFit.fill)),
      child: Padding(
        padding: EdgeInsets.only(
            bottom: MediaQuery.of(context).viewInsets.bottom),
        child: CustomScrollView(
          slivers: [
            SliverFillRemaining(
              hasScrollBody: false,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                .............

This template has some advantages:

  • Move content up when the keyboard appears
  • Column using spaceBetween inside a scroll view
  • Background is sticked phone scren and never change event the keyboard ups
Quinto
  • 31
  • 4
2

I had a very complex widget with Stack, Column and Single ChildChildScrollView, and I fixed it by adding a padding to the SCSV like this:

child: Stack(
  children: [
    Padding(
      padding: const EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
      child: SingleChildScrollView(
        child: Column(
          children: [... a lot of children here, one of them is a TextField],
        ),
      ),
    ),
    // a widget at the bottom of the stack that shows despite the size of the scrollable column
  ],
),
Miro
  • 364
  • 1
  • 12
1
<activity
        android:name="..ActivityName"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize"/>

only for android if you use FlutterFragment add configChanges and windowSoftInputMode for the Activity.

another way add your TextField to a ListView

ListView(
   children: <Widget>[
     TextField(),
     TextField(),
     ]
)
Karzan Kamal
  • 1,074
  • 10
  • 9
0

The above does not work if you have a CustomScrollview in a NestedScrollView.

  1. First, you need to give the TextField a focusNode.

    TextField(focusNode:_focusNode(),
      ...);
    
  2. Use NestedScrollViewState to get access to the innerScrollController of the NestedScrollView. You can view the example here on how to get the innerScrollController. Declare a globalKey and assign it to NestedScrollView.

     body: NestedScrollView(
        key: globalKey,
        ...)
    
  3. Setup the focusNode Listener to listen for when the textfield has been activated and animate the innerScrollController accordingly.

    void initState() {
      super.initState();

      _focusNode.addListener(() {
        if (_focusNode.hasFocus) {

          double innerOffSet = globalKey.currentState.innerController.offset;
          if(innerOffSet < 100)
            globalKey.currentState.innerController.jumpTo(innerOffSet+100);
      }

    });


  }
karmelcorn
  • 512
  • 1
  • 5
  • 12
0
var _contentController;

void _settingModalBottomSheet(BuildContext context, String initialText) {
   _contentController = new TextEditingController(text: initialText);
    showModalBottomSheet(
        context: context,
        isDismissible: true,
        builder: (BuildContext bc) {
          return Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Container(
                height: 40,
                margin: EdgeInsets.only(left: 4, right: 4, bottom: 8),
                decoration: BoxDecoration(
                  color: AppColor.bgTextFieldComment,
                  borderRadius: BorderRadius.circular(16),
                ),
                child: Row(
                  children: <Widget>[
                    Expanded(
                      child: Padding(
                          padding: EdgeInsets.only(left: 24),
                          child: TextField(
                            focusNode: _contentFocusNode,
                            autofocus: true,
                            controller: _contentController,
                            decoration: InputDecoration(
                              hintText: 'Enter Content',
                              border: InputBorder.none,
                              fillColor: AppColor.bgTextFieldComment,
                            ),
                            keyboardType: TextInputType.multiline,
                            maxLines: null,
                            style: TextStyle(
                              color: Colors.black87,
                              fontSize: 16,
                              fontStyle: FontStyle.normal,
                            ),
                          )),
                    ),
                    InkWell(
                      child: Padding(
                        padding: EdgeInsets.only(left: 4, right: 4),
                        child: Icon(
                          Icons.send,
                          color: Colors.blue,
                        ),
                      ),
                      onTap: () {
                          // do ON TAP
                      },
                    ),
                  ],
                ),
              ),
              SizedBox(
                height: MediaQuery.of(bc).viewInsets.bottom,
              ),
            ],
          );
        },).then((value) {
      print('Exit Modal');
    });
    print('request focus');
    _contentFocusNode.requestFocus();
  }
O Thạnh Ldt
  • 1,103
  • 10
  • 11
0

Instead of TextField, use TextFormField and wrap the widget with a list of TextFormField to Form:

Form(
  child: Column(
    children: <Widget> [
      TextFormField(),
      TextFormField(),
        ...
      TextFormField(),
    ]
  )
)
double-beep
  • 5,031
  • 17
  • 33
  • 41
0

you can easily try to use Flexible widget just wrap your widget with it


Flexible(
            child: Image(
              image :
            AssetImage('assets/logo.png'),

            ),
          ),

0

Wrap with MaterialApp, it should work.

 @override
  Widget build(BuildContext context) {
    buildContext = context;
    return ScreenUtilInit(
      designSize: getDeviceSize(context),
      splitScreenMode: true,
      builder: (BuildContext buildContext, Widget? child) {
        return MaterialApp(
          theme: Styles.appTheme(),
          home: Container(
            decoration: const BoxDecoration(
              color: AppColors.backgroundColor,
            ),
Exceptional
  • 2,994
  • 1
  • 18
  • 25
-3

It's very easy in my case check out code

         Column(
          children: [
            Expanded(
              child:// Top View,
            ),
            postSend // edittext. and button 
          ],
        )
Hitesh sapra
  • 248
  • 2
  • 12