3

I have chat window in Flutter app. Messages are presented as widgets inside ListView widget and I also have widget for message input attached to bottom of the window.

I want to

  1. hide keyboard when I scroll the ListView
  2. scroll to last message when new is added from InputWidget

code:

class _MessagesPageState extends State<MessagesPage> {
  final ScrollController listScrollController = ScrollController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    ....
    body: Stack(
        children: [
          ListView.builder(
              controller: listScrollController
              ....
          ),
          InputWidget()]
    );
}

class InputWidget extends StatelessWidget {

  final TextEditingController _textEditingController = TextEditingController();

....
Row (
  children: [
    TextField(
     controller: _textEditingController
    ), 
    IconButton(icon: ...., onPressed: (){})
  ]
 )}
Haroun Hajem
  • 5,223
  • 3
  • 26
  • 39
moonvader
  • 19,761
  • 18
  • 67
  • 116

3 Answers3

8

For hiding keyboard on listview scrolling, you simply add keyboardDismissBehavior to it. Example

ListView(
 keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
 children: [],
)
BLB
  • 663
  • 1
  • 14
  • 27
5

As to point 1 of you question :

You can create a listener function for listScrollController containing a call to an anonymous FocusNode (idea taken from this highly voted answer), and when any scroll event occurs, focus will be taken from your TextField and keyboard will be dismissed:

 class _MessagesPageState extends State<MessagesPage> {

 final ScrollController listScrollController = ScrollController();

 @override
 void initState() {
   listScrollController.addListener(_scrollListener);
   super.initState();
 }

 _scrollListener() {
   FocusScope.of(context).requestFocus(FocusNode());
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
   ....
   body: Stack(
    children: [
      ListView.builder(
          controller: listScrollController
          ....
      ),
      InputWidget(controller: listScrollController)]
   );
}

Point 2 :

You'll notice that I modified your InputWidget to take a ScrollController as a parameter, so you can pass your ListView controller to it. and when the IconButton is pressed, listScrollController will jump to the end as you desire.

 class InputWidget extends StatelessWidget {

 InputWidget({Key key,this.controller}) : super(key: key);

 final ScrollController controller ;

 final TextEditingController _textEditingController = TextEditingController();

 ....
 Row (
  children: [
    TextField(
      controller: _textEditingController
    ), 
    IconButton(icon: ...., onPressed: (){
      controller.jumpTo(controller.position.maxScrollExtent);
    })
  ]
 )}
Mazin Ibrahim
  • 7,433
  • 2
  • 33
  • 40
3

it's easy..Follow these step..

  1. Change class to StatefullWidget
  2. create final ScrollController listScrollController = ScrollController();
  3. ListView should be like this:

         ListView.builder(
              controller: listScrollController,
              reverse: true,
    
  4. If you use firebase change order by like this:

    .orderBy('timestamp', descending: true)

  5. Add this code in your Send button

listScrollController.animateTo(0.0,duration: Duration(milliseconds: 300), curve: Curves.easeOut);

Automatically scroll up your textField, Add your textField and ListView inside Stack

BIS Tech
  • 17,000
  • 12
  • 99
  • 148