如何复用Flutter植物UI代码并通过REST API获取数据?
Hey there! Let's walk through how to adapt that Flutter plants UI repo to fetch data from a REST API instead of relying on local mock data. I’ve worked through similar setups before, so here’s a step-by-step breakdown to get you up and running:
Start by checking the existing Plant model class in the repo and the local mock data it uses. You’ll need to match your API’s response structure to this model. For example, if the original model looks like this:
class Plant { final String name; final String imageUrl; final double price; final String description; Plant({ required this.name, required this.imageUrl, required this.price, required this.description, }); }
Note down all the fields—your API should return JSON objects with matching keys (or you’ll need to adjust the mapping later).
To make API calls, add the http package to your pubspec.yaml (it’s the most common lightweight option):
dependencies: flutter: sdk: flutter http: ^1.1.0 # Use the latest version available
Run flutter pub get to install it.
Encapsulate your API logic in a dedicated service class to keep your code clean and reusable. Here’s a basic example:
import 'dart:convert'; import 'package:http/http.dart' as http; import '../models/plant.dart'; class PlantApiService { // Replace this with your actual API endpoint final String _baseUrl = 'https://your-api-domain.com/api/plants'; Future<List<Plant>> fetchPlants() async { final response = await http.get(Uri.parse(_baseUrl)); if (response.statusCode == 200) { // Parse the JSON response into a list of Plant objects List<dynamic> plantJson = json.decode(response.body); return plantJson.map((json) => Plant.fromJson(json)).toList(); } else { // Handle errors (e.g., network issues, invalid responses) throw Exception('Failed to load plants. Status code: ${response.statusCode}'); } } }
Add a fromJson factory constructor to the Plant class to convert API JSON into usable objects. Make sure the keys match exactly what your API returns:
class Plant { final String name; final String imageUrl; final double price; final String description; Plant({ required this.name, required this.imageUrl, required this.price, required this.description, }); // Factory constructor to convert JSON to Plant factory Plant.fromJson(Map<String, dynamic> json) { return Plant( name: json['name'] ?? 'Unknown Plant', // Add fallbacks for optional fields imageUrl: json['image_url'] ?? '', // Adjust key to match your API's response price: double.parse(json['price'].toString()), // Convert if API returns a string description: json['description'] ?? 'No description available', ); } }
Pro tip: If your API uses different key names (e.g., plant_name instead of name), update the json['key'] values to match.
Instead of using a hardcoded list of plants, use FutureBuilder to handle the asynchronous API call. Here’s how to modify a typical screen from the repo:
import 'package:flutter/material.dart'; import '../services/plant_api_service.dart'; import '../models/plant.dart'; import '../widgets/plant_card.dart'; // Reuse the existing card widget class PlantsScreen extends StatefulWidget { const PlantsScreen({super.key}); @override State<PlantsScreen> createState() => _PlantsScreenState(); } class _PlantsScreenState extends State<PlantsScreen> { late Future<List<Plant>> _plantsFuture; final PlantApiService _apiService = PlantApiService(); @override void initState() { super.initState(); // Trigger the API call when the screen loads _plantsFuture = _apiService.fetchPlants(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Plants')), body: FutureBuilder<List<Plant>>( future: _plantsFuture, builder: (context, snapshot) { if (snapshot.hasData) { // Show the plant list if data is available return ListView.builder( padding: const EdgeInsets.all(16), itemCount: snapshot.data!.length, itemBuilder: (context, index) => PlantCard(plant: snapshot.data![index]), ); } else if (snapshot.hasError) { // Show error message if something goes wrong return Center(child: Text('Error: ${snapshot.error}')); } // Show loading spinner while waiting for data return const Center(child: CircularProgressIndicator()); }, ), ); } }
- Empty state: If your API returns an empty list, add a widget like
Center(child: Text('No plants found'))to inform the user. - Retry functionality: Add a button to retry the API call if it fails.
- Caching: For better performance, use packages like
shared_preferencesorhiveto cache API responses and avoid redundant calls.
内容的提问来源于stack exchange,提问作者Bmn

