MaterialApp
见名思其意,材料设计类型的App,在安卓5.0正式加入一些材料设计类型的组件之后,App风格也越来越趋向于材料设计类型。MaterialApp就是符合材料设计理念的App框架级Widget。它其实也是一个Widget。它由主题,title,路由,主页等。以下是其构造方法:
const MaterialApp({
Key key,
//导航键
this.navigatorKey,
//主页,应用默认所显示的界面 Widget
this.home,
//路由,应用的顶级导航表格,这个是多页面应用用来控制页面跳转的,类似于网页的网址
this.routes = const <String, WidgetBuilder>{},
//初始路由,第一个显示的路由名字,默认值为 Window.defaultRouteName
this.initialRoute,
//生成路由,生成路由的回调函数,当导航的命名路由的时候,会使用这个来生成界面
this.onGenerateRoute,
//未知路由
this.onUnknownRoute,
//导航观察器,应用 Navigator 的监听器
this.navigatorObservers = const <NavigatorObserver>[],
//构造者
this.builder,
//标题,在任务管理窗口中所显示的应用名字
this.title = '',
//生成标题
this.onGenerateTitle,
//颜色,应用的主要颜色值(primary color),也就是安卓任务管理窗口中所显示的应用颜色
this.color,
//主题,应用各种 UI 所使用的主题颜色
this.theme,
this.darkTheme,
this.themeMode = ThemeMode.system,
//地域,国际化
this.locale,
//本地化委托
this.localizationsDelegates,
//区域分辨率回调
this.localeListResolutionCallback,
this.localeResolutionCallback,
//支持区域
this.supportedLocales = const <Locale>[Locale('en', 'US')],
//调试显示材质网格,是否显示 纸墨设计 基础布局网格,用来调试 UI 的工具
this.debugShowMaterialGrid = false,
//显示性能标签
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true,
})
主页
一个用来定义打开应用时候显示的第一个Widget界面。如:
class MaterialMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "我是Flutter标题",
theme: ThemeData(
primaryColor: Colors.redAccent,
),
home:Center(
child: Text("Hello Flutter",style: TextStyle(fontSize: 20),),
)
//MyHomePage(),
,debugShowMaterialGrid: true,
);
}
}
效果图
title
任务窗口中,APP显示的标题名字。如:
class MaterialMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "我是Flutter标题",
theme: ThemeData(
primaryColor: Colors.redAccent,
),
home:MyHomePage(),
);
}
}
路由
Map 类型,是应用的顶级路由表。当我们再使用Navigator.pushNamed进行命名路由的跳转时,会在此路表中进行查找并跳转。如果你的应用程序只有一个页面,则无需使用routes,直接指定home对应的Widget即可。如:
class MaterialMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "我是Flutter标题",
routes: <String,WidgetBuilder>{
"/first":(BuildContext context)=>FirstPage(),
"/second":(BuildContext context)=>SecondPage()
},
theme: ThemeData(
primaryColor: Colors.redAccent,
),
home:/*Center(
child: Text("Hello Flutter",style: TextStyle(fontSize: 20),),
)*/FirstPage()
,
debugShowMaterialGrid: false,
);
}
}
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("跳转到第二页"),),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Center(
child: RaisedButton(onPressed:(){
Navigator.of(context).pop(context);
},child: Text("返回到第一页"),),
),
);
}
}
效果图
国际化
Scaffold
Scaffold是一个路由页的骨架,同样也是Material组件,主要有底部导航,顶部导航,侧面抽屉布局导航。
构造方法
const Scaffold({
Key key,
this.appBar,//设置应用栏,显示在脚手架顶部
this.body,//展示页面的内容
this.floatingActionButton,//设置悬浮于上层区域的按钮
this.floatingActionButtonLocation,//设置floatingActionButton的位置
this.floatingActionButtonAnimator,
this.persistentFooterButtons,
this.drawer,//设置左边侧边栏
this.endDrawer,//设置右边侧边栏
this.bottomNavigationBar,//底部导航栏
this.bottomSheet,//底部抽屉栏
this.backgroundColor,//背景颜色
this.resizeToAvoidBottomPadding,//自动适应底部padding
this.resizeToAvoidBottomInset,
this.primary = true,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.extendBody = false,
this.drawerScrimColor,
})
下面是一个常用的页面导航,包括appBar,drawer,还有bottomNavigationBar。
效果图
appBar
AppBar是一个Material风格的导航栏,通过它可以设置导航栏标题、导航栏菜单、导航栏底部的Tab标题。
其常用属性
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,//背景颜色
...
})
以上示意图AppBar代码。
appBar: new AppBar(
title:new Text("FlutterStudy"),
centerTitle: true,
actions: <Widget>[
IconButton(icon: Icon(Icons.share), onPressed: (){
_scaffoldKey.currentState.showSnackBar(SnackBar(content:Text("点击了分享!")));
})
],
),
图
drawer
Scaffold的drawer和endDrawer属性可以分别接受一个Widget来作为页面的左、右抽屉菜单。如果开发者提供了抽屉菜单,那么当用户手指从屏幕左(或右)侧向里滑动时便可打开抽屉菜单。如果给Scaffold添加了抽屉菜单,默认情况下Scaffold会自动将AppBar的leading设置为菜单按钮。
drawer: new Drawer(
child: new DrawerPage(),//提供一个Widget
),
图
bottomNavigationBar
- BottomNavigationBar 常用的底部导航控件,还有一种BottomAppBar控件,它和FloatingActionButton配合实现底部不规则导航。
new BottomNavigationBar(
items: [
new BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text("Home")
),
new BottomNavigationBarItem(
icon: new Icon(Icons.phone_android),
title: new Text("Android")
),
new BottomNavigationBarItem(
icon: new Icon(Icons.phone_iphone),
title: new Text("iOS")
),
new BottomNavigationBarItem(
icon: new Icon(Icons.settings),
title: new Text("Setting")
),
],
type: BottomNavigationBarType.fixed,
currentIndex: _curIndex,
onTap: (index){
setState(() {
_curIndex=index;
});
},
)
图
- BottomAppBar
BottomAppBar(
color: Colors.white,
shape: CircularNotchedRectangle(), // 底部导航栏打一个圆形的洞
child: Row(
children: [
IconButton(icon: Icon(Icons.home),onPressed: (){
setState(() {
_curIndex=0;
});
},),
IconButton(icon: Icon(Icons.phone_iphone),onPressed: (){
setState(() {
_curIndex=1;
});
},),
SizedBox(), //中间位置空出
IconButton(icon: Icon(Icons.phone_iphone),onPressed: (){
setState(() {
_curIndex=2;
});
},),
IconButton(icon: Icon(Icons.settings),onPressed: (){
setState(() {
_curIndex=3;
});
},),
],
mainAxisAlignment: MainAxisAlignment.spaceAround, //均分底部导航栏横向空间
),
),
floatingActionButton:isNormalShow?null: FloatingActionButton(onPressed: (){
},backgroundColor: Colors.redAccent,
child: Icon(Icons.add),),
floatingActionButtonLocation:isNormalShow?null: FloatingActionButtonLocation.centerDocked,//设置floatingActionButton的位置
控制isNormalShow属性控制显示不同的底部导航。
图
完整代码
import 'package:flutter/material.dart';
class MyScaffold1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "我是标题",
theme: ThemeData(
primaryColor: Colors.redAccent
),
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePage createState() => _HomePage();
}
class _HomePage extends State<HomePage>{
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
int _curIndex=0;
List<ContentPage> contents=new List();
bool isNormalShow=true;
@override
void initState() {
// TODO: implement initState
super.initState();
contents.add(new ContentPage(content:"Home"));
contents.add(new ContentPage(content:"Android"));
contents.add(new ContentPage(content:"iOS"));
contents.add(new ContentPage(content:"Setting"));
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title:new Text("FlutterStudy"),
centerTitle: true,
actions: <Widget>[
IconButton(icon: Icon(Icons.share), onPressed: (){
_scaffoldKey.currentState.showSnackBar(SnackBar(content:Text("点击了分享!")));
})
],
),
drawer: new Drawer(
child: new DrawerPage(),
),
body: contents[_curIndex],
bottomNavigationBar:isNormalShow? new BottomNavigationBar(
items: [
new BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text("Home")
),
new BottomNavigationBarItem(
icon: new Icon(Icons.phone_android),
title: new Text("Android")
),
new BottomNavigationBarItem(
icon: new Icon(Icons.phone_iphone),
title: new Text("iOS")
),
new BottomNavigationBarItem(
icon: new Icon(Icons.settings),
title: new Text("Setting")
),
],
type: BottomNavigationBarType.fixed,
currentIndex: _curIndex,
onTap: (index){
setState(() {
_curIndex=index;
});
},
):BottomAppBar(
color: Colors.white,
shape: CircularNotchedRectangle(), // 底部导航栏打一个圆形的洞
child: Row(
children: [
IconButton(icon: Icon(Icons.home),onPressed: (){
setState(() {
_curIndex=0;
});
},),
IconButton(icon: Icon(Icons.phone_iphone),onPressed: (){
setState(() {
_curIndex=1;
});
},),
SizedBox(), //中间位置空出
IconButton(icon: Icon(Icons.phone_iphone),onPressed: (){
setState(() {
_curIndex=2;
});
},),
IconButton(icon: Icon(Icons.settings),onPressed: (){
setState(() {
_curIndex=3;
});
},),
],
mainAxisAlignment: MainAxisAlignment.spaceAround, //均分底部导航栏横向空间
),
),
floatingActionButton:isNormalShow?null: FloatingActionButton(onPressed: (){
},backgroundColor: Colors.redAccent,
child: Icon(Icons.add),),
floatingActionButtonLocation:isNormalShow?null: FloatingActionButtonLocation.centerDocked,
);
}
}
class DrawerWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new _DrawerWidgetStage();
}
}
class _DrawerWidgetStage extends State<DrawerWidget> {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new ListView(
padding: const EdgeInsets.only(),
children: <Widget>[
new UserAccountsDrawerHeader(
accountName: new Text("HuangSir"),
accountEmail: new Text("1244914544@qq.com"),
currentAccountPicture: new CircleAvatar(
backgroundImage: new NetworkImage(
"http://img.52z.com/upload/news/image/20181108/20181108204521_83402.jpg"),
),
),
_getListTitle("lifecycle 学习", "/LifecyclePage"),
new Divider(),
_getListTitle("Route 学习0", "/RoutePage0"),
new Divider(),
_getListTitle("Route 学习1", "/RoutePage1"),
],
);
}
ListTile _getListTitle(String title, String route) {
return new ListTile(
title: new Text(title),
trailing: new Icon(Icons.arrow_right),
onTap: () {
Navigator.of(context).pop();
Navigator.pushNamed(context, route);
},
);
}
}
class DrawerPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
body: new DrawerWidget(),
);
}
}
//内容页
class ContentPage extends StatelessWidget {
final String content;
const ContentPage({Key key, this.content}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Text(this.content),
);
}
}
还有一种底部导航配合PageView实现的常用的App框架。但是每次点击页面都会调用页面的initState方法,其解决方法是使其内容页 with AutomaticKeepAliveClientMixin,实现
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
即可。
效果图
完整代码
import 'package:flutter/material.dart';
class MaterialMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "我是Flutter标题",
routes: <String, WidgetBuilder>{
"/first": (BuildContext context) => FirstPage(),
"/second": (BuildContext context) => SecondPage()
},
theme: ThemeData(
primaryColor: Colors.redAccent,
),
home: MyHomePage(),
debugShowMaterialGrid: false,
);
}
}
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("跳转到第二页"),
),
),
);
}
}
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二页"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.of(context).pop(context);
},
child: Text("返回到第一页"),
),
),
);
}
}
///
/// 主页
///
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var _curIndex = 0;
var _pagerController = new PageController(initialPage: 0);
List<String> _tabs = ["Gank", "Widgets", "Example", "Setting"];
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: new PageView.builder(
itemBuilder: (BuildContext context, int index) {
return _buildPageItem(context, index);
},
itemCount: _tabs.length,
controller: _pagerController,
onPageChanged: (index) {
_onChangePageView(index);
},
),
bottomNavigationBar: BottomNavigationBar(
items: [
_buildBottomItem(Icons.home, _tabs[0]),
_buildBottomItem(Icons.widgets, _tabs[1]),
_buildBottomItem(Icons.ac_unit, _tabs[2]),
_buildBottomItem(Icons.settings, _tabs[3]),
],
currentIndex: _curIndex,
type: BottomNavigationBarType.fixed,
onTap: (index) {
_pagerController.animateToPage(index,
duration: const Duration(milliseconds: 300), curve: Curves.ease);
},
),
);
}
void _onChangePageView(int index) {
setState(() {
_curIndex = index;
});
}
Widget _buildPageItem(BuildContext context, int index) {
return ContentWidget(content: _tabs[index]);
}
BottomNavigationBarItem _buildBottomItem(IconData iconData, String tab) {
return new BottomNavigationBarItem(icon: Icon(iconData), title: Text(tab));
}
}
///
/// 内容页面
///
class ContentWidget extends StatefulWidget {
final String content;
const ContentWidget({Key key, this.content}) : super(key: key);
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new __ContentWidgetStage();
}
}
class __ContentWidgetStage extends State<ContentWidget>
with AutomaticKeepAliveClientMixin {
@override
void initState() {
// TODO: implement initState
super.initState();
print("initState===>" + this.widget.content);
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text(this.widget.content),
),
body: Center(
child: Text(
this.widget.content,
style: TextStyle(color: Colors.redAccent),
),
),
);
}
@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}
本文分享自微信公众号 - Flutter学习簿(gh_d739155d3b2c)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。