简体   繁体   中英

Range Error (index): Invalid value: Valid value range is empty: 0

I tried to build an Animated List in Flutter and I have been getting RangeError (index): Invalid value: Valid value range is empty: 0 when I run my code. Here is my code. I followed a tutorial and I used a similar process but I am getting errors while there is no error in the tutorial I followed. I have tried to add shrinkwrap to the animated list yet the problem persists.

import 'package:devopsnotepad/core/models/server/dummy_model.dart';
import 'package:devopsnotepad/core/models/server/server_model.dart';
import 'package:devopsnotepad/core/services/api_service.dart';
import 'package:devopsnotepad/ui/shared/colors.dart';
import 'package:devopsnotepad/ui/shared/edge_insets.dart';
import 'package:devopsnotepad/ui/shared/spacing.dart';
import 'package:devopsnotepad/ui/shared/text_styles.dart';
import 'package:devopsnotepad/ui/widgets/app_button.dart';
import 'package:devopsnotepad/ui/widgets/app_spinner.dart';
import 'package:devopsnotepad/ui/widgets/custom_app_bar.dart';
import 'package:devopsnotepad/ui/widgets/server_card_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:stacked/stacked.dart';
import 'server_list_viewmodel.dart';

class ServerListView extends StatefulWidget {
 const ServerListView({Key? key}) : super(key: key);

 @override
 State<ServerListView> createState() => _ServerListViewState();
}

class _ServerListViewState extends State<ServerListView> {
 //final List<Server> serverList;
 final List<ServerList> serverList = List.from(servers);
 List<Widget> animatedTiles = [];
 final GlobalKey<AnimatedListState> _listkey = GlobalKey<AnimatedListState>();
 final Tween<Offset> _offset =
     Tween(begin: const Offset(1, 0), end: const Offset(0, 0));

 @override
 void initState() {
   super.initState();
   WidgetsBinding.instance.addPostFrameCallback((_) {
     addServer();
   });
 }

 void addServer() {
   Future loading = Future(() {});

   for (var server in serverList) {
     loading = loading.then((_) {
       return Future.delayed(const Duration(milliseconds: 100), () {
         animatedTiles.add(
           ServerCard(serverItem: server, onTap: () {}),
         );
         _listkey.currentState!.insertItem(animatedTiles.length - 1);
       });
     });
   }
 }
   @override
 void dispose() {
   super.dispose();
   _controller.dispose();
 }


 @override
 Widget build(BuildContext context) {
   return ViewModelBuilder<ServerListViewModel>.reactive(
     builder: (context, model, child) => Scaffold(
       appBar: CustomAppBar(
         title: "Servers",
         actions: [
           IconButton(
             onPressed: () async {
               showSearch(context: context, delegate: ServerSearch());
             },
             icon: const Icon(Icons.search),
           ),
           IconButton(
             onPressed: model.goToSettingsView,
             icon: const Icon(Icons.settings),
           ),
         ],
       ),
       body: serverList.isEmpty
           //TODO: model.servers.isEmpty
           ? const _EmptyServer()
           : Column(
               mainAxisAlignment: MainAxisAlignment.start,
               crossAxisAlignment: CrossAxisAlignment.start,
               children: <Widget>[
                 verticalSpaceMini,
                 Expanded(
                   child: AnimatedList(
                     shrinkWrap: true,
                     padding: kEdgeInsetsAllMedium,
                     key: _listkey,
                     initialItemCount: serverList.length,
                     itemBuilder: (context, index, animation) {
                       return SlideTransition(
                         position: animation.drive(_offset),
                         child: Slidable(
                             endActionPane: ActionPane(
                                 motion: const StretchMotion(),
                                 children: [
                                   SlidableAction(
                                     onPressed: ((context) {}),
                                     icon: Icons.delete,
                                     backgroundColor: AppColor.kErrorColor,
                                     label: "Delete",
                                   ),
                                 ]),
                             child: animatedTiles[index]),
                       );
                     },
                   ),
                 ),
               ],
             ),
       floatingActionButton: AppButton(
         title: 'Add new server',
         backgroundColor: AppColor.kPrimaryColor.shade900,
         width: 170,
         height: 40,
         trailingIcon: Icons.add_circle_outline,
         onTap: model.goToAddServerView,
         iconColor: Colors.white,
         iconSize: 15,
       ),
     ),
     viewModelBuilder: () => ServerListViewModel(),
   );
 }
}

class ServerSearch extends SearchDelegate {
 @override
 List<Widget> buildActions(BuildContext context) {
   return [
     IconButton(
       icon: const Icon(Icons.clear),
       onPressed: () {
         query = '';
       },
     ),
   ];
 }

 @override
 Widget buildLeading(BuildContext context) {
   return IconButton(
     icon: const Icon(Icons.arrow_back),
     onPressed: () {
       close(context, '');
     },
   );
 }

 @override
 Widget buildResults(BuildContext context) => FutureBuilder(
     future: APIService()
         .get(route: '/server', queryParameters: {"device": "80988579"}),
     builder: ((context, snapshot) {
       if (snapshot.hasData) {
         var test = DataResponse.fromJson(snapshot.data);
         var serverList = test.servers;
         if (query.isNotEmpty) {
           var searchResult = serverList
               .where((element) => element.name.toLowerCase().contains(query))
               .toList();
           if (searchResult.isEmpty) {
             return const Center(child: Text('No result found'));
           } else {
             return ListView.builder(
               itemCount: searchResult.length,
               itemBuilder: (context, index) {
                 return ServerCard(
                     // endPoint: searchResult[index].name,
                     // ipAddress: searchResult[index].ipAddress,
                     // serverHealth: 'Excellent',
                     // serverName: searchResult[index].name,
                     onTap: () {});
               },
             );
           }
         } else {
           return const SizedBox.shrink();
         }
       } else {
         return const Center(
           child: AppSpinner(),
         );
       }
     }));

 @override
 Widget buildSuggestions(BuildContext context) {
   return const SizedBox.shrink();
 }
}

class _EmptyServer extends StatelessWidget {
 const _EmptyServer();

 @override
 Widget build(BuildContext context) {
   return Column(
     mainAxisAlignment: MainAxisAlignment.center,
     children: [
       verticalSpaceMassive,
       const Image(
         image: AssetImage('assets/images/add-notes.png'),
         height: 160,
       ),
       verticalSpaceMini,
       Text(
         'Empty Server List',
         style: kHeading1TextStyle,
       ),
       verticalSpaceMicro,
       Center(
         child: Text(
           'You do not have any servers yet',
           style: kBodyRegularTextStyle,
         ),
       )
     ],
   );
 }
}

@Joel, actually in the very beginning, the animatedTiles is empty as it is being initialize after postFrame along with some dealy & you have only serverList isEmpty check that's why it is throwing out of range exception. So just add isEmpty check of both animatedTiles & serverList and accordingly handle the state it will work smooth.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM