前言在上一篇博客我们了解了 Flutter 中的布局组建。基于布局组建再结合今天学习的功能组建和滚动组件就可以在 Flutter 中实现一个基本可用的页面。目录前言功能组件Textstyle属性的使用行数控制TextSpanImageImage.asset()Image.network()TextFieldUI 结构绘制功能实现滚动组件SingleChildScrollView滚动控制ListView默认构造模式ListView.builderListView.separatedGridViewGridView.count()GridView.extent()GridView.builder()总结功能组件TextText 组件用于在用户界面中显示文本所有的文本显示都需要使用 Text 组件。如果需要在同一段文本中显示不同样式可以使用 Text.rich 构造函数配合 TextSpan 实现。Text 组件本身和其 TextStyle 中都有可能有 overflow 属性此时 Text 组件优先级更高。大量重复使用的文本样式建议统一定义有助于保持一致性提升性能。属性类型作用说明dataString必需。要显示的文本内容。styleTextStyle文本样式可设置颜色、大小、粗细等。textAlignTextAlign文本在容器内的水平对齐方式如.left.right。maxLinesint文本显示的最大行数。style属性的使用Text( style: TextStyle( fontSize: 30, color: Colors.blue, fontStyle: FontStyle.italic, fontWeight: FontWeight.bold, decoration: TextDecoration.underline, decorationColor: Colors.red, ), Hello, Flutter!, ),行数控制当超出 maxLines 时可以使用 overflow 属性指定对超出文本的行为 (如自动转为省略号)。Text( style: TextStyle(color: Colors.blue, fontSize: 30), maxLines: 2, overflow: TextOverflow.ellipsis, 今天天气不错今天天气不..., // 过长省略 ),TextSpan通过使用 Text.rich() 构造函数并传入 TextSpan 组件可以实现对文本形式的单独设置。其中外层设置的是全局样式内层设置的是相对样式。Text.rich( TextSpan( style: TextStyle( fontSize: 30, color: Colors.red, fontWeight: FontWeight.bold, decoration: TextDecoration.underline, decorationColor: Colors.yellow, decorationThickness: 3, ), text: Hello , children: [ TextSpan( style: TextStyle(color: Colors.green), text: Flutter, ), TextSpan(text: !), ], ), ),ImageImage 组件是用于在用户界面中显示图片的核心组件。分类分类作用说明Image.asset()加载项目资源目录 (assets) 中的图片。需要在 pubspec.yaml 文件中声明资源路径Image.network()直接从网络地址加载图片。Image.file()加载设备本地存储中的图片文件。Image.memory()加载内存中的图片数据。常用属性分类类型作用说明width / heightdouble设置图片显示区域的宽度和高度fitBoxFit控制图片如何适应其显示区域如拉伸、裁剪或保持原比例alignmentAlignmentGeometry图片在其显示区域内的对齐方式repeatImageRepeat当图片小于显示区域时设置是否以及如何重复平铺图片Image.asset()步骤配置 pubspec.yaml 文件在 flutter.assets 配置项下配置要读取的图片名或直接加载整个文件夹。配置 pubspec.yaml 时要额外注意缩进问题。flutter: uses-material-design: true assets: - lib/images/在文件中添加 Image 组件并在其中传入图片文件路径。要注意的是由于配置文件修改过而当前运行的程序没有这个配置无法识别到新添加的路径需要重新启动一次程序。Container( alignment: Alignment.center, width: double.infinity, height: double.infinity, color: Colors.amber, child: Image.asset( lib/images/github.png, width: 100, height: 100, // fit: BoxFit.contain, // fit: BoxFit.cover, // fit: BoxFit.fill, fit: BoxFit.fitHeight, ), ),Image.network()相比asset()network()配置相对简单不需要添加资源文件或设置资源路径只需要传入资源地址并保证网络畅通即可。在 Web 环境下不需要关心网络权限但是在如 安卓、IOS、鸿蒙 等环境都需要确保软件具有网络权限。Container( alignment: Alignment.center, width: double.infinity, height: double.infinity, color: Colors.amber, child: Image.network( https://inews.gtimg.com/news_ls/OSBSD0f6k8Md_QZ3W7JJunUuywoclkUuurTrwDgmYq-YwAA_870492/0, width: 300, height: 300, fit: BoxFit.fill, ), ),TextFieldTextField 是用来实现文本输入的核心组件使用时需要控制其中的内容。使用 TextField 时必须使用有状态组件因为 TextField 需要管理自己的状态而只有有状态组件才能管理自己的状态。其核心属性如下属性作用说明controller文本编辑器控制器用于获取、设置文档内容以及监听内容变化decoration控制输入框的外观如标签、提示文字、图标、边框等style定义输入文本的样式maxLines最大行数onChanged输入内容发生变化时执行的回调函数onSubmitted用户提交输入时的回调函数UI 结构绘制decoration 使用的类型为InputDecoration。设定背景颜色时需要同时设定 fillColor 和 filled前者用于设定背景颜色后者用于允许显示背景颜色。hinitText 用于设置输入框的提示文本。同时通过 obscureText 属性可以控制是否显示文本框内实际内容。在 decoration 中通过其中的 border 属性可以控制输入框的边框信息如是否圆角、是否有边框等。通过 borderSide可以控制是否显示输入框的边框通过 borderRadius 可以控制输入框的圆角。在 decoration 中通过 contentPadding 属性可以控制输入框中内容的 padding。使用obscureText属性可以设定是否显示实际内容通常用于密码输入框。Container( padding: EdgeInsets.all(20), color: Colors.white, child: Column( children: [ TextField( decoration: InputDecoration( contentPadding: EdgeInsets.only(left: 20), border: OutlineInputBorder( borderSide: BorderSide.none, borderRadius: BorderRadius.circular(25), ), fillColor: const Color.fromARGB(255, 255, 246, 164), filled: true, hintText: 请输入账号, ), ), SizedBox(height: 10), TextField( obscureText: true, decoration: InputDecoration( contentPadding: EdgeInsets.only(left: 20), border: OutlineInputBorder( borderSide: BorderSide.none, borderRadius: BorderRadius.circular(25), ), fillColor: const Color.fromARGB(255, 255, 246, 164), filled: true, hintText: 请输入密码, ), ), SizedBox(height: 10), Container( height: 50, width: double.infinity, decoration: BoxDecoration( color: Colors.black, borderRadius: BorderRadius.circular(25), ), child: TextButton( onPressed: () {}, child: Text(提交, style: TextStyle(color: Colors.white)), ), ), ], ), ),效果如下功能实现controller为获取 TextField 中的内容需要为 TextField 的 controller 属性传入一个TextEditingController类型组件以实现获取输入框内容的功能。通常在有状态组件的对内类中声明控制器并在相关的方法中通过该控制器获取组件中的内容并对组件进行操作。class MainPage extends StatefulWidget { ... } // 在内部类中定义控制器 class _MainPageState extends StateMainPage { TextEditingController _phoneController TextEditingController(); TextEditingController _passwordController TextEditingController(); override Widget build(BuildContext context) { TextField( controller: _phoneController, ), TextField( controller: _passwordController, ), Container( child: TextButton( onPressed: () { print(登录-账号-${_phoneController.text}); print(登录-密码-${_passwordController.text}); }, child: Text(提交, style: TextStyle(color: Colors.white)), ), ), } }onChanged 和 onSubmitonChanged 回调方法在输入框中内容发生变化时调用onSubmit 方法在输入框中内容提交时进行调用。在浏览器中通过在输入框中回车触发 onSubmit 函数在手机端通过键盘上的提交按钮触发 onSubmit 函数。TextField( onChanged: (value) { print(onChanged: $value); }, onSubmitted: (value) { print(onSubmitted: $value); }, ),滚动组件组件特点使用场景SingleChildScrollView让单个组件可以滚动所有内容一次性全部渲染长表单、设置页、内容量不固定但总量不多的页面ListView线性列表可以通过 builder 实现懒加载性能优异聊天记录、新闻、常见的单列滚动的数据列表GridView网格布局列表支持懒加载可以固定列数图片墙、商品网格、应用图标列表CustomScrollView复杂布局方案通过组合多个 Sliver 组件实现滚动电商首页、社交 App 个人主页多个滚动紧密联动PageView整页滚动效果支持横向和纵向应用引导页、图片轮播页、书籍翻页SingleChildScrollViewSingleChildScrollView 组件用于包裹一个子组件让单个子组件具备滚动能力。通过 List.generate 方法可以快速生成一系列组件。Column( children: List.generate(100, (index) { return Container( margin: EdgeInsets.only(top: 10), width: double.infinity, height: 100, alignment: Alignment.center, color: Colors.blue, child: Text( 我是第${index 1}个, style: TextStyle(color: Colors.white, fontSize: 30), ), ); }), ),生成完后效果如下可以看到提示 “Buttom overflowed by 10326 pixels”即内容超出页面 (因内容无法滚动查看)通过 SingleChildScrollView可以使单个子组件具备滚动功能。同时可以设置 padding 内边距属性。滚动控制通过 SingleChildScrollView 的 controller 属性可以给组件绑定对应的 ScrollController 对象。使用 Controller 组件可以控制 SingleChildScrollView 的滚动位置等。去底部 / 顶部的实现ListViewListView 组件是用于构建可滚动列表的核心部件且提供了流畅的滚动体验。该组件提供多种构造函数, 如默认构造函数、ListView.builder、ListView.separated。除默认构造函数为非懒加载其他构造方式都采用按需渲染的懒加载模式只构建当前可见区域的列表项极大提升长列表性能。ListView 中同样存在 controller 属性其接受值类型与 SingleChildSrcollView 相同控制滚动方式也相同。默认构造模式默认构造函数会一次性构建所有选项适用于静态数量有限数据一次性构建所有表项。ListView( padding: EdgeInsets.all(10), children: List.generate(100, (index) { return Container( margin: EdgeInsets.only(top: 10), width: double.infinity, height: 80, alignment: Alignment.center, decoration: BoxDecoration(color: Colors.blue), child: Text( 第${index 1}个, style: TextStyle(color: Colors.white, fontSize: 30), ), ); }), ),ListView.builderbuilder 模式是处理长列表或动态数据的首选和推荐方式。其接受一个itemBuilder 回调函数来按需构建列表项通过itemCount控制列表长度。回调函数需要传入两个参数分别是构建 UI 上下文 BuilderContext 和 当前组件下标 index。每次构建新表项时都会调用 itemBuilder。优势按需构建不会在初始化时将所有列表项都创建而是根据用户的滚动行为动态地创建和销毁列表项。ListView.separatedListView.separated 模式相当于在 ListView.builder 的基础上额外提供了构建分割线的能力。对于该构造方法需要同时提供 itemBuilder、separatorBuilder、itemCount 三个属性。separatorBuilder 提供一个回调函数用于构建分割线组件。ListView.separated( itemBuilder: (BuildContext context, int i) { return Container( width: double.infinity, height: 80, alignment: Alignment.center, decoration: BoxDecoration(color: Colors.blue), child: Text( 第${i 1}个, style: TextStyle(color: Colors.white, fontSize: 30), ), ); }, separatorBuilder: (BuildContext context, int i) { return Container( height: 10, width: double.infinity, color: Colors.pink, ); }, itemCount: 100, ),GridView用于创建二维可滚动网格布局的核心组件可以通过 scrollDirection 属性设置滚动的方向。GridView 提供多种构建方式如GridView.count() - 基于固定列数的网格布局 (最常用)GridView.entent() - 基于固定子项的最大宽度 / 高度的网格布局 (最常用)GridView.builder() - 懒加载策略用于网格项数量巨大或动态生成的情况需要接收 gridDelegate 布局委托属性。gridDelegate 可接收的属性类型如下SliverGridDelegateWithFixedCrossAxisCount固定列数SliverGridDelegateWithFixedCrossAxisExtent最大宽度在 GridView.builder 中在 gridDelegate 中声明主轴间距和交叉轴间距。同时 GridView 存在默认构造方式但是写起来过于繁琐通常不使用。GridView.count()通过该方法可以构造固定列数网络。GridView.count 以列数为优先。指定网格列数后Flutter自动计算列的宽度在空间内均匀排列。要注意的是当滚动方向发生变化时网格中组件的大小会随着横 / 纵空间大小到的不同而发生变化。GridView.count( // 修改滚动方向为横向 // 修改以后每个组件都会变大一点点, 因为固定空间放三个组件 // 而竖向比横向空间更大 scrollDirection: Axis.horizontal, padding: EdgeInsets.all(10), mainAxisSpacing: 10, crossAxisSpacing: 10, crossAxisCount: 3, children: List.generate(100, (index) { return Container( alignment: Alignment.center, decoration: BoxDecoration(color: Colors.blue), child: Text( 第${index 1}个, style: TextStyle(color: Colors.white), ), ); }), ),GridView.extent()使用 GridView.extent 指定子项的最大宽度或高度。GridView.extent 通过 maxCrossAxisExtent 设置子项最大宽度 / 高度来计算横向或纵向有多少列。GridView.extent( scrollDirection: Axis.vertical, // 由当前方向的最大宽度 / 高度决定该方向的组件数量 maxCrossAxisExtent: 200, mainAxisSpacing: 10, crossAxisSpacing: 10, padding: EdgeInsets.all(10), children: List.generate(100, (index) { return Container( alignment: Alignment.center, decoration: BoxDecoration(color: Colors.blue), child: Text( 第${index 1}个, style: TextStyle(color: Colors.white), ), ); }), ),GridView.builder()使用 GridView.builder 实现动态长网络该构造方式对组件懒加载只渲染可见区域。使用时需要接收布局委托 (通过列数 (类似 count ) 还是宽高 (类似 extent ) 进行网格限制)同时类似 ListView传入 itemBuilder 构造函数和 itemCount。在 GridView.builder 中在 gridDelegate 布局属性中声明主轴间距和交叉轴间距。同时还可以使用 childAspectRatio 控制子组件宽高比。GridView.builder( padding: EdgeInsets.all(10), // 布局委托, 此时为固定列数模式 gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, mainAxisSpacing: 10, crossAxisSpacing: 10, childAspectRatio: 2, ), itemCount: 100, itemBuilder: (BuildContext buildContext, int index) { return Container( alignment: Alignment.center, decoration: BoxDecoration(color: Colors.blue), child: Text( 第${index 1}个, style: TextStyle(color: Colors.white), ), ); }, ),总结如果我的内容对你有帮助请点赞评论收藏。创作不易大家的支持就是我坚持下去的动力