1

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

我无法创建适当地动态调整大小的布局。我想要的是让对话框随着项目添加到列表中而增长,直到适合设备屏幕的最大尺寸。如果内容比这个大,列表中的元素应该是可滚动的。

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

包含两个项目的对话框

包含许多项目的对话框

这是对话框的代码:

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

4

1 回答 1

0

这听起来可能违反直觉,但您应该在 Column 中有 ListView。你需要两者。

在对话框中 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',
                border: const OutlineInputBorder(),
              ),
            ),
          ),
        ],
      ),
    );
  }

  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(),
              shrinkWrap: true,
              padding: EdgeInsets.all(0),
              scrollDirection: Axis.vertical,
              itemCount: entries == null ? 0 : (entries.length),
              itemBuilder: (BuildContext context, int index) {
                return rowEntry(null, null);
              }),
        ]),
      ),
    );
  }
}

上述代码的结果

于 2020-10-09T15:15:58.807 回答