1. 路由Navigator
基础使用
//路由跳转
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>Container()));
//关闭路由
Navigator.pop(context);
带返回值
//路由跳转,接收返回值
Future<int> result = Navigator.of(context).push(MaterialPageRoute(builder: (context)=>Container()));
//关闭路由,传递值1(泛型,当然也可以是其他值)
Navigator.pop(context,1);
定制路由
PageRouteBuilder
可以定制动画或其他样式
//路由自定义动画,改为左边进入
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (context,Animation animation,_)=>FadeTransition(
opacity: animation,
child: SlideTransition(position: Tween<Offset>(begin: Offset(-1.0, 0.0),end: Offset(0.0, 0.0)).animate(animation),child: AnimationContain(),),
)
));
命名导航器路由(静态路由)
//注册 MaterialApp 的routes参数,传递map
//统一定制路由,MaterialApp 的onGenerateRoute参数
var map = <String, WidgetBuilder> {
'/a': (context) =>Container()};
//使用
Navigator.of(context).pushName('/a');
//关闭
Navigator.pop(context);
静态路由和动态路由内部其实是一样的,但是更方便管理,可以用一个map,而map的实例放在一个文件里,这个文件即可集中管理所有路由,修改起来非常方便
ModalRoute
常用路由:
router | 关系 | 用途 |
---|---|---|
PageRoute | 子类 | 页面路由 |
PopupRoute | 子类 | 弹框路由 |
WillPopScope | 组合 | 导航返回拦截 |
a. PageRoute
MaterialPageRoute
和PageRouteBuilder
都是其的子类,与页面有关,覆盖全屏
b. PopupRoute
与弹框有关,无需覆盖全屏
showDialog、showMenu和showModalBottomSheet
等内部创建了PopupRoute
实例,并调用了路由
c.WillPopScope
可实现返回拦截,如短时间连续点击二次退出
内部创建了ModalRoute
实例
源码层简析:https://segmentfault.com/a/1190000011590792?utm_source=tag-newest
2.主题 Theme
先从MaterialApp
的theme
来看,源码的build
方法可以看出其实内部创建了AnimatedTheme
控件,而AnimatedTheme
控件内部其实就是创建了Theme
控件
所以还是要看Theme
Theme
内部创建了_InheritedTheme
class _InheritedTheme extends InheritedWidget {
const _InheritedTheme({
Key key,
@required this.theme,
@required Widget child
}) : assert(theme != null),
super(key: key, child: child);
final Theme theme;
@override
bool updateShouldNotify(_InheritedTheme old) => theme.data != old.theme.data;
}
InheritedWidget
控件比较重要,可用于数据共享,Theme内部明显共享着ThemeData
,这意味着一旦MaterialApp
使用了theme
,后续的控件如果不新建ThemeData
,将共享这主题数据
InheritedWidget
后续再研究,相关信息:https://book.flutterchina.club/chapter7/inherited_widget.html
//修改accentColor,其他默认
Theme(
data: Theme.of(context).copyWith(accentColor: Colors.yellow),
);
//单独使用
color: Theme.of(context).accentColor
//使用新创建的
Theme(
data: ThemeData(
primarySwatch: _themeColor, //用于导航栏、FloatingActionButton的背景色等
iconTheme: IconThemeData(color: _themeColor) //用于Icon颜色
)
3.手势
Listener
原始事件
与android的onTouchEvent
一样,有4个基础手势
- onPointerDown: 手指按下
- onPointerMove: 手指移动
- onPointerUp: 手指抬起
- onPointerCancel: 手指取消
一个HitTestBehavior
enum HitTestBehavior {
//子widget会一个接一个的进行命中测试,如果子Widget中有测试通过的,则当前Widget通过,
//这就意味着,如果指针事件作用于子Widget上时,其父(祖先)Widget也肯定可以收到该事件
deferToChild, //默认
//在命中测试时,将当前Widget当成不透明处理(即使本身是透明的),最终的效果相当于当前Widget的整个区域都是点击区域
opaque,
//当点击透明区域时,可以对底部widget进行命中测试,这意味着底部widget也可以接收事件
//translucent可以在Stack中实现"点透"的效果
translucent,
}
GestureRecognizer
手势识别
GestureDetector
封装手势识别控件,内部使用的是多个GestureRecognizer
使用
Listener(
child: Container(
alignment: Alignment.center,
color: Colors.blue,
width: 300.0,
height: 150.0,
child: Text(_event?.toString()??"",style: TextStyle(color: Colors.white)),
),
onPointerDown: (PointerDownEvent event) => setState(()=>_event=event),
onPointerMove: (PointerMoveEvent event) => setState(()=>_event=event),
onPointerUp: (PointerUpEvent event) => setState(()=>_event=event),
)
注:event内部使用的坐标是绝对坐标
4.动画
官方封装控件比较多,这里就说最基础的
快捷键stanim
创建的state会混合SingleTickerProviderStateMixin
类,用于计时
class ScaleAnimationWidget extends StatefulWidget {
@override
_ScaleAnimationWidgetState createState() => _ScaleAnimationWidgetState();
}
class _ScaleAnimationWidgetState extends State<ScaleAnimationWidget> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
double _value = 255.0;
bool _flag = true;
_changeValue(){
if(_flag) {
_controller.forward();
}else{
_controller.reverse();
}
_flag = !_flag;
}
@override
void initState() {
_controller = AnimationController(duration: Duration(seconds: 1),vsync: this);
//插值器
_animation = CurvedAnimation(parent: _controller, curve: Curves.decelerate);
_animation = Tween(begin: 255.0, end: 80.0).animate(_animation)
..addListener((){
setState(() {});
});
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: _changeValue,
child: Container(
width: _animation.value,
height: _animation.value,
child: FlutterLogo(),
),
);
}
}
动画一般一个AnimationController
管理多个Animation
,共4个AnimationStatus
状态:
a. dismissed 动画在起始点停止
b. forward 动画正在正向执行
c. reverse 动画正在反向执行
d. completed 动画在终点停止
使用步骤
//1.创建动画控制器
_controller = AnimationController(duration: Duration(seconds: 4),vsync: this);
//2.添加动画,可以添加多个
//Interval设置实现动画时间段,设置动画播放方式
_x = Tween(begin: 0.0, end: 200.0).animate(
CurvedAnimation(parent: _controller, curve: Interval(0.0, 0.6,curve: Curves.bounceInOut))
);
//执行动画
_controller.forward();
也可以设置监听
_controller.addListener((){
//每次值改变将调用内部
});
_controller.addStatusListener((AnimationStatus state){
//可对state进行处理
});
小结
这部分使用起来比较简单,但要深入原理需要花费一定时间。
当时学android的时候,刚开始也是一大堆View
,但其实这东西和api一样,用多了就掌握了。
Flutter
其实相对好些,所有能修改的样式其实都放在构造函数中,配合注释其实上手很快的,至于多个括号,其实你用久了感觉还是很舒服的(真香!)
只会使用是没有意义的,接下来进一步深入控件的摆放,绘制及事件
网友评论