容器类Widget

容器类Widget一般只是包装其子Widget,对其添加一些修饰(补白或背景色等)、变换(旋转或剪裁等)、或限制(大小等)

Padding

Padding可以给其子节点添加补白(填充),来看看它的定义:

Padding({
...
EdgeInsetsGeometry padding,
Widget child,
})

EdgeInsetsGeometry是一个抽象类,开发中,我们一般都使用EdgeInsets,它是EdgeInsetsGeometry的一个子类,定义了一些设置补白的便捷方法。

我们看看EdgeInsets提供的便捷方法:

  • fromLTRB(double left, double top, double right, double bottom):分别指定四个方向的补白。
  • all(double value) : 所有方向均使用相同数值的补白。
  • only({left, top, right ,bottom }):可以设置具体某个方向的补白(可以同时指定多个方向)。
  • symmetric({ vertical, horizontal }):用于设置对称方向的补白,vertical指top和bottom,horizontal指left和right。

ConstrainedBox和SizedBox

ConstrainedBox用于对齐子widget添加额外的约束。

例如 实现一个最小高度为50,宽度尽可能大的红色容器。

ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity, //宽度尽可能大
minHeight: 50.0 //最小高度为50像素
),
child: Container(
height: 5.0,
child: redBox
),
)

SizedBox用于给子widget指定固定的宽高,如:

SizedBox(
width: 80.0,
height: 80.0,
child: redBox
)

DecoratedBox

DecoratedBox可以在其子widget绘制前(或后)绘制一个装饰Decoration(如背景、边框、渐变等)。DecoratedBox定义如下:

const DecoratedBox({
Decoration decoration,
DecorationPosition position = DecorationPosition.background,
Widget child
})
  • decoration:代表将要绘制的装饰,它类型为Decoration,Decoration是一个抽象类,它定义了一个接口 createBoxPainter(),子类的主要职责是需要通过实现它来创建一个画笔,该画笔用于绘制装饰。
  • position:此属性决定在哪里绘制Decoration,它接收 DecorationPosition的枚举类型,该枚举类两个值:background:在子widget之后绘制,即背景装饰。foreground:在子widget之上绘制,即前景。

decoration通常会直接使用BoxDecoration,它是一个Decoration的子类,实现了常用的装饰元素的绘制。

BoxDecoration({
Color color, //颜色
DecorationImage image,//图片
BoxBorder border, //边框
BorderRadiusGeometry borderRadius, //圆角
List<BoxShadow> boxShadow, //阴影,可以指定多个
Gradient gradient, //渐变
BlendMode backgroundBlendMode, //背景混合模式
BoxShape shape = BoxShape.rectangle, //形状
})

Transform变换

Transform可以在其子Widget绘制时对其应用一个矩阵变换(transformation),Matrix4是一个4D矩阵,通过它我们可以实现各种矩阵操作。下面是一个例子:

Container(
color: Colors.black,
child: new Transform(
alignment: Alignment.topRight, //相对于坐标系原点的对齐方式
transform: new Matrix4.skewY(0.3), //沿Y轴倾斜0.3弧度
child: new Container(
padding: const EdgeInsets.all(8.0),
color: Colors.deepOrange,
child: const Text('Apartment for rent!'),
),
),
);

Container

Container是DecoratedBox、ConstrainedBox、Transform、Padding、Align等widget的一个组合widget。所以我们只需通过一个Container可以实现同时需要装饰、变换、限制的场景。下面是Container的定义:

Container({
this.alignment,
this.padding, //容器内补白,属于decoration的装饰范围
Color color, // 背景色
Decoration decoration, // 背景装饰
Decoration foregroundDecoration, //前景装饰
double width,//容器的宽度
double height, //容器的高度
BoxConstraints constraints, //容器大小的限制条件
this.margin,//容器外补白,不属于decoration的装饰范围
this.transform, //变换
this.child,
})

示例:

