1. 前言

Flutter是一个由谷歌开发的开源移动应用软件开发工具包,用于为Android和iOS开发应用,同时也将是Google Fuchsia下开发应用的主要工具。其官方编程语言为Dart。

同为跨端开发的react-native的语言是JavaScript,RN是通过原生之间桥接来实现,而flutter是通过dart虚拟机直接编译。

这篇就不和 React-Native 进行详细对比 ,而是从前端开发的角度来看flutter。

2. Dart简介

Dart 比 JAVA 简单,易于理解,比 JavaScript 更加规范,更加工程化,兼具静态和动态语言的一些特性。

  • 强类型,可以直接生命变量类型,也可以类型推断;支持可选类型,用户可以像JavaScript一样写弱类型的定义,也可以确定类型。你可以写出动态语言风格的代码,也可以写出类似于传统静态风格的代码。Dart的类型推导使用final,var,const,dynamic关键字;
  1. var修饰变量;
  2. final表示不可变的,修饰内置数据类型,值不可变;修饰对象表示引用不可变,使用到的频率很高;
  3. const是编译时常量,他表示始终不可变,无论修饰内置类型还是对象,或者是数据结构;
  4. dynamic是任意类型,有点像java里面的Object,Kotlin中的Any
  • 单线程异步事件模型, 独特的隔离区( Isolate ),可以实现多线程;Dart是基于单线程模型的语言。但是在开发当中我们经常会进行耗时操作比如网络请求,这种耗时操作会堵塞我们的代码,所以在Dart也有并发机制,名叫isolate。APP的启动入口main函数就是一个类似Android主线程的一个主isolate。和Java的Thread不同的是,Dart中的isolate无法共享内存,类似于Android中的多进程。
  • DartVM,具有极高的运行效率和优秀的代码运行优化;
  • 面向对象编程,一切数据类型均派生自 Object ;
  • 运算符重载,泛型支持;
  • 异步API: Future (async/await)和 Stream(异步事件流) 模型,可以简单实现高效的代码;
  • Minix 特性,可以更好的实现方法复用;
  • 在语法上,Dart 提供了很多便捷的操作,可以明显减少代码量。比如字符连接,可以直接 "my name is $name, age is $age",无需+号拼接,也无需做类型转换(相当于ES6的模板字符串)。

更多参见官方文档

3. 从前端的角度看Flutter 

对于前端来说,页面就分为 HTML+CSS+JS

页面结构和样式  Flutter for Web 

对于习惯了html+css结合chrome devtools 完成UI效果的前端开发来说,刚开始用这种方式极其不习惯。

本来简单的一个结构和一个样式,加个背景色,渐变这种,css轻松搞定,然而,用widget来就要嵌套好多层,只能说,习惯习惯就好了。。

3.1 先来认识一下Flutter

Hello word入门

lib/main.dart

  1. import 'package:flutter/material.dart';
  2.  
  3. void main() => runApp(MyApp());
  4.  
  5. // StatelessWidget和StatefulWidget两种
  6. // 两者的区别在于状态的改变,StatelessWidget面向那些始终不变的UI控件;而StatefulWidget则是面向可能会改变UI状态的控件。
  7. class MyApp extends StatelessWidget {
  8. @override
  9. Widget build(BuildContext context) {
  10. return MaterialApp(
  11. title: 'Welcome to Flutter', // Title 是用来定义任务管理窗口界面所看到应用名字的
  12. home: Scaffold(
  13. appBar: AppBar( // 导航栏
  14. title: Text('Welcome to Flutter'),
  15. ),
  16. body: Center(
  17. child: Text('Hello World'),
  18. ),
  19. ),
  20. );
  21. }
  22. }

3.2 路由跳转传参

在前端传参很简单,是直接携带携带参数(params和query)跳转路由页面的

flutter里面的路由可以分成两种,一种是直接注册,不能传递参数。另一种要自己构造实例,可以传递参数。

分两种方法 push 和 pushNamed

3.2.1 静态路由的注册

  1. return new MaterialApp(
  2. title: 'Flutter Demo',
  3. theme: new ThemeData(
  4. primarySwatch: Colors.blue,
  5. ),
  6. home: new MyHomePage(title: 'Flutter实例'),
  7. routes: <String, WidgetBuilder> {
  8. // 这里可以定义静态路由,不能传递参数
  9. '/login': (BuildContext context) => new SecondPage(),
  10. '/register': (BuildContext context) => new RouterHomePage(),
  11. },
  12. );

