Button 010 — Flutter Button Widget

Free copy-paste Button 010 for Flutter: a ready-to-use button widget with full Dart source code and a live preview. Works on desktop. No external packages.

  • Category: Buttons
  • Platforms: desktop
  • Flutter SDK only — no external packages
  • Free to copy & use

How to use Button 010 in Flutter

Copy the Dart code below into a new file in your Flutter project (for example lib/widgets/button_010.dart) and use the widget anywhere in your widget tree.

Button 010 – Dart source code

import 'package:flutter/material.dart';

class Button010 extends StatefulWidget {
  const Button010({
    super.key,
    this.label = 'Hover me',
    this.onTap,
    this.lineColor = const Color(0xFFF44336),
    this.textColor = Colors.white,
    this.fontSize = 25.0,
    this.duration = const Duration(milliseconds: 1000),
  });

  final String label;
  final VoidCallback? onTap;
  final Color lineColor, textColor;
  final double fontSize;
  final Duration duration;

  @override
  State<Button010> createState() => _Button010State();
}

class _Button010State extends State<Button010>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late final Animation<double> _anim;
  bool _pressed = false;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: widget.duration);
    _anim = CurvedAnimation(parent: _controller, curve: Curves.easeInOutCubic);
  }

  @override
  void didUpdateWidget(covariant Button010 oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.duration != widget.duration) {
      _controller.duration = widget.duration;
    }
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _onHover(bool hover) {
    if (hover) {
      _controller.forward();
    } else {
      _controller.reverse();
    }
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      opaque: true,
      cursor: SystemMouseCursors.click,
      onEnter: (_) => _onHover(true),
      onExit: (_) => _onHover(false),
      child: GestureDetector(
        behavior: HitTestBehavior.opaque,
        onTapDown: (_) => setState(() => _pressed = true),
        onTapUp: (_) {
          setState(() => _pressed = false);
          widget.onTap?.call();
        },
        onTapCancel: () => setState(() => _pressed = false),
        child: AnimatedScale(
          scale: _pressed ? 0.96 : 1.0,
          duration: const Duration(milliseconds: 100),
          child: AnimatedBuilder(
            animation: _anim,
            builder: (context, child) {
              return CustomPaint(
                foregroundPainter: _UnderlineHoverPainter(
                  progress: _anim.value,
                  lineColor: widget.lineColor,
                ),
                child: child,
              );
            },
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 6),
              child: Text(
                widget.label,
                style: TextStyle(
                  color: widget.textColor,
                  fontSize: widget.fontSize,
                  fontWeight: FontWeight.w600,
                  letterSpacing: 0.5,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class _UnderlineHoverPainter extends CustomPainter {
  const _UnderlineHoverPainter({
    this.progress = 0.0,
    this.lineColor = const Color(0xFFF44336),
  });

  final double progress;
  final Color lineColor;

  @override
  void paint(Canvas canvas, Size size) {
    if (progress <= 0.0) return;

    final Paint paint = Paint()
      ..color = lineColor
      ..style = PaintingStyle.fill;

    const double lineHeight = 2.0;
    final double lineWidth = size.width * progress;

    canvas.drawRect(
      Rect.fromLTWH(size.width - lineWidth, 0, lineWidth, lineHeight),
      paint,
    );

    canvas.drawRect(
      Rect.fromLTWH(0, size.height - lineHeight, lineWidth, lineHeight),
      paint,
    );
  }

  @override
  bool shouldRepaint(_UnderlineHoverPainter oldDelegate) {
    return oldDelegate.progress != progress ||
        oldDelegate.lineColor != lineColor;
  }
}

More Flutter Buttons