Container(
margin: EdgeInsets.only(top: 50.0, left: 120.0), //容器外补白
constraints: BoxConstraints.tightFor(width: 200.0, height: 150.0), //卡片大小
decoration: BoxDecoration(//背景装饰
gradient: RadialGradient( //背景径向渐变
colors: [Colors.red, Colors.orange],
center: Alignment.topLeft,
radius: .98
),
boxShadow: [ //卡片阴影
BoxShadow(
color: Colors.black54,
offset: Offset(2.0, 2.0),
blurRadius: 4.0
)
]
),
transform: Matrix4.rotationZ(.2), //卡片倾斜变换
alignment: Alignment.center, //卡片内文字居中
child: Text( //卡片文字
"5.20", style: TextStyle(color: Colors.white, fontSize: 40.0),
),
)

可以看到Container通过组合多种widget来实现复杂强大的功能,在Flutter中,这也正是组合优先于继承的实例。

Scaffold、TabBar、底部导航

Material库提供了很多Widget,本节介绍一些常用的Widget,其余的读者可以查看文档。

大多数路由页都会包含一个导航栏,有些路由页可能会有抽屉菜单(Drawer)以及底部Tab导航菜单等。Flutter Material库提供了一个Scaffold Widget,它是一个路由页的骨架,可以非常容易的拼装出一个完整的页面。

我们实现一个页面,它包含:

一个导航栏
导航栏右边有一个分享按钮
有一个抽屉菜单
有一个底部导航
右下角有一个悬浮的动作按钮

实现代码如下:

class ScaffoldRoute extends StatefulWidget {
@override
_ScaffoldRouteState createState() => _ScaffoldRouteState();
} class _ScaffoldRouteState extends State<ScaffoldRoute> {
int _selectedIndex = 1; @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar( //导航栏
title: Text("App Name"),
actions: <Widget>[ //导航栏右侧菜单
IconButton(icon: Icon(Icons.share), onPressed: () {}),
],
),
drawer: new MyDrawer(), //抽屉
bottomNavigationBar: BottomNavigationBar( // 底部导航
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(icon: Icon(Icons.business), title: Text('Business')),
BottomNavigationBarItem(icon: Icon(Icons.school), title: Text('School')),
],
currentIndex: _selectedIndex,
fixedColor: Colors.blue,
onTap: _onItemTapped,
),
floatingActionButton: FloatingActionButton( //悬浮按钮
child: Icon(Icons.add),
onPressed:_onAdd
),
);
}
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
void _onAdd(){
}
}

上面代码中我们用到了另外几个Widget:

AppBar

AppBar是一个Material风格的导航栏,它可以设置标题、导航栏菜单、底部Tab等。下面我们看看AppBar的定义:

AppBar({
Key key,
this.leading, //导航栏最左侧Widget,常见为抽屉菜单按钮或返回按钮。
this.automaticallyImplyLeading = true, //如果leading为null,是否自动实现默认的leading按钮
this.title,// 页面标题
this.actions, // 导航栏右侧菜单
this.bottom, // 导航栏底部菜单,通常为Tab按钮组
this.elevation = 4.0, // 导航栏阴影
this.centerTitle, //标题是否居中
this.backgroundColor,
... //其它属性见源码注释
})

TabBar

通过“bottom”属性来添加一个导航栏底部tab按钮组,Material组件库中提供了一个TabBar组件,它可以快速生成Tab菜单,示例:

class _ScaffoldRouteState extends State<ScaffoldRoute>
with SingleTickerProviderStateMixin { TabController _tabController; //需要定义一个Controller
List tabs = ["新闻", "历史", "图片"]; @override
void initState() {
super.initState();
// 创建Controller
_tabController = TabController(length: tabs.length, vsync: this);
} @override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
... //省略无关代码
bottom: TabBar( //生成Tab菜单
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList()),
),
... //省略无关代码 }

上面代码首先创建了一个TabController ,它是用于控制/监听Tab菜单切换。然后通过TabBar生成了一个底部菜单栏,TabBar的tabs属性接受一个Widget数组,表示每一个Tab子菜单,我们可以自定义,也可以像示例中一样直接使用Tab Widget,它也是Material组件库提供的Material风格的Tab菜单。

