Flutter 研发阶段性总结 Widget

Posted 嗡汤圆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter 研发阶段性总结 Widget相关的知识,希望对你有一定的参考价值。

Flutter作为Google一个新的用于构建跨平台的手机App的SDK,最近势头正猛,与原来的Hybrid形式的App相比,性能优势明显,同时官方文档完善。同时也推出了很多官方基础教学视频,能爬梯子的同学可以在油管上看到诸如:

  • Widget of the week: 用1-2分钟时间形象的展示一个Widget的用法和效果(Flutter的所有界面元素包括App框架本身都是Widget)。
  • Flutter in Focus: 用5-10分钟的视频深入讲解Flutter的某一特性,比如异步机制、Widget组件树、Key机制等。一般是一个系列视频,比如Widget相关有4个,异步相关有4个(正在更新中)

国内中文文档也有不少同学在写。我本身主要是做后台研发,看我的其它博客就知道, 对于App研发没有经过原生iosandroid的系统性学习,直接就接触了Flutter, 所以以下的表述可能会存在一些不准确的地方,请见谅。
所以本文主要作用并不是介绍Flutter研发本身,而是把自己自学过程中的一些想法记录下来,基础知识的学习就看官方文档或者其他同学的博客就行。

Widget

Widget类型的UI描述方式的表现能力和缺点

在Flutter中,所有的界面元素都是Widget,他们大概分为布局类,容器类,其中:

  • 布局类:代表了一些元素排布规则,如: Center, Row, Column, Padding, Expanded, Stack …
  • 容器类:代表了有具体形象的容器,用于承载具体内容,如:Text, Card, Image, Icon, RaisedButton …

通过对不同类型的容器的嵌套组合,就能形成不同的界面布局,个人认为这一套UI设计方式的表现灵活性和描述精准性是足够的,比Hybrid中html方式描述界面要准确的多,不涉及分辨率,同时不依赖CSS等规范不太统一的样式描述,可以真正得到不同端的统一展现。况且最近苹果推出的Swift UI 用的也是这种风格的布局描述方式,其实可以看出来这种布局描述方式也逐渐被认可。
不好的地方在于复杂界面的层级嵌套太深,比如一个稍微复杂的列表页可能长成这样:
SingleChildScrollView -> ListView -> Row -> Expanded -> Column -> [Container -> Image, Container -> Text, ..... ] -> ...
这点可以通过适当的Widget封装解决。

其次,容器类Widget的可用形式很多,其实有时候反而会对开发造成困扰,同样一个按钮可以是

  • GestureDetector -> Container
  • RaisedButton
  • ImageButton

同时对于布局实现而言,很多场景下需要对布局类和容器类Widget进行整合形成正真的界面,有时候一些参数是必须提供的,比如:widget, height, scrollDirection等,如果不写会造成布局异常,反映为Flutter的界面报错。面对太多的选择,有时候反而会不知道该如何正确的编写Widget组合,我自己的总结经验如下:

  • 能用Container的尽量用Container: Container+decoration 几乎可以表现任何界面元素,同时它让研发人员可以随心所欲的编辑它的各种属性,参数使用较为简单,也明确,不容易出现渲染异常的问题。
  • 真正开始研发的时候,请事先绘制好界面原型,对于那些用Flexible的布局,那些用Fixed的布局需要事先确定好,避免出现后期界面绘制超出边界的问题。
  • 对于复杂界面的文本Text等容器,请预先设置好Fitted或者Wrap,避免在不同尺寸的屏幕上出现布局问题。

Widget与Element

  • Flutter界面长什么样是有Widget描述的,通过解析Widget形成界面元素的树,它即界面的骨架。
    而Widget实例化的对象是Element。因此Flutter运行时具有两颗树,即:Widget树和Element树。
  • Widget树仅仅用于标定界面元素相对关系和元素类型(Text,Image,Icon等)
  • Element树在反映出Widget树相同结构的同时,带有实例化的参数,比如Text(‘test’)生成的Element就是显示为test的一个文本。Element由Widget的build函数产生。

关于Stateful和Stateless

Widget的基础是Stateless Widget, 它是一种不可变对象(Immutable)所以Stateless Widget 内部声明的变量是final类型的, 所以一旦Stateless Widget对象被生成后,如果需要修改界面显示的元素,就需要销毁重新创建。

Stateful Widget是在Widget的基础上挂上了一个State对象,State状态的改变触发Widget重新生成新的Element替换旧的Element实现了界面的变化。

Widget可以被重新生成的同时State得以被保留,这个是Hot Reload特性得以实现的基本机制,这点在Google 官方 Flutter系列教程里有被提到

这点可以可以从代码结构中看出来:

class SomeWidget extends StatefulWidget 
  final someValue;
  // Stateful Widget本身可以带变量,Widget内的变量仍然是Immutable
  SomeWidget(Key key, this.someValue)
      : super(key: key);
  // State对象是被Widget创建出来的
  @override
  _SomeWidgetState createState() => _SomeWidgetState();


// State与Widget的绑定关系
class _SomeWidgetState extends State<SomeWidget> 
  // State中的变量是可变的
  var _someVariable;
  @override
  Widget build(BuildContext context) 

  doSomething() 
    /// 通过setState方法改变变量的值,通知Flutter状态改变从而触发Widget重绘
    /// 反映出来就是界面元素的值改变了
    /// 这里的重绘其实是重新生成了新的Widget对像Element,替换掉原来的Element
    /// 因此Flutter可以做到Element对象重新生成,但是保留State的值,这就是Hot Reload特性的实现机制
    setState(()
      _someVariable = 'new value';  
    );
  

Key

这个是Flutter独有的东西,第一次接触时候概念很好理解,但是不一定知道如何正确使用。请查看油管的何时使用密钥 - Flutter小部件 101 第四集

Key保存了Widget的基本状态,或者可以简单的认为是Widget的标识

1)何时使用Key

一般情况下是不使用的, 但是在如下情况下可以使用
在一系列相同类型Widget中区分每一个不同的Element,这一点是因为Flutter会优先监测Widget类型变化,如果相同类型的Widget相互交换State,Flutter是感知不出来的。但是带上Key后,Flutter就能区分出来了。

2) 使用何种Key

Key包含: ValueKey, ObjectKey, UniqueKey, PageStorageKey, GlobalKey等

  • 如果需要组件内的值是唯一的,则使用ValueKey
  • 如果组件的值是json类型的对象比如(user:name, age, sex)则用ObjectKey
  • 如果只需要一个随机值则UniqueKey
  • 如果需要跨页面让同一个组件的值公用,比如配置项开关等,则用GlobalKey

以上是关于界面相关的基础点,在这基础上结合其它的教程,对于完成App基本界面的搭建已经足够了。

下一篇准备写一下业务逻辑实现相关常用的一些基本组件。

以上是关于Flutter 研发阶段性总结 Widget的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 研发阶段性总结 基本需求研发总结

Flutter 研发阶段性总结 基本需求研发总结

Flutter 研发阶段性总结 基本设计模式BLoC

Flutter 研发阶段性总结 基本设计模式BLoC

Flutter 研发阶段性总结 基本设计模式MVP

Flutter 研发阶段性总结 基本设计模式MVP