使用fvm管理flutter版本

如果你有使用多版本flutter的需求,那么fvm将会给你提供较大的帮助。下面我列举一下mac + flutter3.35.2的版本的操作命令,完成之后,你将可以随意切换flutter版本

# 下载fvm相关的依赖
brew tap leoafarias/fvm
brew install fvm# 检查版本号
fvm --version
# 3.2.1# 下载flutter, 并使用
fvm install 3.35.2 #或者直接下载具体版本号也行
fvm use 3.35.2# 检查flutter版本号
fvm flutter --version
# 3.35.2

这里由于笔者已经全局安装一个公司私域的flutter, 并且配置了全局的path, fvm目前识别不到已经安装的flutter,由于不想影响已经安装的全局私域flutter,这里可以在flutter命令前直接加fvm,即可使用到fvm安装的官方flutter,如果不是我这种特殊情况的话,直接使用flutter命令理论是可以切到fvm设置的global源的。

创建你的第一flutter应用

前置步骤

创建flutter之前,你需要配置你的开发环境。具体的步骤官网做了较为详细的概括,这里将不再赘述,主要分为几个步骤。

  1. 下载flutter sdk, vscode配置flutter相关插件
  2. 下载配置android studio,下载jdk
  3. 下载配置xcode
  4. 测试手机开启授权

创建flutter应用

fvm flutter create test_app
cd test_app
fvm flutter run

选择浏览器打开,第一个flutter demo就创建完成了

在这里插入图片描述

源代码剖析

结构列表总结

在test_app这个根目录下,大约有十几个子目录,如下。

名称类型主要作用
test_app目录项目根目录
.dart_tool目录Dart 工具链配置与缓存
.idea目录IDE 配置
android目录Android 平台原生代码
build目录构建产物(可删除)
ios目录iOS 平台原生代码
lib目录核心 Dart 应用代码
linux目录Linux 桌面端原生代码
macos目录macOS 桌面端原生代码
test目录测试代码
web目录Web 平台代码
windows目录Windows 桌面端原生代码
.gitignore文件Git 忽略规则
.metadata文件Flutter 工具元数据
analysis_options.yaml文件静态代码分析规则配置
pubspec.lock文件依赖包精确版本锁定
pubspec.yaml文件项目依赖与元数据配置(非常重要)
README.md文件项目说明文档
test_app.iml文件IntelliJ 模块配置

作为入门,我们可以重点关注pubspec.yaml、web、和lib

pubspec.yaml目录

去除了多余的代码之后,整体的结果如下

name: test_app
description: "A new Flutter project."
publish_to: 'none'
version: 1.0.0+1environment:sdk: ^3.9.0dependencies:flutter:sdk: fluttercupertino_icons: ^1.0.8dev_dependencies:flutter_test:sdk: flutterflutter_lints: ^5.0.0flutter:uses-material-design: true
name字段

表示当前flutter应用的包名,是一个最基本的字段

我们在导入其他文件时,就需要使用如下方式,如果包名发生变化的话,相应的路径也需要发生变化

import 'package:flutter_demo/listview_demo/listview_demo.dart';
publish_to

此属性意为包发布到哪里去

  • none:表示此包不发布;
  • 也可以指定发布的服务器,如果删除此项配置,那么默认发布到pub.dev
version

此属性表示当前工程的版本,分为应用程序的版本内部版本号,格式为x.x.x+x,比如1.0.0+1,称为语义版本号

  • +号前面的叫做version number
  • +号后面的叫做build number

在test_app/android/app/build.gradle.kts这个文件里可以看到安卓打包定版本的具体逻辑

environment

可以配置FlutterDart版本

dependencies
dependencies:flutter:sdk: fluttercupertino_icons: ^1.0.8

添加我们用到的第三方的sdk

  • sdk: flutter意为默认获取flutter的最新版本,也就是我们机器上的flutter版本,我们也可以在此处添加version来指定flutter的版本;
  • cupertino_icons:给应用程序添加Cupertino图标的,一般用于iOS;

其实这个本质上跟js项目的生产依赖是一样的

dev_dependencies

开发依赖,只有运行时才会用到

flutter

Flutter相关的配置

# 确保我们的应用程序中包含Material Icons字体,以使我们能够使用material Icons类中的图标;
uses-material-design: true

