Flutter完整开发实战详解(一、Dart语言和Flutter基础)

前言

在如今的 Flutter 大潮下,本系列是让你看完会安心的文章。本系列将完整讲述:如何快速从0开发一个完整的 Flutter APP,配套高完成度 Flutter 开源项目 GSYGithubAppFlutter。同时也会提供一些 Flutter 的开发细节技巧,并针对开发过程中可能遇到的问题进行填坑。

系列文章分为三篇,第一部分是基础篇(针对 Dart 语言和 Flutter 基础),第二部分是 App 快速开发实战篇,第三部分是细节填坑篇。

笔者相继开发过 Flutter、 React Native 、Weex 等主流跨平台框架项目,其中 Flutter 的跨平台兼容性无疑最好。前期开发调试完全在 Android 端进行的情况下,第一次在 IOS 平台运行居然没有任何错误,并且还没出现 UI 兼容问题,相信对于经历过跨平台开发的猿们而言,这是多么的不可思议画面。并且 Flutter 的 HotLoad 相比较其他两个平台,也是丝滑的让人无法相信。吹爆了!

这些特点其实这得益于 Flutter Engine 和 Skia,如果有兴趣的可以看看笔者之前的《移动端跨平台开发的深度解析》。好了,感慨那么多,让我们进入正题吧。

一、基础篇

本篇主要涉及:环境搭建、Dart 语言、Flutter 的基础。

1、环境搭建

Flutter 的环境搭建十分省心,特别对应 Android 开发者而言,只是在 Android Studio 上安装插件,并下载 Flutter SDK 到本地,配置在环境变量即可。其实中文网的搭建 Flutter 开发环境已经很贴心详细,从平台指引开始安装基本都不会遇到问题。

这里主要是需要注意,因为某些不可抗力的原因,国内的用户需要配置 Flutter 的代理,并且国内用户在搜索 Flutter 第三方包时,也是在 https://pub.flutter-io.cn 内查找,下方是需要配置到环境变量的地址。 (ps Android Studio 下运行 IOS 也是蛮有意思的(◐‿◑))

///win直接配置到环境编辑即可,mac配置到bash_profile
export PUB_HOSTED_URL=https://pub.flutter-io.cn //国内用户需要设置
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //国内用户需要设置

对于 iOS 开发者,Flutter 的环境搭建同样简单,但如果你在开发过程中需要频繁上传应用到 App Store,推荐使用 appuploader 这款工具。appuploader 是一款非常便捷的 iOS 应用上传助手,能够帮助你快速完成应用的打包、签名和上传工作,极大地提高了开发效率。

2、Dart 语言下的 Flutter

在跨平台开领域被 JS 一统天下的今天,Dart 语言的出现无疑是一股清流。作为后来者,Dart 语言有着不少 Java、kotlin 和 JS 的影子,所以对于 Android 原生开发者、前端开发者而言无疑是非常友好的。

官方也提供了包括 iOS 开发者,React Native 等开发者迁移到 Flutter 上的文档,所以请不要担心,Dart 语言不会是你掌握 Flutter 的门槛。甚至作为开发者,就算你不懂 Dart 也可以看着代码摸索。

Come on,下面主要通过对比,简单讲述下 Dart 的一些特性,主要涉及的是 Flutter 下使用。

  • 基本类型

var 可以定义变量,如 var tag = "666" ,这和 JS 、 Kotlin 等语言类似,同时 Dart 属于动态类型语言,支持闭包。

Dart 中 number 类型分为 intdouble ,其中 java 中的 long 对应的也是 Dart 中的 int 类型。Dart 中没有 float 类型。

Dart 下只有 bool 型可以用于 if 等判断,不同于 JS 这种使用方式是不合法的 var g = "null"; if(g){}

DART 中,switch 支持 String 类型。

  • 变量

Dart 不需要给变量设置 setter getter 方法, 这和 kotlin 等类似。Dart 中所有的基础类型、类等都继承 Object ,默认值是 NULL, 自带 getter 和 setter ,而如果是 final 或者 const 的话,那么它只有一个 getter 方法。

