Flutter之HolleWold

Flutter 第一个项目是一个计数器

Flutter 的Dart代码是写在lib 文件夹下,而 lib/main.dart 是项目的入口,打开main.dart ,下边是代码:

//引入material UI库,可以理解为iOS的UIKit
import 'package:flutter/material.dart';

// 传说中的main 函数,使用dart 的特有的  => 调用方法
// 调用了MyApp函数
void main() => runApp(new MyApp());

// Widget(部件),可以理解为iOS中的UIView,iOS中叫控件,都由view封装而成,Flutter中都叫部件(小部件),都由widget封装而成
// extends:继承(OC不这么写,因为OC 一个类有2个文件组成 .h和.m)--OC 是最NB的[偷笑]!
class MyApp extends StatelessWidget {
  //重写 build 方法(描述如何构建UI界面)
  @override
  Widget build(BuildContext context) {
  // MaterialApp :是Material库中提供的Flutter APP框架,通过它可以设置应用的名称、主题、语言、首页及路由列表等
    return new MaterialApp(
 //名称
      title: 'Flutter Demo',
//主题
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
//应用首页路由 
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
//首页
class MyHomePage extends StatefulWidget {
//可选参数,首页导航标题,如果不清楚可以
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;
// 加载首页的状态类,StatefulWidget 的特殊写法,下边详细介绍
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}
// State 状态
// <MyHomePage> 这这个类的状态
class _MyHomePageState extends State<MyHomePage> {
//记录计数器的数字
  int _counter = 0;
// 点击 “+” 按钮调用的方法,实现 i++
// _incrementCounter 这种下划线的命名的方法,表示是一个私有方法
  void _incrementCounter() {
// 刷新页面
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
// Scaffold :是Material库中提供的页面脚手架,它包含导航栏和Body以及FloatingActionButton
// 就是一个封装了导航栏等等功能的小部件,可以简单理解为UINavgation
    return new Scaffold(
// 导航栏
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
// Center : 一个空白的view (web 中的 div )
      body: new Center(
// Column: 一种布局方案,下一章布局详细介绍 
        child: new Column(
// 布局中的对齐,居中
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
// lab
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
// 按钮
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,// 调用方法
        tooltip: 'Increment',
        child: new Icon(Icons.add),// icon
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

代码还是比较简单的,点击按钮,调用 _incrementCounter 方法,_counter++,刷新页面,让 Text 显示

接下来,详细介绍一下,里边包含的知识点:

StatelessWidget 和 StatefulWidget

StatelessWidget: 无状态Widget,一旦创建,不能改变
StatefulWidget: 有状态的Widget,可以根据状态改变

  1. StatefulWidget 其实就是 StatelessWidget + 状态组成
  2. 其实 StatefulWidget 能够改变,也只是保存了“状态”,删除了老的StatelessWidget,重新创建了一个新的
  3. 所以StatelessWidget 是一个方法,而StatefulWidget 要多写一个 State 方法

刷新页面 setState

// 下边2种写法都可以
_counter++;
setState(() {});

setState(() {
      _counter++;
});
  1. 调用刷新页面,删除了老的StatelessWidget,新建一个StatelessWidget,重新展示改变状态以后的页面
  2. 代码逻辑其实重新执行build 方法,来重绘,所以build 方法里边只放和页面布局相关的东西,不要放逻辑代码

widget 底层

widget 继承DiagnosticableTree,主要的包括key,Element ,canUpdate等等。

  1. key:这个key属性类似于React/Vue中的key,主要的作用是决定是否在下一次build时复用旧的widget,决定的条件在canUpdate()方法中。
  2. canUpdate:是否用新的Widget对象去更新旧UI树上所对应的Element对象的配置;只要newWidget与oldWidget的runtimeType和key同时相等时就会用newWidget去更新Element对象的配置,否则就会创建新的Element。
  3. Element属性

事实上 Widget 只是 Element 的一个配置描述 ,告诉 Element 这个实例如何去渲染。
从上图注释也可知: Widget 和 Element 之间是一对多的关系 。

而Element 里边有renderObject属性

而renderObject 是Flutter布局和绘制的基本单元

由此可以得出: Widget 生成了 Element,而后创建 RenderObject 关联到 Element 的内部 renderObject 对象上,最后Flutter 通过 RenderObject 数据来布局和绘制。

说到 RenderObject ,就不得不说 RenderBox ,从源码注释可以看出,它是在继承 RenderObject 基础的布局和绘制功能上,实现了“笛卡尔坐标系”:以 Top、Left 为基点,通过宽高两个轴实现布局和嵌套的。

RenderBox 避免了直接使用 RenderObject 的麻烦场景,其中 RenderBox 的布局和计算大小是在 performLayout() 和 performResize() 这两个方法中去处理,很多时候我们更多的是选择继承 RenderBox 去实现自定义。

综合上述情况,我们知道:

  1. Widget只是显示的数据配置,所以相对而言是轻量级的存在,而 Flutter 中对 Widget 的也做了一定的优化,所以每次改变状态导致的 Widget 重构并不会有太大的问题。
  2. RenderObject 就不同了,RenderObject 涉及到布局、计算、绘制等流程,要是每次都全部重新创建开销就比较大了。

所以针对是否每次都需要创建出新的 Element 和 RenderObject 对象,Widget 都做了对应的判断以便于复用,比如:在 newWidget 与oldWidget 的 runtimeType 和 key 相等时会选择使用 newWidget 去更新已经存在的 Element 对象,不然就选择重新创建新的 Element。

由此可知:Widget 重新创建,Element 树和 RenderObject 树并不会完全重新创建。

那么再来个图理解一下:

widget 底层这块参考大神所写:
https://juejin.im/post/5c7e853151882549664b0543

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。