Material Design
Material Design(纸墨设计)是由Google推出的全新设计语言,这种设计语言为手机、平板电脑、台式机和其他平台提供更一致、更广泛的外观和感觉。
主要的Material Design风格组件如下表所示:
组件名称 | 中文名称 | 简单说明 |
---|---|---|
AppBar | 应用按钮组件 | 应用的工具按钮 |
AlertDialog | 对话框组件 | 有操作按钮的对话框 |
BottomNavigationBar | 底部导航条组件 | 底部导航条,可以很容易地在tap之间切换和浏览顶级视图 |
Card | 卡片组件 | 带有边框阴影的卡片组件 |
Drawer | 抽屉组件 | Drawer抽屉组件可以实现类似抽屉拉开关闭的效果 |
FloatingActionButton | 浮动按钮组件 | 应用的主要功能操作按钮 |
FlatButton | 扁平按钮组件 | 扁平化风格的按钮 |
MaterialApp | Material应用组件 | MaterialApp代表使用纸墨设计风格的应用 |
PopupMenuButton | 弹出菜单组件 | 弹出菜单按钮 |
Scaffold | 脚手架组件 | 实现了基本的Material Design布局 |
SnackBar | 轻量提示组件 | 一个轻量级消息提示组件,在屏幕的底部显示 |
SimpleDialog | 简单对话框组件 | 简单对话框组件,只起提示作用,没有交互 |
TabBar | 水平选项卡及视图组件 | 一个显示水平选项卡的Material Design组件 |
TextField | 文本框组件 | 可接受应用输入文本的组件 |
App结构和导航组件
本节介绍的这类组件对App的结构和导航有帮助,如MaterialApp、Scaffold、AppBar、BottomNavigationBar、TabBar、Drawer等。
MaterialApp(应用组件)
MaterialApp代表使用纸墨设计风格的应用,里面包含了其所需要的基本控件。一个完整的Flutter下面就是从MaterialApp这个主组件开始的。
MaterialApp组件常见属性如下表所示:
属性名 | 类型 | 说明 |
---|---|---|
title | String | 应用程序的标题。该标题出现在如下位置: Android:任务管理器的程序快照之上 IOS:程序切换管理器中 |
theme | ThemeData | 定义应用所使用的主题颜色,可以指定一个主题中每个控件的颜色 |
color | Color | 应用的主要颜色值,即primary color |
home | Widget | 这个是一个Widget对象,用来定义当前应用打开时所显示的界面 |
routes | Map<String,WidgetBuilder> | 定义应用中页面跳转规则 |
initialRoute | String | 初始化路由 |
onGenerateRoute | RouteFactory | 路由回调函数。当通过Navigator.of(context).pushNamed跳转路由时,在routes查找不到时,会调用该方法。 |
onLocalChanged | 当系统修改语言的时候,会触发这个回调 | |
navigatorObservers | List |
导航观察器 |
debugShowMaterialGrid | bool | 是否显示纸墨设计基础布局网格,用来调试UI的工具 |
showPerformanceOverlay | bool | 显示性能标签 |
使用home属性设置应用的主页,即整个应用的主组件。示例代码如下:
import 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MaterialApp示例',
home: MyHomePage(),
);
}
}
// 这是一个可改变的Widget
class MyHomePage extends StatefulWidget{
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MaterialApp示例'),
),
body: Center(
child: Text('主页', style: TextStyle(fontWeight: FontWeight.bold),),
),
);
}
}
路由处理
routes对象是一个Map<String, WidgetBuilder>。当使用Navigator.pushNamed来路由的时候,会在routes查找路由名字,然后使用对应的WidgetBuilder来构造
一个带有页面切换动画的MaterialPageRoute。如果应用只有一个界面则不需要设置该属性,使用home设置这个界面即可。
通过routes可以给MaterialApp组件初始化一个路由列表,跳转到指定页面代码如下所示:
Navigator.pushNamed(context, '/somePage');
在MaterialApp组件使用initialRoute属性可以给应用添加一个初始化路由。这两个属性代码如下:
routes:{
'/first': (BuildContext context) => FirstPage(), // 添加路由
'/second': (BuildContext context) => SecondPage(),
},
initialRoutes: '/first', // 初始路由页面为first页面
我们创建两个页面,在页面中添加Button,当点击按钮后互相跳转:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Routes示例',
home: MyHomePage(),
routes: {
'/first': (BuildContext context) => FirstPage(),
'/second': (BuildContext context) => SecondPage(),
},
initialRoute: '/first',
);
}
}
// 这是一个可改变的Widget
class MyHomePage extends StatefulWidget{
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Routes示例'),),
body: Center(
child: Text(
'主页',
style: TextStyle(fontSize: 28.0),
),
),
);
}
}
// 第一个路由页面
class FirstPage extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是第一页'),
),
body: Center(
child: RaisedButton(
onPressed: (){
// 路由跳转到第二个页面
Navigator.pushNamed(context, '/second');
},
child: Text(
'这是第一页',
style: TextStyle(fontSize: 28.0),
),
),
),
);
}
}
// 第二个路由页面
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('这是第二页'),
),
body: Center(
child: RaisedButton(
onPressed: (){
// 路由跳转到第二个页面
Navigator.pushNamed(context, '/first');
},
child: Text(
'这是第二页',
style: TextStyle(fontSize: 28.0),
),
),
),
);
}
}
自定义主题
应用程序的主题,各种定制的颜色都可以设置,用于程序主题切换。示例代码如下所示:
new MaterialApp(
theme: ThemeData(
// 主题色
primarySwatch: Colors.blue,
),
);
Scaffold(脚手架组件)
Scaffold实现了基本的Material Design布局。只要是在Material Design中定义过的单个界面展示的布局组件元素,都可以使用Scaffold来绘制。
属性名 | 类型 | 说明 |
---|---|---|
appBar | AppBar | 显示在界面顶部的一个AppBar |
body | Widget | 当前界面所显示的主要内容 |
floatingActionButton | Widget | 在Material Design中定义的一个功能按钮 |
persistentFooterButtons | List |
固定在下方显示的按钮 |
drawer | Widget | 侧边栏组件 |
bottomNavigationBar | Widget | 显示在底部的导航栏按钮栏 |
backgroundColor | Color | 背景颜色 |
resizeToAvoidBottomPadding | bool | 控制界面内容body是否重新布局来避免底部被覆盖,比如当键盘显示时,重新布局避免被键盘盖住内容。默认值为true |
示例代码如下所示:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: 'Scaffold脚手架组件示例',
home: LayoutDemo(),
),
);
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// 头部元素 比如:左侧返回按钮 中间标题 右侧菜单
appBar: AppBar(
title: Text('Scaffold脚手架组件示例'),
),
// 视图内容部分
body: Center(
child: Text("Scaffold"),
),
// 底部导航栏
bottomNavigationBar: BottomAppBar(
child: Container(
height: 50.0,
),
),
// 添加FAB按钮
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: '增加',
child: Icon(Icons.add),
),
// FAB按钮居中显示
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
AppBar(应用按钮组件)
应用按钮组件有AppBar和SliverAppBar。它们是纸墨设计中的AppBar,也就是Android中的Toolbar。
AppBar和SliverAppBar都继承自StatefulWidget类,都代表Toolbar,两者区别在于AppBar位置是固定在应用最上方,而SliverAppBar是可以跟随内容滚动的。
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
leading | Widget | null | 在标题前面显示一个组件,在首页通常显示应用的logo,在其他界面通常显示为返回按钮 |
title | Widget | null | Toolbar中主要内容,通常显示当前界面的标题文字 |
actions | List |
null | 一个Widget列表,代表Toolbar中所显示的菜单,对于常用的菜单,通常使用IconButton来表示,对于不常用的菜单通常使用Popup-MenuButton来显示为三个点,点击后弹出二级菜单 |
bottom | PreferredSizeWidget | null | 通常是TabBar。用来在Toolbar标题下面显示一个Tab导航栏 |
elevation | double | 4 | 纸墨设计中组件z坐标顺序,对于可滚动的SliverAppBar,当SliverAppBar和内容同级的时候,该值为0,当内容滚动SliverAppBar变为Toolbar的时候,修改elevation的值 |
flexibleSpace | Widget | null | 一个显示在AppBar下方的组件,高度和AppBar高度一样,可以实现一些特殊的效果,该属性通常在SliverAppBar中使用 |
backgroundColor | Color | ThemeData.primaryColor | 背景色 |
brightness | Brightness | ThemeData.primaryColorBrightness | AppBar的亮度,有白色和黑色两种主题 |
iconTheme | IconThemeData | ThemeData.primaryIconTheme | AppBar上图标的颜色、透明度和尺寸信息。 默认值为ThemeData.primaryIconTheme |
textTheme | TextTheme | ThemeData.primaryTextTheme | AppBar上的文字样式 |
centerTitle | bool | true | 标题是否居中显示,默认值根据不同的操作系统,显示方式不一样 |
AppBar可以显示顶部leading、title和actions等内容。底部通常为选项卡TabBar。flexibleSpace显示在AppBar的下方,高度和AppBar高度一样,可以实现一些
特殊的效果,不过该属性通常在SliverAppBar中使用。
接下来是一个示例代码,在上端左侧显示标题,右侧添加两个按钮,示例代码如下:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: 'Scaffold脚手架组件示例',
home: LayoutDemo(),
),
);
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// 头部元素 比如:左侧返回按钮 中间标题 右侧菜单
appBar: AppBar(
title: Text('Scaffold脚手架组件示例'),
),
// 视图内容部分
body: Center(
child: Text("Scaffold"),
),
// 底部导航栏
bottomNavigationBar: BottomAppBar(
child: Container(
height: 50.0,
),
),
// 添加FAB按钮
floatingActionButton: FloatingActionButton(
onPressed: () {},
tooltip: '增加',
child: Icon(Icons.add),
),
// FAB按钮居中显示
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
BottomNavigationBar(底部导航条组件)
BottomNavigationBar是底部导航条,可以很容易地在tap之间切换和浏览顶级视图。很多App主页底部都采用这种切换方式。
属性名 | 类型 | 说明 |
---|---|---|
currentIndex | int | 当前索引,用来切换按钮控制 |
fixedColor | Color | 选中按钮的颜色。如果没有指定值,则用系统主题色 |
iconSize | double | 按钮图标大小 |
items | List |
底部导航条按钮集。每一项是BottomNavigationBarItem,有icon图标及title文本属性 |
onTap | ValueChanged |
按下其中某个按钮回调事件。需要根据返回的索引设置当前索引 |
接下来是一个示例代码,仿一个聊天软件,底部显示“信息”、“通讯录”及“发现”按钮。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'BottomNavigatorBar示例',
home: Scaffold(
body: MyHomePage(),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 1; // 当前选中的索引
final _widgetOptions = [
Text('Index 0: 信息'),
Text('Index 1: 通讯录'),
Text('Index 2: 发现'),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BottomNavigatorBar示例'),
),
body: Center(
// 居中显示某一个文本
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.chat), title: Text('信息')),
BottomNavigationBarItem(
icon: Icon(Icons.contacts), title: Text('通讯录')),
BottomNavigationBarItem(
icon: Icon(Icons.account_circle), title: Text('发现')),
],
currentIndex: _selectedIndex, // 当前选中项的索引
fixedColor: Colors.deepPurple, // 选中项的颜色
onTap: _onItemTapped, // 选择按下处理
),
);
}
// 选择按下处理,设置当前索引为index数
void _onItemTapped(int value) {
setState(() {
_selectedIndex = value;
});
}
}
TabBar(水平选项卡及视图组件)
TabBar是一个显示水平选项卡的Material Design组件,通常需要配套Tab选项组件及TabBarView页面视图组件一起使用。
TabBar组件常见属性如下所示:
属性名 | 类型 | 说明 |
---|---|---|
isScrollable | bool | 是否可以水平移动 |
tabs | List |
Tab选项列表,建议不要放太多项,否则用户操作起来不方便 |
Tab组件常见属性如下所示:
属性名 | 类型 | 说明 |
---|---|---|
icon | Widget | Tab图标 |
text | String | Tab文本 |
TabBarView组件常见属性如下所示:
属性名 | 类型 | 说明 |
---|---|---|
controller | TabController | 指定视图的控制器 |
children | List |
视图组件的child为一个列表,一个选项卡对应一个视图 |
TabBar的选项卡按钮通常显示在应用页面上部,接下来用TabBar实现一个地图类软件。实现这个示例需要以下几个组件:
DefaultTabController
TabBar
Tab
TabBarView
其中,DefaultTabController这个组件是TabBar和TabBarView的控制器,是关联这两个组件的桥梁。
import 'package:flutter/material.dart';
void main() => runApp(
DefaultTabControllerSample(),
);
class DefaultTabControllerSample extends StatelessWidget {
// 选项卡数据
final List<Tab> myTabs = [
Tab(text: '选项卡一',),
Tab(text: '选项卡二',),
];
@override
Widget build(BuildContext context) {
return MaterialApp(
// 用来组装TabBar及TabBarView
home: DefaultTabController(
length: myTabs.length,
child: Scaffold(
appBar: AppBar(
// 添加导航栏
bottom: TabBar(
tabs: myTabs,
),
),
// 添加导航视图
body: TabBarView(
children: myTabs.map((e) => Center(child: Text(e.text))).toList(),
),
),
),
);
}
}
接下来我们编写一个水平选项卡的完整示例,具体代码如下所示:
import 'package:flutter/material.dart';
void main() => runApp(TabBarSample());
class TabBarSample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// 添加DefaultTabController关联TabBar及TabBarView
home: DefaultTabController(
length: items.length,
child: Scaffold(
appBar: AppBar(
title: Text('TabBar选项卡示例'),
bottom: TabBar(
isScrollable: true,
tabs: items
.map((ItemView itemView) => Tab(
text: itemView.title,
icon: Icon(itemView.icon),
))
.toList(),
),
),
body: TabBarView(
children: items
.map((ItemView itemView) => Padding(
padding: EdgeInsets.all(16.0),
child: SelectedView(
itemView: itemView,
),
))
.toList(),
),
),
),
);
}
}
// 视图项数据
class ItemView {
String title; // 标题
IconData icon; // 图标
ItemView(this.title, this.icon); // 标题
}
// 选项卡数据
List<ItemView> items = [
ItemView('自驾', Icons.directions_car),
ItemView('自行车', Icons.directions_bike),
ItemView('轮船', Icons.directions_boat),
ItemView('公交车', Icons.directions_bus),
ItemView('火车', Icons.directions_railway),
ItemView('步行', Icons.directions_walk),
];
// 被选中的视图
class SelectedView extends StatelessWidget {
// 视图数据
ItemView itemView;
SelectedView({Key key, this.itemView}) : super(key: key);
@override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.display1;
return Card(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min, // 垂直方向最小化处理
crossAxisAlignment: CrossAxisAlignment.center, // 水平方向居中对齐
children: [
Icon(
itemView.icon,
size: 128.0,
color: textStyle.color,
),
Text(
itemView.title,
style: textStyle,
),
],
),
),
);
}
}
Drawer(抽屉组件)
Drawer可以实现类似抽屉拉出推入的效果。可以从侧边栏拉出导航面板,好处是可以把一些功能菜单折叠起来。
通常Drawer是和ListView组件组合使用的,常用的属性如下所示:
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
child | Widget | Drawer的child可以放置任意可显示对象 | |
elevation | double | 16 | 纸墨设计中组件的z坐标顺序 |
Drawer组件可以添加头部效果,用以下两个组件可以实现:
DrawerHeader:展示基本信息
UserAccountsDrawerHeader:展示用户头像、用户名、Email等信息。
DrawerHeader通常用于抽屉中在顶部展示一些基本信息,属性及描述如下:
属性名 | 类型 | 说明 |
---|---|---|
decoration | Decoration | header区域的decoration,通常用来设置背景颜色或背景图片 |
curve | Curve | 如果decoration发生变化,则会使用curve设置的变化曲线和duration设置的动画时间来做一个切换动画 |
child | Widget | Header里面所显示的控件内容 |
padding | EdgeInsetsGeometry | Header里面内容控件的padding值,如果child为null,则这个值无效 |
magin | EdgeInsetsGeometry | Header四周的间隙 |
UserAccountsDrawerHeader可以设置用户头像、用户名和Email等信息,显示一个符合Material Design规范的drawer header。
属性名 | 类型 | 说明 |
---|---|---|
magin | EdgeInsetsGeometry | Header四周的间隙 |
decoration | Decoration | header区域的decoration,通常用来设置背景颜色或背景图片 |
currentAccountPicture | Widget | 用来设置当前用户的头像 |
otherAccountsPictures | List |
用来设置当前用户其他账号的头像 |
accountName | Widget | 当前用户的名字 |
accountEmail | Widget | 当前用户的Eamil |
onDetailsPressed | VoidCallback | 当accountName或accountEmail被点击的时候所触发的回调函数,可以用来显示其他额外信息 |
从UserAccountsDrawerHeader的属性和描述来看,我们可以编写一个模仿QQ侧边导航栏的效果:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: 'Drawer抽屉组件示例',
home: LayoutDemo(),
),
);
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Drawer抽屉组件示例'),
),
drawer: Drawer(
child: ListView(
children: [
// 设置用户信息 头像、用户名、Email等
UserAccountsDrawerHeader(
// 设置当前用户头像
currentAccountPicture: CircleAvatar(
backgroundImage: AssetImage('images/1.jpg'),
),
accountName: Text('legend'),
accountEmail: Text('421206860@qq.com'),
onDetailsPressed: (){},
otherAccountsPictures: [
Container(
child: Icon(Icons.directions),
),
],
),
ListTile(
leading: CircleAvatar(child: Icon(Icons.color_lens),), // 导航栏菜单
title: Text('个性装扮'),
),
ListTile(
leading: CircleAvatar(child: Icon(Icons.photo),),
title: Text('我的相册'),
),
ListTile(
leading: CircleAvatar(child: Icon(Icons.wifi),),
title: Text('免费流量特权'),
),
],
),
),
);
}
}
下面中使用到了图片资源需要在pubspec.yaml文件中进行配置:
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
assets:
- images/1.jpg
按钮和提示组件
本节介绍的组件可帮助设计按钮、菜单、对话框等,包括:FloatingActionButton、FlatButton、PopupMenuButton、SimpleDialog、AlertDialog、SnackBar。
FloatingActionButton(悬停按钮组件)
FloatingActionButton对应一个圆形图标按钮,悬停在内容之上,以展示应用程序中的主要动作。通常用于Scaffold.FloatingActionButton字段。
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
child | Widget | child一般为Icon,不推荐使用文字 | |
tooltip | String | 按钮提示文本 | |
foregroundColor | Color | 前景色 | |
backgroundColor | Color | 背景色 | |
elevation | double | 6.0 | 未点击时阴影值,默认6.0 |
hignlightElevation | double | 12.0 | 点击时阴影值 |
onPressed | VoidCallback | 点击时间回调 | |
shape | ShapeBorder | CircleBorder | 定义按钮的shape,设置shape时,默认的elevation将失效 |
示例代码如下所示:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FloatingActionButton示例',
home: Scaffold(
appBar: AppBar(
title: Text('FloatingActionButton示例'),
),
body: Center(
child: Text(
'FloatingActionButton示例',
style: TextStyle(fontSize: 28.0),
),
),
floatingActionButton: Builder(
builder: (BuildContext context) => FloatingActionButton(
child: Icon(Icons.add),
tooltip: '请点击FloatingActionButton',
// 前景色为白色
foregroundColor: Colors.white,
// 背景色为蓝色
backgroundColor: Colors.blue,
// 未点击阴影值
elevation: 7.0,
// 点击阴影值
highlightElevation: 14.0,
onPressed: (){
// 点击回调事件,弹出一句提示语句
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('你点击了FloatingActionButton'),
)
);
},
mini: false,
// 圆形边
shape: CircleBorder(),
isExtended: false,
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, // 居中放置
),
);
}
}
FlatButton(扁平按钮组件)
FlatButton组件是一个扁平的Material Design风格按钮,点击时会有一个阴影效果。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'FlatButton示例',
home: Scaffold(
appBar: AppBar(title: Text('FlatButton示例'),),
body: Center(
child: FlatButton(
onPressed: (){},
child: Text(
'FlatButton',
style: TextStyle(fontSize: 24.0),
),
),
),
),
);
}
}
PopupMenuButton(弹出菜单组件)
PopupMenuButton为弹出菜单按钮,一般放在应用页面的右上角,表示有更多操作。菜单项使用PopupMenuItem组件。
属性名 | 类型 | 说明 |
---|---|---|
child | Widget | child如果提供则弹出菜单组件将使用此组件 |
icon | Icon | 如果提供,则弹出菜单使用此图标 |
itemBuilder | PopupMenuItemBuilder |
菜单项构造器,菜单项为任意类型,文本、图标都可以 |
onSelected | PopupMenuItemSelect |
当某项菜单被选中时回调的方法 |
接下来我们编写一个视频会议产品中关于会控的菜单。包括添加成员、锁定会议、修改布局、挂断所有。
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
// 会控菜单项
enum ConferenceItem{addMember, LockConference, ModifyLayout, TurnoffAll}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PopupMenuButton组件示例',
home: Scaffold(
appBar: AppBar(title: Text('PopupMenuButton组件示例'),),
body: Center(
child: FlatButton(
onPressed: (){},
child: PopupMenuButton<ConferenceItem>(
onSelected: (ConferenceItem item){},
// 菜单构造器
itemBuilder: (BuildContext context) => <PopupMenuEntry<ConferenceItem>>[
// 菜单项
PopupMenuItem(
value: ConferenceItem.addMember,
child: Text('添加成员'),
),
PopupMenuItem(
value: ConferenceItem.LockConference,
child: Text('锁定会议'),
),
PopupMenuItem(
value: ConferenceItem.ModifyLayout,
child: Text('修改布局'),
),
PopupMenuItem(
value: ConferenceItem.TurnoffAll,
child: Text('挂断所有'),
),
],
),
),
),
),
);
}
}
SimpleDialog(简单对话框组件)
SimpleDialog组件用于设计简单对话框,可以显示附加的提示或操作,组件的属性如下表所示:
属性名 | 类型 | 说明 |
---|---|---|
children | List |
对话框子项,典型的应用是一个列表 |
title | Widget | 通常是一个文本组件 |
contentPadding | EdgeInsetsGeometry | 内容部分间距大小 |
titlePadding | EdgeInsetsGeometry | 标题部分间距大小 |
简单对话框通常需要配合SimpleDialogOption组件一起使用,接下来看示例:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
// 会控菜单项
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SimpleDialog组件示例',
home: Scaffold(
appBar: AppBar(title: Text('SimpleDialog组件示例'),),
body: Center(
child: SimpleDialog(
title: Text('对话框标题'),
children: [
SimpleDialogOption(
onPressed: (){},
child: Text('第一行信息'),
),
SimpleDialogOption(
onPressed: (){},
child: Text('第二行信息'),
),
],
),
),
),
);
}
}
注意:对话框都是某个动作来触发渲染的,一般要封装在一个方法里实现。这个过程是异步的需要加入async/await处理。
AlertDialog(提示对话框组件)
AlertDialog组件比SimpleDialog对话框复杂一些,不仅有提示内容,还有操作按钮等。内容部分可以用SingleChildScrollView进行包裹。
属性名 | 类型 | 说明 |
---|---|---|
actions | List |
对话框底部操作按钮,如确定、取消等 |
title | Widget | 通常是一个文本组件 |
contentPadding | EdgeInsetsGeometry | 内容部分间距大小 |
content | Widget | 内容部分,通常为对话框的提示内容 |
titlePadding | EdgeInsetsGeometry | 标题部分间距大小 |
下面编写一个删除确认的示例:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
// 会控菜单项
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'AlertDialog示例',
home: Scaffold(
appBar: AppBar(title: Text('AlertDialog示例'),),
body: Center(
child: AlertDialog(
// 对话框标题
title: Text('提示'),
content: SingleChildScrollView(
// 对话框内容部分
child: ListBody(
children: [
Text('是否要删除?'),
Text('一旦删除数据不可恢复')
],
),
),
actions: [
FlatButton(
child: Text('确定'),
onPressed: (){},
),
FlatButton(
child: Text('取消'),
onPressed: (){},
),
],
),
),
),
);
}
}
SnackBar(轻量提示组件)
SnackBar是一个轻量级消息提示组件,在屏幕底部显示,主要的属性如下所示:
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
action | SnackBarAction | 提示消息里执行的动作,比如用户想撤销时可以点击操作 | |
animation | Animation |
给组件添加动画效果 | |
content | Widget | 提示消息内容,通常为文本组件 | |
duration | Duration | 4.0秒 | 动画执行的时长 |
backgroundColor | Color | 消息面板的背景色 |
完整的示例代码如下:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SnackBar示例',
home: Scaffold(
appBar: AppBar(title: Text('SnackBar示例'),),
body: Center(
child: Text('SnackBar示例', style: TextStyle(fontSize: 28.0),),
),
floatingActionButton: Builder(builder: (BuildContext context) => FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
// 点击回调事件,弹出提示语句
Scaffold.of(context).showSnackBar(SnackBar(content: Text('显示SnackBar'),));
},
),),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
),
);
}
}
其他组件
本节介绍的组件包括文本框、卡片等内容的设计。如TextField、Card等。
TextField(文本框组件)
TextField组件就是用来做文本输入的组件,常见的属性如下表所示:
属性名 | 类型 | 说明 |
---|---|---|
maxLength | int | 最大长度 |
maxLines | int | 最大行数 |
autocorrect | bool | 是否自动更正 |
autofocus | bool | 是否自动对焦 |
obscureText | bool | 是否是密码 |
textAlign | TextAlign | 文本对齐方式 |
style | TextStyle | 输入文本的样式 |
inputFormatters | List |
允许的输入格式 |
onChanged | ValueChanged |
内容改变的回调 |
onSubmitted | ValueChanged |
内容提交时回调 |
enable | bool | 是否禁用 |
获取文本内容仅有输入还不行,还需要传递Controller给TextField。用来监听文本内容的变化。初始化监听器代码如下:
final TextEditingController controller = TextEditingController();
controller.addListener(){
};
绑定监听器代码如下所示:
child:TextField(
controller: controller
),
TextField完整示例代码如下所示:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 添加文本编辑控制器 监听文本输入内容变化
TextEditingController controller = new TextEditingController();
controller.addListener(() {
print('输入的内容为:${controller.text}');
});
return MaterialApp(
title: 'TextField示例',
home: Scaffold(
appBar: AppBar(title: Text('TextField示例'),),
body: Center(
child: Padding(
padding: EdgeInsets.all(20.0),
child: TextField(
// 绑定controller
controller: controller,
// 最大长度,设置此项会在右下角有一个输入数量的统计字符串
maxLength: 30,
// 最大行数
maxLines: 1,
// 是否自动更正
autocorrect: true,
// 是否自动对焦
autofocus: true,
// 文本对其方式
textAlign: TextAlign.center,
// 输入文本的样式
style: TextStyle(fontSize: 26.0, color: Colors.green),
// 文本内容改变时回调
onChanged: (text){
print('文本内容改变时回调:$text');
},
// 内容提交时回调
onSubmitted: (text){
print('内容提交时回调: $text');
},
// 是否禁用
enabled: true,
// 添加装饰效果
decoration: InputDecoration(
fillColor: Colors.grey.shade200,
filled: true,
helperText: '用户名',
// 左侧图标
prefixIcon: Icon(Icons.person),
// 右侧文本提示
suffixText: '用户名',
hintText: '请输入用户名'
),
),
),
),
),
);
}
}
Card(卡片组件)
Card即卡片组件块,内容可以由大多数类型的Widget构成,通常和ListTile一起使用。
属性名 | 类型 | 默认值 | 说明 |
---|---|---|---|
child | Widget | 组件的子元素,任意Widget都可以 | |
magin | EdgeInsetsGeometry | 围绕在decoration和child之外的空白区域,不属于内容区域 | |
shape | ShapeBorder | RoundedRectangBorder | Card的阴影效果,默认的阴影效果为圆角的长方形边,弧度为4.0 |
完整的示例代码如下:
import 'package:flutter/material.dart';
void main() => runApp(
MaterialApp(
title: 'Card布局示例',
home: MyApp(),
),
);
class MyApp extends StatelessWidget{
var card = new SizedBox(
height: 250.0,
child: Column(
children: [
ListTile(
title: Text('11111111111111111', style: TextStyle(fontWeight: FontWeight.w300),),
subtitle: Text('222222222222'),
leading: Icon(Icons.home, color: Colors.lightBlue,),
),
Divider(),
ListTile(
title: Text('aaaaaaaaaaaaaaa', style: TextStyle(fontWeight: FontWeight.w300),),
subtitle: Text('bbbbbbbbbbbb'),
leading: Icon(Icons.school, color: Colors.lightBlue,),
),
Divider(),
],
),
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Card布局示例'),),
body: Center(
child: card,
),
);
}
}