Flutter实现搜索组件与ListView联动滚动,使用SingleChildScrollView报错求助
解决搜索框与ListView联动滚动的问题
你的需求是让搜索组件和列表结果一起滚动,原代码用Column+Expanded+ListView的结构会导致搜索框固定在顶部,无法随列表滚动。以下是可行的解决方案及优化后的完整代码:
核心思路
将搜索框和列表内容纳入同一个滚动组件,同时优化搜索逻辑避免无效空节点占用性能。这里推荐使用CustomScrollView,它能灵活组合不同类型的滚动组件。
完整修改代码
import 'package:coronavirus_app/Services/states_services.dart'; import 'package:coronavirus_app/resources/sizeconfig.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shimmer/shimmer.dart'; import '../Modal/world_countries_modal.dart'; import '../resources/colormanager.dart'; import '../resources/routesmanager.dart'; class CountriesListScreen extends ConsumerStatefulWidget { const CountriesListScreen({Key? key}) : super(key: key); @override ConsumerState<CountriesListScreen> createState() => _CountriesListScreenState(); } class _CountriesListScreenState extends ConsumerState<CountriesListScreen> { final TextEditingController searchcontroller = TextEditingController(); @override Widget build(BuildContext context) { SizeConfig().init(context); final countrydata = ref.watch(countrydataProvider); return Scaffold( appBar: AppBar( elevation: 0, backgroundColor: Theme.of(context).scaffoldBackgroundColor, ), body: countrydata.when( error: (err, stack) => Text('Error: ${err.toString()}'), loading: () => Shimmer.fromColors( baseColor: ColorManager.grey, highlightColor: ColorManager.lightGrey, child: ListView.builder( itemCount: 5, itemBuilder: ((context, index) { return const ListTile( title: SizedBox(height: 20, width: 89, child: ColoredBox(color: Colors.white)), leading: SizedBox(height: 100, width: 50, child: ColoredBox(color: Colors.white)), subtitle: SizedBox(height: 20, width: 89, child: ColoredBox(color: Colors.white)), ); }), ), ), data: ((data) { List<WorldCountriesModal> countrieslist = data.map((e) => e).toList(); // 提前过滤搜索结果,避免空容器占位 List<WorldCountriesModal> filteredCountries = countrieslist.where((country) { if (searchcontroller.text.isEmpty) return true; return country.country!.toLowerCase().contains(searchcontroller.text.toLowerCase()); }).toList(); return CustomScrollView( slivers: [ // 搜索框作为滚动头部 SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.all(8.0), child: SizedBox( height: getProportionateScreenHeight(50), width: double.infinity, child: TextFormField( controller: searchcontroller, onChanged: (value) => setState(() {}), decoration: InputDecoration( contentPadding: const EdgeInsets.symmetric(vertical: 10), hintText: 'Search with country name', prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(50), ), ), ), ), ), ), // 列表内容 SliverList( delegate: SliverChildBuilderDelegate( (context, index) { var data = filteredCountries[index]; return InkWell( onTap: () { FocusScope.of(context).unfocus(); Navigator.pushNamed(context, Routes.detail, arguments: data); }, child: ListTile( title: Text(data.country.toString()), leading: SizedBox( height: getProportionateScreenHeight(100), width: getProportionateScreenWidth(50), child: Image.network(data.countryInfo!.flag.toString()), ), subtitle: Text(data.cases.toString()), ), ); }, childCount: filteredCountries.length, ), ), ], ); }), ), ); } }
关键优化点
- 联动滚动实现:通过
CustomScrollView将搜索框(SliverToBoxAdapter)和列表(SliverList)绑定为同一滚动体,实现滚动同步。 - 搜索逻辑优化:用
where提前过滤列表,替代原代码中返回空容器的写法,减少无效渲染节点,提升性能。 - 代码简化:将嵌套的
Image(image: Image.network(...).image)简化为直接使用Image.network(...),减少冗余代码。
内容的提问来源于stack exchange,提问作者Syed Rehan
相关产品推荐
相关产品推荐

