原来Flutter代码是这样运行在原生系统的!快来了解Flutter标准模板,感受原生系统中Flutter的魅力!

简介: 原来Flutter代码是这样运行在原生系统的!快来了解Flutter标准模板,感受原生系统中Flutter的魅力!

通过Android Studio创建的Flutter应用模板,了解Flutter项目结构,分析Flutter工程与原生Android和iOS工程有哪些联系,体验一个有着基本功能的Flutter应用是如何运转的,从而加深你对构建Flutter应用的关键概念和技术的理解。


Dart只要理解基本编程概念(比如,类型、变量、函数和面向对象),并具备一定前端基础(了解View是什么、页面基本布局等基础),就可以和我一起完成计数器示例工程分析


Android Studio创建Flutter工程应用flutter_app。Flutter会根据自带的应用模板,自动生成简单计数器示例应用Demo。我们先运行此示例,效果如下:

每点击一次右下角带“+”号的悬浮按钮,就可以看到屏幕中央的数字随之+1。

1 工程结构

了解Flutter工程与原生Android和iOS工程关系及这些关系是如何确保Flutter程序最终运行在Android和iOS。

除Flutter本身的代码、资源、依赖和配置,Flutter工程包含Android和iOS工程目录。因为Flutter虽然是跨平台开发方案,但却需要一个容器最终运行到Android和iOS平台,所以 Flutter工程实际是同时内嵌Android和iOS原生子工程的父工程:在lib目录进行Flutter代码开发,某些特殊场景原生功能,则在对应Android和iOS工程提供相应代码实现,供对应Flutter代码引用。


Flutter会将相关依赖和构建产物注入这两个子工程,集成到各自项目。而我们开发Flutter代码,最终以原生工程形式运行。

2 工程代码

Flutter自带的应用模板,即计数器示例,对初学者是极好入门范例。从基础的组件、布局到手势的监听,再到状态的改变,Flutter最核心思想在这60余行代码。

为便学习理解,删掉核心流程无关组件配置代码及布局逻辑,不影响示例功能的情况下对代码进行改写,并分两部分:

  • 应用入口、应用结构以及页面结构,理解构建Flutter程序的基本结构和套路
  • 页面布局、交互逻辑及状态管理,理解Flutter页面是如何构建、如何响应交互,以及如何更新

3 第一部分代码,应用的整体结构

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) => MaterialApp(home: MyHomePage(title: 'Flutter Demo Home Page'));
}
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  Widget build(BuildContext context) => {...};
}

Flutter应用为MyApp类的一个实例,MyApp类继承自StatelessWidget类,即应用本身也是一个Widget。Flutter中的Widget是整个视图描述的基础,Flutter中的包括应用、视图、视图控制器、布局等概念,都建立在Widget之上,Flutter核心设计思想是一切皆Widget。

3.1 Widget

组件视觉效果的封装,UI界面的载体,因此还要为它提供一个方法,告诉Flutter框架如何构建UI界面,即build。

3.1.1 build方法

通过对基础Widget进行相应UI配置或组合各类基础Widget进行UI定制化。如MyApp通过MaterialApp这个Flutter App框架设置应用首页,即MyHomePage。

3.2 MaterialApp类

是对构建material设计风格应用的组件封装框架,有很多可配置属性,如应用主题、应用名称、语言标识符、组件路由等,可参考Flutter官方的 API文档,了解MaterialApp框架的其他配置能力。

3.3 MyHomePage

应用首页,继承自StatefulWidget类,有状态Widget(Stateful Widget), _MyHomePageState就是其状态。


虽然MyHomePage类也是Widget,但与MyApp类不同,它没有build方法返回Widget,而是多个createState方法返回_MyHomePageState对象,而build方法包含在这 _MyHomePageState 类中。

3.4 StatefulWidget V.S StatelessWidget的接口设计

因为Widget要依据数据才能完成构建,对StatefulWidget来说,其依赖的数据在Widget生命周期中可能频繁变化。由State创建Widget,以数据驱动视图更新,而非直接操作UI更新视觉属性,代码表达更精炼,逻辑更清晰。


