关于flutter:flutter系列之widgets构成flutter的基石

3次阅读

共计 5120 个字符,预计需要花费 13 分钟才能阅读完成。

简介

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/

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

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

正文完
 0