Flutter全局menu弹框

全屏幕menu弹框,可以设置位置,居中,居左,居右,居顶,居底部。默认右上角位置


import 'dart:math' as math;
import 'dart:ui' as ui show window;
import 'package:flutter/material.dart';
import 'package:simple_animations/simple_animations.dart';
import 'package:supercharged/supercharged.dart';

class FSMenuPopModel {
  String? title;
  String? id;
  String? icon;
  bool selected; // 是否选中

  FSMenuPopModel({
    this.title,
    this.id,
    this.selected = false,
    this.icon,
  });
}

enum FSMenuLayoutType {
  left, //从左开始
  xCenter,
  right, //从右开始
  top, //从上开始
  yCenter,
  bottom, //从下开始
}

/**
 * example:
    FSMenuPopModel currentModel = FSMenuPopModel();
    showPop() {
    List<FSMenuPopModel> list = [];

    for (int i = 0; i < 5; i++){
    FSMenuPopModel model1 = FSMenuPopModel();
    model1.title = '排序'+i.toString();
    model1.id = (100 + i).toString();
    model1.icon = R.assetsImgCommonQiehuan;
    model1.selected = model1.id == currentModel.id;
    list.add(model1);
    }

    DialogUtil.showMaskView(
    FSMenuPopView(
    itemList: list,
    xLayoutType: FSMenuLayoutType.right,
    // yLayoutType: NavMenuLayoutType.yCenter,
    activeBackground: StyleColor.theme_light_gray,
    yMargin: 10 + ScreenUtil.getAppBarHeight,
    onTap: (FSMenuPopModel model) async {
    currentModel = model;
    NavigatorUtil.pop();
    },
    ),
    backgroundColor: Colors.black.withAlpha(0)
    );
    }
 * */

/// 选择menu
class FSMenuPopView extends StatefulWidget {
  final ValueSetter<FSMenuPopModel>? onTap; //点击回调方法
  final List<FSMenuPopModel>? itemList;
  final Color? menuBackground;
  final Color? normalBackground;
  final Color? activeBackground;
  final double? borderRadius;
  final double? horizontalSpace; //左右边距
  final double? itemVerticalSpace; //上下边距
  final double? imgWidth;
  TextStyle? activeTextStyle;
  TextStyle? normalTextStyle;

  ///定位,默认右上角弹出
  final FSMenuLayoutType? yLayoutType; //y定位类型,默认从顶部
  final FSMenuLayoutType? xLayoutType; //x定位类型,默认从右侧
  final double? xMargin; //距离左右定位的边距,需结合xLayoutType枚举使用
  final double? yMargin; //距离上下定位的边距,需结合yLayoutType枚举使用

  FSMenuPopView({
    @required this.onTap,
    @required this.itemList,
    this.xMargin,
    this.yMargin,
    this.xLayoutType,
    this.yLayoutType,
    this.menuBackground = Colors.white,
    this.normalBackground = Colors.white,
    this.activeBackground = Colors.white,
    this.activeTextStyle,
    this.normalTextStyle,
    this.borderRadius = 5,
    this.imgWidth = 15,
    this.horizontalSpace,
    this.itemVerticalSpace,
  });

  @override
  _FSMenuViewState createState() => _FSMenuViewState();
}

class _FSMenuViewState extends State<FSMenuPopView> {
  // 获取状态栏高度
  static final MediaQueryData _mediaQueryData = MediaQueryData.fromWindow(ui.window);

  static double get _getStatusBarHeight => _mediaQueryData.padding.top;

  //内容距离视图左右默认边距
  double get _defaultSpaceHorizontal => 20;

  //内容距离视图上下默认边距
  double get _defaultSpaceVertical => 10;

  TextStyle get _activeDefaultTextStyle => TextStyle(color: Colors.black, fontSize: 16);

  TextStyle get _normalDefaultTextStyle => TextStyle(color: Color(0xFF595961), fontSize: 16);

  //y布局
  double get _defaultYMargin => _getStatusBarHeight;