我们当资源的配置也是在这个配置下进行设置:

  • assets:配置图片;
  • fonts:配置字体;
  • plugin:该配置只存在于插件项目中,用来配置适配的平台,一般不要修改;如需添加新平台,直接添加即可;
web目录

在这里插入图片描述

主要包含了一些生成web页面的静态资源和模版信息

lib目录

flutter项目的源代码

在这里插入图片描述

main.dart整个应用的入口文件

完整的代码信息如下

import 'package:flutter/material.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),),home: const MyHomePage(title: 'Flutter Demo Home Page'),);}
}class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {int _counter = 0;void _incrementCounter() {setState(() {_counter++;});}@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('You have pushed the button this many times:'),Text('$_counter',style: Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: const Icon(Icons.add),),);}
}
导入依赖
import 'package:flutter/material.dart';

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

应用入口
void main() {runApp(const MyApp());
}

Flutter 应用中 main 函数为应用程序的入口。main 函数中调用了runApp 方法,它的功能是启动Flutter应用。runApp它接受一个 Widget参数,在本示例中它是一个MyApp对象,MyApp()是 Flutter 应用的根组件。

也可以简写成单行函数

void main() => runApp(MyApp());
应用代码结构
class MyApp extends StatelessWidget {const MyApp({super.key});@overrideWidget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),),home: const MyHomePage(title: 'Flutter Demo Home Page'),);}
}
  • MyApp类代表 Flutter 应用,它继承了 StatelessWidget类,这也就意味着应用本身也是一个widget。
  • 在 Flutter 中,大多数东西都是 widget,包括对齐(Align)、填充(Padding)、手势处理(GestureDetector)等,它们都是以 widget 的形式提供。
  • Flutter 在构建页面时,会调用组件的build方法,widget 的主要工作是提供一个 build() 方法来描述如何构建 UI 界面(通常是通过组合、拼装其他基础 widget )。
  • MaterialApp 是Material 库中提供的 Flutter APP 框架,通过它可以设置应用的名称、主题、语言、首页及路由列表等。MaterialApp也是一个 widget。
  • home 为 Flutter 应用的首页,它也是一个 widget。
具体代码解析
MyHomePage
class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;// 重写createState方法,创建与这个Widget关联的状态类@overrideState<MyHomePage> createState() => _MyHomePageState();
}class _MyHomePageState extends State<MyHomePage> {// ...
}

MyHomePage 是应用的首页,它继承自StatefulWidget类,表示它是一个有状态的组件(Stateful widget)。

  1. Stateful widget 可以拥有状态,这些状态在 widget 生命周期中是可以变的,而 Stateless widget 是不可变的。
  2. Stateful widget 至少由两个类组成:
    • 一个StatefulWidget类。
    • 一个 State类; StatefulWidget类本身是不变的,但是State类中持有的状态在 widget 生命周期中可能会发生变化。
    • _MyHomePageState类是MyHomePage类对应的状态类。这里可以看到,和MyApp 类不同, MyHomePage类中并没有build方法,取而代之的是,build方法被挪到了_MyHomePageState方法中,至于为什么,后面会进行解读
const MyHomePage({super.key, required this.title});

构造函数,用于初始化一个名为 MyHomePage 的页面(Widget)。

State类

_MyHomePageState在就是一个state类,在MyHomePage里面被createState出来,里面主要有两部分内容, 一是定义了一个计数器状态,再定义一个状态自增函数,当按钮点击时,会调用此函数,该函数的作用是先自增_counter,然后调用setState 方法。setState方法的作用是通知 Flutter 框架,有状态发生了改变,Flutter 框架收到通知后,会执行 build 方法来根据新的状态重新构建界面, Flutter 对此方法做了优化,使重新执行变的很快,所以你可以重新构建任何需要更新的东西,而无需分别去修改各个 widget。

  int _counter = 0;void _incrementCounter() {setState(() {_counter++;});}

二是定一个build函数,用于构建UI页面

  @overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Theme.of(context).colorScheme.inversePrimary,title: Text(widget.title),),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[const Text('You have pushed the button this many times:'),Text('$_counter',style: Theme.of(context).textTheme.headlineMedium,),],),),floatingActionButton: FloatingActionButton(onPressed: _incrementCounter,tooltip: 'Increment',child: const Icon(Icons.add),),);}

