第二部分将聚焦于 App 开发中最常见的两个需求:
- 长列表与滚动视图 (Scrolling Widgets):如何展示超出屏幕高度的数据,如何高效渲染成百上千条数据。
- 视觉装饰与裁剪 (Styling & Clipping):如何让 UI 变得精致,包括圆角、卡片阴影、透明度变换等。
第二部分:滚动视图与视觉装饰
第四章:滚动与列表组件 (Scrolling Widgets)
在移动端开发中,屏幕空间有限,处理溢出内容是核心技能。Flutter 提供了强大的滚动机制,从简单的单一视图滚动到复杂的嵌套滚动。
1. SingleChildScrollView (单一子元素滚动)
说明:
这是最简单的滚动组件,它只能包含一个子组件(通常是一个 Column)。它的作用类似于 HTML 中的 overflow-y: scroll。
⚠️ 适用场景: 内容量较少,但可能会在小屏幕上溢出(例如注册表单页)。
❌ 不适用场景: 无限列表或数据量很大的列表(性能差,因为它会一次性渲染所有子组件)。
核心属性:
| 属性名 | 类型 | 说明 |
|---|---|---|
child | Widget | 滚动的内容。 |
scrollDirection | Axis | 滚动方向(垂直 Axis.vertical 或 水平 Axis.horizontal)。 |
physics | ScrollPhysics | 滚动物理效果(如 iOS 回弹、Android 阻尼)。 |
padding | EdgeInsets | 内容的内边距。 |
controller | ScrollController | 控制滚动位置。 |
代码示例:
import 'package:flutter/material.dart';
class SingleScrollExample extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("SingleChildScrollView")),
body: SingleChildScrollView(
padding: EdgeInsets.all(20),
child: Column(
children: List.generate(20, (index) {
return Container(
height: 50,
margin: EdgeInsets.only(bottom: 10),
color: Colors.blue[100 * (index % 9 + 1)],
child: Center(child: Text("Item $index")),
);
}),
),
),
);
}
}
2. ListView (线性列表)
说明:
ListView 是 Flutter 中最常用的滚动组件。它支持懒加载(Lazy Loading),即只渲染屏幕可见区域的元素,极大提高了长列表的性能。
主要构造函数:
ListView()(默认构造):- 直接传入
children: <Widget>[]。 - 适用于少量静态数据。
- 直接传入
ListView.builder()(推荐):- 按需构建列表项。
- 适用于大量、动态数据。
- 必填:
itemCount(数量),itemBuilder(构建器)。
ListView.separated():- 在
builder的基础上,增加了separatorBuilder,用于在项之间生成分割线。
- 在
核心属性:
| 属性名 | 类型 | 说明 |
|---|---|---|
itemExtent | double | (可选) 强制指定每个子项的高度。设定此值可大幅优化性能,因为 Flutter 不再需要计算每个 item 的高度。 |
shrinkWrap | bool | 列表长度是否根据内容收缩。若在 Column 中嵌套 ListView,通常需设为 true。 |
physics | ScrollPhysics | BouncingScrollPhysics (iOS风格), ClampingScrollPhysics (Android风格), NeverScrollableScrollPhysics (禁止滚动)。 |
代码示例 (ListView.separated):
import 'package:flutter/material.dart';
class ListViewExample extends StatelessWidget {
final List<String> items = List.generate(100, (i) => "数据项 #$i");
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("ListView Builder")),
body: ListView.separated(
itemCount: items.length,
// 构建分割线
separatorBuilder: (context, index) {
return Divider(color: Colors.grey, height: 1);
},
// 构建每一项
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(child: Text("${index + 1}")),
title: Text(items[index]),
subtitle: Text("这是第 $index 条详情描述"),
trailing: Icon(Icons.arrow_forward_ios, size: 16),
onTap: () {
print("点击了: ${items[index]}");
},
);
},
),
);
}
}
3. GridView (网格布局)
说明:
GridView 用于构建二维网格布局(如相册、商品列表)。
主要构造函数:
GridView.count():直接指定横轴子元素数量 (crossAxisCount)。GridView.extent():指定子元素的最大宽度 (maxCrossAxisExtent),自动计算一行能放几个。GridView.builder():用于大量数据的网格懒加载。
核心委托 (Delegate) 属性:
gridDelegate 是控制网格布局算法的核心。
SliverGridDelegateWithFixedCrossAxisCount: 固定列数。crossAxisCount: 列数。childAspectRatio: 子元素宽高比 (width / height)。mainAxisSpacing: 主轴间距。crossAxisSpacing: 横轴间距。
代码示例 (GridView.builder):
import 'package:flutter/material.dart';
class GridViewExample extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: GridView.builder(
padding: EdgeInsets.all(10),
itemCount: 50,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 一行3个
childAspectRatio: 0.8, // 宽高比 0.8 (偏高)
mainAxisSpacing: 10, // 垂直间距
crossAxisSpacing: 10, // 水平间距
),
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.teal[100 * (index % 9)],
borderRadius: BorderRadius.circular(8),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.photo, size: 40, color: Colors.white),
SizedBox(height: 5),
Text("Item $index"),
],
),
);
},
),
);
}
}
4. CustomScrollView & Slivers (高级滚动)
说明:
当你想实现复杂的滚动效果(例如:顶部 AppBar 随着滚动折叠、下拉放大图片、列表和网格混合在同一个滚动视图中)时,必须使用 CustomScrollView 配合 Sliver 系列组件。
概念: Sliver 是滚动视图中的一个切片。
常用 Sliver 组件:
SliverAppBar: 可折叠的头部。SliverList: 等同于 ListView。SliverGrid: 等同于 GridView。SliverToBoxAdapter: 将普通的 Widget(如 Container)放入 Sliver 视口中。
代码示例 (SliverAppBar 效果):
import 'package:flutter/material.dart';
class SliverExample extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
// 1. 可折叠的头部
SliverAppBar(
pinned: true, // 滑动到顶部固定
floating: true, // 稍微向下拉就显示
expandedHeight: 200.0, // 展开高度
flexibleSpace: FlexibleSpaceBar(
title: Text("Sliver Demo"),
background: Image.network(
"https://picsum.photos/800/400",
fit: BoxFit.cover,
),
),
),
// 2. 一个普通的盒子 (需要适配器)
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(15),
child: Text("下方是混合布局 (Grid + List)",
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
),
),
// 3. 网格区域
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
mainAxisSpacing: 5,
crossAxisSpacing: 5,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return Container(color: Colors.pink[100 * (index % 9)], child: Center(child: Text("$index")));
},
childCount: 8,
),
),
// 4. 列表区域
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return ListTile(title: Text("List Item $index"));
},
childCount: 20,
),
),
],
),
);
}
}
第五章:容器与装饰组件 (Styling & Assets)
这一章我们将介绍如何让 UI 从“能用”变成“好看”。
1. Card (卡片)
说明:
Card 是 Material Design 风格的卡片组件,自带圆角和阴影,通常用于展示相关联的信息块。
核心属性:
| 属性名 | 类型 | 说明 |
|---|---|---|
elevation | double | 阴影高度(z轴高度)。 |
shape | ShapeBorder | 形状(通常使用 RoundedRectangleBorder 设置圆角)。 |
color | Color | 卡片背景色。 |
margin | EdgeInsets | 外边距。 |
代码示例:
Card(
elevation: 5,
margin: EdgeInsets.all(10),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15), // 圆角
),
child: Padding(
padding: EdgeInsets.all(15),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
leading: Icon(Icons.album, size: 50),
title: Text("Card Title"),
subtitle: Text("Card Subtitle Description"),
),
ButtonBar(
children: [
TextButton(onPressed: () {}, child: Text("ACTION 1")),
TextButton(onPressed: () {}, child: Text("ACTION 2")),
],
)
],
),
),
)
2. Clip 系列 (裁剪组件)
说明:
Flutter 的组件默认通常是矩形的。如果需要裁剪成圆形、圆角矩形或自定义形状,需要使用 Clip 组件包裹。
常用组件:
ClipRRect: 圆角矩形裁剪 (Rounded Rect)。最常用,用于给图片加圆角。ClipOval: 椭圆/圆形裁剪。ClipPath: 路径裁剪(配合 CustomClipper 使用,可裁出波浪形、星星等任意形状)。
代码示例:
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// 1. 圆角图片
ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Image.network("https://picsum.photos/100/100", width: 100, height: 100),
),
// 2. 圆形图片
ClipOval(
child: Container(
color: Colors.blue,
width: 100,
height: 100,
child: Center(child: Text("Circle")),
),
),
],
)
3. Transform (变换)
说明:
用于对子组件进行几何变换,如旋转(Rotate)、缩放(Scale)、平移(Translate)。注意:变换只改变视觉效果,不改变组件在布局中占据的实际位置(HitTest 响应区域可能会变)。
代码示例:
Container(
color: Colors.black,
child: Transform(
alignment: Alignment.center, // 变换中心点
transform: Matrix4.rotationZ(0.3), // 旋转弧度
child: Container(
padding: EdgeInsets.all(8),
color: Colors.deepOrange,
child: const Text('Apartment for rent!'),
),
),
)
4. Opacity (透明度)
说明:
改变子组件的透明度。
注意:
如果只是想让颜色透明,尽量使用 Color.withOpacity()。Opacity 组件是一个极其昂贵的组件(因为它可能会触发离屏渲染),如果在动画中频繁使用,建议使用 AnimatedOpacity。
核心属性:
opacity: 0.0 (全透明) 到 1.0 (不透明)。
附录:常见布局陷阱 (Pro Tips)
在学习完第二部分后,新手常遇到的报错如下,请务必留意:
-
无限高度错误 (Vertical viewport was given unbounded height)
- 场景:在
Column中嵌套ListView。 - 原因:Column 想要无限向下延伸,ListView 也想要无限向下延伸,导致冲突。
- 解决:给 ListView 包裹一个
Expanded或者SizedBox(height: xxx)。
// ❌ 错误示范 Column( children: [ Text("Header"), ListView(...) // 报错! ] ) // ✅ 正确示范 Column( children: [ Text("Header"), Expanded( child: ListView(...) ) ] ) - 场景:在
-
RenderFlex overflowed (黄色斑马线条纹)
- 原因:内容超过了 Row 或 Column 的边界。
- 解决:
- 如果是文字溢出,使用
Expanded包裹文字。 - 如果是整体溢出,将 Row/Column 换成
ListView或SingleChildScrollView。
- 如果是文字溢出,使用
第二部分总结:
通过本部分的学习,你已经掌握了 ListView 和 GridView 这两个处理数据的核心武器,并且学会了使用 Card 和 Clip 来美化界面。配合第一部分的布局知识,你现在已经完全有能力开发一个类似“新闻列表”或“电商首页”的静态界面了。
下一步计划:
App 不仅仅是展示,还需要交互。
第三部分 将重点讲解 表单与输入 (TextField, Checkbox, Form) 以及 弹窗与交互反馈 (Dialog, SnackBar),这将赋予你的 App 获取用户数据的能力。

被折叠的 条评论
为什么被折叠?



