路由
页面跳转
Navigator.push跳转到下一个页面,接收2个参数,一个是上下文,另一个是跳转的函数Navigator.pop返回到上一个页面,使用时传递一个上下文,必须上级页面使用了.push才能使用
导航参数传递使用Navigator控件,然后使用路由MaterialPageRoute传递参数,并在子页面接收参数
itemBuilder: (context,index){
return ListTile(
title: Text(items[index].title),
onTap: () async{
final res = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => new GoodsDetail(item:items[index])
)
);
Scaffold.of(context).showSnackBar(SnackBar(content:Text('$res')));
},
);
},
....
children: <Widget>[
Text('${item.description}'),
RaisedButton(
child: Text('选择该商品'),
onPressed: (){
Navigator.pop(context,'已选择${item.title}');
},
)
],
....
Dart的异步请求和等待和ES6中的方法很像,直接使用async...await就可以实现,跳转的时候是异步的,等结果回来后使用SnackBar提示信息控件,SnakeBar是以Scaffold的showSnackBar方法来进行显示的,在Navigator.pop(context,'xxx'),第二个参数就是返回的数据
路由
void main(){
runApp(MaterialApp(
home: MyAppHome(),
routers: <String, WidgetBuilder>{
'/a': (BuildContext context) => MyPage(title: 'pageA'),
'/b': (BuildContext context) => MyPage(title: 'pageB'),
'/c': (BuildContext context) => MyPage(title: 'pageC'),
}
))
}
通过把路由名字push给Navigator来跳转
Navigator.of(context).pushNamed('/b')
通过使用Navigator的push方法,该方法将给定route添加到导航器的历史记录中
Navigator.push(context,MaterialPageRoute(builder: (BuildContext context) => UsualNavscreen()))
路由动画
- 新建自定义路由动画
custom_router.dart - 在页面跳转引入路由动画
dart文件,并使用
onPressed: (){
Navigator.of(context).push(
CustomRoute(SecondPage())
);
},
AppBar组件backgroundColor更改背景颜色,elevation属性是滚动时的融合程度,一般有滚动时默认是4.0,我们设置成0.0可以与页面完全融合 3. 编写自定义动画custom_router.dart文件 路由动画的原理重写PageRouteBuilder的transitionsBuilder方法
import 'package:flutter/material.dart';
class CustomRoute extends PageRouteBuilder{
final Widget widget;
CustomRoute(this.widget):super(
transitionDuration: const Duration(seconds: 1),
pageBuilder:(BuildContext context, Animation<double> animation1,Animation<double> animation2){
return widget;
},
transitionsBuilder: (BuildContext context, Animation<double> animation1, Animation<double> animation2, Widget child){
return FadeTransition(
opacity: Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent:animation1,
curve: Curves.fastOutSlowIn
),
),
child:child,
);
}
}
FadeTransition渐隐渐现过渡效果,主要设置opacity透明度属性animate动画样式,一般使用动画曲线组件CurvedAnimationtransitionDuration设置动画持续时间 缩放路由动画
return ScaleTransition(
scale:Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(
parent:animation1,
curve: Curves.fastOutSlowIn
)
),
child:child
);
旋转缩放路由动画
return RotationTransition(
turns: Tween(begin:0.0, end:1.0).animate(
CurvedAnimation(
parent:animation1,
curve: Curves.fastOutSlowIn
)
),
child: ScaleTransition(
scale:Tween(begin: 0.0, end:1.0).animate(
CurvedAnimation(
parent: animation1,
curve: Curves.fastOutSlowIn
)
),
child: child,
),
);
左右滑动路由动画
return SlideTransition(
position: Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset(0.0, 0.0)
).animate(
CurvedAnimation(
parent: animation1,
curve: Curves.fastOutSlowIn
)
),
child: child,
);
右滑返回上一页
import 'package:flutter/cupertino.dart';
class RightBackDemo extends StatelessWidget {
@override
Widget build(BuildContext context){
return CupertinoPageScaffold(
child:Center(
child: Container(
height: 100.0,
width: 100.0,
color: CupertinoColors.activeBlue,
child: CupertinoButton(
child: Icon(CupertinoIcons.add),
onPressed: (){
Navigator.of(context).push(CupertinoPageRoute(
build: (BuildContext context){
return RightBackDemo
}
))
}
)
)
)
);
}
}
Flutter有两套UI模版,一套material另一套是Cupertino
闪屏动画
AnimationController是Animation的一个子类,它可以控制Animation,可以控制动画比如动画执行时间vsync:this 垂直同步设置,使用this就行了duration 动画持续时间,可以使用seconds秒,也可以使用milliseconds毫秒
import 'package:flutter/material.dart';
import 'home_page.dart';
class SplashScreen extends StatefulWidget {
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _animation;
void initState(){
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 3000)
);
_animation = Tween(begin: 0.0,end: 1.0).animate(_controller);
_animation.addStatusListener((status){
if(status == AnimationStatus.completed){
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(
builder: (context) => MyHomePage()),
(route) => route==null
);
}
});
// 播放动画
_controller.forward();
}
@override
void dispose(){
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context){
return FadeTransition( // 透明度动画控件
opacity: _animation, // 执行动画
child: Image.network(
'xx',
scale: 2.0,
fit: BoxFit.cover,
),
);
}
}
animation.addStatusListener动画事件监听器,可以监听动画的执行状态AnimationStatus.completed表示动画已经执行完毕pushAndRemoveUntil跳转页面兵销毁当前控件
fluro
Flutter路由解决方案
handler相当于一个路由规则,在routers文件夹下新建router_handler.dart
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import '../pages/goods_detail_page.dart';
Handler goodsDetailHandler = Handler(
handlerFunc: (BuildContext context,Map<String,List<String>> params){
String goodsId = params['id'].first;
print('detailId is $goodsId');
return GoodsDetailPage(goodsId);
}
);
handler只是对每个路由的独立配置,还需对路由有个总体的配置,在routers文件夹下新建routes.dart
import 'package:flutter/material.dart';
import 'package:fluro/fluro.dart';
import './router_handler.dart';
class Routers {
static String root = '/';
static String goodsDetailPage = '/goodDetail';
static void configureRoutes(Router router){
router.notFoundHandler = new Handler(
handlerFunc: (BuildContext context,Map<String,List<String>> params){
print('>>>>>>>> Router not Found');
}
);
router.define(goodsDetailPage,handler:goodsDetailHandler);
}
}
- 为了使用方便,直接把
Router进行静态化,这样在任何一个页面都可以直接进行使用了。在routers文件夹下新建Staticize.dart
import 'package:fluro/fluro.dart';
class Staticize {
static Router router;
}
- 在
main.dart文件里进行全局注入
import 'package:fluro/fluro.dart';
import './routers/staticize.dart';
import './routers/routers.dart';
….
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final router = Router();
Routers.configureRoutes(router);
Staticize.router = router;
return Container(
child: MaterialApp(
title: 'LifeShop',
onGenerateRoute: Staticize.router.generator,
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.pink
),
home: IndexPage(),
),
);
}
}
- 在需要跳转路由的页面中使用
import '../routers/staticize.dart';
….
onTap: (){
Staticize.router.navigateTo(context, '/goodDetail?id=${newList[index].goodsId}');
},
hero 动画
class PhotoHero extends StatelessWidget {
const PhotoHero({ Key key, this.photo, this.onTap, this.width }) : super(key: key);
final String photo;
final VoidCallback onTap;
final double width;
Widget build(BuildContext context) {
return new SizedBox(
width: width,
child: new Hero(
category: photo,
child: new Material(
color: Colors.transparent,
child: new InkWell(
onTap: onTap,
child: new Image.asset(
photo,
fit: BoxFit.contain,
),
),
),
),
);
}
}
class HeroAnimation extends StatelessWidget {
Widget build(BuildContext context) {
timeDilation = 5.0; // 1.0 means normal animation speed.
return new Scaffold(
appBar: new AppBar(
title: const Text('Basic Hero Animation'),
),
body: new Center(
child: new PhotoHero(
photo: 'images/flippers-alpha.png',
width: 300.0,
onTap: () {
Navigator.of(context).push(new MaterialPageRoute<Null>(
builder: (BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: const Text('Flippers Page'),
),
body: new Container(
// The blue background emphasizes that it's a new route.
color: Colors.lightBlueAccent,
padding: const EdgeInsets.all(16.0),
alignment: Alignment.topLeft,
child: new PhotoHero(
photo: 'images/flippers-alpha.png',
width: 100.0,
onTap: () {
Navigator.of(context).pop();
},
),
),
);
}
));
},
),
),
);
}
}
