英文:
Using NavigationRail with multiple Futures
问题
我正在尝试创建一个带有NavigationRail
的屏幕,其中每个目标都显示从后端获取的不同数据的表格。
我尝试使用NavigationRail
和三个Future
来实现它,但每次从一个目标过渡到另一个目标时,我看到第二个目标上出现一个红色屏幕,并且然后过渡完成。我的日志显示以下错误:
构建FutureBuilder<List<dynamic>>
时引发了以下TypeErrorImpl
:
预期值的类型为'D1',但却得到了'D2'之一。
相关错误产生的小部件是FutureBuilder<List<dynamic>>
。
您能否看一下我是否遗漏了什么?我尝试了相同的方法,使用carousel_slider
小部件和三个Future
,但没有遇到同样的问题。我猜我在某种程度上误用了NavigationRail
。以下是基本代码:
class DataScreen extends StatefulWidget {
const DataScreen({super.key});
@override
State<DataScreen> createState() => _DataScreenState();
}
class _DataScreenState extends State<DataScreen> {
late Future<List<D1>> data1;
late Future<List<D2>> data2;
late Future<List<D3>> data3;
int _selectedIndex = 0;
@override
void initState() {
super.initState();
data1 = D1Service().getD1();
data2 = D2Service().getD2();
data3 = D3Service().getD3();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
NavigationRail(
selectedIndex: _selectedIndex,
groupAlignment: 0.0,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
leading: const SizedBox(),
trailing: const SizedBox(),
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.perm_identity),
selectedIcon: Icon(Icons.person),
label: Text('D1'),
),
NavigationRailDestination(
icon: Icon(Icons.groups_outlined),
selectedIcon: Icon(Icons.groups),
label: Text('D2'),
),
NavigationRailDestination(
icon: Icon(Icons.inventory_2_outlined),
selectedIcon: Icon(Icons.inventory_2),
label: Text('D3'),
),
],
),
const VerticalDivider(thickness: 1, width: 1),
const Spacer(),
// 这是主要内容。
Center(
child: Container(
child: _toTableAll(),
),
),
const Spacer(),
],
),
);
}
Widget _toTableAll() {
if (_selectedIndex == 0) {
return _toTable(data1);
} else if (_selectedIndex == 1) {
return _toTable(data2);
}
return _toTable(data3);
}
Widget _toTable<T>(Future<List<T>> item) {
return FutureBuilder<List<T>>(
future: item,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
constraints: const BoxConstraints(maxWidth: 800),
child: MTable(snapshot.data!),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
英文:
I am trying to make a screen with NavigationRail where each destination displays table with different data fetched from backend.
I tried implementing it with NavigationRail and three futures, but each time I transit from one destination to another, I see a red screen with error on a second and then transit completes. My logs show following error:
The following TypeErrorImpl was thrown building FutureBuilder<List<dynamic>>(state: _FutureBuilderState<List<dynamic>>#675cb):
Expected a value of type 'D1', but got one of type 'D2'
The relevant error-causing widget was
FutureBuilder<List<dynamic>>
Could you please see if I am missing something? I tried the same approach with three futures with carousel_slider widget and did not run into a same problem. I guess I am misusing NavigationRail somehow.
Here is base code:
class DataScreen extends StatefulWidget {
const DataScreen({super.key});
@override
State<DataScreen> createState() => _DataScreenState();
}
class _DataScreenState extends State<DataScreen> {
late Future<List<D1>> data1;
late Future<List<D2>> data2;
late Future<List<D3>> data3;
int _selectedIndex = 0;
@override
void initState() {
super.initState();
data1 = D1Service().getD1();
data2 = D2Service().getD2();
data3 = D3Service().getD3();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
NavigationRail(
selectedIndex: _selectedIndex,
groupAlignment: 0.0,
onDestinationSelected: (int index) {
setState(() {
_selectedIndex = index;
});
},
labelType: NavigationRailLabelType.all,
leading: const SizedBox(),
trailing: const SizedBox(),
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.perm_identity),
selectedIcon: Icon(Icons.person),
label: Text('D1'),
),
NavigationRailDestination(
icon: Icon(Icons.groups_outlined),
selectedIcon: Icon(Icons.groups),
label: Text('D2'),
),
NavigationRailDestination(
icon: Icon(Icons.inventory_2_outlined),
selectedIcon: Icon(Icons.inventory_2),
label: Text('D3'),
),
],
),
const VerticalDivider(thickness: 1, width: 1),
const Spacer(),
// This is the main content.
Center(
child: Container(
child: _toTableAll(),
),
),
const Spacer(),
],
),
);
}
Widget _toTableAll() {
if (_selectedIndex == 0) {
return _toTable(data1);
} else if (_selectedIndex == 1) {
return _toTable(data2);
}
return _toTable(data3);
}
Widget _toTable<T>(Future<List<T>> item) {
return FutureBuilder<List<T>>(
future: item,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
constraints: const BoxConstraints(maxWidth: 800),
child: MTable(snapshot.data!),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
答案1
得分: 1
使用snapshot.connectionState == ConnectionState.done
替换snapshot.hasData
解决了这个问题。
英文:
Changing snapshot.hasData
with snapshot.connectionState == ConnectionState.done
solved the problem
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论