我尝试使用 BottomSheet、modal_bottom_sheet 和各种类似的库,但它们完全隐藏了小部件。我希望它作为一条小条保留在导航栏上方,并且能够通过滑动或点击将其拉出。
这只是实现您的设计的一个想法,如果您想退出,我将使用 GetX 来实现它,我认为您应该尝试
GestureDetector
来了解拖动偏移
ps.也许这不是最佳实践,所以我只是说只是一个想法希望这会有所帮助
结果
页面小部件
class PlaygroundPage extends StatelessWidget {
const PlaygroundPage({super.key});
@override
Widget build(BuildContext context) {
return GetBuilder<PlaygroundPageController>(
global: false,
init: PlaygroundPageController(),
builder: (controller) => Scaffold(
backgroundColor: AppColors.white,
bottomNavigationBar: _Bottombar(
controller: controller,
),
body: Padding(
padding: EdgeInsets.fromLTRB(0, Get.mediaQuery.padding.top, 0, 0),
child: Column(
children: [
ToButton(
onPressed: () {
Get.back();
},
child: Container(
width: 200,
height: 50,
color: AppColors.green1,
child: const Text('back'),
),
)
],
),
),
),
);
}
}
class _Bottombar extends StatelessWidget {
final PlaygroundPageController controller;
const _Bottombar({
required this.controller,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
child: Container(
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(
boxShadow: [AppShadow.shadowTop],
),
height: (72 + Get.mediaQuery.padding.bottom + 70) + (controller.animation.value * 500),
child: Stack(
children: [
Positioned(
bottom: 0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ToButton(
onPressed: () {
controller.isCollapsed.toggle();
controller.handleToggleExpanded();
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(0 + (24 * controller.animation.value)),
topRight: Radius.circular(0 + (24 * controller.animation.value)),
),
color: AppColors.red,
),
width: Get.width,
height: (72 + Get.mediaQuery.padding.bottom + 70),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.fromLTRB(0, 8, 0, 0),
width: 100,
height: 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
color: AppColors.grey2,
),
)
],
),
),
),
SizeTransition(
axisAlignment: 1.0,
sizeFactor: controller.animation,
child: Container(
width: Get.width,
height: 500,
color: AppColors.green1,
),
),
],
),
),
Positioned(
bottom: ((72 + Get.mediaQuery.padding.bottom) * controller.reverseAnimation.value) - (72 + Get.mediaQuery.padding.bottom),
child: Container(
padding: const EdgeInsets.fromLTRB(0, 16, 0, 0),
width: Get.width,
height: (72 + Get.mediaQuery.padding.bottom),
decoration: const BoxDecoration(
color: AppColors.grey,
boxShadow: [AppShadow.shadowTop],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.red,
width: sizing(20),
height: sizing(20),
padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
),
SizedBox(width: sizing(20)),
Container(
color: Colors.red,
width: sizing(20),
height: sizing(20),
padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
),
SizedBox(width: sizing(20)),
Container(
color: Colors.red,
width: sizing(20),
height: sizing(20),
padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
),
SizedBox(width: sizing(20)),
Container(
color: Colors.red,
width: sizing(20),
height: sizing(20),
padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
),
SizedBox(width: sizing(20)),
Container(
color: Colors.red,
width: sizing(20),
height: sizing(20),
padding: const EdgeInsets.fromLTRB(4, 8, 4, 0).toResponsive(),
),
],
),
),
),
],
),
),
);
}
}
控制器
class PlaygroundPageController extends GetxController with GetTickerProviderStateMixin {
late AnimationController expandController;
late AnimationController collapseController;
late Animation<double> animation;
late Animation<double> reverseAnimation;
final isCollapsed = true.obs;
@override
void onInit() {
super.onInit();
prepareAnimations();
prepareReverseAnimations();
}
void handleToggleExpanded() {
if (!isCollapsed.value) {
expandController.forward();
collapseController.forward();
} else {
expandController.reverse();
collapseController.reverse();
}
}
void prepareAnimations() {
expandController = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 1500,
),
);
Animation<double> curve = CurvedAnimation(
parent: expandController,
curve: Curves.fastOutSlowIn,
);
animation = Tween(begin: 0.0, end: 1.0).animate(curve)..addListener(() => refresh());
}
void prepareReverseAnimations() {
collapseController = AnimationController(
vsync: this,
duration: const Duration(
milliseconds: 1500,
),
);
Animation<double> curve = CurvedAnimation(
parent: collapseController,
curve: Curves.fastOutSlowIn,
);
reverseAnimation = Tween(begin: 1.0, end: 0.0).animate(curve)..addListener(() => refresh());
}
}