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: TheBoxDecoration 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 colors, borderRadius , 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!"); }, ), ), ); } }
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.
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
MediaQueryto 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, ), ), ), ), ), ); } }
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.
onEntersets_isHoveredtotrue, andonExitsets it tofalse.
2. AnimatedContainer:
- Used to smoothly animate the gradient color change when hovering.
- The
durationproperty specifies the animation duration for the hover effect.
3. Gradient Colors on Hover:
- When
_isHoveredistrue,widget.hoverGradientColorsis used for the gradient. - When
_isHoveredisfalse, the defaultwidget.gradientColorsis 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.
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!"); }, ), ), ); } }
width and height values as needed or even make them responsive based on the screen size.
