總體思路
側(cè)滑控件的實現(xiàn)原理: Flutter中Navigator是用來控制路由棧的傻铣,使用方式如下:
Navigator.of(context).push(route);
push接收一個Route九秀,這個Route負責(zé)給出具體的widget吐葱,普通的Route在顯示自己的page時會覆蓋掉原本的頁面秸仙,而PopupRoute就不會袋坑,他的效果類似于android中的popupWindow咙崎,自帶蒙層优幸。
繼承PopupRoute,修改參數(shù)褪猛,重寫buildPage网杆,在buildPage中返回一個帶側(cè)滑動畫的widget
class SlideWindow extends PopupRoute {
...
@override
Color get barrierColor => null;//去掉蒙層
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
...
return slideWindowWidget;//page是全屏的
}
}
布局
這個widget是一個Stack結(jié)構(gòu),底層是全屏的Container蒙層伊滋,上層是一個帶側(cè)滑動畫的內(nèi)容widget碳却,暫時只能是SizedBox,因為側(cè)滑動畫需要知道widget的寬度笑旺,而SizedBox是固定寬度的昼浦。
Stack(children: <Widget>[
//蒙層
GestureDetector(
onTap: widget.onTapOutsize,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: colorAnimation.value,
),
),
//內(nèi)容層
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
alignment: Alignment.centerRight,
//靠右豎直居中的內(nèi)容widget
child: Transform.translate(
offset: Offset(widgetAnimation.value, 0),
child: widget.child,
),
)
]);
動畫
在Flutter中,補間動畫Tween的原理和Android中類似筒主,規(guī)定value變化范圍关噪,value每次變化時setState(),根據(jù)最新的value去重建widget乌妙,在value變化的過程中使兔,widget時不斷重建的,某些屬性也在不斷被修改冠胯,這樣就達到了動畫效果火诸。
這里需要用到兩種動畫,一個是內(nèi)容層的平移荠察,一個是蒙層的顏色變化置蜀,代碼如下奈搜,在初始化狀態(tài)時設(shè)置動畫
@override
void initState() {
super.initState();
//設(shè)置動畫控制器
controller = new AnimationController(
duration: widget.duration,
vsync: this,
);
//設(shè)置插值器
Animation curve = CurvedAnimation(
parent: controller, curve: Curves.fastLinearToSlowEaseIn);
//設(shè)置內(nèi)容層平移動畫
widgetAnimation =
new Tween(begin: widget.child.width, end: 0.0).animate(curve)
..addListener(() {
setState(() {});
});
//設(shè)置蒙層顏色動畫
colorAnimation = new ColorTween(
begin: Colors.black.withOpacity(0),
end: Colors.black.withOpacity(0.4))
.animate(curve);
//開始動畫
controller.forward();
}
然后內(nèi)容需要用一個Transform變換控件包裹,這個控件可以對child做一些變換盯荤,例如移動位置
Transform.translate(
offset: Offset(widgetAnimation.value, 0),
child: widget.child,
)
響應(yīng)退出
調(diào)用Navigator.pop()
因為這是一個Route馋吗,所以是受Navigator控制的,代碼中調(diào)用了Navigator.pop()時我們的頁面是會消失的秋秤,這個消失不做處理的話是不帶側(cè)滑動畫宏粤,也就是很難看,而在pop的過程中灼卢,系統(tǒng)會調(diào)用Route的didpop方法绍哎,所以可以重寫這個方法在里面反轉(zhuǎn)動畫
@override
bool didPop(result) {
slideWindowWidget.state.controller.reverse();//反轉(zhuǎn)
return super.didPop(result);
}
觸摸了蒙層
這種情況需要自己去控制,在蒙層上設(shè)置GestureDetector鞋真,在響應(yīng)中調(diào)用Navigator.pop()崇堰,又回到第一種情況
按到了物理返回鍵
這種情況貌似在ios上不會出現(xiàn),但是android設(shè)備是有返回鍵的涩咖,按了返回鍵后海诲,系統(tǒng)同樣會調(diào)用Navigator.pop(),還是回到第一種情況