【问题标题】:Flutter - dynamic Drawer from JsonList resulting in errorFlutter - 来自 JsonList 的动态 Drawer 导致错误
【发布时间】:2021-03-06 22:32:23
【问题描述】:

我正在尝试构建一个抽屉,从文件中的 json 获取它的项目。当我在调试时进行此操作时,我可以看到它加载了项目,但我的最后一个抽屉导致错误。它指出

[VERBOSE-2:ui_dart_state.cc(186)] 未处理的异常:类型 “List”不是“Map”类型的子类型 #0 loadDropDowns (package:carded1/main.dart:31:36)

为了完成这项工作,

  1. 创建资产文件夹
  2. 将此添加到 pubspec.yaml:

资产:

  • assets/jsonfile.json
  1. 将此添加到 jsonfile.json

    [{ “标题”:“保险”, “listOfItems”:[“亨利”、“杰瑞”、“乱舞”] }, { “标题”:“保险”, “listOfItems”:[“亨利”、“杰瑞”、“乱舞”] }, { “标题”:“保险”, “listOfItems”:[“亨利”、“杰瑞”、“乱舞”] } ]

这是我的 main.dart 文件:

import 'package:flutter/material.dart';
import 'package:flip_card/flip_card.dart';
import 'dart:convert';
import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;

// String rawJson = '{"header":"Insurance","listOfItems":["henry","jerry","flurry"]}';
// Map<String, dynamic> map = jsonDecode(rawJson);
// String header = map['header'];
// List<dynamic> listOfItems = map['listOfItems'];

//List<ExpansionTile> listOfTilesToBuild = [];

void main() {

  runApp(FlipCarded());
}

Future wait(int seconds) {
  return new Future.delayed(Duration(seconds: seconds), () => {});
}

Future<String> _loadADropDownListAsset() async {
  return await rootBundle.loadString('assets/jsonfile.json');
}

Future<DropDownItem> loadDropDowns() async {
  await wait(5);
  String jsonString = await _loadADropDownListAsset();
  final jsonResponse = json.decode(jsonString);
  return new DropDownItem.fromJson(jsonResponse);
}

class FlipCarded extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FlipCard',
      theme: ThemeData.dark(),
      home: HomePage(),
    );
  }
}


class DropDownItem{
  DropDownItem({this.header, this.listOfItems});

  final String header;
  final List<String> listOfItems;

  factory DropDownItem.fromJson(Map<String, dynamic> json){
    return DropDownItem(
      header: json['header'],
      listOfItems: List<String>.from(json['listOfItems'].map((x) => x)),
    );
  }


    Map<String, dynamic> toJson() {
      return {
        'header': header,
        'listOfItems': listOfItems,
      };
    }
}


class HomePage extends StatelessWidget {
  Widget futureDropdown(){
    return new FutureBuilder<DropDownItem>(
      future: loadDropDowns(),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return new ExpansionListTile(header: snapshot.data.header, listOfItems: snapshot.data.listOfItems);
        } else if (snapshot.hasError) {
          return new ExpansionTile(title: Text('Error'));
        }
        return new CircularProgressIndicator();
      }
    );
  }

  //DropDownItem dItem = DropDownItem(header: header, listOfItems: listOfItems);

  _renderBg() {
    return Container(
      decoration: BoxDecoration(color: const Color(0xFFFFFFFF)),
    );
  }

  _renderAppBar(context) {
    return MediaQuery.removePadding(
      context: context,
      removeBottom: true,
      child: AppBar(
        brightness: Brightness.dark,
        elevation: 0.0,
        backgroundColor: Color(0xFFFFFFFF),
      ),
    );
  }

  _renderContext(context) {
    return Card(
        elevation: 0.0,
        margin:
            EdgeInsets.only(left: 32.0, right: 32.0, top: 20.0, bottom: 0.0),
        color: Color(0x00000000),
        child: FlipCard(
          direction: FlipDirection.VERTICAL,
          speed: 1000,
          onFlipDone: (status) {
            print(status);
          },
          front: Container(
            decoration: BoxDecoration(
              color: Color(0xFF006666),
              borderRadius: BorderRadius.all(Radius.circular(8.0)),
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Back',
                  style: Theme.of(context).textTheme.headline1,
                ),
                Text('Click here to flip front',
                    style: Theme.of(context).textTheme.bodyText1),
              ],
            ),
          ),
          back: Container(
            decoration: BoxDecoration(
              color: Color(0xFF006666),
              borderRadius: BorderRadius.all(Radius.circular(8.0)),
            ),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'Back',
                  style: Theme.of(context).textTheme.headline1,
                ),
                Text('Click here to flip back',
                    style: Theme.of(context).textTheme.bodyText1),
              ],
            ),
          ),
        ));
  }


  @override

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('FlipCard'),
      ),
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: <Widget>[
            DrawerHeader(
              child: Text('Drawer'),
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
            ),
            futureDropdown(),
            //ExpansionListTile(header: dItem.header, listOfItems: dItem.listOfItems),
          ],
        ),
      ),
      body: Stack(
        fit: StackFit.expand,
        children: <Widget>[
          _renderBg(),
          Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              _renderAppBar(context),
              Expanded(
                flex: 4,
                child: _renderContext(context),
              ),
              Expanded(
                flex: 1,
                child: Container(),
              )
            ],
          )
        ],
      ),
    );
  }
}

