如何将 Widget 定位在 SingleChildScrollView 的底部?

How to position a Widget at the bottom of a SingleChildScrollView?

我需要使用 SingleChildScrollView 才能使用 keyboard_actions 以便我可以在 iOS 中的键盘顶部放置一个 "Done" 按钮(目前正在使用数字键盘)

SingleChildScrollView 将有一个列作为子项,然后有一个按钮放置在底部。我尝试使用 LayoutBuilder 强制执行 SingleChildScrollView.

的高度
LayoutBuilder(
      builder: (BuildContext context, BoxConstraints viewportConstraints) {
    return SingleChildScrollView(
        child: ConstrainedBox(
            constraints:
                BoxConstraints(minHeight: viewportConstraints.maxHeight),
            child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                mainAxisSize: MainAxisSize.max,
                children: <Widget>[
                  Column(),
                  // Spacer() ?
                  FlatButton()
                ])));
  });

我尝试将 BoxConstraintsmaxHeight 属性一起使用,但最终小部件不会在键盘出现时向上滚动。

旁注:脚手架的 resizeToAvoidBottomInsetresizeToAvoidBottomPadding 都设置为 true(默认值)

SingleChildScrollView 的问题在于它 shrikwrap 它是 children。 因此,要在两者之间设置自动调整大小的小部件 - 我们需要使用 MediaQuery 获取屏幕高度并使用 SizedBox 展开 - SingleChildScrollView.

此处按钮将位于屏幕底部。

工作代码:

double height = MediaQuery.of(context).size.height;

    SingleChildScrollView(
          child: SizedBox(
              height: height,
              child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  mainAxisSize: MainAxisSize.max,
                  children: <Widget>[
                    Column(
                      children: <Widget>[
                        Text('Dummy'),
                        Text('Dummy'),
                        Text('Dummy'),
                      ],
                    ),
                    Spacer(),
                    FlatButton(
                      onPressed: () {},
                      child: Text('Demo'),
                    )
                  ])),
        ) 

选择的答案实际上不起作用,因为使用 SizedBox 将 Column 的最大尺寸限制为屏幕的高度,因此您不能在其中放置任意数量的小部件(否则它们会离开屏幕而不可滚动)。

无论列中有多少小部件,此解决方案都有效: https://github.com/flutter/flutter/issues/18711#issuecomment-505791677

重要说明:它仅在列中的小部件具有固定高度时才有效(例如 TextInputField 没有固定高度)。如果它们的高度可变,则用固定高度的 Container 包裹它们。

您也可以使用此解决方法,您可以像这样在 SingleChildScrollView 中使用填充属性:

SingleChildScrollView(
padding: EdgeInsets.only(top: height),
child: yourWidgets(),

而高度是距离顶部的距离。
您还可以使用此行获取移动屏幕高度:

double height = MediaQuery.of(context).size.height;

我刚刚复制并粘贴了我找到的最佳解决方案,引用自@Quentin,由@NikitaZhelonkin 在 Github 上的 Flutter 第 18711 期中详细阐述。简直就是完美的解决方案!

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('AppBar'),
        ),
        body: LayoutBuilder(builder: (context, constraints) {
          return SingleChildScrollView(
              child: ConstrainedBox(
                  constraints: BoxConstraints(minWidth: constraints.maxWidth, minHeight: constraints.maxHeight),
                  child: IntrinsicHeight(
                    child: Column(
                        mainAxisSize: MainAxisSize.max,
                        children: [
                          Text('header'),
                          Expanded(
                            child: Container(
                              color: Colors.green,
                              child: Text('body'),
                            ),
                          ),
                          Text('footer'),
                        ]
                    ),
                  )
              )
          );
        })
    );
  }
}

我为自己找到的最佳解决方案。

将小部件居中并使用填充从上到下推动它们。

return Scaffold(
    resizeToAvoidBottomInset: true,
    //resizeToAvoidBottomPadding: false,
    backgroundColor: PrimaryColor,
    body: Center(
    SingleChildScrollView(child:
      _body())));


Widget _body() {
return Padding(
 padding: EdgeInsets.only(top: MediaQuery.of(context).size.height/2.7),
 child: Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.end,
    children: <Widget>[
      Text(
        'You have pushed the button this many times:',
      ),
      Visibility(
          visible:
              _userProvider.stateReqVMTokenSocial != 
       StateReqVM.Processing,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
           ...
           ...
           ...
            ],
          )),
      Visibility(
          visible:
              _userProvider.stateReqVMTokenSocial == 
         StateReqVM.Processing,
          child: CircularProgressIndicator()),
      Text(
        '',
        style: Theme.of(context).textTheme.headline4,
      ),
    ],
)
 );
}