Flutter代码精简求助:搜索栏逻辑封装函数失败
代码精简与逻辑封装方案
以下是对你的Flutter代码的精简优化,重点将搜索栏、清除按钮及筛选逻辑封装为独立方法,无需重写整体代码:
核心优化点
- 将搜索栏提取为独立的
_buildSearchBar()方法 - 把清除搜索的逻辑封装到
_clearSearch()函数 - 将列表筛选逻辑抽离为
_filterResults(String query)方法 - 提取列表项构建逻辑到
_buildListItem(Prt item, int index) - 修复潜在的空安全问题及冗余的
setState调用
重构后的完整代码
import 'dart:async'; import 'dart:convert'; import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:velneoapp/api/modelos/api_model_partes.dart'; import 'package:velneoapp/views/partes/detalle_de_parte.dart'; class PartesView extends StatefulWidget { const PartesView({super.key}); @override State<PartesView> createState() => _PartesViewState(); } class Debouncer { Timer? timer; run(VoidCallback action) { timer?.cancel(); timer = Timer(const Duration(milliseconds: 1000), action); } } class _PartesViewState extends State<PartesView> { String _searchQuery = ""; final TextEditingController _searchController = TextEditingController(); Partes? _dataFromAPI; final _debouncer = Debouncer(); bool _isLoading = true; List<Prt> _filteredItems = []; @override void initState() { super.initState(); _fetchData(); } Future<void> _fetchData() async { try { const url = "https://demoapi.velneo.com/verp-api/vERP_2_dat_dat/v1/vta_ped_g?page%5Bsize%5D=20&fields=id,clt,emp&api_key=api123"; final res = await http.get(Uri.parse(url)); if (res.statusCode == 200) { log("Correcto"); _dataFromAPI = Partes.fromJson(json.decode(res.body)); _filteredItems = _dataFromAPI!.vtaPedGs; } else { log("${res.statusCode}"); throw Exception("Error durante la conexión"); } } catch (e) { log("Error antes de conectarse => ${e.toString()}"); _filteredItems = []; } finally { setState(() => _isLoading = false); } } void _clearSearch() { _searchController.clear(); setState(() { _searchQuery = ""; _filteredItems = _dataFromAPI?.vtaPedGs ?? []; }); } void _filterResults(String query) { setState(() { _searchQuery = query; if (_dataFromAPI == null) return; _filteredItems = _dataFromAPI!.vtaPedGs.where((item) => item.id.toString().toLowerCase().contains(query.toLowerCase()) || item.clt.toString().toLowerCase().contains(query.toLowerCase()) || item.emp.toLowerCase().contains(query.toLowerCase()) ).toList(); }); log("valores: $_filteredItems"); } Widget _buildSearchBar() { return Container( padding: const EdgeInsets.all(15), child: TextField( textInputAction: TextInputAction.search, controller: _searchController, decoration: InputDecoration( enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(25.0), borderSide: const BorderSide(color: Colors.grey), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(20.0), borderSide: const BorderSide(color: Colors.blue), ), suffixIcon: IconButton( icon: const Icon(Icons.clear), onPressed: _clearSearch, ), contentPadding: const EdgeInsets.all(15.0), hintText: 'Buscar...', ), onChanged: (query) => _debouncer.run(() => _filterResults(query)), ), ); } Widget _buildListItem(Prt item, int index) { return GestureDetector( onTap: () { setId(_dataFromAPI!.vtaPedGs[index].id); Navigator.push( context, MaterialPageRoute(builder: (context) => const DetalleDePartesView()), ); }, child: Card( child: ClipPath( clipper: ShapeBorderClipper( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3)), ), child: Container( padding: const EdgeInsets.all(4), decoration: const BoxDecoration( border: Border(left: BorderSide(color: Colors.green, width: 5)), ), child: Padding( padding: const EdgeInsets.all(5.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("ID: ${item.id}", style: const TextStyle(fontSize: 16)), Text("Cliente: ${item.clt}", style: const TextStyle(fontSize: 16)), Text("Empresa: ${item.emp}", style: const TextStyle(fontSize: 16)), ], ), ), ), ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("Partes")), body: _isLoading ? const Center(child: CircularProgressIndicator()) : Column( children: [ _buildSearchBar(), Expanded( child: ListView.builder( shrinkWrap: true, physics: const ClampingScrollPhysics(), padding: const EdgeInsets.all(5), itemCount: _filteredItems.length, itemBuilder: (context, index) => _buildListItem(_filteredItems[index], index), ), ), ], ), ); } }
关键优化说明
- 搜索栏封装:
_buildSearchBar()将原本嵌套在build方法中的搜索栏代码完全独立,使主build方法更简洁,且搜索栏逻辑可复用。 - 清除逻辑封装:
_clearSearch()统一处理清空输入框、重置搜索词和恢复全量数据的逻辑,避免重复代码。 - 筛选逻辑抽离:
_filterResults()将列表筛选逻辑单独提取,便于后续修改筛选规则,同时让onChanged回调更简洁。 - 列表项构建:
_buildListItem()把列表项的UI和交互逻辑封装,减少ListView.builder的代码复杂度。 - 空安全与代码规范:
- 修复了数据请求中可能出现的空指针问题
- 使用
finally块确保加载状态正确更新 - 变量命名更具语义化(如
valores改为_filteredItems) - 移除了冗余的
setState调用
内容的提问来源于stack exchange,提问作者Quelox
相关产品推荐
相关产品推荐

