【问题标题】:Why do my containers size bigger than the screen size that causes the SingleChildScrollView() to scroll when the keyboard is down?为什么我的容器尺寸大于导致 SingleChildScrollView() 在键盘按下时滚动的屏幕尺寸?
【发布时间】:2020-07-04 01:10:59
【问题描述】:

我正在颤振中构建一个 RegisterPage,并将我的脚手架分成两个容器。一个用于上半部分,另一个用于下半部分,这样徽标/标题可以在上半部分,表格在下半部分。

现在我在 android 上测试后注意到键盘与输入字段重叠。所以我添加了一个 SingleChildScrollView() 视图来解决这个问题。但有一个问题。内容似乎太大了,即使键盘按下,您现在也可以随时滚动。我添加了一个视频来说明我的意思。

我认为这个空间对此负责

看起来该空间是为 android 导航栏保留的。我该如何删除它?或者我怎样才能以这样的方式调整我的容器大小,以便它们考虑到这一点?为了清楚起见,我最想知道的是如何在键盘按下时停止 SingleChildScrollView() 滚动,这可能是由于容器太大造成的。

the_register_page.dart

  @override
  Widget build(BuildContext context) {
    final AuthenticationProvider authenticationProvider = Provider.of<AuthenticationProvider>(context);
    return Scaffold(
      backgroundColor: Theme.of(context).backgroundColor,
      body: Center(
        child: ScrollConfiguration(
          behavior: ScrollBehaviourWithoutGlow(),
          child: SingleChildScrollView(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,
              children: [
                Container(
                  decoration: BoxDecoration(color: Colors.red),
                  height: MediaQuery.of(context).size.height / 2,
                  child: _buildLogo(),
                ),
                Container(
                  decoration: BoxDecoration(color: Colors.green),
                  height: MediaQuery.of(context).size.height / 2,
                  child: _buildRegisterForm(authenticationProvider),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

请注意,我使用了 SystemChrome.setEnabledSystemUIOverlays([]);在我的 main.dart 中。

ma​​in.dart

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    SystemChrome.setEnabledSystemUIOverlays([]);

    return MultiProvider(
      providers: [
        ChangeNotifierProvider<PreferencesProvider>(
            create: (_) => PreferencesProvider()),
        ChangeNotifierProvider<AuthenticationProvider>(
            create: (_) => AuthenticationProvider()),
        Provider<GroupProvider>(create: (_) => GroupProvider()),
        Provider<UserProvider>(
          create: (_) => UserProvider(),
        ),
      ],
      child: Consumer<PreferencesProvider>(
        builder: (context, preferences, _) => MaterialApp(
          home: TheSplashPage(),
          routes: <String, WidgetBuilder>{
            TheGroupPage.routeName: (BuildContext context) => TheGroupPage(),
            TheSettingsPage.routeName: (BuildContext context) =>
                TheSettingsPage(),
            TheProfilePage.routeName: (BuildContext context) =>
                TheProfilePage(),
            TheGroupCreationPage.routeName: (BuildContext context) =>
                TheGroupCreationPage(),
          },
          theme: preferences.isDarkMode
              ? DarkTheme.themeData
              : LightTheme.themeData,
          debugShowCheckedModeBanner: false,
        ),
      ),
    );
  }
}

由于这篇文章没有得到任何答案,我决定上传一个视频来说明我的意思。这是视频。如您所见,即使键盘按下,您也可以滑动,这不是我想要的。

https://www.youtube.com/watch?v=Rm91KMFqs60

编辑

这是在安卓模拟器上测试的

我的 android 设备是带有 android 7 的 Lenovo P2

编辑

我可以确认这个底部区域是原因。我查看了我的电脑屏幕上的像素高度,然后从容器中减去了它,现在当键盘按下时我无法滚动,这正是我想要的。

所以我想删除这个区域或知道它的高度如何?

【问题讨论】:

  • 导航栏的自动隐藏行为是由您的应用还是由您的设备设置设置的?您使用什么设备和 Android 版本?你能在模拟器中复制它吗?
  • 我将信息添加到我的帖子中。我在 main.dart 中设置了隐藏行为。我在自己的设备上测试了它,一个带有 android 7 的 Lenovo P2 和一个带有 android 10 的 Pixel 2

标签: android flutter dart


【解决方案1】:

你很亲密。将SystemChrome 颜色设置为透明只会使它们透明,但不会将您的应用程序绘制到导航或状态栏的顶部。修复过程分为两步。

  1. 设置SystemChrome.setEnabledSystemUIOverlays([SystemUIOverlay.top]) 仅显示通知栏或设置SystemChrome.setEnabledSystemUIOverlays([]) 全屏显示您的应用。

  2. 在您的 Scaffold 中,当您希望屏幕显示在底部系统 UI 覆盖层之上时,将 resizeToBottomInset 属性设置为 false,并在键盘打开时设置为 true

完整代码示例:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Display your app in full-screen mode
  SystemChrome.setEnabledSystemUIOverlays([]);
  // Show the notification bar but not the navigation bar
  // SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top]);

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  bool resizeToAvoidBottom;

  @override
  void initState() {
    super.initState();
    // Do not avoid bottom by default, this allows the display to paint over
    // where the Android button bar would be.
    resizeToAvoidBottom = false;
  }

  void setResize(bool resize) {
    setState(() {
      resizeToAvoidBottom = resize;
    });
  }

  @override
  Widget build(BuildContext context) {
    final height = MediaQuery.of(context).size.height / 2;

    return Scaffold(
      resizeToAvoidBottomInset: resizeToAvoidBottom,
      body: Container(
        height: MediaQuery.of(context).size.height,
        child: SingleChildScrollView(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Placeholder(
                fallbackHeight: height,
              ),
              Container(
                height: height,
                  color: Colors.green,
                  child: Column(
                    children: <Widget>[
                      // Text fields update the resize property so that you
                      // can still scroll the display when the keyboard is up
                      // You will need to change when setResize(false) is
                      // called to suit the needs of your app
                      TextField(
                        onTap: () {
                          setResize(true);
                        },
                        onSubmitted: (str) {
                          setResize(false);
                        },
                      ),
                      TextField(
                        onTap: () {
                          setResize(true);
                        },
                        onSubmitted: (str) {
                          setResize(false);
                        },
                      ),
                    ],
                  ))
            ],
          ),
        ),
      ),
    );
  }
}

【讨论】:

  • 我也有SystemChrome.setEnabledSystemUIOverlays([]);,它在问题中。但是仅仅使用它并没有完全删除 ui 覆盖,所以我将它与 SystemChrome.setSystemUIOverlayStyle 结合使用。如果删除 SystemChrome.setSystemUIOverlayStyle 可以解决问题,我今天稍后再看看,但我不这么认为。
  • 刚刚测试,问题依旧
  • 看起来很老套,我自己也考虑过。没有优雅的解决方案吗?
  • 截至目前,没有。正如@vnztms 提到的,这目前是框架中的一个错误,并且在 github 存储库上针对此行为打开了一个问题。
  • 猜猜现在必须这样做
【解决方案2】:

这实际上是一个当前的Issue

您可以使用一种解决方法,即在您的 Scaffold 中设置 extendxBody: true。 但如果不是非常关键,我会等待修复部署。

澄清一下:我的回答是关于底部的空白。

【讨论】:

  • extendbody: true 底部没有空格。它还在那里
  • 我目前正在工作,所以我无法查看我的代码以找到正确的参数。我以为是这个。我回家后会调查的;)。在我链接的错误中,他们提到了以下内容: 'resizeToAvoidBottomPadding: false,' ,也许这有效?
  • 所以我刚刚签入了我的个人项目。当我在脚手架中设置“ resizeToAvoidBottomPadding: false ”时,主体会延伸到底部。但就像我说的,谨慎使用它,因为这只是一种解决方法;)
  • 是的,但是当键盘弹出时,您将无法看到输入字段,因为它会阻止 SingleChildScrollView() 工作。
  • 是的,我认为由于这个问题,您目前不能同时拥有两者。据我了解,如果键盘不可见,您希望这两个区域都恰好是屏幕的一半并且不可滚动?所以这仅仅是一个外观问题?如果是这样,您可能暂时忽略它,您可以恢复您的颤振版本,另一方面,您可以通过不为容器使用相当固定的高度来使您的布局更加动态。
猜你喜欢
  • 2012-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多