Tab Widget有三个可选参数,除了可以指定文字外,还可以指定Tab菜单图标,或者直接自定义Widget,定义如下:

Tab({
Key key,
this.text, // 菜单文本
this.icon, // 菜单图标
this.child, // 自定义Widget
})

TabBarView

通过TabBar我们只能生成一个静态的菜单,如果要实现Tab页,Material库提供了一个TabBarView组件,它可以很轻松的配合TabBar来实现同步切换和滑动状态同步,示例如下:

Scaffold(
appBar: AppBar(
... //省略无关代码
bottom: TabBar(
controller: _tabController,
tabs: tabs.map((e) => Tab(text: e)).toList()),
),
drawer: new MyDrawer(),
body: TabBarView(
controller: _tabController,
children: tabs.map((e) { //创建3个Tab页
return Container(
alignment: Alignment.center,
child: Text(e, textScaleFactor: 5),
);
}).toList(),
),
... // 省略无关代码
)

TabBar和TabBarView的controller是同一个!正是如此,TabBar和TabBarView正是通过同一个controller来实现菜单切换和滑动状态同步的。

Drawer

Scaffold的drawer和endDrawer属性可以分别接受一个Widget作为页面的左、右抽屉菜单,当用户手指重屏幕左/右向里滑动时便可打开抽屉菜单。示例如下:

class MyDrawer extends StatelessWidget {
const MyDrawer({
Key key,
}) : super(key: key); @override
Widget build(BuildContext context) {
return Drawer(
child: MediaQuery.removePadding(
context: context,
// DrawerHeader consumes top MediaQuery padding.
removeTop: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 38.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ClipOval(
child: Image.asset(
"imgs/avatar.png",
width: 80,
),
),
),
Text(
"Wendux",
style: TextStyle(fontWeight: FontWeight.bold),
)
],
),
),
Expanded(
child: ListView(
children: <Widget>[
ListTile(
leading: const Icon(Icons.add),
title: const Text('Add account'),
),
ListTile(
leading: const Icon(Icons.settings),
title: const Text('Manage accounts'),
),
],
),
),
],
),
),
);
}
}

FloatingActionButton

FloatingActionButton是Material设计规范中的一种特殊Button,通常悬浮在页面的某一个位置作为某种常用动作的快捷入口

底部Tab导航栏

可以通过Scaffold的bottomNavigationBar属性来设置底部导航,Material组件库提供的BottomNavigationBar和BottomNavigationBarItem两个Widget来实现Material风格的底部导航栏。

Material组件库中提供了一个BottomAppBar Widget,可以和FloatingActionButton配合实现"打洞"效果。源码如下:

bottomNavigationBar: BottomAppBar(
color: Colors.white,
shape: CircularNotchedRectangle(), // 底部导航栏打一个圆形的洞
child: Row(
children: [
IconButton(icon: Icon(Icons.home)),
SizedBox(), //中间位置空出
IconButton(icon: Icon(Icons.business)),
],
mainAxisAlignment: MainAxisAlignment.spaceAround, //均分底部导航栏横向空间
),
)

可以看到,上面代码中没有控制打洞位置的属性,实际上,打洞的位置取决于FloatingActionButton的位置,上面FloatingActionButton的位置为:

floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

BottomAppBar的shape属性决定洞的外形,CircularNotchedRectangle实现了一个圆形的外形。