3.2.2 静态路由的使用

  1. onPressed: () {
  2. Navigator.of(context).pushNamed("/register"); // or
  3.   Navigator.pushNamed(context, '/register')
  4. },

3.2.3 动态路由的使用

  1. Navigator.of(context).push(
    MaterialPageRoute(builder: (_) {
  2. return new SecondPage(title: '传参过去');
  3. }));

3.2.4 关闭页面

  1. Navigator.pop(context); // or
  2. Navigator.of(context).pop();
  3. Navigator.pop(context,"携带参数"); // 可携带参数

3.2.5 push , pushNamed 传参

Pass arguments to a named route

https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments

用 ModalRoute.of()封装路由及传参方法

push方法封装,有一个缺点就是不能只在主页面定义导入跳转的页面,略有代码重复

用pushNamed封装参数传递方法,就比较方便,不用再每一个页面import将要跳转的页面

main.dart

  1. import 'package:flutter/material.dart';
  2. import 'package:app/pages/home/app.dart';
  3. import 'package:app/pages/login/login.dart';
  4. import 'package:app/pages/login/register.dart';
  5. import 'package:app/pages/login/forget.dart';
  6. import 'package:app/pages/home/search_recommend.dart';
  7. import 'package:app/pages/home/search_result.dart';
  8.  
  9. void main() => runApp(MyApp());
  10.  
  11. class MyApp extends StatelessWidget {
  12.  
  13. @override
  14. Widget build(BuildContext context) {
  15. return MaterialApp(
  16. title: 'myapp',
  17. routes: {
  18. "/register": (context) => RegisterPage(),
  19. "/login": (context) => LoginPage(),
  20. "/forget": (context) => ForgetPage(),
  21. "/search": (context) => SearchRecommendPage(),
  22. "/searchresult": (context) => SearchResultPage(),
  23. },
  24. theme: new ThemeData(primarySwatch: Colors.red),
  25. home: AppPage(),
  26. );
  27. }
  28. }

从login跳转到register的时候,携带参数,并在register页面显示相应参数

login.dart

  1. import 'package:app/pages/login/register.dart'; // 用push方法的话就要用到这个
  2.  
  3. onPressed: () => { // 点击按钮跳转事件
  4. Navigator.push( // push方法--支持StatelessWidget和StatefulWidget
  5. context,
  6. MaterialPageRoute(
  7. builder: (context) => RegisterPage(),
  8. settings:RouteSettings(arguments: {'title': '手机号注册'})))
  9.  
  10. // or pushNamed 方法
  11. // Navigator.pushNamed(context, '/register',
  12. // arguments: {'title': '手机号注册'})
  13. },

register.dart 接收参数

  1. class _RegisterPageState extends State<RegisterPage> {
  2. @override
  3.  
  4. Widget build(context) {
  5. // 参数的接收显示
  6. final Map args = ModalRoute.of(context).settings.arguments;
  7.  
  8. return Scaffold(
  9. appBar: AppBar(
  10. title: Text(args['title']),
  11. ),
  12. body: Center(
  13. child: Text('register'),
  14. ),
  15. }
  16. }

3.3 事件触发

3.3.1 触发按钮的点击事件 

https://book.flutterchina.club/chapter3/buttons.html

(1)RaisedButton 漂浮按钮 (2)FlatButton 扁平按钮 (3) OutlineButton  (4) IconButton

几种按钮,触发事件都是 onPressed 点击事件

3.3.2 手势识别GestureDetector

https://book.flutterchina.club/chapter8/gesture.html

常见事件:点击、双击、长按

3.3.3 toast , alert 等弹窗

toast可直接安装 fluttertoast 包进行使用  https://pub.dev/packages/fluttertoast

alert, confirm 弹窗使用

部分代码

  1. import 'package:flutter/material.dart';
  2. onTap: () => showDialog(
  3. context: context,
  4. builder: (_) => _generateAlertDialog("我是弹框的内容")),
  5. )
  6.  
  7. _generateAlertDialog(String contents) {
  8. return AlertDialog(
  9. title: Text('这是标题'),
  10. content: Text(contents),
  11. actions: <Widget>[
  12. FlatButton(
  13. child: Text('取消'),
  14. onPressed: () {
  15. Navigator.of(context).pop(); // 点击取消关掉弹窗
  16. },
  17. ),
  18. FlatButton(
  19. child: Text('确认'),
  20. onPressed: () {
  21. Navigator.of(context).pop(); // 点击确认关掉弹窗再跳转到别的页面
  22.         Navigator.of(context).pushNamed('/register');
  23. },
  24. ),
  25. ],
  26. );
  27. }