MyHomePage第一次创建时,_MyHomePageState类会被创建,当初始化完成后,Flutter框架会调用 widget 的build方法来构建 widget 树,最终将 widget 树渲染到设备屏幕上。具体解读如下:

  • Scaffold 是 Material 库中提供的页面脚手架,它提供了默认的导航栏、标题和包含主屏幕 widget 树(后同“组件树”或“部件树”)的body属性,组件树可以很复杂。本书后面示例中,路由默认都是通过Scaffold创建。
  • body的组件树中包含了一个Center 组件,Center 可以将其子组件树对齐到屏幕中心。此例中, Center 子组件是一个Column 组件,Column的作用是将其所有子组件沿屏幕垂直方向依次排列; 此例中Column子组件是两个 Text,第一个Text 显示固定文本 “You have pushed the button this many times:”,第二个Text 显示_counter状态的数值。
  • floatingActionButton是页面右下角的带“+”的悬浮按钮,它的onPressed属性接受一个回调函数,代表它被点击后的处理器,本例中直接将_incrementCounter方法作为其处理函数。

完整流程如下:

当右下角的floatingActionButton按钮被点击之后,会调用_incrementCounter方法。在_incrementCounter方法中,首先会自增_counter计数器(状态),然后setState会通知 Flutter 框架状态发生变化,接着,Flutter 框架会调用build方法以新的状态重新构建UI,最终显示在设备屏幕上。

为什么把build放在State类中
1.方便状态访问

如果我们的StatefulWidget有很多状态,而每次状态改变都要调用build方法,由于状态是保存在 State 中的,如果build方法在StatefulWidget中,那么build方法和状态分别在两个类中,那么构建时读取状态将会很不方便。如果真的将build方法放在 StatefulWidget 中的话,由于构建用户界面过程需要依赖 State,所以build方法将必须加一个State参数,大概是下面这样:

