本文参考Flutter课程导学_哔哩哔哩_bilibili

1. 创建项目

flutter create --platforms web flutter_demo

注意如果执行命令后什么都不显示,可能是权限不足,使用管理员身份运行PowerShell

看到All done!即可创建成功

2. 运行项目

cd flutter_demo
flutter run -d chrome

进入项目根目录,运行 Web 项目(指定 Chrome 浏览器)

如果遇到该情况(启动失败,打开浏览器,但浏览器显示不出结果),可能是Flutter 启动 Chrome 时的参数组合和浏览器权限冲突。

解决:

用「web-server」模式绕开浏览器启动(最快速验证)

先不通过 Flutter 直接启动浏览器,改用「web 服务器」模式,手动在 Chrome 中打开页面:

# 启动 web 服务器(不自动打开浏览器)
flutter run -d web-server

注意如果执行命令后什么都不显示,可能是权限不足,使用管理员身份运行PowerShell

启动成功后,会输出类似http://localhost:62825 的地址,手动复制这个地址到 Chrome 中打开即可访问项目。

3. 组件学习

3.1基础组件

3.1.1 MaterialAPP

整个应用被MaterialApp包裹,方便对整个应用的属性进行整体设计

void main(List<String> args) {
  runApp(
    MaterialApp(
      title: "materialAPP 体验",//展示标题
      theme: ThemeData(scaffoldBackgroundColor: Colors.blueAccent),//设置主题
      home: Scaffold(),//展示主体内容, Scaffold()骨架组件
    ),
  );
}

注意如果修改代码后浏览器页面还没有变化,终端输入r实现热重载,再刷新浏览器即可得到修改后的页面展示。

3.1.2 Scaffold

代码展示:

runApp(
    MaterialApp(
      title: "materialAPP 体验",
      theme: ThemeData(
        //设置中部与底部主题
        scaffoldBackgroundColor: const Color.fromARGB(255, 127, 147, 183),
      ),
      home: Scaffold(
        appBar: AppBar(title: Text("头部区域"), centerTitle: true),

        body: Container(child: Center(child: Text("中部区域"))),

        bottomNavigationBar: Container(
          height: 80, //设置底部大小,不然中部与底部无法分开,看不到底部效果
          child: Center(child: Text("底部区域")),
        ),
      ),
    ),
  );

效果展示:

3.2 自定义组件

3.2.1无状态组件

无状态组件:创建新的类,继承 StatelessWidget 并实现build方法,build返回Widget

纯展示型组件,没有用户交互操作

import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MainPage());
}

class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "materialAPP 体验",
      theme: ThemeData(
        //设置中部与底部主题
        scaffoldBackgroundColor: const Color.fromARGB(255, 127, 147, 183),
      ),
      home: Scaffold(
        appBar: AppBar(title: Text("头部区域"), centerTitle: true),

        body: Container(child: Center(child: Text("中部区域"))),

        bottomNavigationBar: Container(
          height: 80, //设置底部大小,不然中部与底部无法分开,看不到底部效果
          child: Center(child: Text("底部区域")),
        ),
      ),
    );
  }
}
3.2.2有状态组件

有状态组件管理变化的内部状态,当状态改变时,组件回更新显示内容

第一个类负责向外接收参数,第二个类向内管理状态

import 'package:flutter/material.dart';

void main(List<String> args) {
  runApp(MainPage());
}

//第一个类,创建State对象(接收外部参数)
class MainPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    //返回第二个类的对象
    return _MainPageState();
  }
}

//第二个类 内部类(私有)继承State<第一个类名>,负责管理数据 处理业务逻辑 渲染视图
class _MainPageState extends State<MainPage> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "materialAPP 体验",
      theme: ThemeData(
        //设置中部与底部主题
        scaffoldBackgroundColor: const Color.fromARGB(255, 4, 85, 238),
      ),
      home: Scaffold(
        appBar: AppBar(title: Text("头部区域"), centerTitle: true),

        body: Container(child: Center(child: Text("中部区域"))),

        bottomNavigationBar: Container(
          height: 80, //设置底部大小,不然中部与底部无法分开,看不到底部效果
          child: Center(child: Text("底部区域")),
        ),
      ),
    );
  }
}

3.3 组件生命周期

3.3.1 无状态组件

唯一阶段:build()方法

当组件被创建或父组件状态变化导致其需要重新构建时,build方法会被调用

3.3.2 有状态组件

InheritedWidget:全局状态(如路由),专门用于Widget树中自顶向下高效地共享数据,顶层组件提供数据,子孙节点直接获取

所有方法均在第二个类中实现(如AState)

3.4  点击事件

3.4.1 GestureDelector

