Я получаю данные категории из своего API. Раньше я использовал жестко запрограммированные данные JSON, поэтому они отлично работали в приложении, но теперь, когда я использую данные API, он показывает эту ошибку:
The following RangeError was thrown building FutureBuilder<List<Category>>(dirty, state:
I/flutter (20935): _FutureBuilderState<List<Category>>#a0d90):
I/flutter (20935): RangeError (index): Invalid value: Valid value range is empty:
Это мой код:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:news/explore/search_data.dart';
import 'package:news/models/category.dart';
import 'package:news/models/user.dart';
import 'package:news/video/pages/health_page.dart';
import 'package:http/http.dart' as http;
import 'package:news/api/api.dart';
Widget getErrorWidget(BuildContext context, FlutterErrorDetails error) {
return Center(
child: Text(
"Loadingg........................",
style: Theme.of(context).textTheme.title.copyWith(color: Colors.white),
),
// child: CircularProgressIndicator(),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
ErrorWidget.builder = (FlutterErrorDetails errorDetails) {
return getErrorWidget(context, errorDetails);
};
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: VideoPage(),
);
}
}
class VideoPage extends StatefulWidget {
@override
_VideoPageState createState() => _VideoPageState();
}
class _VideoPageState extends State<VideoPage>
with SingleTickerProviderStateMixin {
List<User> userList = List<User>();
int userID = 0;
List<Category> categoryList = List<Category>();
int id = 0;
ValueNotifier<int> valueNotifier = ValueNotifier(0);
List<Widget> _generateWidgets = List<Widget>();
List<Tab> tabs = new List<Tab>();
static List<Action> _action = <Action>[
Action(
title: 'Upload',
icon: Icons.file_upload,
),
Action(
title: 'Moment',
icon: Icons.contact_mail,
),
Action(
title: 'Article',
icon: Icons.library_books,
),
Action(
title: 'Video',
icon: Icons.video_call,
)
];
Action selectedAction = _action[0];
TabController tabController;
void initState() {
super.initState();
}
Future<List<Category>> getCategory() async {
await Future.delayed(Duration(seconds: 2));
List<Category> categorys = List<Category>();
var url = Api.GETCATEGORY_URL;
var res = await http.get(url);
if (res.statusCode == 200) {
var data = jsonDecode(res.body);
for (int i = 0; i < data.length; i++) {
Category category = Category(data[i]['Categoryid'],
data[i]['Categoryname'], data[i]['Categoryorder']);
categorys.add(category);
// SQLiteDbProvider.db.insertCategory(category);
}
print(data);
}
return categorys;
}
@override
void dispose() {
super.dispose();
}
void _onSelected(Action action) {
setState(() {
selectedAction = action;
Navigator.push(context,
MaterialPageRoute(builder: (context) => selectedAction.widget));
});
}
List<Widget> getWidgets() {
_generateWidgets.clear();
return _generateWidgets;
}
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Category>>(
future: getCategory(),
builder: (c, AsyncSnapshot<List<Category>> s) {
if (s.hasData) {
for (int i = 0; i < s.data.length; i++) {
Category category = s.data[i];
tabs.add(Tab(
child: Text(
category.categoryName,
style: TextStyle(color: Colors.white),
),
));
_generateWidgets.add(HealthPage(
id: categoryList[i].categoryID,
));
}
return DefaultTabController(
initialIndex: valueNotifier.value,
length: s.data.length,
child: Scaffold(
appBar: AppBar(
title: GestureDetector(
onTap: () => showSearch(
context: context, delegate: SearchBarDelegate()),
child: new Container(
width: 400.0,
height: 40.0,
padding: EdgeInsets.only(left: 10.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
width: 2.0,
),
borderRadius: BorderRadius.circular(10.0),
color: Colors.white,
),
child: Row(
children: <Widget>[
Icon(
Icons.search,
color: Colors.black26,
),
SizedBox(
width: 10.0,
),
Text(
'Search...',
style: TextStyle(
color: Colors.black26,
fontSize: 15.0,
),
),
],
),
),
),
actions: <Widget>[
Theme(
data: Theme.of(context).copyWith(
cardColor: Colors.black,
),
child: PopupMenuButton(
itemBuilder: (BuildContext context) {
return _action.map((Action action) {
return PopupMenuItem(
value: action,
child: Container(
width: 75.0,
color: Colors.black,
child: Row(
children: <Widget>[
Icon(
action.icon,
color: Colors.white,
size: 20.0,
),
SizedBox(
width: 3.0,
),
Text(
action.title,
style: TextStyle(
fontSize: 13.0, color: Colors.white),
),
],
),
),
);
}).toList();
},
icon: Icon(
Icons.add_a_photo,
color: Colors.white,
),
offset: Offset(0, 100),
onSelected: _onSelected,
),
),
],
bottom: TabBar(
isScrollable: true,
tabs: tabs,
),
),
body: TabBarView(
children: List.generate(
s.data.length,
(index) => _generateWidgets[index],
),
),
));
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
}
class Action {
final String title;
final IconData icon;
final Widget widget;
const Action({this.title, this.icon, this.widget});
}
class VideoCategory {
final int id;
final String name;
VideoCategory({this.id, this.name});
}