当前位置:   article > 正文

Flutter ShowModalBottomSheet 自定义高度和滚动

showmodalbottomsheet

这是一个官方的组件 但是两个滑动在一起会有冲突简单的实现了一下滑动到头自动收起这个组件

封装成一个通用组件

  1. class ComModalBottomSheet {
  2. /// 展示ModalBottomSheet
  3. /// [context] 上下文
  4. /// [child] 里面的子组件
  5. /// [isDismissible] 外部是否可以点击 默认是true
  6. /// [enableDrag] 是否可以拖动
  7. /// [title] 标题
  8. /// [isLeftTitle]是否居中
  9. /// [useRootNavigator ] 是否使用跟路由
  10. /// [maxHeight] 最小0最大1 取之间数字 小于0.5按0.5算 大于1 按1算
  11. static void show(
  12. {required context,
  13. required child,
  14. isDismissible = true,
  15. enableDrag = true,
  16. useRootNavigator = false,
  17. title,
  18. isScrollOver = false,
  19. isLeftTitle = false,
  20. showRightTopClose = false,
  21. showBottomClose = true,
  22. maxHeight = 0.5}) {
  23. showModalBottomSheet(
  24. context: context,
  25. //背景颜色(下半部弹出的颜色)
  26. backgroundColor: Theme.of(context).scaffoldBackgroundColor,
  27. //上半部分的mask颜色
  28. barrierColor: Colors.black54,
  29. // 如果设定高度小于0.5 是flase默认最大半屏 ,大于0.5按设定高度来
  30. isScrollControlled: maxHeight > 0.5,
  31. //外部是否可以点击
  32. isDismissible: isDismissible ?? true,
  33. //是否可以拖动
  34. enableDrag: enableDrag ?? true,
  35. //是否用根路由
  36. useRootNavigator: useRootNavigator ?? false,
  37. //顶部的圆角矩形
  38. shape: RoundedRectangleBorder(
  39. borderRadius: BorderRadius.only(
  40. topLeft: Radius.circular(ScreenHelper.width(15)),
  41. topRight: Radius.circular(ScreenHelper.width(15))),
  42. ),
  43. builder: (context) {
  44. //返回一个SingleChildScrollView 设定他永不滚动 实现自适应高度
  45. return SingleChildScrollView(
  46. physics: const NeverScrollableScrollPhysics(),
  47. child: Padding(
  48. ///根据设计图设置他的padding
  49. padding: EdgeInsets.all(ScreenHelper.width(18)),
  50. child: Column(
  51. mainAxisAlignment: MainAxisAlignment.start,
  52. children: [
  53. //如果有标题或者有右上角的 X就展示这个组件
  54. if(title!=null||showRightTopClose)
  55. _buildHead(title, isLeftTitle, showRightTopClose, context),
  56. ///如果最大宽度小于0.5自适应 否则强制设置最大高度
  57. if (maxHeight <= 0.5)
  58. child
  59. else
  60. SizedBox(
  61. height: ScreenHelper.screenHeight *
  62. (maxHeight >= 0.87 ? 0.87 : maxHeight),
  63. child: child,
  64. ),
  65. ///是否展示下方的取消按钮
  66. if (showBottomClose)
  67. SizedBox(
  68. width: double.infinity,
  69. child: comMaterialButton(context,
  70. onPressed: () => Navigator.pop(context),
  71. buttonName: "取消"),
  72. )
  73. ],
  74. ),
  75. ),
  76. );
  77. },
  78. );
  79. }
  80. static Stack _buildHead(
  81. title, isLeftTitle, showRightTopClose, BuildContext context) {
  82. return Stack(
  83. children: [
  84. if(title!=null)
  85. Container(
  86. width: double.infinity,
  87. padding: EdgeInsets.symmetric(vertical: ScreenHelper.width(8)),
  88. margin: EdgeInsets.only(bottom: ScreenHelper.width(18)),
  89. child: Text(
  90. title ?? "",
  91. textAlign: isLeftTitle ? TextAlign.start : TextAlign.center,
  92. ),
  93. ),
  94. if (showRightTopClose)
  95. Positioned(
  96. right: 0,
  97. child: InkWell(
  98. onTap: () => Navigator.pop(context),
  99. child: Padding(
  100. padding: EdgeInsets.all(ScreenHelper.width(8)),
  101. child: comIcon(context, iconPoint: 0xe7e4),
  102. ),
  103. ))
  104. ],
  105. );
  106. }
  107. }

