[ -Flutter漫谈篇- ] StatelessWidget Or StatefulWidget

抉择的条件若是是错误的,那么抉择的自己没有任何意义。----张风捷特烈bash

人生最难莫过抉择,特别是分不清好坏的时候。To be, or not to be, that is a question
在你Flutter中的第一个抉择也许就是 StatelessWidget Or StatefulWidget
本文就来跟大家说说这两个家伙是干吗的,有什么不一样,该怎么用。微信


1.描述统一形式化
#define by 张风捷特烈 做用域:本文
[0].用户打开应用到应用进程结束的过程称做一次[会话]

[1].具备可视化表现能力的元素,称为[显示元],如一个文字、按钮、图片...  
[2].显示元的一切属性集称为[状态],如颜色,大小,样式...  
[3].一个显示元在一次会话中的全部状态称为[状态集]  

[4].用户看到的一屏显示元组成的集合,称为[界面]
[5].一次会话中全部的界面集合,称为[UI]
[6].具备改变显示元状态的行为称为[事件]
[7].一次会话中全部的事件集合称为[事件集]

设:某显示元的一次会话中[状态集]为 S, 令 |S|表示集合元素个数
定义: StatelessWidget ⇔ |S| = 1
定义: StatefulWidget ⇔ |S| > 1
复制代码

引理1: 状态(s)决定显示元(w)的表现。且s与w一一对应,称为满射 f 
记做: w = f(s) 

引理2: 事件(e)能够改变显示元状态(s),每一个e对应状态,称为映射 g
记做: s = g(e)  推论:w = f(g(e))  f与g的合成映射记做F,则 w = F(e)
复制代码
  • StatelessWidget性质:对于任意e, 有恒定s ⇔ 任意 e,有恒定w

  • StatefulWidget性质:存在e, 使 s 变化

#define endless


1.StatelessWidget : f(x) = 2

若是要显示下面的界面元,在没有任何前提的状况下,选择StatelessWidget
下面是由四个显示元构成的界面,每一个显示元一旦诞生就是不可变的ide

//指定半径,是否选择,颜色,边线色
class ShapeColor extends StatelessWidget {
  ShapeColor(
      {Key key,
      this.radius = 20,
      this.checked = true,
      this.color=Colors.red,
      this.shadowColor=Colors.blue,
      this.elevation=2})
      : super(key: key);
  final double radius; //半径
  final bool checked; //标记是否被选中
  final Color shadowColor; //颜色
  final Color color; //颜色
  final double elevation; //颜色

  @override
  Widget build(BuildContext context) {
    var shape = Container(
      width: radius,
      height: radius,
      decoration: BoxDecoration(//圆形装饰线
        color: color ?? Colors.red,
        shape: BoxShape.circle,
        boxShadow: checked
            ? [
                BoxShadow(//阴影
                  color: shadowColor,
                  offset: Offset(0.0, 0.0),
                  spreadRadius: elevation,
                  blurRadius: elevation
                ),
              ]
            : [],
      ),
    );
    return shape;
  }
}
复制代码

2.StatefulWidget : g(x) = 2x

因为StatelessWidget自己不可变,但并不意味着它不能借助外界来变
就像 f(x) = 2 是一条不变的横线。 无论x多么努力,都不可能摆脱2的无用命运
若是如今有一个g(x) = 2x , 那 g(f(x)) = 4x 。这时f(x)和 g(x)协做完成了4x
StatefulWidget就像是这个g映射,你没有舞台,我给你,也能发挥你的价值。post

class ShapeColorRadio extends StatefulWidget {
  ShapeColorRadio({Key key,this.radius = 20,
    this.color=Colors.red,
    this.shadowColor=Colors.blue,
    this.elevation=2}):super(key:key);
  
  final double radius; //半径
  final Color shadowColor; //颜色
  final Color color; //颜色
  final double elevation; //颜色
  @override
  _ShapeColorRadioState createState() => _ShapeColorRadioState();
}

class _ShapeColorRadioState extends State<ShapeColorRadio> {
  var _checked =false;

