Flutter: Gradient rounded button

 To create a gradient rounded button, we will use the Container widget with a BoxDecoration that includes both a LinearGradient for the background color and BorderRadius for the rounded corners. Wrap this Container inside a GestureDetector or InkWell to make it respond to touch events. 

Here’s a code snippet for our stateless widget (gradient_rounded_button.dart):

import 'package:flutter/material.dart';

class GradientRoundedButton extends StatelessWidget {
  final double borderRadius;
  final String text;
  final List<Color> gradientColors;
  final VoidCallback onPressed;

  const GradientRoundedButton({
    required this.text,
    required this.gradientColors,
    required this.onPressed,
    this.borderRadius = 30,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onPressed,
      child: Container(
        padding: EdgeInsets.symmetric(vertical: 15, horizontal: 30),
        decoration: BoxDecoration(
          gradient: LinearGradient(
            colors: gradientColors,
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
          ),
          borderRadius: BorderRadius.circular(borderRadius),
          boxShadow: [
            BoxShadow(
              color: gradientColors.last.withOpacity(0.5),
              offset: Offset(0, 4),
              blurRadius: 10,
            ),
          ],
        ),
        child: Center(
          child: Text(
            text,
            style: TextStyle(
              color: Colors.white,
              fontSize: 16,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
      ),
    );
  }
}

Explanation of important keys to make this widget 

    1. Gradient: The BoxDecoration uses a LinearGradient to apply a gradient effect with gradientColors, which you can customize by passing a list of colors.
    2. Rounded Corners: The borderRadius property of BoxDecoration rounds the corners. Adjust the BorderRadius.circular value to change the level of roundness.
    3. Shadow: The boxShadow property adds a subtle shadow effect, using the last color in gradientColors for a cohesive look.
    4. Text and Gesture: The GestureDetector wraps the Container, making the button tappable. Text styling is applied for better readability over the gradient background.

Usage of the widget

In the code above, the GradientRoundedButton widget is reusable. Pass the text, gradient colorsborderRadius , and an onPressed callback to create multiple gradient buttons with different styles. Here is an example on how to use the widget (main.dart).

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: GradientRoundedButtonDemo(),
    );
  }
}

class GradientRoundedButtonDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Gradient Rounded Button"),
      ),
      body: Center(
        child: GradientRoundedButton(
          text: "PressMe",
          gradientColors: [Colors.blue, Colors.purple],
          onPressed: () {
            print("Button Pressed!");
          },
        ),
      ),
    );
  }
}

(Hmmmm...) This is the sample result of the above code.

The output sample above does not give users feedback when the user interacts with the UI. We need to enhance the widget we created to make the button feel more responsive and polished. And, in the current state of the button we need to wrap it with the other widget to define the width and height.

By adding hover effects, as well as specifying the width and height for buttons, we can enhance the user interface, especially in applications where user interaction is essential, such as on desktops or web platforms. Here’s why these additions are beneficial:

1. Hover Effects

  • Improved User Experience: Hover effects give users feedback when they interact with UI elements, making the application feel more responsive and polished.
  • Visual Cue: Hovering can signal to the user that the element is clickable or interactive, which is particularly important on larger screens (like desktop and web) where the pointer is used.
  • Aesthetic Appeal: Transitioning colors or shadows when hovering can add a level of visual sophistication, making the app feel more engaging and modern.

In Flutter, hover effects are especially relevant when building apps that run on desktops or web, where the user interacts with the UI via a mouse or trackpad rather than just touch.

2. Width and Height

  • Consistent Button Size: Specifying width and height ensures the button remains consistent in size across different screens or layouts. Without set dimensions, the button might resize based on its content, leading to a less uniform appearance.
  • Layout Control: Setting dimensions allows you to control the exact placement and alignment of the button within its parent container, giving you more control over the overall layout.
  • Responsive Design: On larger screens, having specific dimensions prevents UI elements from looking disproportionately small or large. You can also make the dimensions responsive to adapt to different screen sizes (e.g., by using MediaQuery to set the size based on screen dimensions).

Updated Code Example with Hover Effects, and  Width and Height

Here’s an updated code (gradient_rounded_button.dart) that includes hover colors, and width and height for the button:

class GradientRoundedButton extends StatefulWidget {
  final double? width;
  final double? height;
  final String text;
  final List<Color> gradientColors;
  final List<Color> hoverGradientColors;
  final VoidCallback onPressed;

  const GradientRoundedButton({
    required this.text,
    required this.gradientColors,
    required this.hoverGradientColors,
    required this.onPressed,
    this.width,
    this.height,
  });

  @override
  _GradientRoundedButtonState createState() => _GradientRoundedButtonState();
}

class _GradientRoundedButtonState extends State<GradientRoundedButton> {
  bool _isHovered = false;

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onEnter: (_) {
        setState(() {
          _isHovered = true;
        });
      },
      onExit: (_) {
        setState(() {
          _isHovered = false;
        });
      },
      child: GestureDetector(
        onTap: widget.onPressed,
        child: AnimatedContainer(
          width: widget.width,
          height: widget.height ?? 50,
          duration: Duration(milliseconds: 200),
          padding: EdgeInsets.symmetric(vertical: 15, horizontal: 30),
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: _isHovered ? widget.hoverGradientColors : widget.gradientColors,
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
            ),
            borderRadius: BorderRadius.circular(30),
            boxShadow: [
              BoxShadow(
                color: (_isHovered ? widget.hoverGradientColors.last : widget.gradientColors.last).withOpacity(0.5),
                offset: Offset(0, 4),
                blurRadius: 10,
              ),
            ],
          ),
          child: Center(
            child: Text(
              widget.text,
              style: TextStyle(
                color: Colors.white,
                fontSize: 16,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

As we can see in the updated codes, we changed from StatelessWidget into StatefulWidget and added some properties for hoverGradientColors  , and width /height . And wrap it with MouseRegion with a core functions onEnter and onExit that handles the changes of the hover state.

Explanation of the changes

    1. MouseRegion Widget:

    • Wraps the button to detect mouse enter and exit events.
    • onEnter sets _isHovered to true, and onExit sets it to false.

    2. AnimatedContainer:

    • Used to smoothly animate the gradient color change when hovering.
    • The duration property specifies the animation duration for the hover effect.

    3. Gradient Colors on Hover:

    • When _isHovered is true, widget.hoverGradientColors is used for the gradient.
    • When _isHovered is false, the default widget.gradientColors is used.

    4. Hover Shadow:

    • Adjusts the shadow color based on whether the button is hovered, creating a subtle shadow effect that changes with the gradient.

Usage of the changes

In this example, you specify both the normal gradient colors (gradientColors) and the hover gradient colors (hoverGradientColors) when creating the GradientRoundedButton. Now, when you hover over the button, it will smoothly transition to the hover gradient colors. Adjust the colors as needed for your desired hover effect.


Here is the example of the updated code for (main.dart).

class GradientRoundedButtonDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Gradient Rounded Button"),
      ),
      body: Center(
        child: GradientRoundedButton(
          width: 200,
          text: "Press Me",
          gradientColors: [Colors.blue, Colors.purple],
          hoverGradientColors: [Colors.purple, Colors.blue],
          onPressed: () {
            // Handle button press
            print("Button Pressed!");
          },
        ),
      ),
    );
  }
}

The final result of our changes.



With these adjustments, the button will have a consistent size and a responsive hover effect, making it well-suited for web or desktop applications. You can modify width and height values as needed or even make them responsive based on the screen size.

Previous Post Next Post

نموذج الاتصال