Как прокрутить до нижней части SingleChildScrollView, когда TextField получает фокус? - PullRequest
1 голос
/ 16 апреля 2019

Итак, у меня есть страница входа в систему с двумя TextFields, а затем RaisedButton для входа в систему в самом низу.Когда я нажимаю на поле электронной почты и появляется всплывающая клавиатура, я бы хотел, чтобы SingleChildScrollView (родительский элемент всего на странице) прокрутил до maxScrollExtent.

Вещи, которые я пробовал, которые не сработали:

  • Использование возможности Scaffold делать это автоматически (Scaffold - родительский виджет всего в приложении)
  • Использование этого урока , в котором создается вспомогательный виджет.Также использует WidgetBindingsObserver, но учебник в целом не работает для меня.Интересно, может ли WidgetBindingsObserver по-прежнему быть полезным, однако.

Что почти работает:

  • Присоединение FocusNode к TextForm, затем присоединение слушателя в initState (), который будетанимировать до maxScrollExtent, когда он имеет фокус.

Почти, вот что я имею в виду (извините обесцвечивание GIF):

enter image description here

Как вы видите, он не работает с первого раза, поэтому мне нужно нажать на поле пароля, а затем повторно указать поле электронной почты, чтобы его оживить.Я попытался добавить задержку (даже до 500 мс), чтобы у окна просмотра было время полностью изменить размер, прежде чем это сделать, но это тоже не сработало.

Если вы узнаете эту тему входа, это потому, что я адаптировал ее с здесь .Файл довольно длинный, но вот соответствующие биты:

@override
  void initState() {
    super.initState();
    scrollController = ScrollController();
    focusNode = FocusNode();

    focusNode.addListener(() {
      if (focusNode.hasFocus) {
        scrollController.animateTo(scrollController.position.maxScrollExtent,
            duration: Duration(milliseconds: 500), curve: Curves.ease);
      }
    });

    _emailFieldController = TextEditingController();
    _passFieldController = TextEditingController();

    _emailFieldController.addListener(() {
      _emailText = _emailFieldController.text;
    });

    _passFieldController.addListener(() {
      _passText = _passFieldController.text;
    });
  }
 @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      controller: scrollController,
      child: Container(
        height: MediaQuery.of(context).size.height,
        decoration: BoxDecoration(
          color: Colors.white,
          image: DecorationImage(
            colorFilter: ColorFilter.mode(
                Colors.black.withOpacity(0.05), BlendMode.dstATop),
            image: AssetImage('assets/images/mountains.jpg'),
            fit: BoxFit.cover,
          ),
        ),
        child: new Column(
          children: <Widget>[
            // this is where all other widgets in the file are

Container(
              width: MediaQuery.of(context).size.width,
              margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
              alignment: Alignment.center,
              decoration: BoxDecoration(
                border: Border(
                  bottom: BorderSide(
                      color: Colors.deepPurple,
                      width: 0.5,
                      style: BorderStyle.solid),
                ),
              ),
              padding: const EdgeInsets.only(left: 0.0, right: 10.0),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  Expanded(
                    child: TextField(
                      controller: _emailFieldController,
                      keyboardType: TextInputType.emailAddress,
                      focusNode: focusNode,
                      obscureText: false,
                      textAlign: TextAlign.left,
                      decoration: InputDecoration(
                        border: InputBorder.none,
                        hintText: 'coolname@bestemail.com',
                        hintStyle: TextStyle(color: Colors.grey),
                      ),
                    ),
                  ),
                ],
              ),
            ),

Любое руководство будет с благодарностью.Спасибо!

1 Ответ

2 голосов
/ 16 апреля 2019

Используйте addPostFrameCallback для прослушивания после создания виджета.

          _onLayoutDone(_){
              FocusScope.of(context).requestFocus(focusNode);
          } 

          @override
          void initState() {
            //... your stuff

            WidgetsBinding.instance.addPostFrameCallback(_onLayoutDone);
            super.initState();
          }

ОБНОВЛЕНИЕ

Я вижу ошибку при первом использовании scrollController.position.maxScrollExtentзначение равно 0, после того как вы нажали на пароль textField и изменили фокус на email, теперь maxScrollExtent отличается, потому что клавиатура открыта.

Если вы хотите, чтобы это работало, сделайтелогика для вычисления пробела и установки значения напрямую.

Если вы используете

 scrollController.animateTo(180.0,
        duration: Duration(milliseconds: 500), curve: Curves.ease);

Это должно работать.

...