如何在Flutter Carousel Slider中展示API JSON数据(附无GetX完整示例)
Flutter Carousel Slider 加载API JSON数据实现步骤
1. 定义对应JSON的数据模型
根据你提供的JSON结构,创建继承Equatable的数据类,方便数据比较和状态管理:
import 'package:equatable/equatable.dart'; class CarouselItem extends Equatable { final String name; final String description; final String imageUrl; const CarouselItem({ required this.name, required this.description, required this.imageUrl, }); // 从JSON解析为模型实例 factory CarouselItem.fromJson(Map<String, dynamic> json) { return CarouselItem( name: json['CarouselName'], description: json['CarouselDescription'], imageUrl: json['CarouselImage'], ); } @override List<Object?> get props => [name, description, imageUrl]; }
2. 实现HTTP数据请求方法
编写异步函数,发起HTTP请求并将返回的JSON解析为CarouselItem列表:
import 'dart:convert'; import 'package:http/http.dart' as http; Future<List<CarouselItem>> fetchCarouselItems() async { // 替换为你的实际API地址 final response = await http.get(Uri.parse('https://your-api-domain/carousel-data')); if (response.statusCode == 200) { List<dynamic> jsonList = json.decode(response.body); return jsonList.map((json) => CarouselItem.fromJson(json)).toList(); } else { throw Exception('加载轮播数据失败'); } }
3. 重构页面状态与UI
使用StatefulWidget管理数据加载状态(加载中、成功、错误),替换原有静态数据为API返回内容:
完整页面代码示例
import 'package:flutter/material.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:equatable/equatable.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; // 数据模型类 class CarouselItem extends Equatable { final String name; final String description; final String imageUrl; const CarouselItem({ required this.name, required this.description, required this.imageUrl, }); factory CarouselItem.fromJson(Map<String, dynamic> json) { return CarouselItem( name: json['CarouselName'], description: json['CarouselDescription'], imageUrl: json['CarouselImage'], ); } @override List<Object?> get props => [name, description, imageUrl]; } // HTTP请求方法 Future<List<CarouselItem>> fetchCarouselItems() async { final response = await http.get(Uri.parse('https://your-api-domain/carousel-data')); if (response.statusCode == 200) { List<dynamic> jsonList = json.decode(response.body); return jsonList.map((json) => CarouselItem.fromJson(json)).toList(); } else { throw Exception('加载轮播数据失败'); } } // 页面主组件 class CarouselPage extends StatefulWidget { const CarouselPage({super.key}); @override State<CarouselPage> createState() => _CarouselPageState(); } class _CarouselPageState extends State<CarouselPage> { int initialPage = 0; late Future<List<CarouselItem>> _carouselItemsFuture; @override void initState() { super.initState(); // 初始化时发起数据请求 _carouselItemsFuture = fetchCarouselItems(); } @override Widget build(BuildContext context) { return Scaffold( body: FutureBuilder<List<CarouselItem>>( future: _carouselItemsFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { // 加载中状态 return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { // 错误状态 return Center(child: Text('加载失败: ${snapshot.error}')); } else if (snapshot.hasData) { // 数据加载成功,渲染轮播 final carouselItems = snapshot.data!; return CarouselSlider( options: CarouselOptions( aspectRatio: 1.5, viewportFraction: 0.95, enlargeStrategy: CenterPageEnlargeStrategy.height, enlargeCenterPage: true, reverse: false, enableInfiniteScroll: true, autoPlay: true, autoPlayAnimationDuration: const Duration(milliseconds: 900), initialPage: initialPage, onPageChanged: (index, reason) { setState(() { initialPage = index; debugPrint('$initialPage'); }); }, ), items: carouselItems .map((item) => HeroCarouselCard(item: item)) .toList(), ); } else { // 无数据状态 return const Center(child: Text('暂无轮播数据')); } }, ), ); } } // 适配新模型的轮播卡片组件 class HeroCarouselCard extends StatelessWidget { final CarouselItem item; const HeroCarouselCard({super.key, required this.item}); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.symmetric(horizontal: 4.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(8.0), image: DecorationImage( // 若为本地图片,替换为AssetImage并在pubspec.yaml中声明资源 image: NetworkImage('https://your-image-host/${item.imageUrl}'), fit: BoxFit.cover, ), ), child: Container( padding: const EdgeInsets.all(16.0), decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.bottomCenter, end: Alignment.topCenter, colors: [Colors.black.withOpacity(0.7), Colors.transparent], ), ), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.name, style: const TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Text( item.description, style: const TextStyle( color: Colors.white, fontSize: 14, ), maxLines: 2, overflow: TextOverflow.ellipsis, ), ], ), ), ); } }
注意事项
- 替换代码中的API地址和图片主机地址为你的实际服务地址
- 若使用本地图片,需将
NetworkImage替换为AssetImage,并在pubspec.yaml的assets字段中声明图片路径 - 可根据需求扩展错误处理逻辑,比如添加重试按钮
内容的提问来源于stack exchange,提问作者Talal Habib
相关产品推荐
相关产品推荐