07-容器类Widget的更多相关文章

  1. 【Flutter】容器类组件简介

    前言 容器类Widget和布局类Widget都作用于其子Widget,不同的是: 布局类Widget一般都需要接收一个widget数组(children),他们直接或间接继承自(或包含)MultiCh ...

  2. python单元测试框架 pyunit

    概况 系统要求 使用PyUnit构建自己的测试 安装 测试用例介绍 创建一个简单测试用例 复用设置代码:创建固件 包含多个测试方法的测试用例类 将测试用例聚合成测试套件 嵌套测试用例 测试代码的放置位 ...

  3. Qt中设置widget背景颜色/图片的注意事项(使用样式表 setStyleSheet())

    在Qt中设置widget背景颜色或者图片方法很多种:重写paintEvent() , 调色板QPalette , 样式表setStyleSheet等等. 但是各种方法都有其注意事项,如果不注意则很容易 ...

  4. Qt容器类(总结)(新发现的QQueue和QStack,注意全都是泛型)

    Introduction Qt库提供了一组基于模板的一般化的容器类.这些容器可以存储指定的类型的元素.例如,如果你需要一个可变大小的Qstring数组,可以用QVector<QString> ...

  5. QT 信号槽connect中解决自定义数据类型或数组作为函数参数的问题——QT qRegisterMetaType 注册MetaType——关键:注册自定义数据类型或QMap等容器类

    一般情况下信号槽直接连接方式不会出现问题,但是如果信号与槽在不同线程或Qt::QueuedConnection方式连接,可能会在连接期间报以下类似问题,如: QObject::connect: Can ...

  6. Qt——容器类(译)

    注:本文是我对Qt官方文档的翻译,错误之处还请指正. 原文链接:Container Classes 介绍 Qt库提供了一套通用的基于模板的容器类,可以用这些类存储指定类型的项.比如,你需要一个大小可变 ...

  7. cocos代码研究(26)Widget子类RichView学习笔记

    理论部分 一个显示多个RichElement的容器类. 我们可以使用它很容易显示带图片的文本,继承自 Widget. 代码实践 static RichText * create ()创建一个空的Ric ...

  8. java.lang.ClassCastException: android.widget.ImageButton异常处理

    在调程序时总是出现异常关闭的现象,log显示: 03-26 07:58:09.528: E/AndroidRuntime(398): Caused by: java.lang.ClassCastExc ...

  9. m2014_c->c语言容器类工具列

    转自:http://www.cnblogs.com/sniperHW/category/374086.html cocos2dx内存管理 摘要: cocos2dx基于引用计数管理内存,所有继承自CCO ...

随机推荐

  1. stderr: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

    错误提示: (1). stderr: xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer direc ...

  2. [T-ARA][괜찮아요][没关系]

    歌词来源: 没关系:http://music.163.com/#/song?id=22704448 没关系(Remix Ver.):http://music.163.com/#/song?id=258 ...

  3. [零基础学JAVA]Java SE面向对象部分.面向对象基础(04)

     2.代码块 1.内部类 3.链表 2.代码块: 1.) 普通代码块. 2.)静态代码块. 3.)构造代码块. 4.)同步代码块. class Test{//构造块    {        Syste ...

  4. 阿里嘉年华ADC Workshop PPT分享

    前段时间在阿里嘉年华的workshop做了一些关于memcache高可用和MMM Mod的分享. 下面是相关的PPT,特此分享. ADC官网直接在线查看:http://adc.alibabatech. ...

  5. 《metasploit渗透测试魔鬼训练营》学习笔记第六章--客户端渗透

    四.客户端攻击      客户端攻击与服务端攻击有个显著不同的标识,就是攻击者向用户主机发送的恶意数据不会直接导致用户系统中的服务进程溢出,而是需要结合一些社会工程学技巧,诱使客户端用户去访问这些恶意 ...

  6. SpringMVC如何解决POST请求中文乱码问题,GET的又如何处理呢?

    在web.xml中 <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-c ...

  7. 关于python接口基础到进阶随笔

    想了很久,闲来无事,今天想了下还是总结了下写下来,部分参考官方源码理解,还有就是这么久的理解, 如果觉得有帮助请记得点赞 先讲下接口url组成拿后台服务为例 通常一个后台请求url格式: http:/ ...

  8. PAT——1030. 完美数列

    给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列. 现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列. ...

  9. HDU 1165 公式推导题

    题目链接: acm.hdu.edu.cn/showproblem.php?pid=1165 Eddy's research II Time Limit: 4000/2000 MS (Java/Othe ...

  10. 用画布canvas画安卓logo

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...