下方按钮的封装

  1. Padding comMaterialButton(BuildContext context,
  2. {required buttonName, onPressed, padding}) {
  3. return Padding(
  4. padding: EdgeInsets.symmetric(
  5. horizontal: ScreenHelper.width(18)),
  6. child: MaterialButton(
  7. color: Theme.of(context).textTheme.button?.color,
  8. height: ScreenHelper.width(44),
  9. shape: ContinuousRectangleBorder(
  10. borderRadius: BorderRadius.circular(ScreenHelper.width(15))),
  11. onPressed: () {
  12. if (onPressed != null) {
  13. onPressed();
  14. }
  15. },
  16. child: Text(
  17. buttonName ?? "",
  18. style: TextStyle(color: Theme.of(context).textTheme.subtitle2?.color),
  19. ),
  20. ),
  21. );
  22. }

showModalBottomSheet里面的ScrollView的封装

  1. class BottomSheetScrollView extends StatefulWidget {
  2. //传进来的列表
  3. final List<dynamic> list;
  4. //传进来的Widget
  5. final Widget Function(dynamic) child;
  6. const BottomSheetScrollView(
  7. {Key? key, required this.list, required this.child})
  8. : super(key: key);
  9. @override
  10. State<BottomSheetScrollView> createState() => _BottomSheetScrollViewState();
  11. }
  12. class _BottomSheetScrollViewState extends State<BottomSheetScrollView> {
  13. ///最后一次点击的位置
  14. double lastPoint = 0.0;
  15. ///当前条目的距离
  16. double offset = 0.0;
  17. ///是否滚动到头了
  18. bool isOverScroll = true;
  19. ///滚动控制器
  20. ScrollController controller = ScrollController();
  21. @override
  22. void initState() {
  23. // TODO: implement initState
  24. super.initState();
  25. ///添加监听 滚动的距离保存
  26. controller.addListener(() {
  27. offset = controller.offset;
  28. });
  29. }
  30. @override
  31. Widget build(BuildContext context) {
  32. return Listener(
  33. ///添加对界面手指移动的监听
  34. onPointerMove: (event) {
  35. if (event.position.dx - lastPoint > 0) {
  36. 如果当前的位置比按下的位置大 那么是向上滑的 那么永远滚不到最顶上
  37. setState(() => isOverScroll = false);
  38. } else {
  39. //如果当前滚动到最顶上的时候就设置isOverScroll 是true
  40. setState(() => isOverScroll = offset == 0.0);
  41. }
  42. },
  43. onPointerDown: (event) {
  44. ///按下时记录此时的位置
  45. setState(() {
  46. lastPoint = event.position.dx;
  47. });
  48. },
  49. child: Padding(
  50. padding: EdgeInsets.symmetric(vertical: ScreenHelper.width(18)),
  51. child: ListView.builder(
  52. //控制器
  53. controller: controller,
  54. ///如果到头了就禁止它滑动,如果没到头就继续滑动
  55. physics: isOverScroll
  56. ? const NeverScrollableScrollPhysics()
  57. : const ClampingScrollPhysics(),
  58. //长度是传进来的列表的长度
  59. itemCount: widget.list.length,
  60. 构造也是传进来的
  61. itemBuilder: (context, index) =>
  62. widget.child(model.list[index])),
  63. ),
  64. );
  65. }
  66. }

使用

  1. TextButton(
  2. onPressed: () {
  3. model.addModelBottomSheetListener();
  4. ComModalBottomSheet.show(
  5. useRootNavigator: false,
  6. maxHeight: 0.7,
  7. isDismissible: false,
  8. context: context,
  9. child: BottomSheetScrollView(
  10. list: ["1", "2", "3", "4","1", "2", "3", "4","1", "2", "3", "4","1", "2", "3", "4","1", "2", "3", "4""1", "2", "3", "4""1", "2", "3", "4""1", "2", "3", "4"],
  11. child: (item) => ListTile(title: Text(item),),
  12. ));
  13. },
  14. child: Text("弹出测试"),
  15. ),

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/268697
推荐阅读
相关标签
  

闽ICP备14008679号