这是一个模拟添加多张照片的小实例,主要学习一下流式布局在Flutter里的应用。如果你作为一个前端开发者,那这节课的内容将非常容易

流式布局 模拟添加照片效果 - 图1

mediaQuery 媒体查询

使用meidaQuery可以很容易的得到屏幕的宽和高,得到宽和高的代码如下:

  1. final width = MediaQuery.of(context).size.width;
  2. final height = MediaQuery.of(context).size.height;

Wrap流式布局

  • Flutter中流式布局大概有三种常用方法,这节课先学一下Wrap的流式布局。有的小伙伴会说Wrap中的流式布局可以用Flow很轻松的实现出来,但是Wrap更多的式在使用了Flex中的一些概念,某种意义上说式跟Row、Column更加相似的。
  • 单行的Wrap跟Row表现几乎一致,单列的Wrap则跟Column表现几乎一致。但Row与Column都是单行单列的,Wrap则突破了这个限制,mainAxis上空间不足时,则向crossAxis上去扩展显示。
  • 从效率上讲,Flow肯定会比Wrap高,但Wrap使用起来会更方便一些。

GestureDetector 手势操作识别

  • 它是一个Widget,但没有任何的显示功能,而只是一个手势操作,用来触发事件的
  • 虽然很多Button组件是有触发事件的,比如点击,但是也有一些组件是没有触发事件的,比如:Padding、Container、Center这时候我们想让它有触发事件就需要再它们的外层增加一个GestureDetector
  • 比如我们让Padding有触发事件,代码如下:
    1. Widget buildAddButton(){
    2. return GestureDetector(
    3. onTap:(){
    4. if(list.length<9){
    5. setState(() {
    6. list.insert(list.length-1,buildPhoto());
    7. });
    8. }
    9. },
    10. child: Padding(
    11. padding:const EdgeInsets.all(8.0),
    12. child: Container(
    13. width: 80.0,
    14. height: 80.0,
    15. color: Colors.black54,
    16. child: Icon(Icons.add),
    17. ),
    18. ),
    19. );
    20. }

入口文件main.dart

入口文件很简单,就是引用了warp_demo.dart文件,然后再home属性中使用了WarpDemo,代码如下:

  1. import 'package:flutter/material.dart';
  2. import 'warp_demo.dart';
  3. void main()=>runApp(MyApp());
  4. class MyApp extends StatelessWidget {
  5. @override
  6. Widget build(BuildContext context) {
  7. return MaterialApp(
  8. title: 'Flutter Demo',
  9. theme: new ThemeData.dark(),
  10. home:WarpDemo()
  11. );
  12. }
  13. }

warp_demo.dart

  1. import 'package:flutter/material.dart';
  2. //继承与动态组件
  3. class WarpDemo extends StatefulWidget {
  4. _WarpDemoState createState() => _WarpDemoState();
  5. }
  6. class _WarpDemoState extends State<WarpDemo> {
  7. final double squareSidelength = 40.0;
  8. int sictureCount = 30;
  9. List<Widget> list; //声明一个list数组
  10. @override
  11. //初始化状态,给list添加值,这时候调用了一个自定义方法`buildAddButton`
  12. void initState() {
  13. list = List<Widget>()..add(buildAddButton());
  14. super.initState();
  15. }
  16. @override
  17. Widget build(BuildContext context) {
  18. //得到屏幕的高度和宽度,用来设置Container的宽和高
  19. final width = MediaQuery.of(context).size.width;
  20. final height = MediaQuery.of(context).size.height;
  21. return Scaffold(
  22. appBar: AppBar(
  23. title: Text('Wrap流式布局'),
  24. ),
  25. body: Center(
  26. child: Opacity(
  27. opacity: 0.8,
  28. child: Container(
  29. width: width,
  30. // height: height / 2,
  31. color: Colors.grey,
  32. child: Wrap(
  33. //流式布局,
  34. children: list,
  35. spacing: squareSidelength / 4, //设置间距
  36. ),
  37. ),
  38. ),
  39. ));
  40. }
  41. Widget buildAddButton() {
  42. //返回一个手势Widget,只用用于显示事件
  43. return GestureDetector(
  44. onTap: () {
  45. //this可以省略
  46. if (list.length <= this.sictureCount) {
  47. setState(() {
  48. list.insert(list.length - 1, buildPhoto());
  49. });
  50. }
  51. },
  52. child: Padding(
  53. padding: const EdgeInsets.all(8.0),
  54. child: Container(
  55. width: squareSidelength,
  56. height: squareSidelength,
  57. color: Colors.black54,
  58. child: Icon(Icons.add),
  59. ),
  60. ),
  61. );
  62. }
  63. Widget buildPhoto() {
  64. return Padding(
  65. padding: const EdgeInsets.all(8.0),
  66. child: Container(
  67. width: squareSidelength,
  68. height: squareSidelength,
  69. color: Colors.amber,
  70. child: Center(
  71. child: Text('照片'),
  72. ),
  73. ),
  74. );
  75. }
  76. }

附件

流式布局 模拟添加照片效果-lib.zip