  @override
  Widget build(BuildContext context) {

    return GestureDetector(
      onTap: (){
        setState(() {//改变状态
          _checked=!_checked;
        });
      },
      child: ShapeColor(
        color: widget.color,
        elevation: widget.elevation,
        shadowColor: widget.shadowColor,
        radius: widget.radius,
        checked: _checked,
      ),
    );
  }
}
复制代码

3.如何抉择

若是你一开始就意识到须要的是 g(x) = 4x ,你彻底能够一步到位。但本质上的逻辑是相同的。
就像你吃草莓蛋糕,能够一口吞,也能够草莓和蛋糕分开吃,最后都在你肚子里。
一口吞简单方便,分开吃你能够单独体会草莓的味道,回味和复用。ui

class ShapeColorRadio extends StatefulWidget {
  ShapeColorRadio({Key key,this.radius = 20,
    this.color=Colors.red,
    this.shadowColor=Colors.blue,
    this.elevation=2}):super(key:key);

  final double radius; //半径
  final Color shadowColor; //颜色
  final Color color; //颜色
  final double elevation; //颜色
  @override
  _ShapeColorRadioState createState() => _ShapeColorRadioState();
}

class _ShapeColorRadioState extends State<ShapeColorRadio> {
  var _checked =false;

  @override
  Widget build(BuildContext context) {
    var shape = Container(
      width: widget.radius,
      height: widget.radius,
      decoration: BoxDecoration(
        //圆形装饰线
        color: widget.color ?? Colors.red,
        shape: BoxShape.circle,
        boxShadow: _checked
            ? [
          BoxShadow(//阴影
              color: widget.shadowColor,
              offset: Offset(0.0, 0.0),
              spreadRadius: widget.elevation,
              blurRadius: widget.elevation
          ),
        ]
            : [],
      ),
    );
    return GestureDetector(
      onTap: (){
        setState(() {//改变状态
          _checked=!_checked;
        });
      },
      child: shape,
    );
  }
}
复制代码

4.StatefulWidget得天独厚的优点

StatefulWidget得天独厚的优点在于它有生命周期,initState,didChangeDependencies,didUpdateWidget,reassemble,build,deactivate,dispose。 每一个方法都会在组件相应的状态回调,这样看来StatefulWidget更像是一个有生命的东西,而StatelessWidget更像是个死的玩偶。若是你想要去更细粒度地掌控一个组件StatefulWidget是你最佳选择。this


若是你在Widget中写了一个不是final的字段,虽然不会崩,但AS小姐姐会抱怨: "TM,说好的在一块儿,永远不改变immutable(不可变),你不final是几个意思。"吓得我立马加上final。spa

但有时确实须要有改变的字段怎么办?一个字:用StatefulWidget
若是想在组件移除的时候释放对象怎么办:一个字:用StatefulWidget
什么是用StatelessWidget。f(x) = 2code


5.滥用StatefulWidget-机智如你

有人会说,既然StatefulWidget这么好,我都用StatefulWidget不就好了吗?
我反问一句。表达直线 f(x) = 2 。 你会用 f(x) = g(1) 其中g(x) = 2x吗?
若是不会,那就乖乖地垃圾分类。若是以为无所谓,那随你喽,乱扔垃圾罚得也不是我
食物链能量的传递效率是逐级递减的,只要有传递,就会有损耗。cdn

abstract class StatelessWidget extends Widget {
  const StatelessWidget({ Key key }) : super(key: key);
  @override
  StatelessElement createElement() => StatelessElement(this);
 considerations.
  @protected
  Widget build(BuildContext context);
}

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);
  @protected
  State createState();
}
复制代码

StatelessWidget依靠StatelessElement建立元素,StatefulElement依靠StatefulElement建立元素,他俩有个共同的爹叫ComponentElement,爷爷是Element。因此他俩是兄弟,那么既然同一个爹生的,差异咋就这么大呢?预知后事如何,且听下回分解。

满纸荒唐言,一把辛酸泪。都言做者痴,谁解其中味。

本文到此接近尾声了,若是想快速尝鲜Flutter,《Flutter七日》会是你的必备佳品;若是想细细探究它,那就跟随个人脚步,完成一次Flutter之旅。
另外本人有一个Flutter微信交流群,欢迎小伙伴加入,共同探讨Flutter的问题,本人微信号:zdl1994328,期待与你的交流与切磋。

相关文章
相关标签/搜索