Widget build(BuildContext context, State state){//state.counter...}

这样的话就只能将State的所有状态声明为公开的状态,这样才能在State类外部访问状态!但是,将状态设置为公开后,状态将不再具有私密性,这就会导致对状态的修改将会变的不可控。但如果将build()方法放在State中的话,构建过程不仅可以直接访问状态,而且也无需公开私有状态,这会非常方便。

2.方便继承StatefulWidget

例如,Flutter 中有一个动画 widget 的基类AnimatedWidget,它继承自StatefulWidget类。AnimatedWidget中引入了一个抽象方法build(BuildContext context),继承自AnimatedWidget的动画 widget 都要实现这个build方法。现在设想一下,如果StatefulWidget 类中已经有了一个build方法,正如上面所述,此时build方法需要接收一个 State 对象,这就意味着AnimatedWidget必须将自己的 State 对象(记为_animatedWidgetState)提供给其子类,因为子类需要在其build方法中调用父类的build方法

class MyAnimationWidget extends AnimatedWidget{@overrideWidget build(BuildContext context, State state){//由于子类要用到AnimatedWidget的状态对象_animatedWidgetState,//所以AnimatedWidget必须通过某种方式将其状态对象_animatedWidgetState//暴露给其子类   super.build(context, _animatedWidgetState)}
}

这样很显然是不合理的,因为

  • AnimatedWidget的状态对象是AnimatedWidget内部实现细节,不应该暴露给外部。
  • 如果要将父类状态暴露给子类,那么必须得有一种传递机制,而做这一套传递机制是无意义的,因为父子类之间状态的传递和子类本身逻辑是无关的。
总结来说
  • build 方法需要根据可变状态(如 _counter 来构建用户界面。这些可变状态保存在 State 子类(如 _MyHomePageState)中。将 build 方法放在 State 子类里,可以直接访问(通过context)这些状态(例如 _counter),无需通过复杂的传递机制或将状态设置为公开,从而破坏了状态的封装性。
  • StatefulWidget对外的,负责接收不可变的配置数据。
  • State对内的,负责管理可变的状态。

参考

《Flutter实战·第二版》

https://juejin.cn/post/7033933629403168799

4.拓展阅读

flutter专栏–移动开发技术的发展与flutter的概要

flutter专栏–dart基础知识

关注我,有空一起闲聊

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95284.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95284.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/95284.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB 聚合查询超时:索引优化与分片策略的踩坑记录

人们眼中的天才之所以卓越非凡&#xff0c;并非天资超人一等而是付出了持续不断的努力。1万小时的锤炼是任何人从平凡变成超凡的必要条件。———— 马尔科姆格拉德威尔 &#x1f31f; Hello&#xff0c;我是Xxtaoaooo&#xff01; &#x1f308; “代码是逻辑的诗篇&#xff…

Augmentcode免费额度AI开发WordPress商城实战

Augment AI开发WordPress商城实战&#xff1a;从零构建到免费额度续杯完整指南 前言 在AI编程工具日益普及的今天&#xff0c;如何高效利用这些工具来开发实际项目成为了开发者关注的焦点。本文将详细介绍如何使用Augment AI从零开始构建一个功能完整的WordPress商城系统&#…

【C++八股文】数据结构篇

一、单例模式优化实现 原代码问题分析 ​内存序重排序风险​&#xff1a;双重检查锁在C中可能因指令重排导致半初始化对象被访问​锁粒度过大​&#xff1a;每次获取实例都需要加锁&#xff0c;影响性能​线程安全性不足​&#xff1a;未考虑C11前的内存模型问题 改进方案&a…

并发编程——15 线程池ForkJoinPool实战及其工作原理分析

1 一道算法题引发的思考及其实现 1.1 算法题 问&#xff1a;如何充分利用多核 CPU 的性能&#xff0c;快速对一个2千万大小的数组进行排序&#xff1f; 这道题可以通过归并排序来解决&#xff1b; 1.2 什么是归并排序&#xff1f; 归并排序&#xff08;Merge Sort&#xff…

Kafka面试精讲 Day 6:Kafka日志存储结构与索引机制

【Kafka面试精讲 Day 6】Kafka日志存储结构与索引机制 在“Kafka面试精讲”系列的第6天&#xff0c;我们将深入剖析 Kafka的日志存储结构与索引机制。这是Kafka高性能、高吞吐量背后的核心设计之一&#xff0c;也是中高级面试中的高频考点。面试官常通过这个问题考察候选人是否…

Linux 字符设备驱动框架学习记录(三)

Linux字符设备驱动开发新框架详解 一、新旧驱动框架对比 传统字符设备驱动流程 手动分配设备号 (register_chrdev_region)实现file_operations结构体使用mknod手动创建设备节点 新式驱动框架优势 自动设备号分配&#xff1a;动态申请避免冲突自动节点创建&#xff1a;通过class…

《计算机网络安全》实验报告一 现代网络安全挑战 拒绝服务与分布式拒绝服务攻击的演变与防御策略(1)

目 录 摘 要 一、研究背景与目的 1.1 介绍拒绝服务&#xff08;DoS&#xff09;和分布式拒绝服务&#xff08;DDoS&#xff09;攻击的背景 &#xff08;1&#xff09;拒绝服务攻击&#xff08;DoS&#xff09;  &#xff08;2&#xff09;分布式拒绝服务攻击&#xff0…

深度学习篇---模型组成部分

模型组成部分&#xff1a;在 PyTorch 框架下进行图像分类任务时&#xff0c;深度学习代码通常由几个核心部分组成。这些部分中有些可以在不同网络间复用&#xff0c;有些则需要根据具体任务或网络结构进行修改。下面我将用通俗易懂的方式介绍这些组成部分&#xff1a;1. 数据准…

关于ANDROUD APPIUM安装细则

1&#xff0c;可以先参考一下连接 PythonAppium自动化完整教程_appium python教程-CSDN博客 2&#xff0c;appium 需要对应的版本的node&#xff0c;可以用nvm对node 进行版本隔离 3&#xff0c;对应需要安装android stuido 和对应的sdk &#xff0c;按照以上连接进行下载安…

八、算法设计与分析

1 算法设计与分析的基本概念 1.1 算法 定义 &#xff1a;算法是对特定问题求解步骤的一种描述&#xff0c;是有限指令序列&#xff0c;每条指令表示一个或多个操作。特性 &#xff1a; 有穷性&#xff1a;算法需在有限步骤和时间内结束。确定性&#xff1a;指令无歧义&#xff…

机器学习从入门到精通 - 神经网络入门:从感知机到反向传播数学揭秘

机器学习从入门到精通 - 神经网络入门&#xff1a;从感知机到反向传播数学揭秘开场白&#xff1a;点燃你的好奇心 各位&#xff0c;有没有觉得那些能识图、懂人话、下棋碾压人类的AI特别酷&#xff1f;它们的"大脑"核心&#xff0c;很多时候就是神经网络&#xff01;…

神经网络模型介绍

如果你用过人脸识别解锁手机、刷到过精准推送的短视频&#xff0c;或是体验过 AI 聊天机器人&#xff0c;那么你已经在和神经网络打交道了。作为深度学习的核心技术&#xff0c;神经网络模仿人脑的信息处理方式&#xff0c;让机器拥有了 “学习” 的能力。一、什么是神经网络&a…

苹果开发中什么是Storyboard?object-c 和swiftui 以及Storyboard到底有什么关系以及逻辑?优雅草卓伊凡

苹果开发中什么是Storyboard&#xff1f;object-c 和swiftui 以及Storyboard到底有什么关系以及逻辑&#xff1f;优雅草卓伊凡引言由于最近有个客户咨询关于 苹果内购 in-purchase 的问题做了付费咨询处理&#xff0c;得到问题&#xff1a;“昨天试着把您的那几部分code 组装成…

孩子玩手机都近视了,怎样限制小孩的手机使用时长?

最近两周&#xff0c;我给孩子检查作业时发现娃总是把眼睛眯成一条缝&#xff0c;而且每隔几分钟就会用手背揉眼睛&#xff0c;有时候揉得眼圈都红了。有一次默写单词&#xff0c;他把 “太阳” 写成了 “大阳”&#xff0c;我给他指出来&#xff0c;他却盯着本子说 “没有错”…

医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(六)

第五章 案例三:GoEHRStream - 实时电子病历数据流处理系统 5.1 案例背景与需求分析 5.1.1 电子病历数据流处理概述 电子健康记录(Electronic Health Record, EHR)系统是现代医疗信息化的核心,存储了患者从出生到死亡的完整健康信息,包括 demographics、诊断、用药、手术、…

GEM5学习(2):运行x86Demo示例

创建脚本 配置脚本内容参考官网的说明gem5: Creating a simple configuration script 首先根据官方说明创建脚本文件 mkdir configs/tutorial/part1/ touch configs/tutorial/part1/simple.py simple.py 中的内容如下&#xff1a; from gem5.prebuilt.demo.x86_demo_board…

通过 FinalShell 访问服务器并运行 GUI 程序,提示 “Cannot connect to X server“ 的解决方法

FinalShell 是一个 SSH 客户端&#xff0c;默认情况下 不支持 X11 图形转发&#xff08;不像 ssh -X 或 ssh -Y&#xff09;&#xff0c;所以直接运行 GUI 程序&#xff08;如 Qt、GNOME、Matplotlib 等&#xff09;会报错&#xff1a; Error: Cant open display: Failed to c…

1.人工智能——概述

应用领域 替代低端劳动&#xff0c;解决危险、高体力精力损耗领域 什么是智能制造&#xff1f;数字孪生&#xff1f;边缘计算&#xff1f; 边缘计算 是 数字孪生 的 “感官和神经末梢”&#xff0c;负责采集本地实时数据和即时反应。琐碎数据不上传总服务器&#xff0c;实时进行…

传统园区能源转型破局之道:智慧能源管理系统驱动的“源-网-荷-储”协同赋能

传统园区能源结构转型 政策要求&#xff1a;福建提出2025年可再生能源渗透率≥25%&#xff0c;山东强调“源网荷储一体化”&#xff0c;安徽要求清洁能源就地消纳。系统解决方案&#xff1a;多能协同调控&#xff1a;集成光伏、储能、充电桩数据&#xff0c;通过AI算法动态优化…

[光学原理与应用-353]:ZEMAX - 设置 - 可视化工具:2D视图、3D视图、实体模型三者的区别,以及如何设置光线的数量

在光学设计软件ZEMAX中&#xff0c;2D视图、3D视图和实体模型是三种不同的可视化工具&#xff0c;分别用于从不同维度展示光学系统的结构、布局和物理特性。它们的核心区别体现在维度、功能、应用场景及信息呈现方式上&#xff0c;以下是详细对比&#xff1a;一、维度与信息呈现…