QinGang_interested/lib/customWidget/custom_button.dart

174 lines
5.2 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'package:flutter/material.dart';
/// 按钮样式类型
enum ButtonStyleType {
primary, // 主样式:纯色背景,无边框
secondary, // 次样式:白色背景,深灰文字,深灰边框
}
/// 自定义默认按钮(支持不可点击/禁用状态和防连点功能)
class CustomButton extends StatefulWidget {
final String text; // 按钮文字
final Color backgroundColor; // 按钮背景色
final double borderRadius; // 圆角半径默认5
final VoidCallback? onPressed; // 点击事件回调
final EdgeInsetsGeometry? padding; // 内边距
final EdgeInsetsGeometry? margin; // 外边距
final double? height; // 按钮高度
final TextStyle? textStyle; // 文字样式
/// 新增是否可点击true 可点false 禁用)
/// 注意:如果 onPressed 为 null也会被视为不可点击
final bool enabled;
/// 新增:禁用时的背景色(可选)
final Color? disabledBackgroundColor;
/// 新增:禁用时的文字颜色(可选)
final Color? disabledTextColor;
/// 新增:文字颜色(可选)
final Color? textColor;
/// 新增:防连点间隔时间(毫秒)
final int debounceInterval;
/// 新增:按钮样式类型
final ButtonStyleType buttonStyle;
/// 新增:边框颜色(仅在 secondary 样式下使用,如不指定则使用默认深灰色)
final Color? borderColor;
/// 新增:边框宽度(仅在 secondary 样式下使用)
final double borderWidth;
const CustomButton({
super.key,
required this.text,
this.backgroundColor = Colors.blue,
this.borderRadius = 5.0,
this.onPressed,
this.padding,
this.margin,
this.height,
this.textStyle,
this.textColor,
this.enabled = true,
this.disabledBackgroundColor,
this.disabledTextColor,
this.debounceInterval = 1000, // 默认1秒防连点
this.buttonStyle = ButtonStyleType.primary, // 默认为主样式
this.borderColor,
this.borderWidth = 1.0,
});
@override
State<CustomButton> createState() => _CustomButtonState();
}
class _CustomButtonState extends State<CustomButton> {
// 记录最后一次点击时间
DateTime _lastClickTime = DateTime(0);
@override
Widget build(BuildContext context) {
// 如果 enabled 为 false 或 onPressed 为 null则视为不可点击
final bool isEnabled = widget.enabled && widget.onPressed != null;
// 根据按钮样式计算背景色、文字颜色和边框
final Color bgColor;
final Color textColor;
final Color? borderColor;
if (widget.buttonStyle == ButtonStyleType.secondary) {
// 次样式:白色背景,深灰文字,深灰边框
bgColor = isEnabled
? Colors.white
: (widget.disabledBackgroundColor ?? Colors.grey.shade200);
textColor = isEnabled
? Colors.grey[800]!
: (widget.disabledTextColor ?? Colors.grey.shade500);
borderColor = isEnabled
? (widget.borderColor ?? Colors.grey.shade400)
: (widget.disabledTextColor ?? Colors.grey.shade300);
} else {
// 主样式:原有逻辑
bgColor = isEnabled
? widget.backgroundColor
: (widget.disabledBackgroundColor ?? Colors.grey.shade400);
textColor = widget.textColor ?? (isEnabled ? Colors.white : (widget
.disabledTextColor ?? Colors.white70));
borderColor = null; // 主样式默认无边框
}
// 计算最终文字样式
TextStyle finalTextStyle;
if (widget.textStyle != null) {
finalTextStyle = widget.textStyle!.copyWith(color: textColor);
} else {
finalTextStyle = TextStyle(
color: textColor,
fontSize: 14,
fontWeight: FontWeight.bold,
);
}
// 处理点击事件(添加防连点逻辑)
void handleOnPressed() {
final now = DateTime.now();
if (now
.difference(_lastClickTime)
.inMilliseconds < widget.debounceInterval) {
// 在防连点间隔内,不执行操作
return;
}
_lastClickTime = now;
if (widget.onPressed != null) {
widget.onPressed!();
}
}
// 构建边框
final BoxBorder? border = borderColor != null
? Border.all(
color: borderColor,
width: widget.borderWidth,
)
: null;
// 点击拦截器 + 视觉反馈(禁用时降低不透明度)
return Opacity(
opacity: isEnabled ? 1.0 : 0.65,
child: AbsorbPointer(
absorbing: !isEnabled,
child: GestureDetector(
onTap: isEnabled ? handleOnPressed : null,
child: Container(
height: widget.height ?? 45,
// 默认高度45
padding: widget.padding ?? const EdgeInsets.all(6),
// 默认内边距
margin: widget.margin ?? const EdgeInsets.symmetric(horizontal: 5),
// 默认外边距
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(widget.borderRadius),
color: bgColor,
border: border,
),
child: Center(
child: Text(
widget.text,
style: finalTextStyle,
),
),
),
),
),
);
}
}