简介

flutter中所有的组件都是由widgets组成的,flutter中有各种各样的widgets,这些widgets形成了flutter这个大厦。

那么flutter中的widget有什么特点呢?咱们应该怎么学习widget呢? 一起来看看吧。

StatelessWidget和StatefulWidget

实时上,flutter中的widgets是受到React的启发来实现的。flutter中的widget能够分为StatefulWidget和StatelessWidget,别离代表有状态的Widgets和无状态的Widgets。

有状态和无状态,大家听起来是不是很相熟,咱们在应用程序中也常常会用到有状态的Bean和无状态的Bean。他们的原理和flutter的两类Widget其实是差不多的。

StatelessWidget因为是无状态的,所以它只会依据初始传入的配置信息来构建Widget,因为Widget是不可变的,所以StatelessWidget创立进去就不会再变动。

对于StatefulWidget来说,除了依据初始传入的配置来创立Widget之外,它外部还蕴含了一个State。这个State用来和用户的行为进行交互,从而对State中的值进行批改。当State被批改后,和其绑定的Widget会依据特定的算法进行比拟,看是否须要进行重绘,从而将用户的交互反映在用户界面上。

widget提供了一个build办法,build办法返回一个Widget,用于生成最初的RenderObject对象。

build办法的定义如下:

Widget build(BuildContext context);

但事实上,只有StatelessWidget中才有build办法。那么StatefulWidget为什么没有build办法呢?

StatefulWidget尽管没有build办法,然而它有一个createState办法用来创立跟它关联的State:

State createState(); 

而这个build办法是放在State外面的。

StatelessWidget详解

什么样的组件能够做成无状态的组件呢?那些不须要和用户交互的组件就能够。

flutter中的无状态Widget都有那些呢?

这里列出几个flutter中根本和常常应用的StatelessWidget:

Text: 用来创立文本。

Row和Column: 示意的是纵向扩大和横向扩大的行和列。Row和Column是基于web的flexbox布局。

还有一个基于web的相对定位的布局叫做Positioned,Positioned通常是和Stack一起应用的。

Stack就是一个栈的构造,在Stack中你能够将一个widget放在另外一个widget的下面。

Positioned用在Stack中,能够绝对于top, right, bottom或者left边界进行绝对定位,十分好用。

另外一个罕用的组件就是Container,它示意的是一个长方形的元素,Container能够用BoxDecoration来润饰,用来示意背景、边框和暗影等。

Container还能够蕴含margins,padding和尺寸限度等个性。

接下来咱们来通过一个具体的例子来阐明StatelessWidget到底是怎么应用的。

如果咱们想构建一个上面款式的界面,该怎么做呢?

这个界面能够分为两局部,下面的个别称之为appBar,上面的个别叫做content。

appBar按列的布局又能够分为三局部,第一局部是一个IconButton示意导航菜单,第二局部是一个Text示意页面题目,第三局部也是一个IconButton示意搜寻按钮。 这三局部依照Row来进行组合.

那么依照Flutter的widget的构建准则,咱们能够把appBar构建成一个Widget。因为这个Widget的行为只跟初始化状态无关,所以能够将其设置成为StatelessWidget:

