Flutter布局全解

由上面的架构图可以看出来,flutter最上层是google 的纸墨设计Material Design(MaterialApp)组件,关于Material Design设计理念大家可以去官网安利一下啊material.io

在MaterialApp下面是所有组件的基类Widget,而在Widget的上层是statelessWdiget(无状态组件)、statefulWidget(有状态组件)和InheritedWidget(可以向子类View树种传递信息),包括我们在上篇文章中用到的Scaffold、Center、Text都是statelessWdiget、statefulWidget的子类。

开始之前,我们需要知道一些名词的含义和作用,在这里不懂的也没有关系,逐渐往后面看,往后面使用后,会有越来越清晰的理解。

  • MaterialApp

是我们app开发中常用的符合MaterialApp Design设计理念的入口Widget。

  • StatelessWidget

StatelessWidget是非动态的,它不依赖于除了传入数据以外的任何其他数据,这意味着改变其显示的唯一方式,就是改变传入其构造函数的参数。比如Text,Button,Icon这些控件。

  • StatefulWidget

StatefulWidget是动态的,他们允许我们创建一个能动随时间改变内容的widget,并且不依赖于其初始化时被传入的静态状态,可以随着用户的输入,各种形式的异步回包或其他形式的状态变化而变化。比如Image,CheckBox,Form这些控件。

  • Scaffold

Scaffold 翻译过来就是脚手架的意思,它实现了基本的 Material Design 可视化布局结构。简单的说,Scaffold就是一个提供 Material Design 设计中基本布局的 widget。

const Scaffold({
  Key key,
  this.appBar, // 标题栏
  this.body,  // 用于显示当前界面主要内容的Widget
  this.floatingActionButton, // 一个悬浮在body上的按钮,默认显示在右下角
  this.floatingActionButtonLocation, // 用于设置floatingActionButton显示的位置
  this.floatingActionButtonAnimator, // floatingActionButton移动到一个新的位置时的动画
  this.persistentFooterButtons, // 多状态按钮
  this.drawer, // 左侧的抽屉菜单
  this.endDrawer, //  右'侧的抽屉菜单
  this.bottomNavigationBar,// 底部导航栏。
  this.bottomSheet, // 显示在底部的工具栏
  this.backgroundColor,// 内容的背景颜色
  this.resizeToAvoidBottomPadding = true, // 控制界面内容 body 是否重新布局来避免底部被覆盖,比如当键盘显示的时候,重新布局避免被键盘盖住内容。
  this.primary = true,// Scaffold是否显示在页面的顶部
}) 

一个 MaterialApp 由多个 Scalfold 页面组成,每个 Scalfold 的主要结构如下:
AppBar:顶部导航栏
body:中间内容体
BottomNavigationBar:底部导航栏

  • Container

它是一个结合了绘制(painting)、定位(positioning)以及尺寸(sizing)widget的widget。

Container({
    Key key,
    this.alignment,
    this.padding,
    Color color,
    Decoration decoration,
    this.foregroundDecoration,
    double width,
    double height,
    BoxConstraints constraints,
    this.margin,
    this.transform,
    this.child,
  })

alignment:控制child的对齐方式
decoration:绘制在child后面的装饰

  • padding/margin

控件加入内/外边距。属性如下:

EdgeInsets.all(12),// 指定四个方向相同的值
EdgeInsets.fromLTRB(10, 20, 30, 40),// 分别指定四个方向的值
EdgeInsets.only(left: 10,right: 30),// 指定任意个方向的值EdgeInsets.symmetric(vertical: 10,horizontal: 50),//指定水平(left right)或垂直方向(top,bottom)的值。

  • 线性布局Row、Column

Row和Column分别是Flutter中的水平和垂直布局,对应Android里面的LinearLayout的水平垂直方向布局。

MainAxisAlignment (主轴)属性:

enum MainAxisAlignment {
//将子控件放在主轴的开始位置
start,
//将子控件放在主轴的结束位置
end,
//将子控件放在主轴的中间位置
center,
//将主轴空白位置进行均分,排列子元素,手尾没有空隙
spaceBetween,
//将主轴空白区域均分,使中间各个子控件间距相等,首尾子控件间距为中间子控件间距的一半
spaceAround,
//将主轴空白区域均分,使各个子控件间距相等
spaceEvenly,
}

CrossAxisAlignment(交叉轴)属性:

enum CrossAxisAlignment {
//将子控件放在交叉轴的起始位置
start,
//将子控件放在交叉轴的结束位置
end,
//将子控件放在交叉轴的中间位置
center,
//使子控件填满交叉轴
stretch,
//将子控件放在交叉轴的上,并且与基线相匹配(不常用)
baseline,
}

配合Expanded使用,使Expanded中的child充满空白区域。Expanded组件必须用在Row、Column、Flex内。

Expanded(  
          flex: 1,
          child: Text(""),
        )

属性:

crossAxisAlignment:交叉轴子组件对齐方式
mainAxisAlignment:主轴子组件排列方式
mainAxisSize:Main 轴大小,相当于match_parent,wrap_content
verticalDirection:从下向上或从上向下摆放子组件

效果:


  • 相对布局Stack

Stack 这个是Flutter中布局用到的组件,跟Android中FrameLayout或RelativeLayout很像。是一个在布局中使用相当频繁的布局组件,相当重要的一个布局,这里当然要着重讲解。

Stack({
  Key key,
  this.alignment = AlignmentDirectional.topStart,
  this.textDirection,
  this.fit = StackFit.loose,
  this.overflow = Overflow.clip,
  List<Widget> children = const <Widget>[],
})
  • alignment : 指的是子Widget的对其方式,子view从哪个方位开始对齐
  • fit :用来决定没有Positioned方式时候子Widget的大小,StackFit.loose 指的是子Widget 多大就多大,StackFit.expand使子Widget的大小和父组件一样大
  • overflow :指子Widget 超出Stack时候如何显示,默认值是Overflow.clip,子Widget超出Stack会被截断,Overflow.visible超出部分还会显示的
  • Positioned:
    这个使用控制Widget的位置,通过他可以随意摆放一个组件,有点像绝对布局
Positioned({
  Key key,
  this.left,
  this.top,
  this.right,
  this.bottom,
  this.width,
  this.height,
  @required Widget child,
})
  • 配合Align使用,可以单独设置子Widget的布局方位。
    Stack(
        children: [
           Align(
               alignment: Alignment.centerLeft,
               child: Text("你创作的,就是头条", style: TextStyle(fontSize: 15))
         )
    ]

推荐阅读更多精彩内容