我有一个包含对话框的颤振网络应用程序(将来可能会成为桌面应用程序)。该对话框允许用户编辑包含元素列表的模型对象的属性。用户应该能够通过在列表中添加或删除元素来编辑列表。所以对话框内容的高度是可变的——它取决于列表中元素的数量。
我无法创建适当地动态调整大小的布局。我想要的是让对话框随着项目添加到列表中而增长,直到适合设备屏幕的最大尺寸。如果内容比这个大,列表中的元素应该是可滚动的。
我附上了两张我目前工作的截图;第一个有一个只有两个项目的列表,很容易显示。第二个是相同的对话框,其中许多项目显示溢出。
这是对话框的代码:
Widget build(BuildContext context) {
return AlertDialog(
actions: [
FlatButton(
child: const Text('CANCEL'),
onPressed: () => Navigator.of(context).pop(),
),
FlatButton(
child: const Text('OK'),
onPressed: () =>
Navigator.of(context).pop<Modifier>(_createModifier()),
),
],
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Damage Editor'),
Divider(),
columnSpacer,
DiceSpinner(
onChanged: (value) => setState(() => _dice = value),
initialValue: _dice,
textFieldWidth: 90.0,
),
columnSpacer,
Container(
padding: const EdgeInsets.only(left: 12.0, right: 12.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
border: Border.all(color: Colors.grey),
),
child: DropdownButton<DamageType>(
underline: Container(),
value: _type,
items: _damageTypeItems(),
onChanged: (value) => setState(() => _type = value),
),
),
columnSpacer,
SwitchListTile(
value: _direct,
onChanged: (state) => setState(() => _direct = state),
title: Text(_direct ? 'Internal (Direct)' : 'External (Indirect)'),
),
if (!_direct) ...<Widget>[
columnSpacer,
CheckboxListTile(
value: _explosive,
onChanged: (state) => setState(() => _explosive = state),
title: Text('Explosive'),
),
],
columnSpacer,
DynamicListHeader(
title: 'Enhancements/Limitations',
onPressed: () => setState(() =>
_modifiers.add(TraitModifier(name: 'Undefined', percent: 0))),
),
SingleChildScrollView(
child: ListBody(
children: _enhancementList(),
),
),
],
),
);
}
List<Widget> _enhancementList() {
var list = <Widget>[];
_modifiers.forEach(
(element) {
if (_modifiers.length > 0) list.add(columnSpacer);
list.add(_EnhancerEditor(element, index: _modifiers.indexOf(element),
onChanged: (index, enhancer) {
_modifiers[index] = enhancer;
}));
},
);
return list;
}
typedef TraitModifierCallback = void Function(int, TraitModifier);
class _EnhancerEditor extends StatefulWidget {
_EnhancerEditor(this.enhancer, {this.onChanged, this.index});
final TraitModifier enhancer;
final TraitModifierCallback onChanged;
final int index;
@override
__EnhancerEditorState createState() => __EnhancerEditorState();
}
class __EnhancerEditorState extends State<_EnhancerEditor> {
TextEditingController _nameController;
TextEditingController _percentController;
bool _validInput = true;
@override
void initState() {
super.initState();
_nameController = TextEditingController(text: widget.enhancer.name);
_nameController.addListener(_onChanged);
_percentController =
TextEditingController(text: widget.enhancer.percent.toString());
_percentController.addListener(_onChanged);
}
@override
void dispose() {
_nameController.removeListener(_onChanged);
_nameController.dispose();
_percentController.removeListener(_onChanged);
_percentController.dispose();
super.dispose();
}
void _onChanged() {
String text = _percentController.text.trim();
setState(() {
int value = int.tryParse(text);
_validInput = (value != null);
if (_validInput) {
widget.onChanged(widget.index,
TraitModifier(name: _nameController.text, percent: value));
}
});
}
@override
Widget build(BuildContext context) {
return IntrinsicHeight(
child: Row(
children: [
Expanded(
child: TextField(
controller: _nameController,
decoration: const InputDecoration(
labelText: 'Enhancer/Limitation',
border: const OutlineInputBorder(),
),
),
),
rowSmallSpacer,
SizedBox(
width: 80.0,
child: TextField(
controller: _percentController,
textAlign: TextAlign.end,
keyboardType: TextInputType.numberWithOptions(signed: true),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[0-9\-]'))
],
decoration: const InputDecoration(
suffixText: '%',
labelText: 'Pct',
border: const OutlineInputBorder(),
),
),
),
],
),
);
}
}