ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

【Flutter入门练中学】第3课:滚动与列表

【Flutter入门练中学】第3课:滚动与列表 目标理解为什么需要滚动内容高度或宽度超出屏幕。掌握SingleChildScrollView、ListView、ListView.builder、ListView.separated。掌握GridView.count、GridView.builder的基础用法。理解scrollDirection、physics、shrinkWrap的作用与代价。能实现待办列表、商品网格、聊天列表、相册网格。能识别并修复Vertical viewport was given unbounded height等常见滚动错误。通过“题目要求 → 答案 → 答案解读”的多元化习题完成练中学。一、本课核心概念速览Widget / 属性作用SingleChildScrollView让单个子组件可滚动适合少量内容ListView可滚动列表children适合少量固定项ListView.builder按需构建列表项适合大量或动态数据ListView.separated带分隔线的列表GridView.count固定列数的网格GridView.builder按需构建网格项scrollDirection滚动方向垂直或水平physics滚动物理效果如回弹、禁用滚动shrinkWrap让列表按内容高度收缩慎用可能影响性能一句话口诀少量内容用 SingleChildScrollView大量列表用 builder网格用 GridView。二、最小可运行示例把lib/main.dart改成importpackage:flutter/material.dart;voidmain(){runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});overrideWidgetbuild(BuildContextcontext){returnMaterialApp(home:Scaffold(appBar:AppBar(title:constText(滚动与列表)),body:ListView.builder(itemCount:30,itemBuilder:(context,index){returnListTile(leading:CircleAvatar(child:Text($index)),title:Text(第$index项),subtitle:constText(练中学滚动列表),);},),),);}}按r热重载滚动页面观察ListView.builder如何按需构建列表项。三、多元化习题练习0热重载体验滚动题目要求运行最小示例完成以下操作并记录变化把ListView.builder改成SingleChildScrollView Column放 10 个ListTile。再把scrollDirection改成Axis.horizontal。最后把physics改成NeverScrollableScrollPhysics()。答案// 1. SingleChildScrollView Columnbody:SingleChildScrollView(child:Column(children:List.generate(10,(index)ListTile(title:Text(第$index项)),),),),// 2. 水平滚动body:ListView.builder(scrollDirection:Axis.horizontal,itemCount:10,itemBuilder:(context,index){returnContainer(width:120,margin:constEdgeInsets.all(8),color:Colors.blue.shade100,alignment:Alignment.center,child:Text(第$index项),);},),// 3. 禁止滚动body:ListView.builder(physics:constNeverScrollableScrollPhysics(),itemCount:30,itemBuilder:(context,index)ListTile(title:Text(第$index项)),),答案解读SingleChildScrollView适合内容不多的页面它会一次性构建所有子项。ListView.builder适合长列表会按需构建可见项。scrollDirection控制滚动方向。NeverScrollableScrollPhysics()可以禁用滚动常用于嵌套滚动或自定义滚动控制。练习1选择题题目要求当列表项数量很多且需要动态生成时推荐使用哪个A.ListView(children: [...])B.ListView.builderC.ColumnD.SingleChildScrollView答案B。答案解读ListView(children: [...])会一次性构建所有子项适合少量固定内容。ListView.builder按需构建性能更好适合大量或动态数据。Column本身不滚动SingleChildScrollView也是一次性构建所有子项。练习2判断题题目要求判断对错并说明理由SingleChildScrollView适合超长列表。ListView.builder会按需构建子项。GridView.count可以指定交叉轴列数。shrinkWrap: true总是提升性能。答案错。对。对。错。答案解读SingleChildScrollView会一次性构建所有子项超长列表会占用大量内存应该用ListView.builder。GridView.count的crossAxisCount可以指定列数。shrinkWrap: true让列表按内容收缩但通常会增加布局计算成本只有在嵌套滚动等必要场景才使用。练习3连线题题目要求将左侧 Widget 或属性与右侧作用连线左侧右侧SingleChildScrollView按需构建列表ListView.builder单个子组件可滚动ListView.separated滚动物理效果GridView.count带分隔线的列表physics固定列数网格答案SingleChildScrollView — 单个子组件可滚动ListView.builder — 按需构建列表ListView.separated — 带分隔线的列表GridView.count — 固定列数网格physics — 滚动物理效果答案解读这些是滚动与列表最常用的成员。先记住用途再通过组合完成页面。练习4排序题题目要求实现一个页面顶部标题下面 20 个列表项。请按从外到内的嵌套顺序排列Scaffold、Column、Text、Expanded、ListView.builder、ListTile答案Scaffold→Column→Text→Expanded→ListView.builder→ListTile答案解读Scaffold是页面骨架Column垂直排列标题和列表。Expanded让ListView占满剩余高度否则ListView在Column中会得到无界高度而报错。ListView.builder生成ListTile。练习5填空题题目要求补全代码生成 20 个列表项ListView.builder(itemCount:______,itemBuilder:(context,______){returnListTile(title:Text(第$index项));},)答案ListView.builder(itemCount:20,itemBuilder:(context,index){returnListTile(title:Text(第$index项));},)答案解读itemCount决定列表项数量。itemBuilder接收context和index返回对应位置的 Widget。index从 0 开始所以显示 0 到 19。练习6代码预测题题目要求阅读代码预测屏幕显示内容ListView.builder(itemCount:3,itemBuilder:(context,index){returnListTile(title:Text($index));},)答案屏幕显示三行0、1、2。答案解读itemCount: 3表示生成 3 项index分别为 0、1、2。ListTile的title显示当前索引。练习7改错题题目要求下面代码会报错找出来并修正Column(children:[constText(标题),ListView.builder(itemCount:10,itemBuilder:(context,index)ListTile(title:Text($index)),),],)答案修正方式之一Column(children:[constText(标题),Expanded(child:ListView.builder(itemCount:10,itemBuilder:(context,index)ListTile(title:Text($index)),),),],)答案解读Column给子项的高度约束是无界的而ListView在垂直方向需要有限高度。用Expanded包裹后ListView会获得剩余高度。也可以给ListView固定高度或设置shrinkWrap: true但Expanded更常用。练习8补全代码题题目要求做一个水平滚动列表显示 5 个彩色方块SizedBox(height:100,child:ListView.builder(scrollDirection:______,itemCount:5,itemBuilder:(context,index){returnContainer(width:100,margin:constEdgeInsets.all(8),color:Colors.primaries[index%Colors.primaries.length],);},),)答案SizedBox(height:100,child:ListView.builder(scrollDirection:Axis.horizontal,itemCount:5,itemBuilder:(context,index){returnContainer(width:100,margin:constEdgeInsets.all(8),color:Colors.primaries[index%Colors.primaries.length],);},),)答案解读水平滚动必须给ListView一个有限高度所以外层用SizedBox(height: 100)。scrollDirection: Axis.horizontal让列表水平滚动。每个Container有固定宽度 100。练习9动手编码题待办列表题目要求用ListView.builder显示 10 个待办项。每项使用ListTile包含leading圆形序号title待办内容trailing完成图标。答案body:ListView.builder(itemCount:10,itemBuilder:(context,index){returnListTile(leading:CircleAvatar(child:Text(${index1})),title:Text(待办事项${index1}),subtitle:constText(练中学列表项),trailing:constIcon(Icons.check_circle_outline),);},)答案解读ListTile是列表项的标准组件leading放左侧组件title和subtitle放文字trailing放右侧组件。index 1让序号从 1 开始。练习10动手编码题商品网格题目要求用GridView.count做 2 列商品网格共 6 个商品。每个格子显示一个图标和商品名称。答案body:GridView.count(crossAxisCount:2,padding:constEdgeInsets.all(12),mainAxisSpacing:12,crossAxisSpacing:12,children:List.generate(6,(index){returnContainer(decoration:BoxDecoration(color:Colors.blue.shade50,borderRadius:BorderRadius.circular(12),),child:Column(mainAxisAlignment:MainAxisAlignment.center,children:[constIcon(Icons.shopping_bag,size:40,color:Colors.blue),constSizedBox(height:8),Text(商品${index1}),],),);}),)答案解读GridView.count的crossAxisCount: 2表示两列。mainAxisSpacing和crossAxisSpacing控制间距。List.generate快速生成 6 个格子。每个格子用Container加圆角和背景色。练习11综合挑战聊天列表 输入栏题目要求用Column Expanded ListView.builder做聊天页面上方是聊天记录列表下方是输入栏。列表显示 20 条消息输入栏包含一个TextField和一个发送按钮。答案body:Column(children:[Expanded(child:ListView.builder(padding:constEdgeInsets.all(12),itemCount:20,itemBuilder:(context,index){finalisMeindex%20;returnAlign(alignment:isMe?Alignment.centerRight:Alignment.centerLeft,child:Container(margin:constEdgeInsets.symmetric(vertical:4),padding:constEdgeInsets.all(12),decoration:BoxDecoration(color:isMe?Colors.blue.shade100:Colors.grey.shade200,borderRadius:BorderRadius.circular(12),),child:Text(消息$index),),);},),),Container(padding:constEdgeInsets.all(8),color:Colors.white,child:Row(children:[constExpanded(child:TextField(decoration:InputDecoration(hintText:输入消息,border:OutlineInputBorder(),),),),constSizedBox(width:8),ElevatedButton(onPressed:(){},child:constText(发送),),],),),],)答案解读Column垂直排列聊天区和输入栏。聊天区用Expanded包裹ListView.builder占满剩余空间。每条消息根据index判断左右对齐。底部Row中TextField用Expanded占剩余宽度按钮固定宽度。练习12开放式挑战相册网格题目要求用GridView.builder做 3 列相册共 12 张。每格是彩色方块带圆角和图标。要求使用SliverGridDelegateWithFixedCrossAxisCount。答案示例body:GridView.builder(padding:constEdgeInsets.all(12),itemCount:12,gridDelegate:constSliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:3,mainAxisSpacing:8,crossAxisSpacing:8,),itemBuilder:(context,index){returnContainer(decoration:BoxDecoration(color:Colors.primaries[index%Colors.primaries.length].shade200,borderRadius:BorderRadius.circular(12),),child:constIcon(Icons.photo,size:36,color:Colors.white),);},)答案解读GridView.builder按需构建网格项适合数量较多的情况。SliverGridDelegateWithFixedCrossAxisCount指定列数、间距。index % Colors.primaries.length让颜色循环使用。开放题没有唯一答案重点是能运行、能滚动、能热重载修改。练习13错误观察挑战题目要求故意在Column中直接放ListView不包Expanded运行后观察控制台错误记录关键错误词。答案示例错误代码Column(children:[constText(标题),ListView.builder(itemCount:10,itemBuilder:(context,index)ListTile(title:Text($index)),),],)控制台常见错误Vertical viewport was given unbounded height.或RenderFlex children have non-zero flex but incoming height constraints are unbounded.答案解读Column在垂直方向给子项的高度约束是无界的而ListView作为垂直视口需要有限高度。解决方法用Expanded包裹ListView或给ListView固定高度或设置shrinkWrap: true。学会看这个错误就能快速定位嵌套滚动问题。四、本课小结这一课你练了SingleChildScrollView与ListView的区别ListView.builder、ListView.separated的按需构建GridView.count、GridView.builder的网格布局scrollDirection、physics、shrinkWrap的用途待办列表、商品网格、聊天页面、相册网格的实现通过故意制造无界高度错误学会看Vertical viewport was given unbounded height。下一课可以进入状态管理与交互setState进阶、TextField、Checkbox、Switch、Slider、Form继续用“练中学”的方式做可交互页面。
返回列表