如何解决创建动态增长的可滚动列表的最佳方法
我有一个波动的网络应用程序(将来可能会成为桌面应用程序),其中包含一个对话框。该对话框允许用户编辑包含元素列表的模型对象的属性。用户应该能够通过在列表中添加或删除元素来编辑列表。因此,对话框内容的高度可变-它取决于列表中元素的数量。
我在创建可以适当地动态调整大小的布局时遇到了麻烦。我想要的是对话框随着项目添加到列表中而增长,直至达到设备屏幕上的最大大小。如果内容大于此内容,则列表中的元素应可滚动。
我已经附上了我目前工作的两个屏幕截图;第一个列表只有两个项目,很容易显示。第二个是同一对话框,其中有许多项目显示溢出。
以下是对话框的代码:
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,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),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'),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',);
}
}
解决方法
您可以使用列表视图小部件代替列小部件
https://api.flutter.dev/flutter/widgets/ListView-class.html
Column(
mainAxisSize: MainAxisSize.min,children: <Widget>[
Container(
child: ListView.builder(
shrinkWrap: true,...
),);
],);
......
,这听起来似乎违反直觉,但您应该在Column中包含ListView。你们两个都需要。
在对话框中,“列”将处理对话框的大小,而“列表视图”将处理在其中的滚动。
Column(
mainAxisSize: MainAxisSize.min,children:[
ListView(padding: EdgeInsets.all(0),shrinkWrap: true,physics: ClampingScrollPhysics(),
好,你去...对话框的简单调用...
FlatButton(
onPressed: () {
showDialog(
useRootNavigator: false,context: context,builder: (BuildContext context) => Test(),);
},child: Text('Suppper'),)
然后对话框的代码...这很简单... 您可以在添加新条目时要处理的地图中放置的所有控制器...添加和删除都非常容易...让我知道是否需要进一步的帮助。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class Test extends StatefulWidget {
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
@override
void initState() {
super.initState();
}
Widget rowEntry(_nameController,_percentController) {
return IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
Expanded(
child: TextField(
controller: _nameController,decoration: const InputDecoration(
labelText: 'Enhancer/Limitation',border: const OutlineInputBorder(),),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',],);
}
addEntry() async {
entries.add('new value');
setState(() {});
}
List entries = [];
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),child: Container(
padding: EdgeInsets.all(16),width: 300,child: ListView(shrinkWrap: true,children: [
Text('here you will put all that is above (+)'),Container(
margin: EdgeInsets.only(top: 16,bottom: 16),child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
Text('Exhancements/Limitations'),InkWell(
onTap: () {
addEntry();
},child: Icon(Icons.add),ListView.builder(
physics: ClampingScrollPhysics(),padding: EdgeInsets.all(0),scrollDirection: Axis.vertical,itemCount: entries == null ? 0 : (entries.length),itemBuilder: (BuildContext context,int index) {
return rowEntry(null,null);
}),]),);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。