Flutter:SingleChildScrollView存在下方内容却无法向下滚动
问题:SingleChildScrollView无法滚动查看全部列表内容
JSON数据解析正常,所有列表项均可加载,但SingleChildScrollView组件内下方内容(如仅露出一小部分的item6及后续项)无法向下滚动查看,怀疑是SingleChildScrollView嵌套在Container与Scaffold中导致冲突。
完整代码
import 'dart:async'; import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; Future<List<Event>> fetchEvents(http.Client client) async { final response = await http.get(Uri.parse('https://my-json-server.typicode.com/Evgen1987RUS/test-json/events/')); // TODO: тестовый джей сон поменять на нормальный return compute(parseEvents, response.body); } List<Event> parseEvents(String responseBody) { final parsed = (jsonDecode(responseBody) as List).cast<Map<String, dynamic>>(); return parsed.map<Event>((json) => Event.fromJson(json)).toList(); } class Event { final String id; final String name; final String description; final String date; final String imgPath; const Event({ required this.id, required this.name, required this.description, required this.date, required this.imgPath, }); factory Event.fromJson(Map<String, dynamic> json) { return Event ( id: json['id'] as String, name: json['name'] as String, description: json['description'] as String, date: json['date'] as String, imgPath: json['imgPath'] as String, ); } } void main() => runApp(const SPNRApp()); class SPNRApp extends StatelessWidget { const SPNRApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'СПНР', theme: ThemeData( primarySwatch: Colors.amber ), home: const HomePage( title: 'Главная страница' ), ); } } class HomePage extends StatelessWidget { const HomePage({Key? key, required this.title}) : super(key: key); // make it require the title as a key value final String title; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(title) ), body: Container( height: 100, color: Colors.amber, child: SingleChildScrollView( child: FutureBuilder<List<Event>>( future: fetchEvents(http.Client()), builder: (context, snapshot) { if (snapshot.hasError) { print('line 83 snapshot failure'); return const Center( child: Text('Ошибка'), ); } else if (snapshot.hasData) { return EventsList(events: snapshot.data!); } else { return const Center( child: CircularProgressIndicator(), ); } }, ), ), ), ); } } class EventsList extends StatelessWidget { const EventsList({super.key, required this.events}); final List<Event> events; @override Widget build(BuildContext context) { return ListView.builder( shrinkWrap: true, itemCount: events.length, itemBuilder: (context, int index) { return Text(events[index].name); } ); } }
问题演示

解决方案
问题根源有两点:
- 滚动组件嵌套冲突:
SingleChildScrollView和ListView都是滚动组件,嵌套后会导致滚动事件被拦截,无法正常触发外层滚动。 - 固定高度限制:外层
Container设置了height:100,未给滚动组件留出合理的滚动空间逻辑支持。
方案一:移除冗余的SingleChildScrollView(推荐)
直接使用 ListView 处理滚动,无需嵌套 SingleChildScrollView,同时调整外层容器的高度设置:
修改 HomePage 的 body 部分:
body: Container( color: Colors.amber, child: FutureBuilder<List<Event>>( future: fetchEvents(http.Client()), builder: (context, snapshot) { if (snapshot.hasError) { print('line 83 snapshot failure'); return const Center( child: Text('Ошибка'), ); } else if (snapshot.hasData) { return EventsList(events: snapshot.data!); } else { return const Center( child: CircularProgressIndicator(), ); } }, ), ),
同时修改 EventsList 中的 ListView,去掉 shrinkWrap: true(让ListView自适应父容器高度并支持滚动):
class EventsList extends StatelessWidget { const EventsList({super.key, required this.events}); final List<Event> events; @override Widget build(BuildContext context) { return ListView.builder( itemCount: events.length, itemBuilder: (context, int index) { return Text(events[index].name); } ); } }
方案二:保留SingleChildScrollView,禁用ListView的滚动
如果必须保留嵌套结构,需要禁用 ListView 的滚动能力,避免事件冲突:
修改 EventsList 中的 ListView:
class EventsList extends StatelessWidget { const EventsList({super.key, required this.events}); final List<Event> events; @override Widget build(BuildContext context) { return ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), // 禁用ListView自身滚动 itemCount: events.length, itemBuilder: (context, int index) { return Text(events[index].name); } ); } }
同时确保外层 Container 的高度设置合理,让 SingleChildScrollView 能正确计算滚动范围。
内容的提问来源于stack exchange,提问作者Evgenii Isaenko
相关产品推荐
相关产品推荐