class MyAppBar extends StatelessWidget {  const MyAppBar({required this.title, Key? key}) : super(key: key);  final Widget title;  @override  Widget build(BuildContext context) {    return Container(      height: 56.0, // bar的高度      padding: const EdgeInsets.symmetric(horizontal: 8.0),      decoration: BoxDecoration(color: Colors.blue[500]),      // 按Row来进行布局      child: Row(        children: [          const IconButton(            icon: Icon(Icons.menu),            tooltip: '导航菜单',            onPressed: null, // 目前不可点击          ),          // Expanded组件,用于填充所有可用的空间          Expanded(            child: title,          ),          const IconButton(            icon: Icon(Icons.search),            tooltip: '搜寻',            onPressed: null,          ),        ],      ),    );  }}

下面的代码中,咱们把Row蕴含在一个Container中,而后将这个Container返回作为appBar的理论内容。

UI上面的局部比较简单, 就是一个居中的Text。咱们将其合和appBar合并起来,放在一个Column中,按行进行宰割:

class MyScaffold extends StatelessWidget {  const MyScaffold({Key? key}) : super(key: key);  @override  Widget build(BuildContext context) {    return Material(      // 构建一个两行的column,一个是bar, 一个是具体的内容      child: Column(        children: [          MyAppBar(            title: Text(              'StatelessWidget',              textAlign: TextAlign.center,              style: Theme.of(context)                  .primaryTextTheme                  .headline6,            ),          ),          const Expanded(            child: Center(              child: Text('这是一个Text组件!'),            ),          ),        ],      ),    );  }}

它也是一个StatelessWidget,在build办法中返回了Material这个widget。

而后,咱们将MyScaffold包装在一个MaterialApp中,作为最初返回的MyApp:

class MyApp extends StatelessWidget {  const MyApp({Key? key}) : super(key: key);  // 这是应用程序的根widget  @override  Widget build(BuildContext context) {    return MaterialApp(      title: '第一个StatelessWidget',      theme: ThemeData(        primarySwatch: Colors.green,      ),      home: const SafeArea(        child: MyScaffold(),      ),    );  }}

最初在runApp办法中运行MyApp即可:

void main() {  runApp(const MyApp());}

StatefulWidget详解

下面咱们解说了一个如何应用StatelessWidget来结构一个app的办法。大家应该对根本的流程有所相熟。

这里要留神的是,StatelessWidget并不是说widget中不能存储任何变量,如下面的例子所示,MyAppBar这个StatelessWidget其实是蕴含一个title的Widget,然而这个widget是final的,也就是说定义过一次之后就不可能再变动,所以叫做StatelessWidget。

StatefulWidget和StatelessWidget不同的中央在于,StatefulWidget能够和一个State进行关联。State中能够蕴含一些可变的属性,这些属性能够跟用户的操作进行交互,从而实现一些比较复杂的性能。

如果咱们须要上面的一个界面,界面右下方有一个按钮,点击一次,能够将两头的数字加一。

这是一个很显著的和用户交互的行为。这里咱们就能够用到StatefulWidget。

这里咱们创立一个MyHomePage的StatefulWidget,并创立一个_MyHomePageState的state和其进行关联:

class MyHomePage extends StatefulWidget {  const MyHomePage({Key? key, required this.title}) : super(key: key);  final String title;  @override  State<MyHomePage> createState() => _MyHomePageState();}

留神,可变属性是存在和StatefulWidget关联的state中的,而不是StatefulWidget自身。

所以咱们须要在_MyHomePageState中定义一个int的_counter变量,用来存储用户点击次数。而后定义一个_incrementCounter用来对_counter进行累加。

在_incrementCounter须要调用setState办法用来对State的状态进行刷新。

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

而后在State中的build办法中就能够返回对应UI的Widget了。这里咱们应用Scaffold组件,这个组件自带了appBar和body:

Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: Text(widget.title),      ),      body: Center(        child: Column(          mainAxisAlignment: MainAxisAlignment.center,          children: <Widget>[            const Text(              '按钮被点了:',            ),            Text(              '$_counter',              style: Theme.of(context).textTheme.headline4,            ),            const Text(              '次',            ),          ],        ),      ),      floatingActionButton: FloatingActionButton(        onPressed: _incrementCounter,        tooltip: 'Increment',        child: const Icon(Icons.add),      ),    );  }

这里body中咱们抉择应用Center组件用来展现内容信息。而浮动的按钮则应用FloatingActionButton,它的onPressed办法会触发咱们后面写的_incrementCounter办法,用来将_counter加一。

最初将咱们构建的组件传入MaterialApp中,如下所示:

class MyApp extends StatelessWidget {  const MyApp({Key? key}) : super(key: key);  // 根Widget  @override  Widget build(BuildContext context) {    return MaterialApp(      title: '第一个StatefulWidget',      theme: ThemeData(        primarySwatch: Colors.green,      ),      home: const MyHomePage(title: 'StatefulWidget'),    );  }}

总结

以上,咱们简略的解说了StatelessWidget和StatefulWidget的简略应用状况。后续咱们将会这些组件进行深刻,敬请期待。

本文的代码能够参考:https://github.com/ddean2009/learn-flutter, 感觉好的话,请点个赞,谢谢。

更多内容请参考 http://www.flydean.com/02-flutter-widget/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!