4. 异步请求

flutter中的请求方式

  • Dart 原生的网络请求 HttpClient
  • 库 http
  • Flutter中文网发布的 dio

4.1 HttpClient

4.2 使用官方 http 库

https://flutter.dev/docs/cookbook/networking/fetch-data

4.3 使用 dio http请求框架 

https://book.flutterchina.club/chapter10/dio.html

dio比较流行的一个请求包,它支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传、文件下载等

先看简单的请求

  1. import 'dart:async';
  2. import 'package:dio/dio.dart';
  3.  
  4. var dio = new Dio();
  5.  
  6. void getHttp() async {
  7. try {
  8. Response response = await dio.get("http://www.google.com");
  9. print(response);
  10. } catch (e) {
  11. print(e);
  12. }
  13. }

可以封装一个通用请求模板,利用拦截器一并处理通用模块-比如请求前加loading, 结束关闭loading, 统一网络请求错误处理等

utils文件夹下的 net.dart

  1. import 'dart:async';
  2. import 'package:dio/dio.dart';
  3.  
  4. Dio dio;
  5.  
  6. class NetRequest {
  7. static Future<Dio> instance() async{
  8. if (dio == null) {
  9. dio = new Dio();
  10. }
  11. //添加拦截器
  12. dio.interceptors.add(
  13. InterceptorsWrapper(
  14. onRequest: (RequestOptions options) {
  15. print("请求之前");
  16. // Do something before request is sent
  17. return options; //continue
  18. },
  19. onResponse: (Response response) {
  20. print("响应之前");
  21. // Do something with response data
  22. return response; // continue
  23. },
  24. onError: (DioError e) {
  25. print("错误之前");
  26. // Do something with response error
  27. return e; //continue
  28. },
  29. ),
  30. );
  31. return dio;
  32. }
  33.  
  34. static Future get(String url, Map<String, dynamic> params) async {
  35. var response = await (await instance()).get(url, queryParameters: params);
  36. print(response.data.toString());
  37. return response.data;
  38. }
  39.  
  40. static Future post(String url, Map<String, dynamic> params) async {
  41. var response = await (await instance()).post(url, data: params);
  42. print(response.data.toString());
  43. return response.data;
  44. }
  45. }

发起请求

  1. import 'package:flutter/material.dart';
  2. import 'package:app/utils/net.dart';
  3.  
  4. class MyFriends extends StatefulWidget {
  5. MyFriends({Key key}) : super(key: key);
  6.  
  7. @override
  8. _MyFriendsState createState() => _MyFriendsState();
  9. }
  10.  
  11. class _MyFriendsState extends State<MyFriends> {
  12. void _getInfo() async {
  13. Map list = await NetRequest.get(url,{});
  14. print(list); // 发起get请求之后获得的数据
  15. }
  16.  
  17. @override
  18. void initState() {
  19. super.initState();
  20. _getInfo();
  21. }
  22.  
  23. Widget build(BuildContext context) {
  24. return Scaffold(
  25. body: Container(
  26. child: Text('friends'),
  27. ),
  28. );
  29. }
  30. }

post 请求同理

4. 开发者工具

https://flutter.github.io/devtools

Dart DevTools还是预览版,目前功能也还比较简单

VsCode   Dart: Open DevTools命令打开

5. 后记

刚开始写flutter各种不习惯,和js的模式不一样,更偏向于后端语言,作为跨端语言的新秀,又有Google这颗大树,设计之初就是作为跨多终端来实现的,这两年的发展也很快,国内很多团队有些已经在使用了。

官方发布版本也很勤,随着生态的逐渐完善,还是有很大的发展空间的,值得期待。

参考:

Flutter 官网

科普Dart语言

Flutter 中文网

