Flutter基础(前端教程⑦-Http和卡片)

1. 假设后端返回的数据格式

复制代码
{
  "code": 200,
  "data": [
    {
      "name": "张三",
      "age": 25,
      "email": "zhangsan@example.com",
      "avatar": "https://picsum.photos/200/200?random=1",
      "status": "在线"
    },
    {
      "name": "李四",
      "age": 30,
      "email": "lisi@example.com",
      "avatar": "https://picsum.photos/200/200?random=2",
      "status": "离线"
    },
    {
      "name": "王五",
      "age": 22,
      "email": "wangwu@example.com",
      "avatar": "https://picsum.photos/200/200?random=3",
      "status": "忙碌"
    },
    {
      "name": "赵六",
      "age": 28,
      "email": "zhaoliu@example.com",
      "avatar": "https://picsum.photos/200/200?random=4",
      "status": "在线"
    }
  ]
}

2. 修改后代码实现

Dart 复制代码
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('多人数据展示')),
        body: const UserListPage(),
      ),
    );
  }
}

// 数据模型(保持不变)
class User {
  final String name;
  final int age;
  final String email;
  final String avatar;
  final String status;

  User({
    required this.name,
    required this.age,
    required this.email,
    required this.avatar,
    required this.status,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'],
      age: json['age'],
      email: json['email'],
      avatar: json['avatar'],
      status: json['status'],
    );
  }
}

// 主页面
class UserListPage extends StatefulWidget {
  const UserListPage({super.key});

  @override
  _UserListPageState createState() => _UserListPageState();
}

class _UserListPageState extends State<UserListPage> {
  List<User> _users = []; // 存储多个用户数据
  bool _isLoading = true;
  String? _errorMessage;

  @override
  void initState() {
    super.initState();
    _fetchUsersData();
  }

  // 调用API获取多用户数据
  void _fetchUsersData() async {
    try {
      final response = await http.get(
        Uri.parse('https://api.example.com/users'), // 替换为实际API地址
      );

      if (response.statusCode == 200) {
        final Map<String, dynamic> jsonData = json.decode(response.body);
        
        if (jsonData['code'] == 200) {
          // 解析JSON数组为User列表
          final List<dynamic> userList = jsonData['data'];
          setState(() {
            _users = userList.map((item) => User.fromJson(item)).toList();
            _isLoading = false;
          });
        } else {
          setState(() {
            _errorMessage = '获取数据失败:${jsonData['message']}';
            _isLoading = false;
          });
        }
      } else {
        setState(() {
          _errorMessage = '请求失败:状态码 ${response.statusCode}';
          _isLoading = false;
        });
      }
    } catch (e) {
      setState(() {
        _errorMessage = '网络错误:${e.toString()}';
        _isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    if (_errorMessage != null) {
      return Center(
        child: Text(
          _errorMessage!,
          style: const TextStyle(color: Colors.red, fontSize: 16),
        ),
      );
    }

    // 数据为空的情况
    if (_users.isEmpty) {
      return const Center(child: Text('暂无用户数据'));
    }

    // 使用ListView展示多个用户卡片
    return ListView.builder(
      padding: const EdgeInsets.all(16),
      itemCount: _users.length,
      itemBuilder: (context, index) {
        return Padding(
          padding: const EdgeInsets.only(bottom: 16),
          child: _buildUserCard(_users[index]), // 为每个用户构建卡片
        );
      },
    );
  }

  // 构建单个用户卡片(保持不变)
  Widget _buildUserCard(User user) {
    return Card(
      elevation: 4,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
      ),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ClipRRect(
              borderRadius: BorderRadius.circular(8),
              child: Image.network(
                user.avatar,
                width: 80,
                height: 80,
                fit: BoxFit.cover,
              ),
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        user.name,
                        style: const TextStyle(
                          fontSize: 18,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      Container(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 8,
                          vertical: 2,
                        ),
                        decoration: BoxDecoration(
                          color: user.status == '在线' 
                              ? Colors.green[100] 
                              : Colors.grey[200],
                          borderRadius: BorderRadius.circular(4),
                        ),
                        child: Text(
                          user.status,
                          style: TextStyle(
                            color: user.status == '在线' 
                                ? Colors.green 
                                : Colors.grey[600],
                            fontSize: 12,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 8),
                  Text(
                    '年龄:${user.age}岁',
                    style: const TextStyle(color: Colors.grey),
                  ),
                  const SizedBox(height: 4),
                  Text(
                    '邮箱:${user.email}',
                    style: const TextStyle(color: Colors.grey),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

123

相关推荐
Binary-Jeff2 小时前
一文读懂 HTTPS 协议及其工作流程
网络协议·web安全·http·https
崔庆才丨静觅3 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60614 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了4 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅4 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅5 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
renke33645 小时前
Flutter for OpenHarmony:色彩捕手——基于HSL色轮与感知色差的交互式色觉训练系统
flutter
崔庆才丨静觅5 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment5 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅5 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端