美文网首页Flutter烂笔头
Flutter小知识-widget初窥

Flutter小知识-widget初窥

作者: RidingWind2023 | 来源:发表于2019-07-13 10:25 被阅读3次

    Android当中,一切都是View。布局类View称为ViewGroup。Flutter当中,一切都是Widget。
    而根据Widget是否需要包含子节点将Widget分为了三类:

    • 没有子节点的widget
    • 只有一个孩子的widget
    • 包含多个孩子的widget

    而我们在前文中也提到过,Element树才是最终的绘制树,Element树是通过widget树来创建的(通过Widget.createElement()),widget其实就是Element的配置数据。
    Flutter中,根据Widget是否需要包含子节点将Widget分为了三类,分别对应三种Element,如下表:

    Widget 对应的Element 用途
    LeafRenderObjectWidget LeafRenderObjectElement Widget树的叶子节点,用于没有子节点的widget,通常基础widget都属于这一类,如Text、Image。
    SingleChildRenderObjectWidget SingleChildRenderObjectElement 包含一个子Widget,如:ConstrainedBox、DecoratedBox等
    MultiChildRenderObjectWidget MultiChildRenderObjectElement 包含多个子Widget,一般都有一个children参数,接受一个Widget数组。如Row、Column、Stack等

    注意,Flutter中的很多Widget是直接继承自StatelessWidget或StatefulWidget,然后在build()方法中构建真正的RenderObjectWidget,如Text,它其实是继承自StatelessWidget,然后在build()方法中通过RichText来构建其子树,而RichText才是继承自LeafRenderObjectWidget。所以为了方便叙述,我们也可以直接说Text属于LeafRenderObjectWidget(其它widget也可以这么描述),这才是本质。读到这里我们也会发现,其实StatelessWidget和StatefulWidget就是两个用于组合Widget的基类,它们本身并不关联最终的渲染对象(RenderObjectWidget)。

    基础Widget简介

    与原生开发中“控件”不同的是,Flutter中的widget的概念更广泛,它不仅可以表示UI元素,也可以表示一些功能性的组件如:用于手势检测的 GestureDetector widget、用于应用主题数据传递的Theme等等。
    这里特指直接呈现UI的widget,比如文本、按钮、图片、Icon、输入框表单等等。
    比如,Material widget库中提供了多种按钮Widget如RaisedButton、FlatButton。所有Material 库中的按钮都有如下相同点:

    1. 按下时都会有“水波动画”。
    2. 有一个onPressed属性来设置点击回调,当按钮按下时会执行该回调,如果不提供该回调则按钮会处于禁用状态,禁用状态不响应用户点击。
    RaisedButton(
      child: Text("normal"),
      onPressed: () => {},
    ),
    FlatButton(
      child: Text("normal"),
      onPressed: () => {},
    ),
    OutlineButton(
      child: Text("normal"),
      onPressed: () => {},
    ),
    IconButton(
      icon: Icon(Icons.send),
      onPressed: () => {},
    ),
    FlatButton(
      child: Text("Submit"),
      color: Colors.blue,
      highlightColor: Colors.blue[700],
      colorBrightness: Brightness.dark,
      textColor: Colors.white,
      padding: EdgeInsets.all(10),
      shape: RoundedRectangleBorder(
          borderRadius : BorderRadius.circular(20)
      ),
      splashColor: Colors.grey,
      onPressed: (){},
    ),
    

    对应的效果如下:


    Widget基础

    布局类Widget

    直接或间接继承(包含)MultiChildRenderObjectWidget的Widget,它们一般都会有一个children属性用于接收子Widget。
    比如 线性布局Row和Column、弹性布局Flex、流式布局Wrap、Flow、层叠布局Stack、Positioned等。
    这里以Wrap举例。Flutter中,子widget超出屏幕范围,则会报溢出错误。

    overflow
    可以看到,右边溢出部分报错。这是因为Row默认只有一行,如果超出屏幕不会折行。我们把超出屏幕显示范围会自动折行的布局称为流式布局。Flutter中通过Wrap和Flow来支持流式布局,将上例中的Row换成Wrap后溢出部分则会自动折行。下面是Wrap的定义:
    Wrap({
      ...
      this.direction = Axis.horizontal,
      this.alignment = WrapAlignment.start,
      this.spacing = 0.0,
      this.runAlignment = WrapAlignment.start,
      this.runSpacing = 0.0,
      this.crossAxisAlignment = WrapCrossAlignment.start,
      this.textDirection,
      this.verticalDirection = VerticalDirection.down,
      List<Widget> children = const <Widget>[],
    })
    

    样例代码如下:

    Wrap(
      spacing: 8.0, // 主轴(水平)方向间距
      runSpacing: 4.0, // 纵轴(垂直)方向间距
      alignment: WrapAlignment.center, //沿主轴方向居中
      children: <Widget>[
        new Chip(
          avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('A')),
          label: new Text('Hamilton'),
        ),
        new Chip(
          avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('M')),
          label: new Text('Lafayette'),
        ),
        new Chip(
          avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('H')),
          label: new Text('Mulligan'),
        ),
        new Chip(
          avatar: new CircleAvatar(backgroundColor: Colors.blue, child: Text('J')),
          label: new Text('Laurens'),
        ),
      ],
    )
    

    效果如下图:


    wrap

    容器类Widget

    直接或间接继承(包含)SingleChildRenderObjectWidget的Widget,它们一般都会有一个child属性用于接收子Widget。
    这一类的widget有Padding、ConstrainedBox、DecoratedBox等。

    容器类Widget和布局类Widget都作用于其子Widget,不同的是:

    • 布局类Widget一般都需要接收一个widget数组(children),他们直接或间接继承自(或包含)MultiChildRenderObjectWidget.
      布局类Widget是按照一定的排列方式来对其子Widget进行排列;

    • 容器类Widget一般只需要接收一个子Widget(child),他们直接或间接继承自(或包含)SingleChildRenderObjectWidget。
      容器类Widget一般只是包装其子Widget,对其添加一些修饰(补白或背景色等)、变换(旋转或剪裁等)、或限制(大小等)。

    更多widget了解可以跳转这里


    如果你觉得这篇文章对你有益,还请帮忙转发和点赞,万分感谢。

    Flutter烂笔头

    相关文章

      网友评论

        本文标题:Flutter小知识-widget初窥

        本文链接:https://www.haomeiwen.com/subject/ktspkctx.html