`
class ParentSheetPage extends StatefulWidget {
const ParentSheetPage({
super.key,
required this.buildBottomSheet,
required this.buildTopSheet,
});
/// 位于下方的[Widget]
final Widget Function(BuildContext context) buildBottomSheet;
/// 位于上方的[Widget]
final Widget Function(BuildContext context) buildTopSheet;
@override
State<StatefulWidget> createState() => _ParentSheetState();
}
class _ParentSheetState extends State<ParentSheetPage> with TickerProviderStateMixin {
/// 默认高度
double bottomBarToTop = 300;
/// 上层widget的两段高度级别
double bottomBarHigh = 300;
double bottomBarLow = 600;
@override
Widget build(BuildContext context) {
return Stack(
children: [
Positioned.fill(child: widget.buildBottomSheet(context)),
Positioned(left: 0, right: 0, bottom: 0, top: bottomBarToTop, child: body(context)),
],
);
}
Widget body(BuildContext context) {
return Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(topRight: Radius.circular(10), topLeft: Radius.circular(10)),
),
child: Column(
children: [_dragBar(), Expanded(child: widget.buildTopSheet(context))],
)
);
}
Widget _dragBar() {
return GestureDetector(
onVerticalDragUpdate: (DragUpdateDetails details) {
if (details.globalPosition.dy > bottomBarLow || details.globalPosition.dy < bottomBarHigh) return;
setState(() {
bottomBarToTop = details.globalPosition.dy;
});
},
onVerticalDragCancel: () {
calibrationBottomHeight();
},
onVerticalDragEnd: (DragEndDetails details) {
calibrationBottomHeight();
},
child: Container(
padding: EdgeInsets.only(top: 14.w, bottom: 13.w),
color: Colors.transparent,
alignment: AlignmentDirectional.center,
child: Container(
width: 36.w,
height: 5.w,
decoration: BoxDecoration(
color: AppColors.grey_color300.withOpacity(0.3),
borderRadius: AppRadii.k4pxRadius,
),
),
),
);
}
void calibrationBottomHeight() async {
final mediumLimit = (bottomBarHigh + bottomBarLow) / 2;
double endValue = bottomBarToTop > mediumLimit ? bottomBarLow : bottomBarHigh;
//根据本次偏移的行程调整动画时长
double stroke = (bottomBarToTop - endValue).abs();
double proportion = stroke / (bottomBarLow - bottomBarHigh);
AnimationController controller = AnimationController(
duration: Duration(milliseconds: (200 * proportion).round()),
vsync: this,
);
Animation<double> valueAnimation = Tween(
begin: bottomBarToTop,
end: endValue,
).animate(
CurvedAnimation(
parent: controller,
curve: Curves.easeIn,
),
);
valueAnimation.addListener(() {
setState(() {
bottomBarToTop = valueAnimation.value;
});
});
await controller.forward();
controller.dispose();
}
}
`