4 第二部分-页面布局及交互逻辑

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  void _incrementCounter() => setState(() {_counter++;});
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(Widget.title)),
      body: Text('You have pushed the button this many times:$_counter')),
      floatingActionButton: FloatingActionButton(onPressed: _incrementCounter)
    );
  }

_MyHomePageState中创建的Widget Scaffold,是Material库提供的页面布局结构,包含:

  • AppBar,页面导航栏,直接将MyHomePage中的title属性作为标题使用
  • body,Text组件,显示了一个根据_counter属性可变的文本:‘You have pushed the button this many times:$_counter’。

floatingActionButton,页面右下角的“+”悬浮按钮。将 _incrementCounter 作为其点击处理函数

_incrementCounter

使用setState方法自增状态属性_counter。setState方法是Flutter以数据驱动视图更新的函数,会通知Flutter框架:我这儿有状态改变,赶紧给我刷新界面!而Flutter框架收到通知后,会执行Widget#build,根据新状态重建界面。


状态的更改一定要配合使用setState。通过该方法调用,Flutter会在底层标记Widget的状态,随后触发重建。示例即使修改_counter,若不调用setState,Flutter框架也不会感知到状态变化,因此界面也不会有任何改变。


图计数器示例的代码流程示意图,把这实例的整个代码流程串起:

MyApp为Flutter应用的运行实例,在main函数中调用runApp函数实现程序的入口。

应用首页则为MyHomePage,一个拥有_MyHomePageState状态的StatefulWidget。_MyHomePageState通过调用build方法以相应数据配置完成包括导航栏、文本及按钮的页面视图的创建。


而当按钮被点击之后,其关联的控件函数_incrementCounter会触发调用。在这个函数中,通过调用setState更新_counter属性同时,也通知Flutter框架其状态发生变化。随后,Flutter重新调用build方法以新数据配置重建_MyHomePageState的UI,最终完成页面重新渲染。


Widget只是视图的“配置信息”,是数据的映射,“只读”。对StatefulWidget,当数据改变时,需重建Widget去更新界面,即Widget创建销毁会很频繁。


为此,Flutter对此机制

5 优化

其框架9内部会通过一个中间层收敛上层UI配置对底层真实渲染的改动,从而最大程度降低对真实渲染视图的修改,提高渲染效率,而不是上层UI配置变就要销毁整个渲染视图树重建。


这样Widget仅是一个轻量级的数据配置存储结构,它的重新创建速度非常快,所以我们可放心重建任何需更新的视图,无需分别修改各子Widget特定样式。

6 总结

先通过Flutter标准模板创建了计数器示例,并分析了Flutter的项目结构,以及Flutter工程与原生Android、iOS工程的联系,知道了Flutter代码是怎么运行在原生系统上的。


然后,学习示例项目代码,了解了Flutter应用结构及页面结构,并认识了构建Flutter的基础,也就是Widget,以及状态管理机制,知道了Flutter页面是如何构建的,StatelessWidget与StatefulWidget的区别,以及如何通过State的成员函数setState以数据驱动的方式更新状态,从而更新页面。


有原生Android和iOS框架开发经验的同学,可能更习惯命令式UI编程风格:手动创建UI组件,在需要更改UI时调用其方法修改视觉属性。而Flutter采用声明式UI设计,只需描述当前UI状态(即State),不同UI状态的视觉变更由Flutter在底层完成。


虽然命令式的UI编程风格更直观,但声明式UI编程方式好处是,可以让我们把复杂的视图操作细节交给框架去完成,这样一来不仅可以提高我们的效率,也可专注整个应用和页面的结构和功能。

7 FAQ

示例项目代码在_MyHomePageState类中,直接在build函数里以内联的方式完成了Scaffold页面元素的构建,这样做的好处是什么呢?在实现同样功能的情况下,如果将Scaffold页面元素的构建封装成一个新Widget类,我们该如何处理?


