import 'dart:math' as math;
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
class CustomButton extends StatefulWidget {
const CustomButton({
Key key,
@required this.onPressed,
this.onLongPress,
this.onHighlightChanged,
this.mouseCursor,
this.fillColor,
this.focusColor,
this.hoverColor,
this.highlightColor,
this.splashColor,
this.backgroundColor = const Color(0xfff3f5f9),
this.padding = EdgeInsets.zero,
this.borderRadius = 0.0,
this.visualDensity = const VisualDensity(),
this.shape,
this.showAnimation = true,
this.animationDuration = kThemeChangeDuration,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
MaterialTapTargetSize materialTapTargetSize,
this.child,
this.enableFeedback = true,
}) : materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded,
assert(padding != null),
assert(animationDuration != null),
assert(clipBehavior != null),
assert(autofocus != null),
super(key: key);
final VoidCallback onPressed;
final VoidCallback onLongPress;
final ValueChanged<bool> onHighlightChanged;
final MouseCursor mouseCursor;
final Color fillColor;
final Color focusColor;
final Color hoverColor;
final Color highlightColor;
final Color splashColor;
final Color backgroundColor;
final EdgeInsetsGeometry padding;
final double borderRadius;
final VisualDensity visualDensity;
final ShapeBorder shape;
final Duration animationDuration;
final bool showAnimation;
final Widget child;
bool get enabled => onPressed != null || onLongPress != null;
final MaterialTapTargetSize materialTapTargetSize;
final FocusNode focusNode;
final bool autofocus;
final Clip clipBehavior;
final bool enableFeedback;
@override
State<StatefulWidget> createState() => _CustomButtonState();
}
class _CustomButtonState extends State<CustomButton> {
final Set<MaterialState> _states = <MaterialState>{};
bool get _hovered => _states.contains(MaterialState.hovered);
bool get _focused => _states.contains(MaterialState.focused);
bool get _pressed => _states.contains(MaterialState.pressed);
bool get _disabled => _states.contains(MaterialState.disabled);
void _updateState(MaterialState state, bool value) {
value ? _states.add(state) : _states.remove(state);
}
void _handleHighlightChanged(bool value) {
if (_pressed != value) {
setState(() {
_updateState(MaterialState.pressed, value);
if (widget.onHighlightChanged != null) {
widget.onHighlightChanged(value);
}
});
}
}
void _handleHoveredChanged(bool value) {
if (_hovered != value) {
setState(() {
_updateState(MaterialState.hovered, value);
});
}
}
void _handleFocusedChanged(bool value) {
if (_focused != value) {
setState(() {
_updateState(MaterialState.focused, value);
});
}
}
@override
void initState() {
super.initState();
_updateState(MaterialState.disabled, !widget.enabled);
}
@override
void didUpdateWidget(CustomButton oldWidget) {
super.didUpdateWidget(oldWidget);
_updateState(MaterialState.disabled, !widget.enabled);
if (_disabled && _pressed) {
_handleHighlightChanged(false);
}
}
double get _effectiveElevation {
if (_disabled) {
return 0.0;
}
if (_pressed) {
return 8.0;
}
if (_hovered) {
return 4.0;
}
if (_focused) {
return 4.0;
}
return 2.0;
}
@override
Widget build(BuildContext context) {
final shape = widget.shape ?? RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(widget.borderRadius)));
final ShapeBorder effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(shape, _states);
final Offset densityAdjustment = widget.visualDensity.baseSizeAdjustment;
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
widget.mouseCursor ?? MaterialStateMouseCursor.clickable,
_states,
);
final EdgeInsetsGeometry padding = widget.padding.add(
EdgeInsets.only(
left: densityAdjustment.dx,
top: densityAdjustment.dy,
right: densityAdjustment.dx,
bottom: densityAdjustment.dy,
),
).clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity);
final Widget inkWell = InkWell(
focusNode: widget.focusNode,
canRequestFocus: widget.enabled,
onFocusChange: _handleFocusedChanged,
autofocus: widget.autofocus,
onHighlightChanged: _handleHighlightChanged,
splashColor: widget.splashColor,
highlightColor: widget.highlightColor,
focusColor: widget.focusColor,
hoverColor: widget.hoverColor,
onHover: _handleHoveredChanged,
onTap: widget.onPressed,
onLongPress: widget.onLongPress,
enableFeedback: widget.enableFeedback,
customBorder: effectiveShape,
mouseCursor: effectiveMouseCursor,
child: Container(
padding: padding,
child: widget.child,
),
);
if (widget.showAnimation == false)
return backgroundCard(inkWell);
final Widget result = Material(
elevation: _effectiveElevation,
shape: effectiveShape,
color: widget.fillColor,
type: widget.fillColor == null ? MaterialType.transparency : MaterialType.button,
animationDuration: widget.animationDuration,
clipBehavior: widget.clipBehavior,
child: inkWell,
);
Size minSize;
switch (widget.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
minSize = Size(
densityAdjustment.dx,
densityAdjustment.dy,
);
assert(minSize.width >= 0.0);
assert(minSize.height >= 0.0);
break;
case MaterialTapTargetSize.shrinkWrap:
minSize = Size.zero;
break;
}
return backgroundCard(result);
}
Widget backgroundCard(Widget child) {
return Container(
child: child,
decoration: BoxDecoration(
borderRadius:BorderRadius.all(Radius.circular(widget.borderRadius)),
color: widget.backgroundColor,
),);
}
}