首先效果上图:

now,let‘s go。
分为三节:
本节为第一节底部下拉框
思想:在Stack中包含,并且位于底部,并将框框控件用Transform.translate包住,通过offset使其向底部偏移。给框框顶部设置手势,手势通过改变offset而改变框框位置。再给框框设置点击事件,以及通过距离和速度判断是应该上去还是下去,这点通过动画实现。
PageChangeMiddle是身子,DragContainer是底部,我们只用关心底部即可 此处通过Align 放在Stack的底部,
Stack(
children: <Widget>[
PageChangeMiddle(
controll: sliverSelfControll,
),
Align(
alignment: Alignment.bottomCenter,
child: DragContainer()
),
]
)
此处通过translate使其向y轴偏移,偏移量为offsetDistance
//practiceBottomDrawerHeight是这个框框的最大高度
double practiceBottomDrawerHeight = 500;
//videoFixHeight是框框顶部高度
double videoFixHeight = 50;
//offsetDistance即初始时需要偏移的高度
double offsetDistance = practiceBottomDrawerHeight - videoFixHeight;
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0.0, offsetDistance),
child: RawGestureDetector(
gestures: {BottomDrawerVerticalDragGestureRecognizer: getRecognizer()},
child: _DrawerWidget(),
),
);
}
RawGestureDetector即给设置手势,此处仅仅粘贴核心代码,若要仔细研究,请去github
///垂直移动
void _onUpdate(DragUpdateDetails details) {
print('垂直移动${details.delta}');
offsetDistance = offsetDistance + details.delta.dy;
//设置界限
if (offsetDistance <= 0) {
//当offsetDistance<=0时,即达到最高点禁止滑动
offsetDistance = 0;
} else if (offsetDistance >=
(practiceBottomDrawerHeight - videoFixHeight)) {
//当offsetDistance<=0时,即达到最高点禁止滑动
offsetDistance = practiceBottomDrawerHeight - videoFixHeight;
} else {
//offset在允许的范围改变,即需要刷新
setState(() {});
}
}
以上即根据手势滑动。
当手指离开时,需要确定是展开还是回缩。
当然,前面还需要初始化动画
void _onEnd(DragEndDetails details) {
print('离开屏幕');
double halfOffset = (practiceBottomDrawerHeight - videoFixHeight) / 2;
double velocityY = details.velocity.pixelsPerSecond.dy;
//先根据速度判断
if (velocityY.abs() > 400) {
if (velocityY > 0) {
endSliver(false);
} else {
endSliver(true);
}
} else {
//如果速度太低则根据滑动距离判断
if (offsetDistance >= halfOffset) {
endSliver(false);
} else {
endSliver(true);
}
}
}
void endSliver(isShow) {
if (isShow) {
print('展开');
start = offsetDistance;
end = 0;
} else {
print('回收');
start = offsetDistance;
end = practiceBottomDrawerHeight - videoFixHeight;
}
animalController.value = 0.0;
animation = Tween(begin: start, end: end).animate(curve)
..addListener(() {
offsetDistance = animation.value;
widget.onOffSliver(offsetDistance);
setState(() {});
});
animalController.forward();
}
封装这个endSliver是非常到位的。。。当我们点击底部展开,只需要加个点击事件然后调用 endSliver(true);即可,回收也是同理。
GestureDetector(
child: _buttonItemCount(
'images/practice_count.png', '${current + 1}', '$countNum'),
onTap: () {
endSliver(true);
},
)
下拉框就是这么简单。如果觉得能看,请看下节。