在 Flutter 中,什么是在对话中动态显示列表的最佳小部件

In Flutter, what is the best widget to dynamically display a list in a dialogue

在我的 Flutter 应用中,我在对话框中显示了联系人的 phone 号码列表,这样用户就可以点击他们想要用来给联系人打电话或发短信的号码。 仅当联系人的号码超过 1 个时才会显示对话。

我正在使用 flutter_dialogs 包(可能相关也可能不相关?) 问题是我不知道如何动态设置容器的高度。 如果我没有指定高度,我会收到错误消息,我已经尝试了很多方法,但要么对话的高度几乎填满了屏幕,要么我收到错误消息,例如 RenderShrinkWrappingViewport 不支持返回固有尺寸......等等。 我试过将列表视图包装在 SingleChildScrollView 中(有和没有物理:NeverScrollableScrollPhysics() 和 shrinkWrap: true)、Column、Row、Align,天知道还有什么!

高度:100,舒适地显示 2 个数字,但如果联系人有 3 个数字,则不滚动就看不到第 3 个数字,你不会知道它在那里!

请帮忙,我应该使用什么小部件或setting/property?

对话框:

  showPlatformDialog(
    context: context,
    builder: (_) => BasicDialogAlert(
      title: Text("picknumber".tr),
      content: Container(
          width: double.maxFinite,
          // TODO height shouldn't be fixed
          height: 100, 
          child: ListView.builder(
            itemCount: phoneNumbersList.length,
            itemBuilder: (context, index) {
              String pn = phoneNumbersList[index].value.toString();
              return ListTile(
                title: Text(pn),
                onTap: () {
                  _pickedNumber = pn;
                  Navigator.of(context).pop();
                },
              );
            },
          )
      ),
      actions: <Widget>[
        BasicDialogAction(
          title: Text("cancel".tr),
          onPressed: () {
            Navigator.of(context).pop();
            _pickedNumber = null;
          },
        ),
      ],
    ),
  );

如果我没有正确理解你的问题。试试这个。

class MyHomePage extends StatefulWidget {
  MyHomePage({
    Key key,
  }) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<User> _users = [];

  @override
  void initState() {
    super.initState();
    _users.add(User()
      ..name = "John"
      ..phones = []
      ..phones.add("(875) 225-5490"));

    _users.add(User()
      ..name = "Mike"
      ..phones = []
      ..phones.add("(875) 225-5490")
      ..phones.add("(239) 218-9284")
      ..phones.add("(893) 918-0036")
      ..phones.add("(875) 225-5490"));

    _users.add(User()
      ..name = "Kevin"
      ..phones = []
      ..phones.add("(875) 225-5490")
      ..phones.add("(239) 218-9284")
      ..phones.add("(893) 918-0036")
      ..phones.add("(875) 225-5490"));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView.builder(
          shrinkWrap: true,
          itemCount: _users.length,
          itemBuilder: (BuildContext context, int index) {
            return Card(
              shadowColor: Colors.black26,
              clipBehavior: Clip.antiAlias,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(2),
              ),
              child: ListTile(
                dense: true,
                onTap: () {
                  if (_users[index].phones.length > 1)
                    ExampleDialog.showyDialog(
                        context: context, user: _users[index]);
                },
                title: Text(_users[index].name),
                subtitle: _users[index].phones.length > 1
                    ? Text("${_users[index].phones.first} Click to see more")
                    : Text(_users[index].phones.first),
              ),
            );
          }),
    );
  }
}

class User {
  String name;
  List<String> phones;
  User({
    this.name,
    this.phones,
  });
}

class ExampleDialog {
  static Future<void> showyDialog({BuildContext context, User user}) async {
    return showDialog<void>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return AlertDialog(
          insetPadding: EdgeInsets.all(15.0),
          contentPadding: EdgeInsets.only(left: 3, right: 3),
          title: Center(
              child: Container(
                  margin: EdgeInsets.only(bottom: 5),
                  child: Text("View phones"))),
          content: Container(
            width: MediaQuery.of(context).size.width,
            child: SingleChildScrollView(
              child: ListBody(
                children: [
                  ListView.builder(
                      physics: NeverScrollableScrollPhysics(),
                      shrinkWrap: true,
                      itemCount: user.phones.length,
                      itemBuilder: (BuildContext context, int index) {
                        return Card(
                          shadowColor: Colors.black26,
                          clipBehavior: Clip.antiAlias,
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(2),
                          ),
                          child: ListTile(
                            dense: true,
                            onTap: () {},
                            title: Text("${user.phones[index]}"),
                          ),
                        );
                      })
                ],
              ),
            ),
          ),
          actions: <Widget>[
            ElevatedButton.icon(
              onPressed: () => Navigator.of(context).pop(),
              icon: Icon(
                Icons.cancel,
                color: Colors.white,
                size: 24.0,
              ),
              label: Text("Close"),
            ),
          ],
        );
      },
    );
  }
}

我终于找到了适合我的解决方案。 我用 mainAxisSize.min 的列替换了 listView,该列填充了小部件列表 (card(ListTile))。 我首先尝试了一个 ListBody,它在 iOS 模拟器上运行良好,但 Android 模拟器给出了错误,所以我使用了一个列。 此方法使用导航器 return 所选号码。

测试代码:

showPlatformDialog(
    context: context,
    builder: (_) => BasicDialogAlert(
      title: Text("Pick a number"),
      content: Column( 
        mainAxisSize: MainAxisSize.min,
        children: getAlertOptions(),
      ),
      actions: <Widget>[
        BasicDialogAction(
          title: Text("Cancel"),
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
      ],
    ),
);



List<Widget> getAlertOptions() {
  List<Widget> options = [];
  List<String> lItems = ["1","2","3","4","5","6"];

for (int i = 0; i < lItems.length; i++)

  options.add(
    Card(
      child: ListTile(
        title: Text(lItems[i]),
        dense: true,
        onTap: () {
          Navigator.of(context).pop();
          print(lItems[i]);
        },
      ),
    )
  );

  return options;

}

应用代码:

Future<String> getPhoneNumber(BuildContext context, List  
    phoneNumbersList) async {
  String _pickedNumber;

if (phoneNumbersList.length == 1) {
  _pickedNumber = phoneNumbersList[0].value;
} else {
  _pickedNumber = await showPlatformDialog(
    context: context,
    builder: (_) => BasicDialogAlert(
      title: Text("picknumber".tr),
      content: Column(
        mainAxisSize:  MainAxisSize.min,
        children: getNumberList(phoneNumbersList),
      ),
      actions: <Widget>[
        BasicDialogAction(
          title: Text("cancel".tr),
          onPressed: () {
            Navigator.of(context).pop();
            _pickedNumber = null;
          },
        ),
      ],
    ),
  );
}

  return _pickedNumber;

}




List<Widget> getNumberList(List phoneNumbers) {
List<Widget> options = [];

for (int i = 0; i < phoneNumbers.length; i++)

options.add(
      Card(
        shadowColor: Colors.blue,
        clipBehavior: Clip.antiAlias,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(8)),
        ),
        child: ListTile(
          title: Text(phoneNumbers[i].value.toString()),
          dense: true,
          onTap: () {
          Navigator.of(context).pop(phoneNumbers[i].value.toString());
          },
        ),
      )
  );

  return options;
}