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

| 8 | 从0开始写一个基于Flutter的开源中国客户端(8)
插件的使用
|

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 {
@override
Widget 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 {
@override
Widget 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.0
margin: 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 {
@override
Widget 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 {
@override
Widget 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”),
)

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 {
@override
Widget 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: [
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 {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: “Test”,
home: new Scaffold(
appBar: new AppBar(
title: new Text(“Test”)
),
body: new Column(
children: [
new Text(“hello”),
new Text(“world”),
new Text(“nihao~”)
],
)
),
);
}
}

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

Stack组件

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: “Test”,
home: new Scaffold(
appBar: new AppBar(
title: new Text(“Test”)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

最后这里放上我这段时间复习的资料,这个资料也是偶然一位朋友分享给我的,里面包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。

还有 高级架构技术进阶脑图、高级进阶架构资料 帮助大家学习提升进阶,也可以分享给身边好友一起学习。

一起互勉~

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

oid)**

最后

最后这里放上我这段时间复习的资料,这个资料也是偶然一位朋友分享给我的,里面包含了腾讯、字节跳动、阿里、百度2019-2021面试真题解析,并且把每个技术点整理成了视频和PDF(知识脉络 + 诸多细节)。

还有 高级架构技术进阶脑图、高级进阶架构资料 帮助大家学习提升进阶,也可以分享给身边好友一起学习。

[外链图片转存中…(img-SztxY7GN-1713505195778)]

[外链图片转存中…(img-gYQsjvUF-1713505195778)]

一起互勉~

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 29
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值