Flutter如何在ListView.builder中正确展示嵌套结构的JSON数据
第一步:调整API接口返回值
你当前的接口只返回了PartnerData列表,但DietName存放在接口响应的根级别Data对象中,不属于PartnerDatum的属性,所以首先要修改接口返回完整的模型对象,同时修复现有代码的小问题:
// 修改返回类型为DietDetailsModel Future<DietDetailsModel> dietcianDetailsApi() async { var response = await http.post( Uri.parse("http://myapin/api/api/DietDetails"), body: ({ 'EncId': 'pEl2tetIxLJO76eQ==' // 修复两个问题:原key末尾多了空格、参数值要包裹引号 })); if (response.statusCode == 200) { DietDetailsModel dataModel = dietDetailsModelFromJson(response.body); // 原代码print(arrData[1].partnerName)会报错:你的示例JSON里PartnerData只有1个元素,索引从0开始,最多访问到arrData[0] return dataModel; } else { throw Exception("Faild to fetch"); } }
第二步:调整FutureBuilder逻辑,展示三层嵌套数据
现在接口返回完整的DietDetailsModel,你可以先在列表外层展示DietName,再在每个列表项里展示PartnerName、合作伙伴信息,以及DayList里的所有可预约日期:
Container( height: blockSizeVertical*30, child: FutureBuilder<DietDetailsModel>( future: dietcianDetailsApi(), builder: (BuildContext context, AsyncSnapshot<DietDetailsModel> snapshot) { if (snapshot.hasError) { return Text("Somthing went wrong"); } if (snapshot.hasData) { final dietData = snapshot.data!; return Column( children: [ // 最外层展示DietName Text( dietData.data.dietName, style: TextStyle( fontWeight: FontWeight.bold, fontSize: blockSizeHorizontal*4, ), ), SizedBox(height: 10), Expanded( child: ListView.builder( scrollDirection: Axis.horizontal, physics: BouncingScrollPhysics(), shrinkWrap: true, itemCount: dietData.partnerData.length, itemBuilder: (BuildContext context, int index) { final partner = dietData.partnerData[index]; // 把DayList的日期拼接成字符串,也可以嵌套ListView逐个展示时段 final availableDays = partner.dayList.map((day) => day.dayName).join("、"); return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), ), width: blockSizeHorizontal*80, margin: EdgeInsets.all(10), child: Stack(children: [ Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: blockSizeVertical*0.5), Text( partner.partnerName, style: TextStyle( fontWeight: FontWeight.bold, fontSize: blockSizeHorizontal*3.5, fontFamily: 'Poppins', color: Theme.of(context).primaryColor, ), textAlign: TextAlign.center, ), SizedBox(height: blockSizeVertical*0.8), Container( padding: EdgeInsets.symmetric(horizontal: 10), child: Center( child: Column( children: [ Text( '地址:${partner.partnerAddress}\n费用:${partner.fee} 优惠后:${partner.discountedFee}', style: TextStyle( fontFamily: 'Poppins', fontSize: blockSizeHorizontal*2.5, color: Theme.of(context).primaryColor), textAlign: TextAlign.center, maxLines: 4, ), SizedBox(height: 5), // 展示拼接好的可预约日期 Text( '可预约日期:$availableDays', style: TextStyle( fontFamily: 'Poppins', fontSize: blockSizeHorizontal*2.3, color: Colors.grey[700]), ), ], ), ), ), ] ), Positioned( bottom: 5, left: 2, child: Padding( padding: const EdgeInsets.only(left:15.0, bottom: 5), child: InkWell( onTap: () {}, child: Container( alignment: Alignment.center, height: blockSizeVertical*5, width: blockSizeHorizontal*30, decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(10), gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.topRight, colors: [ Theme.of(context).primaryColor, Theme.of(context).accentColor ], ), ), child: Text( 'Show Details', style: TextStyle( color: Colors.white, fontSize: blockSizeHorizontal*2.7, fontWeight: FontWeight.bold, fontFamily: 'Poppins', ), ), ), ), ), ), ]), ); }, ), ) ], ); } return CircularProgressIndicator(); }, ), )
如果需要单独展示每个日期的具体时段,在对应位置嵌套Column或者ListView.builder遍历partner.dayList的元素即可。
内容的提问来源于stack exchange,提问作者Toujo
相关产品推荐
相关产品推荐

