基于GetX保留现有Controller与UI,如何动态修改API参数拉取不同产品数据
动态分类拉取实现方案
服务层调整(仅修改硬编码分类值)
原ProductServices.fetchProducts为静态无参方法,内部硬编码分类值4,仅给方法新增分类入参,替换硬编码值,其余请求、解析、错误判断逻辑完全保留:
class ProductServices { static var client = http.Client(); // 新增category入参,方法主体逻辑不做任何改动 static Future fetchProducts(String category) async { var response = await client.post( Uri.https('********.com', 'api/getProduct'), // 替换原硬编码的"4"为动态传入的category值 body:'{"category":"$category","search":"","sortBy":"relavance","page":"","size":""}'); if (response.statusCode == 200) { var jsonString = response.body; print(productsScreenFromJson(jsonString)); return productsScreenFromJson(jsonString); } else { return null; } } }
Controller层调整(不改动原有核心结构)
原ProductController的响应式列表、生命周期、数据赋值逻辑全部保留,仅新增分类存储逻辑,给拉取方法加可选入参,不破坏原有首次加载流程:
import 'package:get/state_manager.dart'; import 'package:get_it_test/services/product_services.dart'; class ProductController extends GetxController { // 原有响应式列表完全保留,无任何修改 var ProductList = [].obs; // 新增响应式变量存储当前生效的分类值,默认值设为原硬编码的4,不影响首次加载行为 var currentCategory = "4".obs; @override void onInit() { // 首次加载逻辑和原实现完全一致,调用拉取方法传入当前分类 fetchProduct(category: currentCategory.value); super.onInit(); } // 原fetchProduct方法仅增加可选命名参数,内部拉取、赋值逻辑不做改动 void fetchProduct({String? category}) async { // 如果传入了新的分类值,同步更新存储的当前分类 if (category != null) currentCategory.value = category; // 调用服务层时传入当前分类值,替换原无参调用逻辑 var productsList = await ProductServices.fetchProducts(currentCategory.value); print(productsList.data.products); if (productsList != null) { ProductList.assignAll(productsList.data.products); } } }
UI层调整(不改动原有页面结构)
原页面的列表渲染、Obx监听、底部栏布局逻辑全部保留,仅调整Controller的获取时机,解决初始化器无法访问实例成员的编译告警:
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:get_it_test/Views/Widgets/BottomBar.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:get_it_test/Controller/product_controller.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; class ProductScreen extends StatelessWidget { // 原有title参数保留 final String title; // 新增可选参数接收页面跳转时传入的初始分类,默认值为原硬编码4,不破坏原有页面调用方式 final String initialCategory; // 构造函数适配新增参数,无强制传参要求 ProductScreen({this.title = "", this.initialCategory = "4"}); // 把原字段级的Get.put声明改为懒加载声明,解决初始化器阶段无法访问实例成员的问题 late final ProductController productController; @override Widget build(BuildContext context) { // 在build方法内完成Controller的获取/注册,此时已可正常访问页面实例成员 productController = Get.put(ProductController()); // 若传入的初始分类和Controller默认值不一致,触发一次对应分类的数据拉取,不影响原有页面布局 if (productController.currentCategory.value != initialCategory) { productController.fetchProduct(category: initialCategory); } return Scaffold( // 以下所有原有UI代码完全保留,无任何改动 appBar: AppBar( iconTheme: IconThemeData(color: Colors.black), backgroundColor: Colors.white, title: Text( title, style: TextStyle(color: Colors.black), ), ), body: SafeArea( child: Column( children: [ Expanded( child: Obx(() => StaggeredGridView.countBuilder( crossAxisCount: 2, itemCount: productController.ProductList.length, itemBuilder: (BuildContext context, int index) => new Container( width: 200, child: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ CachedNetworkImage( imageUrl: productController .ProductList[index].image, placeholder: (context, url) => new CircularProgressIndicator(), errorWidget: (context, url, error) => new Image .network( '****.com/noimage.png'), ), Text(productController .ProductList[index].prodName), ], ), )), staggeredTileBuilder: (int index) => new StaggeredTile.fit(1), mainAxisSpacing: 4.0, crossAxisSpacing: 4.0, )), ), BottomBar() ], ), ), ); } }
按钮触发动态拉取的用法
页面上的分类按钮,在原有点击事件中仅需加一行调用即可实现数据切换,按钮的布局、样式、交互逻辑完全不需要修改:
// 示例:分类按钮的点击事件 onPressed: () { // 传入对应分类的数字字符串,即可自动拉取对应分类的产品,列表会因Obx监听自动刷新 productController.fetchProduct(category: "对应的分类号"); }
内容的提问来源于stack exchange,提问作者Aryan Yadav
相关产品推荐
相关产品推荐