Flutter 简介(事件、路由、异步请求)的更多相关文章

  1. 在Silverlight中的DispatcherTimer的Tick中使用基于事件的异步请求

    需求:在silverlight用户界面上使用计时器定时刷新数据. 在 Silverlight 中的 DispatcherTimer 的 Tick 事件 中使用异步请求数据时,会出现多次请求的问题,以下 ...

  2. day92:flask:flask简介&基本运行&路由&HTTP请求和响应

    目录 1.Flask简介 2.关于使用flask之前的准备 3.flask的基本运行 4.flask加载配置 5.传递路由参数(没有限定类型) 6.传递路由参数(通过路由转换器限定路由参数的类型) 7 ...

  3. .NET - 基于事件的异步模型

    注:这是大概四年前写的文章了.而且我离开.net领域也有四年多了.本来不想再发表,但是这实际上是Active Object模式在.net中的一种重要实现方法,因此我把它掏出来发布一下.如果该模型有新的 ...

  4. MVC&WebForm对照学习:ajax异步请求

    写在前面:由于工作需要,本人刚接触asp.net mvc,虽然webform的项目干过几个.但是也不是很精通.抛开asp.net webform和asp.net mvc的各自优劣和诸多差异先不说.我认 ...

  5. AJAX发送异步请求教程详解

    AJAX 一.AJAX简介 什么是 AJAX ? AJAX = 异步 JavaScript 和 XML. AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可 ...

  6. vue-d2admin前端axio异步请求详情

    vue-d2admin前端axio异步请求详情 d2admin>src>api>sys.login.js 设计axio api import request from '@/plug ...

  7. ajax异步请求

    做前端开发的朋友对于ajax异步更新一定印象深刻,作为刚入坑的小白,今天就和大家一起聊聊关于ajax异步请求的那点事.既然是ajax就少不了jQuery的知识,推荐大家访问www.w3school.c ...

  8. AJAX实现简单的注册页面异步请求

    p { margin: 0px; padding: 0px } AJAX简介 (1)AJAX = 异步 JavaScript 和 XML. (2)AJAX 是一种用于创建快速动态网页的技术. (3)通 ...

  9. Ajax_02之XHR发起异步请求

    1.Ajax: AJAX:Asynchronous Javascript And Xml,异步的JS和XML: 同步请求:地址栏输入URL.链接跳转.表单提交-- 异步请求:使用Ajax发起,底层使用 ...

随机推荐

  1. stone [期望]

    也许更好的阅读体验 \(\mathcal{Description}\) 有 \(n\) 堆石子,依次编号为 \(1, 2,\ldots , n\),其中第 \(i\) 堆有 \(a_i\) 颗石子 你 ...

  2. Aspx后台遍历控件

    aspx设计页面 //这个是检测按钮,检测下面的checkbox是否被选中.选中时打印其值 //https://www.cnblogs.com/pwblog/articles/3456385.html ...

  3. 记一次node爬虫经历,手把手教你爬虫

    今天业务突然来了个爬虫业务,爬出来的数据以Excel的形式导出,下班前一个小时开始做,加班一个小时就做好了.因为太久没做爬虫了!做这个需求都是很兴奋! 需求说明 访问网站 (循环)获取页面指定数据源 ...

  4. 如何获取图片上传OSS后的缩略图 超简单

    OSS是使用通过URL尾部的参数指定图片的缩放大小 图片路径后面拼接如下路径:     ?x-oss-process=image/[处理类型],x_100,y_50[宽高等参数] ?x-oss-pro ...

  5. java之spring mvc之拦截器

    1. springmvc 中的拦截器是由实现 HandlerInterceptor 或者继承 HandlerInterceptorAdapter 来实现的. 2. 自定义实现一个拦截器的步骤: a). ...

  6. CentOS7配置网卡上网、安装wget、配置163yum源

    2019/09/12,CentOS 7 VMware 摘要:CentOS7安装完成(最小化安装)后,不能联网(已选择桥接网络),需要修改配置文件及配置yum源 修改配置文件 进入网卡配置目录 cd / ...

  7. 从实践到原理,带你参透 gRPC

    gRPC 在 Go 语言中大放异彩,越来越多的小伙伴在使用,最近也在公司安利了一波,希望这一篇文章能带你一览 gRPC 的巧妙之处,本文篇幅比较长,请做好阅读准备.本文目录如下: 简述 gRPC 是一 ...

  8. HANA- SAP S4/HANA BP屏幕增强添加自定义字段(BDT方式)

    转载:https://www.cnblogs.com/hhelibeb/p/7412792.html 这里我们可以使用的技术是Business Data Toolset(以下简称BDT). 以下是网络 ...

  9. Linux内核同步机制之completion

    内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束.这个活动可能是,创建一个新的内核线程或者新的用户空间进程.对一个已有进程的某个请求,或者某种类型的硬件动作,等等.在这种 ...

  10. 如何使用Fiddler抓取APP接口和微信授权网页源代码

    Fiddler,一个抓包神器,不仅可以通过手机访问APP抓取接口甚至一些数据,还可以抓取微信授权网页的代码. 下载安装 1. 下载地址(官网):  https://www.telerik.com/do ...