You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Flutter Carousel Slider中展示API JSON数据(附无GetX完整示例)

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 08:05:23