将Scaffold页面元素的构建封装成一个新Widget类的好处是可以提高代码的可复用性和可维护性。这样可以将Scaffold的构建逻辑封装到一个独立的组件中,方便在其他地方重复使用,也方便后续进行修改和维护。


如果要将Scaffold页面元素的构建封装成一个新Widget类,可以创建一个新的StatelessWidget或StatefulWidget类,然后在该类的build方法中返回Scaffold组件的代码。这样就可以在其他地方使用该组件来构建Scaffold页面元素。例如:

class MyScaffold extends StatelessWidget {
  final Widget body;
  const MyScaffold({Key? key, required this.body}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('My App'),
      ),
      body: body,
    );
  }
}

然后在其他地方可以通过MyScaffold来构建页面元素,例如:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MyScaffold(
      body: Center(
        child: Text('Hello, World!'),
      ),
    );
  }
}
目录
相关文章
|
1月前
|
存储 开发框架 开发者
flutter:代码存储&基本组件 (五)
本文档介绍了Flutter中的一些基本组件和代码示例,包括代码存储、基本组件如AppBar的简单使用、可滑动切换的标签栏、TextField的多种用法(如简单使用、登录页面、文本控制器的监听与使用、修饰等),以及如何实现点击空白区域隐藏键盘等功能。通过这些示例,开发者可以快速掌握在Flutter应用中实现常见UI元素的方法。
|
30天前
|
IDE 调度 开发工具
鸿蒙Flutter实战:08-如何调试代码
本文介绍了鸿蒙Flutter项目的开发环境搭建、配置、日志查看及调试方法。首先按照指南搭建开发环境,安装IDE插件;接着配置vscode的launch.json文件;通过IDE调试控制台或命令行查看日志;提供两种调试Flutter的方式,包括IDE直接运行和使用DevEco;最后介绍ArkTs和Webview的调试方法。
44 0
|
1月前
|
小程序 Java Android开发
flutter:注意点&快速代码&链接虚拟机&改配置 (一)
这段内容主要介绍了Flutter开发中的一些注意事项和快速代码示例。首先,在构建Flutter小程序时,`setState`方法只能在`StatefulWidget`和`State`类中使用,且初始化数据应放在`initState`方法内。接着,通过一个简单的示例展示了如何构建一个包含`Scaffold`的基本Flutter应用,并指出了在`MaterialApp`中移除调试横幅的方法。此外,文档还提供了关于搭建Flutter开发环境、配置虚拟机、解决安装错误以及配置相关文件(如`build.gradle`)的指导信息。
|
3月前
|
Dart
Flutter之ExpansionTile实现以代码方式码折叠、展开
Flutter之ExpansionTile实现以代码方式码折叠、展开
121 4
|
3月前
|
Dart
Flutter笔记:手动配置VSCode中Dart代码自动格式化
Flutter笔记:手动配置VSCode中Dart代码自动格式化
458 5
|
3月前
|
开发工具 iOS开发
解决Flutter运行报错Could not run build/ios/iphoneos/Runner.app
解决Flutter运行报错Could not run build/ios/iphoneos/Runner.app
140 2
|
3月前
|
iOS开发
解决Flutter运行IOS报错:Podfile is out of date
解决Flutter运行IOS报错:Podfile is out of date
74 1
|
3月前
|
Dart 开发工具 Android开发
Flutter学习:从搭建环境到运行
Flutter学习:从搭建环境到运行
45 0
|
6月前
|
Dart 安全
简化代码、提高效率:Dart和Flutter开发小技巧
在日常开发中,我们常常会使用一些常用的技巧或语法糖,以简化代码、提高开发效率。本文将分享一些在Dart和Flutter中常用的小贴士,帮助你更轻松地编写优雅高效的代码。
简化代码、提高效率:Dart和Flutter开发小技巧
|
4月前
|
Dart Android开发 iOS开发
flutter 创建项目、运行项目、项目目录
flutter 创建项目、运行项目、项目目录
168 0