Dart 中 final 和 const 表示常量,比如 final name = 'GSY'; const value= 1000000; 同时 static const 组合代表了静态常量。其中 const 的值在编译期确定,final 的值要到编译时才确定。 (ps Flutter 在 Release 下是 AOT 模式。)

Dart 下的数值,在作为字符串使用时,是需要显式指定的。比如:int i = 0; print("aaaa" + i); 这样并不支持,需要 print("aaaa" + i.toString()); 这样使用。这和 Java 与 JS 存在差异。所以在使用动态类型时,需要注意不要把 number 类型当做 String 使用。

DART 中数组等于列表,所以 var list = [];List list = new List() 可以简单看做一样。

  • 方法

Dart 下 ????= 属于操作符,如: AA ?? "999" 表示如果 AA 为空,返回99;AA ??= "999" 表示如果 AA 为空,给 AA 设置成 99。

Dart 方法可以设置 参数默认值指定名称 。比如: getDetail(Sting userName, reposName, {branch = "master"}){} 方法,这里 branch 不设置的话,默认是 “master” 。 参数类型 可以指定或者不指定。调用效果: getRepositoryDetailDao(“aaa", "bbbb", branch: "dev");

Dart 不像 Java ,没有关键词 public 、private 等修饰符,_下横向直接代表 private ,但是有 @protected 注解。

Dart 中多构造函数,可以通过如下代码实现的。默认构造方法只能有一个,而通过Model.empty() 方法可以创建一个空参数的类,其实方法名称随你喜欢。而变量初始化值时,只需要通过 this.name 在构造方法中指定即可:

class ModelA {String name;String tag;//默认构造方法,赋值给name和tagModelA(this.name, this.tag);//返回一个空的ModelAModelA.empty();//返回一个设置了name的ModelAModelA.forName(this.name);
}
  • Flutter

Flutter 中支持 async/await 。这一点和 ES7 很像,如下代码所示 ,只是定义的位置不同。同时异步操作也和 ES6 中的Promise 很像,只是 Flutter 中返回的是 Future 对象,通过 then 可以执行下一步。如果返回的还是 Future 便可以 then().then.() 的流式操作了 。

  ///模拟等待两秒,返回OKrequest() async {await Future.delayed(Duration(seconds: 1));return "ok!";}///得到"ok!"后,将"ok!"修改为"ok from request"doSomeThing() async {String data = await request();data = "ok from request";return data;}///打印结果renderSome() {doSomeThing().then((value) {print(value);///输出ok from request});}

Flutter 中 setState 很有 React Native 的既视感,Flutter 中也是通过 state 跨帧实现管理数据状态的,这个后面会详细讲到。

Flutter 中一切皆 Widget 呈现,通过 build方法返回 Widget,这也是和 React Native 中,通过 render 函数返回需要渲染的 component 一样的模式。

3、Flutter Widget

在 Flutter 中,一切的显示都是 Widget 。Widget 是一切的基础,作为响应式的渲染,属于 MVVM 的实现机制。我们可以通过修改数据,再用setState 设置数据,Flutter 会自动通过绑定的数据更新 Widget 。 所以你需要做的就是实现 Widget 界面,并且和数据绑定起来

Widget 分为 有状态无状态 两种,在 Flutter 中每个页面都是一帧。无状态就是保持在那一帧。而有状态的 Widget 当数据更新时,其实是绘制了新的 Widget,只是 State 实现了跨帧的数据同步保存。

这里有个小 Tip ,当代码框里输入 stl 的时候,可以自动弹出创建无状态控件的模板选项,而输入 stf 的时,就会弹出创建有状态 Widget 的模板选项。

代码格式化的时候,括号内外的逗号都会影响格式化时换行的位置。

如果觉得默认换行的线太短,可以在设置-Editor-Code Style-Dart-Wrapping and Braces-Hard wrap at 设置你接受的数值。

3.1、无状态 StatelessWidget

直接进入主题,下方代码是无状态 Widget 的简单实现。

继承 StatelessWidget,通过build 方法返回一个布局好的控件。可能现在你还对 Flutter 的内置控件不熟悉,but Don’t worry , take is easy ,后面我们就会详细介绍。这里你只需要知道,一个无状态的 Widget 就是这么简单。

Widget 和 Widget 之间通过 child: 进行嵌套。其中有的 Widget 只能有一个 child,比如下方的 Container ;有的 Widget 可以多个 child ,也就是children:,比如` Colum 布局。下方代码便是 Container Widget 嵌套了 Text Widget。

import 'package:flutter/material.dart';class DEMOWidget extends StatelessWidget {final String text;//数据可以通过构造方法传递进来DEMOWidget(this.text);@overrideWidget build(BuildContext context) {//这里返回你需要的控件//这里末尾有没有的逗号,对于格式化代码而已是不一样的。return Container(//白色背景color: Colors.white,//Dart语法中,?? 表示如果text为空,就返回尾号后的内容。child: Text(text ?? "这就是无状态DMEO"),);}
}
3.2、有状态 StatefulWidget

继续直插主题,如下代码,是有状态的 widget 的简单实现。

你需要创建管理的是主要是 State , 通过 State 的 build 方法去构建控件。在 State 中,你可以动态改变数据,这类似 MVVM 实现,在 setState 之后,改变的数据会触发 Widget 重新构建刷新。而下方代码中,是通过延两秒之后,让文本显示为 “这就变了数值”

如下代码还可以看出,State 中主要的声明周期有 :

  • initState :初始化,理论上只有初始化一次,第二篇中会说特殊情况下。
  • didChangeDependencies :在 initState 之后调用,此时可以获取其他 State 。
  • dispose :销毁,只会调用一次。

看到没,Flutter 其实就是这么简单!你的关注点只要在:创建你的 StatelessWidget 或者 StatefulWidget 而已。你需要的就是在build 中堆积你的布局,然后把数据添加到 Widget 中,最后通过 setState 改变数据,从而实现画面变化。

import 'dart:async';
import 'package:flutter/material.dart';class DemoStateWidget extends StatefulWidget {final String text;通过构造方法传值DemoStateWidget(this.text);///主要是负责创建state@override_DemoStateWidgetState createState() => _DemoStateWidgetState(text);
}class _DemoStateWidgetState extends State<DemoStateWidget> {String text;_DemoStateWidgetState(this.text);@overridevoid initState() {///初始化,这个函数在生命周期中只调用一次super.initState();///定时2秒new Future.delayed(const Duration(seconds: 1), () {setState(() {text = "这就变了数值";});});}@overridevoid dispose() {///销毁super.dispose();}@overridevoid didChangeDependencies() {///在initState之后调 Called when a dependency of this [State] object changes.super.didChangeDependencies();}@overrideWidget build(BuildContext context) {return Container(child: Text(text ?? "这就是有状态DMEO"),);}
}
4、Flutter 布局

Flutter 中拥有需要将近30种内置的 布局 Widget,其中常用有 Container、Padding、Center、Flex、Stack、Row、Colum、ListView 等,下面简单讲解它们的特性和使用。

类型作用特点
Container只有一个子 Widget。默认充满,包含了padding、margin、color、宽高、decoration 等配置。
Padding只有一个子 Widget。只用于设置Padding,常用于嵌套child,给child设置padding。
Center只有一个子 Widget。只用于居中显示,常用于嵌套child,给child设置居中。
Stack可以有多个子 Widget。 子Widget堆叠在一起。
Colum可以有多个子 Widget。垂直布局。
Row可以有多个子 Widget。水平布局。
Expanded只有一个子 Widget。在 Colum 和 Row 中充满。
ListView可以有多个子 Widget。自己意会吧。
  • Container :最常用的默认布局!只能包含一个child:,支持配置 padding,margin,color,宽高,decoration(一般配置边框和阴影)等配置 ,在 Flutter 中,不是所有的控件都有 宽高、padding、margin、color 等属性,所以才会有 Padding、Center 等 Widget 的存在。 new Container( ///四周10大小的maring margin: EdgeInsets.all(10.0), height: 120.0, width: 500.0, ///透明黑色遮罩 decoration: new BoxDecoration( ///弧度为4.0 borderRadius: BorderRadius.all(Radius.circular(4.0)), ///设置了decoration的color,就不能设置Container的color。 color: Colors.black, ///边框 border: new Border.all(color: Color(GSYColors.subTextColor), width: 0.3)), child:new Text(“666666”));
  • Colum、Row 绝对是必备布局, 横竖布局也是日常中最常见的场景。如下方所示,它们常用的有这些属性配置:主轴方向是 start 或 center 等;副轴方向方向是 start 或 center 等;mainAxisSize 是充满最大尺寸,或者只根据子 Widget 显示最小尺寸。
//主轴方向,Colum的竖向、Row我的横向
mainAxisAlignment: MainAxisAlignment.start, 
//默认是最大充满、还是根据child显示最小大小
mainAxisSize: MainAxisSize.max,
//副轴方向,Colum的横向、Row我的竖向
crossAxisAlignment :CrossAxisAlignment.center,
  • Expanded 在 Colum 和 Row 中代表着平均充满,当有两个存在的时候默认均分充满。同时页可以设置 flex 属性决定比例。
    new Column(///主轴居中,即是竖直向居中mainAxisAlignment: MainAxisAlignment.center,///大小按照最小显示mainAxisSize : MainAxisSize.min,///横向也居中crossAxisAlignment : CrossAxisAlignment.center,children: <Widget>[///flex默认为1new Expanded(child: new Text("1111"), flex: 2,),new Expanded(child: new Text("2222")),],);

接下来我们来写一个复杂一些的控件。首先我们创建一个私有方法_getBottomItem,返回一个 Expanded Widget,因为后面我们需要将这个方法返回的 Widget 在 Row 下平均充满。

如代码中注释,布局内主要是现实一个居中的Icon图标和文本,中间间隔5.0的 padding:

  ///返回一个居中带图标和文本的Item_getBottomItem(IconData icon, String text) {///充满 Row 横向的布局return new Expanded(flex: 1,///居中显示child: new Center(///横向布局child: new Row(///主轴居中,即是横向居中mainAxisAlignment: MainAxisAlignment.center,///大小按照最大充满mainAxisSize : MainAxisSize.max,///竖向也居中crossAxisAlignment : CrossAxisAlignment.center,children: <Widget>[///一个图标,大小16.0,灰色new Icon(icon,size: 16.0,color: Colors.grey,),///间隔new Padding(padding: new EdgeInsets.only(left:5.0)),///显示文本new Text(text,//设置字体样式:颜色灰色,字体大小14.0style: new TextStyle(color: Colors.grey, fontSize: 14.0),//超过的省略为...显示overflow: TextOverflow.ellipsis,//最长一行maxLines: 1,),],),),);}

item效果

item效果

接着我们把上方的方法,放到新的布局里。如下流程和代码:

  • 首先是 Container包含了Card,用于快速简单的实现圆角和阴影。
  • 然后接下来包含了FlatButton实现了点击,通过Padding实现了边距。
  • 接着通过Column垂直包含了两个子Widget,一个是Container、一个是Row
  • Row 内使用的就是_getBottomItem方法返回的 Widget ,效果如下图。
  @overrideWidget build(BuildContext context) {return new Container(///卡片包装child: new Card(///增加点击效果child: new FlatButton(onPressed: (){print("点击了哦");},child: new Padding(
ntainer`、一个是`Row`。* Row 内使用的就是`_getBottomItem`方法返回的 Widget ,效果如下图。```txt@overrideWidget build(BuildContext context) {return new Container(///卡片包装child: new Card(///增加点击效果child: new FlatButton(onPressed: (){print("点击了哦");},child: new Padding(padding: new EdgeInsets.only(left: 0.0, top: 10.0, right: 10.

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

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

相关文章

Spring 事件监听机制介绍以及源码分析

在复杂的业务系统中&#xff0c;模块间的过度耦合往往会导致代码维护困难、扩展性受限。Spring 事件监听机制基于观察者模式&#xff0c;提供了一种优雅的解耦方案&#xff0c;使得组件间通过事件驱动实现松耦合通信。这种机制不仅被 Spring 框架内部使用&#xff08;如容器生命…

【VSCode的安装与配置】

目录&#xff1a; 一&#xff1a;下载 VSCode二&#xff1a;安装 VSCode三&#xff1a;配置 VSCode 一&#xff1a;下载 VSCode 下载地址&#xff1a;https://code.visualstudio.com/download 下载完成之后&#xff0c;在对应的下载目录中可以看到安装程序。 二&#xff1a;安装…

2024年认证杯SPSSPRO杯数学建模C题(第二阶段)云中的海盐全过程文档及程序

2024年认证杯SPSSPRO杯数学建模 C题 云中的海盐 原题再现&#xff1a; 巴黎气候协定提出的目标是&#xff1a;在2100年前&#xff0c;把全球平均气温相对于工业革命以前的气温升幅控制在不超过2摄氏度的水平&#xff0c;并为1.5摄氏度而努力。但事实上&#xff0c;许多之前的…

Scala基础语法与简介

对象 -对象有属性和行为。例如&#xff1a;一只狗的状属性有&#xff1a;颜色&#xff0c;名字&#xff0c;行为有&#xff1a;叫、跑、吃等。对象是一个类的实例。 类 -类是对象的抽象&#xff0c;而对象是类的具体实例。 方法 -方法描述的基本的行为&#xff0c;一个类可以…

鸿蒙UI开发

鸿蒙UI开发 本文旨在分享一些鸿蒙UI布局开发上的一些建议&#xff0c;特别是对屏幕宽高比发生变化时的应对思路和好的实践。 折叠屏适配 一般情况&#xff08;自适应布局/响应式布局&#xff09; 1.自适应布局 1.1自适应拉伸 左右组件定宽 TypeScript //左右定宽 Row() { …

BeeWorks:为企业打造专网部署即时通讯解决方案

在数字化快速发展的今天&#xff0c;企业的沟通与协作越来越依赖于高效的即时通讯工具。然而&#xff0c;保障信息安全和数据隐私也变得愈发重要。这种情况下&#xff0c;专网部署即时通讯软件成为许多企业的首要选择。BeeWorks作为一款优质的专网部署即时通讯软件&#xff0c;…

uniapp笔记-swiper组件实现轮播图

思路 主要就是参考 swiper | uni-app官网 实现轮播图。 实例 新建一个banner.vue通用组件。 代码如下&#xff1a; <template><view>轮播图</view> </template><script> </script><style> </style> 随后在index.vue中导…

企业在人工智能创新与安全之间走钢丝

2025 年全球 AI/ML 工具使用量将激增&#xff0c;企业将 AI 融入运营之中&#xff0c;员工也将 AI 嵌入日常工作流程中。报告显示&#xff0c;企业对 AI/ML 工具的使用同比增长 3,000% 以上&#xff0c;凸显了各行各业迅速采用 AI 技术&#xff0c;以提升生产力、效率和创新水平…

vue - [Vue warn]: Duplicate keys detected: ‘0‘. This may cause an update error.

问题描述&#xff1a; vue项目中&#xff0c;对表单数组赋值时&#xff0c;控制台抛出警告&#xff1a; 问题代码&#xff1a; 问题分析&#xff1a; 1、Vue 要求每个虚拟 DOM 节点必须有唯一的 key。该警告信息通常出现在使用v-for循环的场景中&#xff0c;多个同级节点使用…

Containerd+Kubernetes搭建k8s集群

虚拟机环境设置&#xff0c;如果不是虚拟机可以忽略不看 1、安装配置containerd 1.1 添加 Kubernetes 官方仓库 安装cri-tools的时候需要用到 cat > /etc/yum.repos.d/kubernetes.repo << EOF [kubernetes] nameKubernetes baseurlhttps://mirrors.aliyun.com/kub…

ubuntu服务器server版安装,ssh远程连接xmanager管理,改ip网络连接。图文教程

ventoy启动服务器版iso镜像&#xff0c;注意看server名称&#xff0c;跟之前desktop版ubuntu不一样。没有gui界面。好&#xff0c;进入命令行界面。语言彻底没汉化了&#xff0c;选英文吧&#xff0c;别的更看不懂。 跟桌面版ubuntu类似&#xff0c;选择是否精简系统&#xff0…

QOpenGLWidget视频画面上绘制矩形框

一、QPainter绘制 在QOpenGLWidget中可以绘制&#xff0c;并且和OpenGL的内容叠在一起。paintGL里面绘制完视频后&#xff0c;解锁资源&#xff0c;再用QPainter绘制矩形框。这种方式灵活性最好。 void VideoGLWidget::paintGL() {glClear(GL_COLOR_BUFFER_BIT);m_program.bi…

蓝桥杯备考:真题之飞机降落(暴搜+小贪心)

我们最多有十架飞机&#xff0c;可以选择dfs暴力搜索&#xff0c;枚举每种情况 那么&#xff0c;我们降落的时候怎么确定新的起点也就是newend呢&#xff1f; 如果飞机飞到机场的时刻是大于原来的end的&#xff0c;我们就让tili作为newend 否则&#xff0c;我们就让end作为ne…

解决 Element UI 嵌套弹窗的状态管理问题!!!

解决 Element UI 嵌套弹窗的状态管理问题 &#x1f527; 问题描述 ❓ 在使用 Element UI 开发一个多层嵌套弹窗功能时&#xff0c;遇到了以下问题&#xff1a; 弹窗只能打开一次&#xff0c;第二次点击无法打开 &#x1f6ab;收到 Vue 警告&#xff1a;避免直接修改 prop 值…

实时图像处理:让你的应用更智能

一、项目背景 在数字化飞速发展的今天&#xff0c;图像处理技术已成为众多领域不可或缺的核心组件。从医疗影像的精准诊断&#xff0c;到自动驾驶汽车对道路环境的实时感知&#xff0c;再到安防系统中对异常行为的迅速捕捉&#xff0c;实时图像处理正以惊人的速度改变着我们的…

AWVS中lodash如何验证

作为一名漏扫攻城狮&#xff0c;时不时会在AWVS中看到lodash这个漏洞&#xff0c;但是我只管导出报告&#xff0c;该怎么验证呢&#xff1f; 验证POC 下面就是用于验证的POC&#xff0c;把这个html中的src进行修改为扫描的网站中的lodash.min.js然后浏览器打开 <!DOCTYPE …

【算法学习计划】贪心算法(上)

目录 前言&#xff08;什么是贪心&#xff09; leetcode 860.柠檬水找零 leetcode 2208.将数组和减半的最少操作次数 leetcode 179.最大数 leetcode 376.摆动序列 leetcode 300.最长递增子序列 leetcode 334.递增的三元子序列 leetcode 674.最长连续递增序列 leetcode …

Ubuntu 22.04 安装向日葵远程控制

1. 前言 由于公司客户的服务器用是图形化桌面&#xff0c;所以我们需要一个远程控制工具来控制服务器&#xff0c;目前市面上两款比较热门的控制软件就是ToDesk和向日葵了&#xff0c;我们今天就来学习一下向日葵的使用 2. 下载软件 前往向日葵官网下载 向日葵远程控制app官…

Linux网络编程(七)——套接字的多种可选项

文章目录 7 套接字的多种可选项 7.1 套接字可选项和I/O缓冲大小 7.1.1 套接字多种可选项 7.1.2 getsockopt & setsockopt 7.1.3 SO_SNDBUF & SO_RCVBUF 7.2 地址再分配 SO_REUSEADDR 7.2.1 发生地址分配错误&#xff08;Binding Error&#xff09; 7.2.2 Time-…

使用 langchain_deepseek 实现自然语言转数据库查询SQL

文章目录 Github官网简介腾讯云DeepSeek APIDeepSeek APIChatDeepSeek安装相关库创建 .env 文件验证 API 接口 生成数据库查询SQL获取测试用数据库验证数据库查询生成数据库查询SQL Github https://github.com/langchain-ai/langchain 官网 https://python.langchain.com/do…