class ExpansionListTile extends StatelessWidget {
  final String header;
  final List<String> listOfItems;

  ExpansionListTile({this.header, this.listOfItems});

  @override
  Widget build(BuildContext context) {
    return ExpansionTile(
        title: Text(header),
        children: List.generate(listOfItems.length, (index) {
          return GestureDetector(
            onTap: (){print('Yep i pressed shit');},
              child: Text(listOfItems[index].toString()));
        }));
  }
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    当你这样做时:

    Future<DropDownItem> loadDropDowns() async {
      await wait(5);
      String jsonString = await _loadADropDownListAsset();
      final jsonResponse = json.decode(jsonString);
      return new DropDownItem.fromJson(jsonResponse);
    }
    

    根据您的 JSON 数据,jsonResponse 将是 List&lt;Map&lt;String,dynamic&gt;&gt;

    但是你的 factory DropDownItem.fromJson is waiting for Map` 参数。


    更新 - 代码运行没有错误

    注意:我没有完全审查代码。

    import 'package:flutter/material.dart';
    import 'package:flip_card/flip_card.dart';
    import 'dart:convert';
    import 'dart:async' show Future;
    import 'package:flutter/services.dart' show rootBundle;
    
    // String rawJson = '{"header":"Insurance","listOfItems":["henry","jerry","flurry"]}';
    // Map<String, dynamic> map = jsonDecode(rawJson);
    // String header = map['header'];
    // List<dynamic> listOfItems = map['listOfItems'];
    
    //List<ExpansionTile> listOfTilesToBuild = [];
    
    void main() {
      runApp(FlipCarded());
    }
    
    Future wait(int seconds) {
      return new Future.delayed(Duration(seconds: seconds), () => {});
    }
    
    Future<String> _loadADropDownListAsset() async {
      return await rootBundle.loadString('assets/jsonfile.json');
    }
    
    Future<List<DropDownItem>> loadDropDowns() async {
      // await wait(5);
      String jsonString = await _loadADropDownListAsset();
      final jsonResponse = json.decode(jsonString);
      return jsonResponse
          .map<DropDownItem>((json) => DropDownItem.fromJson(json))
          .toList();
    }
    
    class FlipCarded extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'FlipCard',
          theme: ThemeData.dark(),
          home: HomePage(),
        );
      }
    }
    
    class DropDownItem {
      DropDownItem({this.header, this.listOfItems});
    
      final String header;
      final List<String> listOfItems;
    
      factory DropDownItem.fromJson(Map<String, dynamic> json) {
        print('JSON: $json');
        return DropDownItem(
          header: json['header'],
          listOfItems: List<String>.from(json['listOfItems']),
        );
      }
    
      Map<String, dynamic> toJson() {
        return {
          'header': header,
          'listOfItems': listOfItems,
        };
      }
    }
    
    class HomePage extends StatelessWidget {
      Widget futureDropdown() {
        return new FutureBuilder<List<DropDownItem>>(
            future: loadDropDowns(),
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return ListView(
                  shrinkWrap: true,
                  children: snapshot.data
                      .map(
                        (dropDownItem) => ExpansionListTile(
                          header: dropDownItem.header,
                          listOfItems: dropDownItem.listOfItems,
                        ),
                      )
                      .toList(),
                );
              } else if (snapshot.hasError) {
                return new ExpansionTile(title: Text('Error'));
              }
              return new CircularProgressIndicator();
            });
      }
    
      //DropDownItem dItem = DropDownItem(header: header, listOfItems: listOfItems);
    
      _renderBg() {
        return Container(
          decoration: BoxDecoration(color: const Color(0xFFFFFFFF)),
        );
      }
    
      _renderAppBar(context) {
        return MediaQuery.removePadding(
          context: context,
          removeBottom: true,
          child: AppBar(
            brightness: Brightness.dark,
            elevation: 0.0,
            backgroundColor: Color(0xFFFFFFFF),
          ),
        );
      }
    
      _renderContext(context) {
        return Card(
            elevation: 0.0,
            margin:
                EdgeInsets.only(left: 32.0, right: 32.0, top: 20.0, bottom: 0.0),
            color: Color(0x00000000),
            child: FlipCard(
              direction: FlipDirection.VERTICAL,
              speed: 1000,
              onFlipDone: (status) {
                print(status);
              },
              front: Container(
                decoration: BoxDecoration(
                  color: Color(0xFF006666),
                  borderRadius: BorderRadius.all(Radius.circular(8.0)),
                ),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text(
                      'Back',
                      style: Theme.of(context).textTheme.headline1,
                    ),
                    Text('Click here to flip front',
                        style: Theme.of(context).textTheme.bodyText1),
                  ],
                ),
              ),
              back: Container(
                decoration: BoxDecoration(
                  color: Color(0xFF006666),
                  borderRadius: BorderRadius.all(Radius.circular(8.0)),
                ),
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text(
                      'Back',
                      style: Theme.of(context).textTheme.headline1,
                    ),
                    Text('Click here to flip back',
                        style: Theme.of(context).textTheme.bodyText1),
                  ],
                ),
              ),
            ));
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('FlipCard'),
          ),
          drawer: Drawer(
            child: ListView(
              padding: EdgeInsets.zero,
              children: <Widget>[
                DrawerHeader(
                  child: Text('Drawer'),
                  decoration: BoxDecoration(
                    color: Colors.blue,
                  ),
                ),
                futureDropdown(),
                //ExpansionListTile(header: dItem.header, listOfItems: dItem.listOfItems),
              ],
            ),
          ),
          body: Stack(
            fit: StackFit.expand,
            children: <Widget>[
              _renderBg(),
              Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                children: <Widget>[
                  _renderAppBar(context),
                  Expanded(
                    flex: 4,
                    child: _renderContext(context),
                  ),
                  Expanded(
                    flex: 1,
                    child: Container(),
                  )
                ],
              )
            ],
          ),
        );
      }
    }
    
    class ExpansionListTile extends StatelessWidget {
      final String header;
      final List<String> listOfItems;
    
      ExpansionListTile({this.header, this.listOfItems});
    
      @override
      Widget build(BuildContext context) {
        return ExpansionTile(
            title: Text(header),
            children: List.generate(listOfItems.length, (index) {
              return GestureDetector(
                  onTap: () {
                    print('Yep i pressed shit');
                  },
                  child: Text(listOfItems[index].toString()));
            }));
      }
    }
    

    【讨论】:

    • 根据您的回答,我搜索并来到了这篇文章:stackoverflow.com/questions/56770972/…。我实现了,但结果还是一样。
    • 我不太确定数据代表什么,我上传的完整源代码可能达不到您的要求。但至少,它运行时没有错误,可能会让您走上最终解决方案的道路。晚安!
    • 哦,非常感谢!!我会在早上做一个比较。
    猜你喜欢
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 2020-04-06
    • 2021-04-09
    • 2021-11-04
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    相关资源
    最近更新 更多