Flutter 扩展/占用 TextFormField 以填充屏幕的其余部分

Posted

技术标签:

【中文标题】Flutter 扩展/占用 TextFormField 以填充屏幕的其余部分【英文标题】:Flutter Expand/Occupy TextFormField to Fill Rest of Screen 【发布时间】:2019-04-01 08:07:25 【问题描述】:

我有一个带有一些 TextFormField 的表单,我想扩展最后一个 TextFormField 以占据屏幕的其余部分。最后一个 TextFormField 可以有多行文本。

我无法做到这一点,并尝试了SizedBox.expand()Expanded 小部件,但没有运气。

下面是当前代码:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              "What is this new clas-s-room?"
            ),
            SizedBox(height: 8.0,),
            Expanded(
              child: Form(
              key: _formKey,
              child: ListView(
                padding: EdgeInsets.all(8.0),
                children: <Widget>[
                  Container(
                    padding: EdgeInsets.symmetric(vertical: 8.0),
                    child: TextFormField(
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: "Clas-s-room Name",
                        hintText: "What's name of the new clas-s-room?",
                      ),
                    )
                  ),
                  SizedBox(height: 8.0,),
                  Container(
                    padding: EdgeInsets.symmetric(vertical: 8.0),
                    child: TextFormField(
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: "Description",
                        hintText: "Description of the new clas-s-room",
                      ),
                      //maxLines: 5,
                    ),
                  ),
                ]
              ),
            ),
          ),
        ],
      ),
    ),
    );
  

【问题讨论】:

【参考方案1】:

我稍微编辑了您的代码。但是没有用。请参考以下代码。我将尝试在代码下方解释我的理解

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text("What is this new clas-s-room?"),
            SizedBox(
              height: 8.0,
            ),
            Expanded(
                child: Form(
              key: _formKey,
              child: Column(children: <Widget>[
                Container(
                    padding: EdgeInsets.symmetric(vertical: 8.0),
                    child: TextFormField(
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: "Clas-s-room Name",
                        hintText: "What's name of the new clas-s-room?",
                      ),
                    )),
                SizedBox(
                  height: 8.0,
                ),
                Expanded(
                  child: Container(
                    padding: EdgeInsets.symmetric(vertical: 8.0),
                    child: TextFormField(
                      maxLines: null,
                      decoration: InputDecoration(
                        border: OutlineInputBorder(),
                        labelText: "Description",
                        hintText: "Description of the new clas-s-room",
                      ),
                    ),
                  ),
                ),
              ]),
            )),
          ],
        ),
      ),
    );
  

我用您的代码检查了视图。 TextField 里面的 TextFormField 没有占据屏幕的其余部分。所以我编辑让TextField 拥有屏幕的其余部分。上面的代码就是这样做的。查看检查视图

但是有InputDecorator(它是我们的TextField 的孩子)绘制了边界线。在我们的例子中,它根据内容绘制边界线。

可能的解决方法是:

    maxLines = null 将把 TextField 扩展为内容组。但初始视图将是一行。 给出固定的maxLines(如 10 或 20),这看起来像是占据了屏幕。但它不是动态的(不会根据屏幕尺寸/屏幕方向而变化)

【讨论】:

这两种方法都有其局限性,但我想不出更好的办法。 +1 使用检查器!【参考方案2】:

您还可以在小部件渲染后使用addPostFrameCallbackinitState() 中设置contentPadding。 但是您必须根据上述所有小部件的位置和高度手动计算新高度。

例子:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget 
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final _tffKey1 =
      GlobalKey();
  final _tffKey2 = GlobalKey();
  final _scaffoldKey = GlobalKey();
  final _textKey = GlobalKey();
  double _height = 0;

  //Set callback that will be called after widgets are rendered.
  @override
  void initState() 
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) 
      final RenderBox scaffoldKeyBox = _scaffoldKey.currentContext.findRenderObject();
      final RenderBox tffBox = _tffKey1.currentContext.findRenderObject();
      final RenderBox textBox = _textKey.currentContext.findRenderObject();
      final tffPos = tffBox.localToGlobal(Offset.zero);
      final textPos = textBox.localToGlobal(Offset.zero);

      //Calculate widget's height.
      _height = (scaffoldKeyBox.size.height -
          (tffBox.size.height + tffPos.dy) -
          (textBox.size.height + textPos.dy));

      setState(() );
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Text(
              "What is this new clas-s-room?",
              key: _textKey,
            ),
            SizedBox(
              height: 8.0,
            ),
            Expanded(
              child: Form(
                key: _formKey,
                child:
                    ListView(padding: EdgeInsets.all(8.0), children: <Widget>[
                  Container(
                      padding: EdgeInsets.symmetric(vertical: 8.0),
                      child: TextFormField(
                        key: _tffKey1,
                        decoration: InputDecoration(
                          border: OutlineInputBorder(),
                          labelText: "Clas-s-room Name",
                          hintText: "What's name of the new clas-s-room?",
                        ),
                      )),
                  Container(
                    padding: EdgeInsets.symmetric(vertical: 8.0),
                    child: TextFormField(
                      key: _tffKey2,
                      decoration: InputDecoration(
                        contentPadding: EdgeInsets.only(left: 8, top: _height), // Set new height here
                        border: OutlineInputBorder(),
                        labelText: "Description",
                        hintText: "Description of the new clas-s-room",
                      ),
                    ),
                  ),
                ]),
              ),
            ),
          ],
        ),
      ),
    );
  

【讨论】:

【参考方案3】:

我知道这有点晚了,但答案已发布here。 您只需要以下内容

TextField(
  keyboardType: TextInputType.multiline,
  maxLines: whatever,
)

【讨论】:

【参考方案4】:

我找到了解决方案,也许它可以帮助某人。您可以创建 Container 或其他具有与 TextField 相同的边框的小部件,并使其扩展以填充整个屏幕,并使用 Stack 小部件将 TextField 放入 maxLines: null 且无边框。

[编辑] 它也可以在没有 Stack 小部件的情况下工作。这是我的代码

Expanded(
                  child: Material(
                    borderRadius: BorderRadius.circular(10),                      
                    color: Colors.white,
                    child: TextField(                         
                      decoration: InputDecoration(
                        border: InputBorder.none,  
                        hintText: "Description",                         
                      ),
                      keyboardType: TextInputType.multiline,
                      maxLines: null,
                    ),
                  ),
                ),

【讨论】:

以上是关于Flutter 扩展/占用 TextFormField 以填充屏幕的其余部分的主要内容,如果未能解决你的问题,请参考以下文章

Flutter Web - TextFormField 禁用复制和粘贴

Flutter(Web)提供程序不在发布模式下工作,但在调试中工作

Flutter中具有最小高度的扩展小部件

Flutter 文本字段随用户类型扩展

防止小部件填充Flutter中扩展的祖先

Flutter中常用的组件-Expanded