  FSMenuLayoutType get _defaultLayoutTypeY => FSMenuLayoutType.top;

  //x布局
  double get _defaultXMargin => 20;

  FSMenuLayoutType get _defaultLayoutTypeX => FSMenuLayoutType.right;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.pop(context);
      },
      child: Container(
        decoration: BoxDecoration(
          color: Colors.black.withAlpha(0),
        ),
        child: PlayAnimation<double>(
          tween: 0.0.tweenTo(1.0),
          duration: 300.milliseconds,
          curve: Curves.easeOut,
          builder: (context, child, value) {
            return Transform.scale(
              scale: value,
              child: Column(
                mainAxisSize: MainAxisSize.max,
                children: [
                  //顶部占位视图
                  (widget.yLayoutType ?? _defaultLayoutTypeY) == FSMenuLayoutType.top
                      ? Container(height: widget.yMargin ?? _defaultYMargin)
                      : Expanded(
                          child: Container(
                          color: Colors.black.withAlpha(0),
                        )),
                  Row(
                    mainAxisSize: MainAxisSize.max,
                    children: [
                      //左侧占位视图
                      (widget.xLayoutType ?? _defaultLayoutTypeX) == FSMenuLayoutType.left
                          ? Container(width: widget.xMargin ?? _defaultXMargin)
                          : Expanded(child: Container()),
                      //内容
                      _contentWidget,
                      //右侧占位视图
                      (widget.xLayoutType ?? _defaultLayoutTypeX) == FSMenuLayoutType.right
                          ? Container(width: widget.xMargin ?? _defaultXMargin)
                          : Expanded(child: Container()),
                    ],
                  ),
                  //底部占位视图
                  (widget.yLayoutType ?? _defaultLayoutTypeY) == FSMenuLayoutType.bottom
                      ? Container(height: widget.yMargin ?? _defaultYMargin)
                      : Expanded(child: Container()),
                ],
              ),
            );
          },
        ),
      ),
    );
  }

  /// 界面
  Widget get _contentWidget {
    return Container(
      clipBehavior: Clip.antiAlias,
      decoration: new BoxDecoration(
        color: widget.menuBackground ?? Colors.white,
        borderRadius: BorderRadius.all(
          Radius.circular(widget.borderRadius ?? 0),
        ),
        boxShadow: [
          BoxShadow(
            offset: Offset(4.0, 4.0),
            blurRadius: 10,
            color: Color(0xFFF2F2F6),
          )
        ],
      ),
      child: Column(
        children: (widget.itemList ?? []).map((item) {
          return GestureDetector(
            onTap: () {
              if (widget.onTap != null) widget.onTap!(item);
            },
            child: Container(
              decoration: BoxDecoration(
                border: Border(
                  bottom: item == (widget.itemList ?? []).last
                      ? BorderSide.none
                      : BorderSide(
                          width: 1,
                          color: Color(0xFFEFEFEF),
                        ),
                ),
              ),
              child: Container(
                padding: EdgeInsets.symmetric(
                  vertical: (widget.itemVerticalSpace ?? _defaultSpaceVertical),
                  horizontal: (widget.horizontalSpace ?? _defaultSpaceHorizontal),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Offstage(
                      offstage: item.icon == null || item.icon!.isEmpty,
                      child: Padding(
                        padding: const EdgeInsets.only(right: 8.0),
                        child: Image.asset(
                          item.icon ?? '',
                          width: widget.imgWidth,
                          height: widget.imgWidth,
                        ),
                      ),
                    ),
                    Text(
                      item.title ?? '',
                      textAlign: TextAlign.center,
                      style: item.selected == true ? (widget.activeTextStyle ?? _activeDefaultTextStyle) : (widget.normalTextStyle ?? _normalDefaultTextStyle),
                    ),
                  ],
                ),
                decoration: BoxDecoration(
                  color: item.selected == true ? widget.activeBackground : widget.normalBackground,
                ),
              ),
            ),
          );
        }).toList(),
      ),
    );
  }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值