在 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;
}
在我的 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;
}