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】:您还可以在小部件渲染后使用addPostFrameCallback
在initState()
中设置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 禁用复制和粘贴