skip to Main Content

I have a stacked Card that contains 2 TextFields inside a SingleChildScrollView. My point is, I want to make SingleChildScrollView to scroll back to initialScrollOffset immediately after both TextFields are filled and done button is tapped. Below is what I have accomplished but still not what I want.
Could anyone here can help me, thank you.

class Takok extends StatefulWidget {
  const Takok({super.key});

  @override
  State<Takok> createState() => _TakokState();
}

class _TakokState extends State<Takok> with TickerProviderStateMixin {
  TextEditingController user = TextEditingController();
  TextEditingController pass = TextEditingController();
  ScrollController _scrollController = ScrollController();
  void autoBackToPosition() {
    if (_scrollController.offset > 100) {
      _scrollController.animateTo(_scrollController.initialScrollOffset,
          duration: const Duration(milliseconds: 500),
          curve: Curves.decelerate);
    }
  }

  @override
  void initState() {
    _scrollController.addListener(autoBackToPosition);
    super.initState();
  }

  @override
  void dispose() {
    user.dispose();
    pass.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
          body: Stack(
        children: [
          Positioned.fill(
              child: Container(
            color: Colors.amber,
          )),
          Align(
            alignment: Alignment.bottomCenter,
            child: SingleChildScrollView(
              controller: _scrollController,
              physics: const BouncingScrollPhysics(),
              child: Container(
                margin: EdgeInsets.only(
                    top: MediaQuery.of(context).size.height * .32),
                height: MediaQuery.of(context).size.height,
                child: Card(
                  elevation: 6,
                  margin: const EdgeInsets.symmetric(horizontal: 20),
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(24)),
                  child: Padding(
                    padding:
                        const EdgeInsets.symmetric(horizontal: 20, vertical: 6),
                    child: Column(
                      children: [
                        SizedBox(
                          height: 50,
                        ),
                        TextField(
                          textInputAction: TextInputAction.next,
                        ),
                        SizedBox(
                          height: 20,
                        ),
                        TextField(),
                        SizedBox(
                          height: 30,
                        ),
                        Spacer()
                      ],
                    ),
                  ),
                ),
              ),
            ),
          )
        ],
      )),
    );
  }
}

PS: on the image below, I’m scrolling the Card downward after I fill both TextField so that the function autoScrollBackToPosition are running.

pic 1

2

Answers


  1. Chosen as BEST ANSWER

    After a couple of hours trying to solve this, finally I've found a solution. just for who want same behavior in their UI, here's the code and short explanation.

    Just added boolean variable for the keyboard if showed up, then added the same if inside ScrollListener to onSubmitted() on secondth TextField. And dont forget to adjust the height of ScrollControllers Offset

    import 'package:flutter/material.dart';
    import 'package:flutter_riverpod/flutter_riverpod.dart';
    
    class Takok extends StatefulWidget {
      const Takok({super.key});
    
      @override
      State<Takok> createState() => _TakokState();
    }
    
    class _TakokState extends State<Takok> with TickerProviderStateMixin {
      TextEditingController user = TextEditingController();
      TextEditingController pass = TextEditingController();
      ScrollController _scrollController = ScrollController();
      late bool isKeyboardShowed;  // to check if the keyboard is showed up or not
    
      void autoBackToPosition() {
        if (WidgetsBinding.instance.window.viewInsets.bottom != 0) {
          setState(() {
            isKeyboardShowed = true;
          });
        } else {
          setState(() {
            isKeyboardShowed = false;
          });
        }
        // adjust the height of Offset
        if (_scrollController.offset > 90 && !isKeyboardShowed) {
          _scrollController.animateTo(_scrollController.initialScrollOffset,
              duration: const Duration(milliseconds: 500),
              curve: Curves.decelerate);
        }
      }
    
      @override
      void initState() {
        isKeyboardShowed = false;
        _scrollController.addListener(autoBackToPosition);
        super.initState();
      }
    
      @override
      void dispose() {
        user.dispose();
        pass.dispose();
        _scrollController.removeListener(autoBackToPosition);
        _scrollController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
          child: Scaffold(
              body: Stack(
            children: [
              Positioned.fill(
                  child: Container(
                color: Colors.amber,
              )),
              Align(
                alignment: Alignment.bottomCenter,
                child: SingleChildScrollView(
                  controller: _scrollController,
                  physics: const BouncingScrollPhysics(),
                  child: Container(
                    margin: EdgeInsets.only(
                        top: MediaQuery.of(context).size.height * .32),
                    height: MediaQuery.of(context).size.height,
                    child: Card(
                      elevation: 6,
                      margin: const EdgeInsets.symmetric(horizontal: 20),
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(24)),
                      child: Padding(
                        padding:
                            const EdgeInsets.symmetric(horizontal: 20, vertical: 6),
                        child: Column(
                          children: [
                            SizedBox(
                              height: 50,
                            ),
                            TextField(
                              textInputAction: TextInputAction.next,
                            ),
                            SizedBox(
                              height: 20,
                            ),
                            TextField(
                              onSubmitted: (value) {
                                setState(() {
                                  // set the bool variable to false
                                  isKeyboardShowed = false;
                                  // this is the same part inside autoBackToPosition()
                                  if (_scrollController.offset > 90 &&
                                      !isKeyboardShowed) {
                                    _scrollController.animateTo(
                                        _scrollController.initialScrollOffset,
                                        duration: const Duration(milliseconds: 500),
                                        curve: Curves.decelerate);
                                  }
                                });
                              },
                            ),
                            SizedBox(
                              height: 30,
                            ),
                            Spacer()
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              )
            ],
          )),
        );
      }
    }
    
    

    Here is the result:

    enter image description here


  2. Can you replace the last textfield according to this and try it?

    TextField(
      onSubmitted: (value) {
        autoBackToPosition(); //or something else
      },
    ),
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search