乐趣区

关于flutter:八天让iOS开发者上手Flutter二

Flutter 布局

Alignment

Container 类里有一个 alignment 属性,翻译过去应该叫对齐形式,这个属性用来管制 Container 的子控件绝对于它本身的一个地位。在咱们 iOS 开发中,咱们晓得坐标系的原点是在左上角。而在 flutter 中,坐标系的原点在父控件的正核心,能够应用这个 alignment 属性来管制子控件在父控件中的地位,它有两个参数别离是 double 类型的 x,y。取值是 - 1 到 1,当 0,0 的时候示意子控件在父控件的正核心;当 1,0 的时候,示意子控件位于 x 方向上的最右侧,y 方向上居中;当 -1,- 1 的时候,示意子控件位于父控件的左上角地位。有点相似于 CALayer 的 anchorPoint 属性。如图代码如下:

Row

Row 示意程度布局,它有一个 children 属性,用来寄存它的子控件。代码如下:

其中 Icon 类是 flutter 提供的一个疾速创立一些罕用图标的类。如果想给每个 Icon 都加一个背景色,间接设置 Icon 的 color 是不行的,这样批改的是图标的色彩而不是背景色,给 Icon 包一层 Container 容器,而后再设置 Container 色彩这样就能够实现了。

最开始咱们尝试了 alignment 属性的作用,当它是 0,0 的时候,Text 的地位默认是在屏幕地方的。为什么这里换成咱们的 Row 之后,Row 的子控件地位不在屏幕地方呢?

首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的 iOS 开发公众号:编程大鑫,不论你是小白还是大牛都欢送入驻,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)

mainAxisAlignment

Row 和 Column 都有一个 mainAxisAlignment 属性,叫作主轴对齐形式,默认是 MainAxisAlignment.start 意思沿着主轴方向开始,Row 布局下就是从左至右,Column 布局下就是从上至下。
MainAxisAlignment.spaceAround: 将剩下的空间平均分配
MainAxisAlignment.spaceBetween: 将剩下的空间调配到子控件之间
MainAxisAlignment.spaceEvenly: 等间距调配子控件

crossAxisAlignment

穿插轴对齐形式,start,end,center 这几种形式试一下很好了解,stretch 会将子控件拉伸。而 baseline 用的比拟少, 独自应用它会报错,须要和 Text 文本联合,还须要配合 textBaseline 属性一起应用。如下图所示,如果不设置 CrossAxisAlignment.baselineTextBaseline.alphabetic就会依据控件高度程度对齐,而如果设置了就会依据控件内文本的基线对齐。

Column

这个和 Row 是对应的,Row 是程度布局,这个 Column 是垂直布局

class LayoutDemo extends StatelessWidget {const LayoutDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      alignment: Alignment(0, 0),
      child: Column(
        children: [
          Container(child: Icon(Icons.add, size: 180,),
            color: Colors.red,
          ),
          Container(child: Icon(Icons.ac_unit, size: 120,),
            color: Colors.yellow,
          ),
          Container(child: Icon(Icons.access_alarm, size: 60,),
            color: Colors.blue,
          ),
        ],
      ),
    );
  }
}
复制代码

显示成果如图:

mainAxisAlignment

这个跟 Row 相似

crossAxisAlignment

这个跟 Row 相似

Stack

这个是用在 Z 轴上的布局的,row 是 X 轴,column 是 Y 轴。children 数组第一个放在最底部,最初一个放在下面,离用户最近的中央。

class LayoutDemo extends StatelessWidget {const LayoutDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      alignment: Alignment(0, 0),
      child: Stack(
        children: [
          Container(child: Icon(Icons.add, size: 180,),
            color: Colors.red,
          ),
          Container(child: Icon(Icons.ac_unit, size: 120,),
            color: Colors.yellow,
          ),
          Container(child: Icon(Icons.access_alarm, size: 60,),
            color: Colors.blue,
          ),
        ],
      ),
    );
  }
}
复制代码

APP 显示成果:

alignment

Stack 里有一个 alignment 属性,它用来管制所有子控件绝对于最大那个子控件的地位

class StackDemo extends StatelessWidget {const StackDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.bottomRight,
      children: [
        Container(child: Icon(Icons.add, size: 180,),
          color: Colors.red,
        ),
        Container(child: Icon(Icons.ac_unit, size: 120,),
          color: Colors.yellow,
        ),
        Container(child: Icon(Icons.access_alarm, size: 60,),
          color: Colors.blue,
        ),
      ],
    );
  }
}
复制代码

Positioned

Stack 里配合 Positioned 类应用的话,跟咱们 iOS 的束缚有点相似了,能够设置上,左间距之类的

class StackDemo extends StatelessWidget {const StackDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Positioned(
          child: Container(
            child: Icon(
              Icons.add,
              size: 180,
            ),
            color: Colors.red,
          ),
        ),
        Positioned(
          child: Container(
            child: Icon(
              Icons.ac_unit,
              size: 120,
            ),
            color: Colors.yellow,
          ),
        ),
        Positioned(
          top: 20,
          left: 20,
          right: 20,
          child: Container(
            child: Icon(
              Icons.access_alarm,
              size: 60,
            ),
            color: Colors.blue,
          ),
        ),
      ],
    );
  }
}