GestureDelector是Flutter中最常用、功能最丰富的手势检测组件

onTap:点击  onDoubleTap:双击  等以on开头的方法

用法:GestureDelector包裹被点击的元素,传入方法(以on开头)

body: Container(
          child: Center(
            child: GestureDetector(//包裹
              // onTap: () { //点击事件
              //   print("点击了该区域");
              // },
              onDoubleTap: () {
                print("双击该区域");
              },
              child: Text("中部区域"),//被点击的元素
            ),
          ),
        ),
3.4.2 组件点击事件

 body: Container(
          child: Center(
            child: TextButton(
              onPressed: () {
                //处理点击逻辑
                print("组件点击");
              },
              child: Text("文本按钮"),
            ),
          ),
        ),

3.5 状态更新

数据的变化要更新UI视图,需要执行setState方法,setState方法会造成build的重新执行

body: Center(
          child: Row(
            children: [
              TextButton(
                onPressed: () {
                  setState(() {
                    //如不加setState,则页面上count的值永远为1(UI不更新)
                    count--;
                  });
                },
                child: Text("-"),
              ),
              Text(count.toString()),
              TextButton(
                onPressed: () {
                  count++;
                  setState(() {}); //也可以这样写,setState是异步操作,最后执行
                },
                child: Text("+"),
              ),
            ],
          ),
        ),

3.6 组件

布局组件

3.6.1 Container组件

相当于HTML的div

常见属性

return MaterialApp(
      home: Scaffold(
        body: Container(
          transform: Matrix4.rotationZ(0.05),//变换角度0.05是弧度而非角度,
          margin: EdgeInsets.all(20),//外边距
          alignment: Alignment.center,//子组件居中
          width: 200,//宽  width:double.infinity正无穷大,填满整个空间宽
          height: 200,//高
          decoration: BoxDecoration(
            color: Colors.blue,//背景颜色
            borderRadius: BorderRadius.circular(15),//圆角
            border: Border.all(width: 3,color: Colors.yellow)//边框
          ),
          child: Text(//Text内置样式
            "hello world ",
            style: TextStyle(color: Colors.white, fontSize: 20),
          ),
          //color:Colors.blue 简单的背景与颜色
        ),
      ),
    );

width:double.infinity正无穷大,填满整个空间宽

3.6.2 Center组件

将子组件在父容器的空间内进行水平和垂直方向上的居中排列

必须有child,默认全部占用父容器空间,若子组件只占用部分父组件,则可以在child中嵌套Container

3.6.3 Align组件

3.6.4 Padding组件

属性:padding,必须有,定义内边距的大小和方向,通常使用EdgeInsets类来设置

所有方向用EdgeInsets.all(),

任意方向用EdgeInsets.only(top: ,bottom: ,left: ,right: ),

对称方向用EdgeInsets.symmetric(horizontal: ,vertical: )

child:需要被添加内边距的子组件

3.6.5 Column组件

3.6.6 Row组件

3.6.7 Flex和Expanded

Flex是Column和Row的结合体

3.6.8 Wrap换行组件

3.6.9 Stack/Position

Stack类似相对定位,后者叠在前者上(children中排列顺序)

3.6.10 Text组件

3.6.11 Image组件

3.6.12 TextField文本输入组件

onSubmitted :电脑端Enter键

注意:

写来试试

3.6.13 SingleChildScrollView组件

3.6.14 ListView组件

3.6.15 GridView组件
3.6.16 CustomScrollView组件
3.6.17 PageView组件

3.7 组件通信

3.7.1 父传子

无状态组件:Child类中定义构造函数(需要的参数),使用传入参数值,父组件的类(或对内类)调用构造函数(给出具体参数值)

有状态组件:Child对外的类接收属性(定义构造函数),Child对内的类获取属性(使用属性值,widget.参数名)

父组件类(对内类)调用构造函数(给出具体参数值)

3.7.2 子传父

删除图标可以如此写

3.8 网络请求

3.8.1 Dio基本使用

命令安装插件

flutter pub add dio

基本使用: Dio().get(地址).then().catchError()

一般情况下,在初始化状态initState获取页面数据

3.8.2 封装Dio工具

1. 创建工具类DioUtil

连续赋值简写(..),前提:调用函数的主体一致

2. 构造函数中设置基础地址和超时时间

3. 添加各类拦截器

4. 封装统一请求方法

5. 获取数据

6. 解决跨域问题

3.9 路由管理

3.9.1 基本路由

每一个MaterialApp有一套路由系统

3.9.2 命名路由

3.9.3 命名路由传递参数

3.9.4 基本路由传参

3.9.5 高级路由控制

3.9.6 404路由

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