Flutter Scrolling widgets
默认情况下,布局组件内的子组件内容超出容器宽度时会出现一个溢出警告
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Row'), ), body: Stack( children: [ Row( children: List.generate( 20, (index) => OutlinedButton( onPressed: () {}, child: Text('按钮 ${index + 1}'), ), ), ), ], ), ); } }
列表 -- SingleChildScrollView
支持单组件滚动,类似 Android 中的 ScrollView
属性:
child:Widget,单个子组件
padding:EdgeInsets,内边距
scrollDirection:Axis,滚动方向,默认值 vertical(Axis.horizontal | Axis.vertical)
reverse:bool,初始滚动位置,默认值 false(false:头部,true:尾部)
physics
ClampingScrollPhysics:Android 下微光效果
BouncingScrollPhysics:IOS 下弹性效果
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('SingleChildScrollView'), ), body: Stack( children: [ // 水平方向的滚动 Container( width: double.infinity, padding: const EdgeInsets.all(10), child: SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.all(10), // 初始滚动位置:尾部 reverse: true, // 触底效果 physics: const ClampingScrollPhysics(), child: Row( children: List.generate( 20, (index) => OutlinedButton( onPressed: () {}, child: Text('按钮 ${index + 1}'), ), ), ), ), ), // 垂直方向的滚动 Container( width: double.infinity, margin: const EdgeInsets.only(top: 100), padding: const EdgeInsets.all(10), child: SingleChildScrollView( scrollDirection: Axis.vertical, padding: const EdgeInsets.all(10), // 初始滚动位置:头部 reverse: false, // 触底效果 physics: const BouncingScrollPhysics(), child: Column( children: List.generate( 20, (index) => OutlinedButton( onPressed: () {}, child: Text('按钮 ${index + 1}'), ), ), ), ), ), ], ), ); } }
列表 -- ListView
ListView
加载列表的组件(加载所有 Widgets,适用 Widget 较少的场景)
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('ListView'), ), body: Column( children: [ Container( height: 200, color: Colors.yellow[100], padding: const EdgeInsets.all(10), child: ListView( // 默认垂直方向滚动 children: const [ ListTile( leading: Icon( Icons.favorite, size: 50, ), title: Text('收藏'), subtitle: Text('子标题'), trailing: Icon(Icons.keyboard_arrow_right), // 是否选中,默认值 false selected: true, // 选中的文本和icon的颜色 selectedColor: Colors.red, ), ListTile( leading: Icon( Icons.audiotrack, size: 50, ), title: Text('音乐'), subtitle: Text('子标题'), trailing: Icon(Icons.keyboard_arrow_right), ), ListTile( leading: Icon( Icons.beach_access, size: 50, ), title: Text('海滩'), subtitle: Text('子标题'), trailing: Icon(Icons.keyboard_arrow_right), ), ListTile( leading: Icon( Icons.shopping_cart, size: 50, ), title: Text('购物车'), subtitle: Text('子标题'), trailing: Icon(Icons.keyboard_arrow_right), ), ], ), ), ], ), ); } }
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('ListView Horizontal'), ), body: Container( height: 100, padding: const EdgeInsets.all(10), child: ListView( // 水平方向滚动 scrollDirection: Axis.horizontal, children: [ Container( width: 100, color: Colors.yellow, ), Container( width: 100, color: Colors.blueGrey, ), Container( width: 100, color: Colors.pink[100], ), Container( width: 100, color: Colors.green[100], ), Container( width: 100, color: Colors.red[100], ), Container( width: 100, color: Colors.purple[300], ), ], ), ), ); } }
ListView.builder
按需加载 Widget,性能比默认构造函数高,适用 Widget 较多的场景
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); List<Widget> getUsers() { return List<Widget>.generate( 20, (index) => OutlinedButton( onPressed: () {}, child: Text('按钮 $index'), ), ); } @override Widget build(BuildContext context) { List<Widget> userList = getUsers(); return Scaffold( appBar: AppBar( title: const Text('ListView.builder'), ), body: Container( height: 150, padding: const EdgeInsets.all(10), child: ListView.builder( // 列表数量 itemCount: userList.length, // 列表子组件高度 itemExtent: 50, // 列表子组件构造器 itemBuilder: (context, index) { return userList[index]; }, ), ), ); } }
ListView.separated
比 ListView.builder 多了个分隔器
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); List<Widget> getProducts() { return List<Widget>.generate( 20, (index) => ListTile( leading: Image.network( 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', ), title: Text('商品标题 ${index + 1}'), subtitle: const Text('子标题'), trailing: const Icon(Icons.keyboard_arrow_right), ), ); } @override Widget build(BuildContext context) { List<Widget> products = getProducts(); // 偶数分隔器 Widget dividerOdd = const Divider( color: Colors.red, thickness: 2, // 分隔线的粗细 ); // 奇数分隔器 Widget dividerEven = const Divider( color: Colors.green, thickness: 2, ); return Scaffold( appBar: AppBar( title: const Text('ListView.seperated'), ), body: Column( children: [ const ListTile(title: Text('商品列表')), Container( height: 200, padding: const EdgeInsets.symmetric(horizontal: 10), child: ListView.separated( // 列表的数量 itemCount: products.length, // 列表子组件构造器 itemBuilder: (context, index) { return products[index]; }, // 分隔器的构造器 separatorBuilder: (context, index) { return index % 2 == 0 ? dividerEven : dividerOdd; }, ), ), ], ), ); } }
列表 -- GridView(网格布局)
属性:
children:Widgets,子组件
scrollDirection:滚动方向
gridDelegate:
SilverGridDelegateWithFixedCrossAxisCount:指定列数,子组件宽度自适应
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('GridView'), ), body: Container( width: double.infinity, padding: const EdgeInsets.all(10), child: GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 4, // 必填,指定列数 mainAxisSpacing: 20, // 主轴方向的间距 crossAxisSpacing: 20, // 交叉轴方向的间距 ), children: [ Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_1003.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_1007.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_1023.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10263.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10715.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10822.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10832.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10982.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_11006.jpg', ), ], ), ), ); } }
SilverGridDelegateWithMaxCrossAxisCount:指定子组件宽度,列数自适应
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('GridView'), ), body: Container( width: double.infinity, padding: const EdgeInsets.all(10), child: GridView( gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 120, // 必填,子组件的最大宽度 mainAxisSpacing: 20, crossAxisSpacing: 20, ), children: [ Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_1003.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_1007.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_1023.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10263.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10715.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10822.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10832.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_10982.jpg', ), Image.network( 'https://images.dog.ceo/breeds/hound-afghan/n02088094_11006.jpg', ), ], ), ), ); } }
GirdView.count() 列数固定
属性:
crossAxisCount:int,必填项,列数
scrollDirection:Axis,默认值 veritical,滚动方向,默认纵向滚动
mainAxisSpacing:double,主轴方向的子组件间距
crossAxisSpacing:double,交叉轴方向的子组件间距
childAspectRadio:double,子组件的分辨率,默认值 1.0
children:List<Widget>,子组件
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('GridView.count'), ), body: Container( padding: const EdgeInsets.all(10), child: GridView.count( // scrollDirection: Axis.horizontal, crossAxisCount: 2, // 列数 mainAxisSpacing: 10, // 交叉轴上(水平)子组件之间的间距 crossAxisSpacing: 20, // 主轴上(垂直)子组件之间的间距 childAspectRatio: 2, // 子组件的缩放比例 children: List.generate( 10, (index) => Image.asset('assets/image2.jpg'), ), ), ), ); } }
GridView.extent() 子组件宽度固定
属性:
maxCrossAxisExtent:double,必填项,子组件最大宽度
scrollDirection:Axis,默认值 veritical,滚动方向,默认纵向滚动
mainAxisSpacing:double,主轴方向的子组件间距
crossAxisSpacing:double,交叉轴方向的子组件间距
childAspectRadio:double,子组件的分辨率,默认值 1.0
children:List<Widget>,子组件
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('GridView.extent'), ), body: Container( padding: const EdgeInsets.all(10), child: GridView.extent( maxCrossAxisExtent: 120, // 子组件最大宽度 mainAxisSpacing: 10, // 主轴方向(纵向)子组件间距 crossAxisSpacing: 10, // 交叉轴(横向)子组件间距 // scrollDirection: Axis.horizontal, children: List.generate( 50, (index) => Image.network( 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'), ), ), ), ); } }
GridView.builder() 动态网格布局
physics:ScrollPhysics,确定可滚动控件的物理特性
BouncingScrollPhysics():允许超出边界 -- 反弹效果
ClampingScrollPhysics():防止超出边界 -- 夹住效果
AlwaysScrollableScrollPhysics():始终响应滚动
NeverScrollableScrollPhysics():不响应滚动
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final List<Image> images = List<Image>.generate( 50, (index) => Image.network( 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', ), ); return Scaffold( appBar: AppBar( title: const Text('GridView.builder'), ), body: Container( padding: const EdgeInsets.all(10), child: GridView.builder( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, mainAxisSpacing: 10, crossAxisSpacing: 10, ), itemCount: images.length, itemBuilder: (context, index) { return images[index]; }, physics: const BouncingScrollPhysics(), // 反弹效果 // physics: const ClampingScrollPhysics(), // 夹住的效果(触底没什么反应) // physics: const AlwaysScrollableScrollPhysics(), // 滚动 // physics: const NeverScrollableScrollPhysics(), // 禁止滚动 ), ), ); } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!