import 'package:flutter/material.dart'; import '../../theme/app_colors.dart'; import '../../utils/constants.dart'; /// 按钮类型 enum ButtonType { primary, secondary, danger, text } /// 按钮尺寸 enum ButtonSize { small, medium, large } /// 应用按钮组件 class AppButton extends StatelessWidget { final String? text; final Widget? child; final VoidCallback? onPressed; final ButtonType type; final ButtonSize size; final bool loading; final IconData? icon; final bool fullWidth; const AppButton({ Key? key, this.text, this.child, this.onPressed, this.type = ButtonType.primary, this.size = ButtonSize.medium, this.loading = false, this.icon, this.fullWidth = false, }) : assert(text != null || child != null, 'text or child must be provided'), super(key: key); @override Widget build(BuildContext context) { final content = child ?? Text(text!); final buttonContent = loading ? SizedBox( width: _getIconSize(), height: _getIconSize(), child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(_getTextColor()), ), ) : Row( mainAxisSize: fullWidth ? MainAxisSize.max : MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ if (icon != null) ...[ Icon(icon, size: _getIconSize(), color: _getTextColor()), SizedBox(width: AppSpacing.sm), ], content, ], ); final button = _buildButton(context, buttonContent); if (fullWidth) { return SizedBox(width: double.infinity, child: button); } return button; } Widget _buildButton(BuildContext context, Widget content) { switch (type) { case ButtonType.primary: return ElevatedButton( onPressed: loading ? null : onPressed, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: Colors.white, padding: _getPadding(), minimumSize: Size(0, _getHeight()), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), ), child: content, ); case ButtonType.secondary: return OutlinedButton( onPressed: loading ? null : onPressed, style: OutlinedButton.styleFrom( foregroundColor: AppColors.primary, padding: _getPadding(), minimumSize: Size(0, _getHeight()), side: const BorderSide(color: AppColors.primary), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), ), child: content, ); case ButtonType.danger: return ElevatedButton( onPressed: loading ? null : onPressed, style: ElevatedButton.styleFrom( backgroundColor: AppColors.error, foregroundColor: Colors.white, padding: _getPadding(), minimumSize: Size(0, _getHeight()), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), ), child: content, ); case ButtonType.text: return TextButton( onPressed: loading ? null : onPressed, style: TextButton.styleFrom( foregroundColor: AppColors.primary, padding: _getPadding(), minimumSize: Size(0, _getHeight()), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(6), ), ), child: content, ); } } EdgeInsets _getPadding() { switch (size) { case ButtonSize.small: return const EdgeInsets.symmetric(horizontal: 12, vertical: 6); case ButtonSize.medium: return const EdgeInsets.symmetric(horizontal: 24, vertical: 12); case ButtonSize.large: return const EdgeInsets.symmetric(horizontal: 32, vertical: 16); } } double _getHeight() { switch (size) { case ButtonSize.small: return 28; case ButtonSize.medium: return 40; case ButtonSize.large: return 48; } } double _getIconSize() { switch (size) { case ButtonSize.small: return 14; case ButtonSize.medium: return 18; case ButtonSize.large: return 20; } } Color _getTextColor() { switch (type) { case ButtonType.primary: case ButtonType.danger: return Colors.white; case ButtonType.secondary: case ButtonType.text: return AppColors.primary; } } }