• Flutter:计数器应用分析


    前言

    在上一篇文章 Flutter:环境搭建、项目创建 中我们搭建好了环境,并使用命令flutter create 项目名称 创建了一个默认应用。下面来简单看一下该默认应用。

    参考:

    Flutter案例分析

    计数器应用示例

    目录结构

    切换到项目下可以看到如下图:
    在这里插入图片描述

    • .dart_tool 存放与项目相关的一些工具包信息,不要随便修改
    • .ideaAndroid Studio 是基于 IDEA 开发的,所以会有一个.idea,是对当前项目的一些基本配置
    • androidios 对应安卓和苹果两个工程
    • lib 后续我们进行flutter开发,所有代码都放在该目录下。该目录下会有一个main.dart ,该文件作为整个flutter 项目的一个启动入口
    • test 用于做测试
    • linuxmacoswebwindow 对应其他平台,毕竟Flutter 的目标是跨平台(目前好像还不太成熟,当前主要用于app开发)
    • .gitignore 这个就不说了,搞过开发的都知道是干嘛的
    • .metadata 用来记录与版本有关的一些信息,不要修改
    • .packagespubspec.lockpubspec.yaml 与使用第三方库有关
    • README.md 这个也不过多介绍了

    实际开发中主要会用到 libpubspec.yaml

    按钮

    第一次启动项目
    在这里插入图片描述
    热更新和热重启
    在这里插入图片描述
    在这里插入图片描述
    热更新主要更新build 方法里面的内容,热重启会重新启动项目。

    main.dart

    导入包

    import 'package:flutter/material.dart';
    
    • 1

    此行代码作用是导入了 Material UI 组件库。Material (opens new window)是一种标准的移动端和web端的视觉设计语言, Flutter 默认提供了一套丰富的 Material 风格的UI组件。

    应用入口

    void main() {
      runApp(const MyApp());
    }
    
    • 1
    • 2
    • 3

    runApp 函数,存在于 Material UI 组件库
    从下图中可以看到runApp函数需要一个Widget 类型的参数
    在这里插入图片描述
    在这里Widget是一个抽象类,所以需要实例化它的子类 class MyApp extends StatelessWidget {}

    简单示例

    非常推荐 看一下 Flutter案例分析这个教学视频,里面的老师说的很正确,不要死记硬背,可以通过查看源码的方式来知道需要哪些参数。(window是ctrl+鼠标可以查看对应类的源码)

    void main() {
      runApp(const Text("Hello Flutter",
          textDirection: TextDirection.ltr, textAlign: TextAlign.center));
    }
    
    • 1
    • 2
    • 3
    • 4

    查看Text 类,可以知道需要一个必填参数,也就是文本。这里还需要一个可选参数textDirection :文字排列方向。点开textDirection 可以看到 textDirection 需要一个枚举值
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    void main() {
      runApp(const Center(
        child: Text("Hello Flutter", textDirection: TextDirection.ltr,style:TextStyle(
          color:Colors.blue,
          fontSize:30
        ) ,),
      ));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    垂直并且水平居中

    使用Material UI 的示例

    void main() {
      runApp(MaterialApp(
          home: Scaffold(
        // Scaffold是内置的脚手架,帮助我们快速的搭建页面
        appBar: AppBar(
          title: const Text("第一个 Flutter App"),
        ), //app顶部导航栏
        body: const Center(
          child: Text("Hello Flutter",
              style: TextStyle(color: Colors.blue, fontSize: 30)),
        ),
      )));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在flutter可以理解为万物皆是Widget,可以通过嵌套Widget来实现一些功能。一层层嵌套搞得有点晕,而且有些类的实例还要求用const 进行定义

    效果图
    在这里插入图片描述

    嵌套问题的解决

    为了解决嵌套问题,可以将代码抽离成一个个的Widget。
    Widget分为有状态和无状态两种:

    • 有状态:StatefulWidget,在允许过程中需要改变一些数据时使用
    • 无状态:StatelessWidget,内容是确定的,没用数据的改变时使用

    注: 所有的widget里都不能写状态

    runApp 方法的参数就是一个Widget,可以将这一部分进行抽离

    void main() {
      runApp( const MyApp());
    }
    
    //抽离runApp的参数为一个widget
    
    class MyApp extends StatelessWidget{
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // build告诉flutter我们的widget希望渲染什么
        //build方法没办法主动执行,只有数据发生改变时才会执行
    
        //返回一个Widget
        return MaterialApp(
            home: Scaffold(
              // Scaffold是内置的脚手架,帮助我们快速的搭建页面
              appBar: AppBar(
                title: const Text("第一个 Flutter App"),
              ), //app顶部导航栏
              body: const Center(
                child: Text("Hello Flutter",
                    style: TextStyle(color: Colors.blue, fontSize: 30)),
              ),
            ))
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    此时main方法里只有一条语句,这时可以使用箭头函数简写

    main() =>  runApp( const MyApp());
    
    • 1

    YCHomePage 进行进一步抽取,最终代码

    import 'package:flutter/material.dart';
    
    //使用箭头函数简写
    main() => runApp(const MyApp());
    
    //抽离runApp的参数为一个widget
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // build告诉flutter我们的widget希望渲染什么
        //build方法没办法主动执行,只有数据发生改变时才会执行
    
        //返回一个Widget
        return const MaterialApp(home: YCHomePage());
      }
    }
    
    //首页
    class YCHomePage extends StatelessWidget {
      const YCHomePage({Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            // Scaffold是内置的脚手架,帮助我们快速的搭建页面
            appBar: AppBar(
              title: const Text("第一个 Flutter App"),
            ), //app顶部导航栏
            body: const YCContentBody());
      }
    }
    
    //内容
    class YCContentBody extends StatelessWidget {
      const YCContentBody({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return const Center(
          child: Text("加油!", style: TextStyle(color: Colors.blue, fontSize: 30)),
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    demo

    视频讲解见:Flutter 案例分析

    在Flutter开发中,所有的widget都不能定义状态,因为widget是不变的。
    在这里插入图片描述
    但是StatelessWidget中有一个抽象方法createState,通过实现该抽象方法来定义一个单独的类用来管理状态
    在这里插入图片描述

    import 'package:flutter/material.dart';
    
    //使用箭头函数简写
    main() => runApp(const MyApp());
    
    //抽离runApp的参数为一个widget
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        // build告诉flutter我们的widget希望渲染什么
        //build方法没办法主动执行,只有数据发生改变时才会执行
    
        //返回一个Widget
        return const MaterialApp(home: YCHomePage());
      }
    }
    
    //首页
    class YCHomePage extends StatelessWidget {
      const YCHomePage({Key? key}) : super(key: key);
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            // Scaffold是内置的脚手架,帮助我们快速的搭建页面
            appBar: AppBar(
              title: const Text("第一个 Flutter App"),
            ), //app顶部导航栏
            body: const YCContentBody());
      }
    }
    
    //内容
    class YCContentBody extends StatefulWidget {
      const YCContentBody({Key? key}) : super(key: key);
    
      @override
      State<StatefulWidget> createState() {
        //单独定义一个类,用来管理状态
        return YCContentState();
      }
    }
    
    //状态维护类,点开State可以看到其对应的泛型是StatefulWidget,而YCContentBody继承自StatefulWidget
    class YCContentState extends State<YCContentBody> {
      var flag = true;
      @override
      Widget build(BuildContext context) {
        return Center(
            child: Row(
                //设置x轴的对齐方式
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
              Checkbox(
                value: flag,
                onChanged: (value) {
                  //不能直接赋值,需要借助setState方法,setState方法是继承自State的,用来改变状态
                  setState(() {
                    flag = value ?? false; //判定value是否为null
                  });
                },
              ),
              const Text(
                "同意协议",
                style: TextStyle(fontSize: 20),
              )
            ]));
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    在这里插入图片描述

    哎,感觉对我这种初学者有亿点点难。

  • 相关阅读:
    二分法求多项式单根
    腾讯面试 Java 高频 210 题解析:Spirng+ 设计模式 +Redis+MySQL
    [附源码]Python计算机毕业设计SSM家居购物系统(程序+LW)
    Mac可以卸载掉系统自带的软件吗 Mac第三方软件无法卸载是为什么
    【AUTOSAR-Nm】-2.1-APP SWC如何获取CanNm/LinNm...状态机的跳转
    MySQL的MHA
    如何使用分治算法的思想,分治技巧详解
    redis--windows配置--redis基础
    log4j日志漏洞问题
    面试题--从键盘输入网站到网页显示,之间发生了什么
  • 原文地址:https://blog.csdn.net/weixin_41897680/article/details/125901725