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
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, ), ), ), ), ), ); } }
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
totrue
, andonExit
sets it tofalse
.
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
istrue
,widget.hoverGradientColors
is used for the gradient. - When
_isHovered
isfalse
, the defaultwidget.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.
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.