能够看到最小的蓝色视图的上左右均设置了 20 的间距,是不是相熟的束缚滋味。。。

Expanded

Expanded 是一个相似 Container 的罕用的布局容器,它用来填充布局,应用了填充布局在主轴方向上是不会有距离的, 所以 Expanded 用在 Row 外面的时候,子控件的宽度设置就没有意义了,而在 Column 外面应用的应用,子控件的高度设置就没有意义了。这里以 Column 为例:

class LayoutDemo extends StatelessWidget {const LayoutDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      alignment: Alignment(0, 0),
      child: Column(
        children: [
          Expanded(
              child: Container(child: Icon(Icons.add, size: 180,),
                color: Colors.red,
              ),
          ),
          Expanded(
              child: Container(child: Icon(Icons.ac_unit, size: 120,),
                color: Colors.yellow,
              ),
          ),
          Expanded(
              child: Container(child: Icon(Icons.access_alarm, size: 60,),
                color: Colors.blue,
              ),
          ),
        ],
      ),
    );
  }
}
复制代码

AspectRatio

AspectRatio 是一个容器类,它有一个属性 aspectRatio 示意宽高比。如果指定了宽度,依据这个 aspectRatio 能够主动算出高度;如果指定了高度,依据 aspectRatio 能够主动算出宽度。如上面代码指定了父视图高度为 100,aspectRatio 宽高比为 2,子视图宽度就是 200,再把父视图撑起来也是 200。

class LayoutDemo extends StatelessWidget {const LayoutDemo({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
        color: Colors.green,
        alignment: Alignment(0, 0),
        child: Container(
          color: Colors.blue,
          height: 100,
          child: AspectRatio(
            aspectRatio: 2,
            child: Icon(Icons.add,),
          ),
        ));
  }
}

Flutter 状态治理

之前介绍的这么多类都是无状态的,意思是显示之后没方法更新 UI 的,如果想要实时更新 UI 的话,就不能继承无状态的类了。咱们先来看一个例子:明明 count 变动了,然而界面显示没有变动

记得批改 APP 的 home 视图

而后点击屏幕右下角的加号按钮,能够发现明明控制台打印了 count 的值曾经产生了变动,然而界面显示仍然是 0

上面咱们解决这个问题,将 StateManagerDemo 继承改为 StatefulWidget,实现 createState 办法返回一个自定义的 State 对象,自定义的 State 对象外面实现 build 办法。还须要留神在按钮的点击办法里调用一下 setState 办法。这样每次点击加号按钮就能实时更新 UI 了。革新完之后如下图所示:

我的项目搭建之底部 TabBar

到目前为止,咱们对 flutter 的一些基础知识就算是介绍的差不多了。接下来咱们开始做一个简略的仿微信 APP。咱们应该都有教训,实践的常识学得再多,不入手开始敲代码,不在我的项目中使用,是很难真正把握一门常识的。

新建一个 flutter 工程,命名 wechat_demo:

删掉多余的代码,能够全副从新本人写:

创立底部的 TabBar 和 item, 默认的 type 是红色的,显示成果很难看所以改为 fixed,还能够设置 fixedColor:

这样底部的 TabBar 就显示进去了,会发现点击没有成果,比照 iOS 会发现这块中央还是 iOS 提供的 UITabBarController 封装的更难受,每个平台都各有优劣吧。

BottomNavigationBar 有一个属性 currentIndex 即代表了以后选中的下标。咱们能够通过设置它的值来管制哪个按钮被选中。既然须要扭转 UI 了,阐明咱们须要将 StatelessWidget 改为 StatefulWidget 了。还有一个参数 onTap 是用来回调点击事件的。实现点击事件,切换 currentIndex,从新 setState 就能够实现,点击切换了。咱们将 bottomNavigationBar 相干代码放到一个新的文件 rootPage 中。代码如下:

记得批改 main.dart 文件中

这样就实现了 APP 的底部 TabBar 的展现,点击性能。点击每个 item 的时候,会发现 flutter 的 bottomNavigationBar 还自带了动画成果 …

咱们晓得 Scaffold 还有一个 body 的属性,示意展现在屏幕上的内容。咱们每个 item 对应的界面都须要一个 AppBar,那么兴许意味着,body 属性还须要一个 Scaffold 来展现咱们的每个 item 对应的内容。

能够看到微信首页就曾经大略进去了,然而点击的时候只会显示这个微信页面,怎么实现切换不同的页面呢,必定须要一个数组,来寄存对应的每个页面了。

而后 body 里,依据咱们的_currentIndex 返回对应的 body

这样点击每个 item 都会跳转到对应的界面了,APP 的主框架的搭建好了。

总结

明天次要讲了 flutter 的三大布局类 Row,Column,Stack 以及他们的一些属性。而后是有状态的 Widget 和无状态的 Widget,最初搭建了一下咱们要做的仿微信 APP 的底部 bottomNavigationBar 和切换页面性能。

退出移动版