写点什么

从 0 开始写一个基于 Flutter 的开源中国客户端(4)—

用户头像
Android架构
关注
发布于: 刚刚

Flutter 布局容器

在 Android 开发中,我们使用 xml 文件写布局,有诸如LinearLayoutRelativeLayoutConstraintLayout等布局方式,在 ReactNative 或 WEEX 开发中,我们使用的布局方式都是基于前端的 flex 布局,无论是 Android 还是 RN 或者 WEEX,他们的布局特点都是代码和布局是分开的,而在 Flutter 开发中,布局比较另类一点,因为逻辑代码和布局代码都写在一起了,都是使用 Dart 来写。


说到布局就不得不说到容器,不论使用原生或者 RN、WEEX 这类跨平台移动开发方式,布局都会涉及到容器,比如原生 Android 开发中,LinearLayout 是个布局,同时是一个可以包含多个子组件的容器,在 RN 开发中,<View>是一个组件,同时也是可以包含多个子组件的容器,在 WEEX 开发中<div>也是一个可以包含多个子组件的容器。


Flutter 中的布局容器主要分为两类:只能包含一个子 Widget 的布局容器和可以包含多个子 Widget 的容器,下面分别说明其用法。

包含单个子 Widget 的布局容器

Center 组件

Center 组件中的子组件会居中显示。Center 组件会尽可能的大,如果你不给它设置任何约束。下面是 Center 组件的使用方法:


import 'package:flutter/material.dart';


main() {runApp(new MyApp());}


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new Center(child: new Text("hello world")),),);}}

Container 组件

Container 是使用非常多的一个布局容器,关于 Container 容器的显示规则,有如下几条:


  1. 如果 Container 中没有子组件,则 Container 会尽可能的大

  2. 如果 Container 中有子组件,则 Container 会适应子组件的大小

  3. 如果给 Container 设置了大小,则 Container 按照设置的大小显示

  4. Container 的显示规则除了跟自身约束和子组件有关,跟它的父组件也有关


下面的代码展示了 Container 的用法:


import 'package:flutter/material.dart';


main() {runApp(new MyApp());}


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new Container(width: 100.0,height: 100.0,color: Colors.red,child: new Text("Flutter!"),)),);}}


如果我们分别注释掉上面 Container 代码中的 width/height、child 属性,显示出的界面就会有所不同:





Container 还可以设置内边距和外边距,如下代码所示:


body: new Container(// 设置外边距都为 20.0margin: const EdgeInsets.all(20.0),// 设置内边距,4 个边分别设置 padding: const EdgeInsets.fromLTRB(10.0, 20.0, 30.0, 40.0),width: 100.0,height: 100.0,color: Colors.red,child: new Text("Flutter!"),)

Padding 组件

Padding 组件专门用于给它的子组件设置内边距,用法比较简单:


new Padding(padding: new EdgeInsets.all(8.0),child: const Card(child: const Text('Hello World!')),)

Align 组件

Align 组件用于将它的子组件放置到确定的位置,比如下面的代码展示了将 Text 组件放置到 100*100 的容器的右下角:


new Container(width: 100.0,height: 100.0,color: Colors.red,child: new Align(child: new Text("hello"),alignment: Alignment.bottomRight,),)


Alignment类中有如下一些静态常量:


/// The top left corner.static const Alignment topLeft = const Alignment(-1.0, -1.0);


/// The center point along the top edge.static const Alignment topCenter = const Alignment(0.0, -1.0);


/// The top right corner.static const Alignment topRight = const Alignment(1.0, -1.0);


/// The center point along the left edge.static const Alignment centerLeft = const Alignment(-1.0, 0.0);


/// The center point, both horizontally and vertically.static const Alignment center = const Alignment(0.0, 0.0);


/// The center point along the right edge.static const Alignment centerRight = const Alignment(1.0, 0.0);


/// The bottom left corner.static const Alignment bottomLeft = const Alignment(-1.0, 1.0);


/// The center point along the bottom edge.static const Alignment bottomCenter = const Alignment(0.0, 1.0);


/// The bottom right corner.static const Alignment bottomRight = const Alignment(1.0, 1.0);

FittedBox 组件

FittedBox组件根据fit属性来确定子组件的位置,fit属性是一个BoxFit类型的值,BoxFit是个枚举类,取值有如下几种:


enum BoxFit {fill,contain,cover,fitWidth,fitHeight,none,scaleDown,}


在我的上一篇博文中,在说到Image组件时,已有对于这几种 BoxFit 类型的介绍,这里再用一段代码和截图来直观说明上面几种 BoxFit,在下面的代码中,我们在大小为 200*100 的 Container 中放置一个 Text,使用 FittedBox 来控制 Text 的不同显示状态:


new Container(width: 200.0,height: 100.0,color: Colors.red,child: new FittedBox(child: new Text("hello world"),fit: BoxFit.fill,))


当 fit 取不同值时,上面的代码运行结果如下图所示:







AspectRatio 组件

AspectRatio 组件用于让它的子组件按一定的比例显示,下面是示例代码:


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new AspectRatio(// Container 组件按 16:9(width / height)显示 aspectRatio: 16.0 / 9.0,child: new Container(color: Colors.red,),)),);}}


如果将 aspectRatio 设置为 1.0,则 Container 显示为正方形。(注意,Dart 中/代表除法运算,不是取整运算,使用~/做取整运算)

ConstrainedBox 组件

ConstrainedBox 组件用于给它的子组件强制加上一些约束,比如下面的代码:


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new ConstrainedBox(constraints: const BoxConstraints.expand(width: 50.0, height: 50.0),child: new Container(color: Colors.red,width: 200.0,height: 200.0,))),);}}


