Flutter SingleChildScrollView如何在键盘隐藏后立即自动滚动回initialScrollOffset

insrf1ej  于 2023-06-30  发布在  Flutter
关注(0)|答案(2)|浏览(133)

我有一个堆叠的Card,它在SingleChildScrollView中包含2个TextField。我的观点是,我想让SingleChildScrollView在两个TextField都被填充并点击 done 按钮后立即滚动回 initialScrollOffset。下面是我所做的,但不是我想要的。这里有没有人可以帮我,谢谢。

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:在下图中,我在填充两个TextField后向下滚动Card,以便运行autoScrollBackToPosition函数。

g6ll5ycj

g6ll5ycj1#

你能根据这个替换最后一个文本字段吗?

TextField(
  onSubmitted: (value) {
    autoBackToPosition(); //or something else
  },
),
rm5edbpk

rm5edbpk2#

经过几个小时的努力,我终于找到了解决办法。只是为了那些希望在他们的UI中有相同行为的人,这里是代码和简短的解释。
只是为键盘添加了 boolean 变量,然后在ScrollListener中添加了相同的 if 到第二个TextFieldonSubmitted()。不要忘记调整ScrollController s 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()
                      ],
                    ),
                  ),
                ),
              ),
            ),
          )
        ],
      )),
    );
  }
}

结果如下:

相关问题