创建动态增长的可滚动列表的最佳方法

问题描述

我有一个波动的网络应用程序(将来可能会成为桌面应用程序),其中包含一个对话框。该对话框允许用户编辑包含元素列表的模型对象的属性用户应该能够通过在列表中添加删除元素来编辑列表。因此,对话框内容的高度可变-它取决于列表中元素的数量

我在创建可以适当地动态调整大小的布局时遇到了麻烦。我想要的是对话框随着项目添加到列表中而增长,直至达到设备屏幕上的最大大小。如果内容大于此内容,则列表中的元素应可滚动。

我已经附上了我目前工作的两个屏幕截图;第一个列表只有两个项目,很容易显示。第二个是同一对话框,其中有许多项目显示溢出。

Dialog with Two Items

Dialog with Many Items

以下是对话框的代码

  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);
              }),]),);
  }
}

result of the above code

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...