在上面的代码中,我们给 Container 设置了长宽都为 200,但是 Container 被 ConstrainedBox 组件包裹了,而且 ConstrainedBox 设置了约束constraints: const BoxConstraints.expand(width: 50.0, height: 50.0),由于 ConstrainedBox 的约束是强制性的,所以最后 Container 显示出的大小是 50 而不是 200,如下图所示:


IntrinsicWidth & IntrinsicHeight

这两个组件的作用是将他们的子组件调整到组件本身的宽度/高度。


这个类是非常有用的,例如,当宽度/高度没有任何限制时,你会希望子组件按更合理的宽度/高度显示而不是无限的扩展。

LimitedBox 组件

LimitedBox 是一个当其自身不受约束时才限制其大小的容器。


如果这个组件的最大宽度是没有约束,那么它的宽度就限制在maxWidth。类似地,如果这个组件的最大高度没有约束,那么它的高度就限制在maxHeight

Offstage 组件

Offstage 组件用于显示或隐藏它的子组件,如下代码所示:


new Offstage(offstage: false, // true: 隐藏, false: 显示 child: new Text("hello world")


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


,)

OverflowBox & SizedOverflowBox

OverflowBox 组件它给它的子组件带来不同的约束,而不是从它的父组件中得到,可能允许子组件溢出到父组件中。


SizedOverflowBox 组件是一个指定大小的组件,它的约束会传递给子组件,子组件可能溢出。

SizedBox 组件

SizedBox 是一个指定了大小的容器。


如果指定了 SizedBox 的大小,则子组件会使用 SizedBox 的大小,如果没有指定 SizedBox 的大小,则 SizedBox 会使用子组件的大小。如果 SizedBox 没有子组件,SizedBox 会按它自己的大小来显示,将 nulls 当作 0。


new SizedBox(// 如果指定 width 和 height,则 Container 按照指定的大小显示,而不是 Container 自己的大小,如果没有指定 width 和 height,则 SizedBox 按照 Container 的大小显示 width: 50.0,height: 50.0,child: new Container(color: Colors.red,width: 300.0,height: 300.0,),)

Transform 组件

Transform 用于在绘制子组件前对子组件进行某些变换操作,比如平移、旋转、缩放等。


示例代码如下:


new Container(color: Colors.black,child: new Transform(alignment: Alignment.topRight,// 需要导包:import 'dart:math' as math;transform: new Matrix4.skewY(0.3)..rotateZ(-math.pi / 12.0),child: new Container(padding: const EdgeInsets.all(8.0),color: const Color(0xFFE8581C),child: const Text('Apartment for rent!'),),),)


运行效果如下图:


包含多个子 Widget 的布局容器

Row 组件

Row 组件字面理解就是代表一行,在一行中可以放入多个子组件。


下面是示例代码:


import 'package:flutter/material.dart';


main() {runApp(new MyApp());}


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new Row(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[new Text("hello"),new Container(width: 50.0,height: 50.0,color: Colors.red,),new Text("world")],)),);}}


在模拟器上运行的效果如下图:



Row 组件的构造方法中,children参数是一个数组,表示可以有多个子组件,mainAxisAlignment表示 Row 中的子组件在主轴(Row 组件主轴表示水平方向,交叉轴表示垂直方向,Column 组件主轴表示垂直方向,交叉轴表示水平方向)上的对齐方式,可以有如下几个取值:


  • MainAxisAlignment.start

  • MainAxisAlignment.center

  • MainAxisAlignment.end

  • MainAxisAlignment.spaceBetween

  • MainAxisAlignment.spaceAround

  • MainAxisAlignment.spaceEvenly


关于上面几个取值,用如下几个图来说明:







Column 组件

Column 组件表示一列,可以在一列中放入多个组件,如下代码所示:


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new Column(children: <Widget>[new Text("hello"),new Text("world"),new Text("nihao~")],)),);}}


Column 和 Row 组件一样,可以通过MainAxisAlignment或者CrossAxisAlignment来设置主轴和交叉轴的对齐方式,这里不再赘述。

Stack 组件

Stack 组件类似于 Android 中的 FrameLayout,其中的子组件是一层层堆起来的,并不像 Row 或者 Column 中的子组件,按水平或垂直方向排列,下面用代码说明:


class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return new MaterialApp(title: "Test",home: new Scaffold(appBar: new AppBar(title: new Text("Test")),body: new Stack(children: <Widget>[new Container(width: 100.0,height: 100.0,color: Colors.red,),new Container(width: 30.0,height: 30.0,color: Colors.green,)

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
从0开始写一个基于Flutter的开源中国客户端(4)—