import 'dart:ui'; import 'package:flutter/material.dart'; import '../../core/theme/app_color_scheme.dart'; import '../../core/theme/app_spacing.dart'; /// GlassPanel - 毛玻璃效果面板 /// /// Material Design 3 风格的毛玻璃效果组件 /// 用于卡片、弹窗、底部抽屉等需要毛玻璃效果的容器 /// /// 示例: /// ```dart /// GlassPanel( /// child: Text('内容'), /// ) /// ``` class GlassPanel extends StatelessWidget { /// 子组件 final Widget child; /// 模糊程度,默认 20.0 final double blur; /// 背景色,默认使用 GlassPanel 背景色 final Color? backgroundColor; /// 边框色,默认使用 GlassPanel 边框色 final Color? borderColor; /// 圆角,默认特大圆角 final BorderRadius? borderRadius; /// 内边距 final EdgeInsetsGeometry? padding; /// 外边距 final EdgeInsetsGeometry? margin; /// 宽度 final double? width; /// 高度 final double? height; /// 是否显示边框 final bool showBorder; const GlassPanel({ super.key, required this.child, this.blur = 20.0, this.backgroundColor, this.borderColor, this.borderRadius, this.padding, this.margin, this.width, this.height, this.showBorder = true, }); @override Widget build(BuildContext context) { final bgColor = backgroundColor ?? AppColorScheme.glassPanelBackground; final brColor = borderColor ?? AppColorScheme.glassPanelBorder; final br = borderRadius ?? BorderRadius.circular(AppRadius.xl); Widget content = ClipRRect( borderRadius: br, child: BackdropFilter( filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), child: Container( width: width, height: height, padding: padding ?? EdgeInsets.all(AppSpacing.md), decoration: BoxDecoration( color: bgColor, borderRadius: br, border: showBorder ? Border.all( color: brColor, width: 1, ) : null, ), child: child, ), ), ); if (margin != null) { content = Padding( padding: margin!, child: content, ); } return content; } } /// GlassCard - 带毛玻璃效果的卡片 /// /// 用于列表项、信息展示等场景 /// 预设了常用配置,简化使用 class GlassCard extends StatelessWidget { /// 子组件 final Widget child; /// 点击回调 final VoidCallback? onTap; /// 长按回调 final VoidCallback? onLongPress; /// 内边距 final EdgeInsetsGeometry? padding; /// 外边距 final EdgeInsetsGeometry? margin; /// 圆角 final BorderRadius? borderRadius; /// 是否显示霓虹光效 final bool showNeonGlow; /// 霓虹光效颜色 final Color? neonGlowColor; const GlassCard({ super.key, required this.child, this.onTap, this.onLongPress, this.padding, this.margin, this.borderRadius, this.showNeonGlow = false, this.neonGlowColor, }); @override Widget build(BuildContext context) { final br = borderRadius ?? BorderRadius.circular(AppRadius.xl); final glowColor = neonGlowColor ?? AppColorScheme.neonGlowPrimary; Widget card = GlassPanel( padding: padding ?? EdgeInsets.all(AppSpacing.md), margin: margin, borderRadius: br, child: child, ); if (showNeonGlow) { card = Container( decoration: BoxDecoration( borderRadius: br, boxShadow: [ BoxShadow( color: glowColor, blurRadius: 15, spreadRadius: 0, ), ], ), child: card, ); } if (onTap != null || onLongPress != null) { return GestureDetector( onTap: onTap, onLongPress: onLongPress, child: card, ); } return card; } } /// GlassBottomSheet - 毛玻璃底部抽屉 /// /// 用于弹出的底部面板 class GlassBottomSheet extends StatelessWidget { /// 子组件 final Widget child; /// 标题 final String? title; /// 是否显示关闭按钮 final bool showCloseButton; /// 内边距 final EdgeInsetsGeometry? padding; const GlassBottomSheet({ super.key, required this.child, this.title, this.showCloseButton = true, this.padding, }); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: AppColorScheme.glassPanelBackground, borderRadius: const BorderRadius.vertical( top: Radius.circular(AppRadius.xxl), ), border: Border.all( color: AppColorScheme.glassPanelBorder, ), ), child: ClipRRect( borderRadius: const BorderRadius.vertical( top: Radius.circular(AppRadius.xxl), ), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), child: Column( mainAxisSize: MainAxisSize.min, children: [ // 顶部拖动条 Container( margin: const EdgeInsets.only(top: 12, bottom: 8), width: 40, height: 4, decoration: BoxDecoration( color: AppColorScheme.darkOutlineVariant.withValues(alpha: 0.5), borderRadius: BorderRadius.circular(2), ), ), // 标题栏 if (title != null || showCloseButton) Padding( padding: EdgeInsets.fromLTRB( AppSpacing.lg, AppSpacing.sm, AppSpacing.sm, AppSpacing.md, ), child: Row( children: [ if (title != null) Expanded( child: Text( title!, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: AppColorScheme.darkOnSurface, ), ), ), if (showCloseButton) GestureDetector( onTap: () => Navigator.of(context).pop(), child: Container( padding: EdgeInsets.all(AppSpacing.sm), decoration: BoxDecoration( color: AppColorScheme.darkOutlineVariant .withValues(alpha: 0.2), shape: BoxShape.circle, ), child: const Icon( Icons.close, size: 18, color: AppColorScheme.darkOnSurfaceVariant, ), ), ), ], ), ), // 内容 Padding( padding: padding ?? EdgeInsets.fromLTRB( AppSpacing.lg, 0, AppSpacing.lg, AppSpacing.xl, ), child: child, ), ], ), ), ), ); } /// 显示底部抽屉 static Future show({ required BuildContext context, required Widget Function(BuildContext) builder, bool isScrollControlled = false, bool isDismissible = true, bool enableDrag = true, }) { return showModalBottomSheet( context: context, isScrollControlled: isScrollControlled, isDismissible: isDismissible, enableDrag: enableDrag, backgroundColor: Colors.transparent, builder: builder, ); } }