Rick
Rick

Reputation: 2271

How to create a button with rounded corner, and gradient background?

I have been trying to create a raised button with a rounded corner, and gradient background but to no success. I can only implement one or the other. It's been 2 hours and I haven't found a solution myself, on how I can implement both a rounded corner, and a gradient background together.

Below are my codes of my latest attempt to implement a raised button with rounded corner, and gradient background.

Custom class of GradientButton

class RaisedGradientButton extends StatelessWidget {
  final Widget child;
  final Gradient gradient;
  final double width;
  final double height;
  final Function onPressed;

  const RaisedGradientButton({
    Key key,
    @required this.child,
    this.gradient,
    this.width = double.infinity,
    this.height = 50.0,
    this.onPressed,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: width,
      height: 50.0,
      decoration: BoxDecoration(
        gradient: new LinearGradient(
          colors: [
            Colors.blue,
            Colors.red,
          ],
          begin: FractionalOffset.centerLeft,
          end: FractionalOffset.centerRight,
        ),
      ),
      child: Material(
        shape: new RoundedRectangleBorder(
            borderRadius: new BorderRadius.circular(128.0)),
//        color: Colors.transparent,
        child: InkWell(
            onTap: onPressed,
            child: Center(
              child: child,
            )),
      ),
    );
  }
}

How I use the above code:

RaisedGradientButton(
    onPressed: navigateToNextPage,
        child: Text("Select Community"),
)

How it looks like:

enter image description here

As you can see, the gradient is there, but when I attempt to create a rounded corner, it overlaps, and the gradient is behind.

Upvotes: 3

Views: 7158

Answers (4)

CopsOnRoad
CopsOnRoad

Reputation: 267584

Use ElevatedButton (Recommended as of Flutter 2.0)

enter image description here


@override
Widget build(BuildContext context) {
  final radius = BorderRadius.circular(20);
  return Scaffold(
    body: Center(
      child: DecoratedBox(
        decoration: BoxDecoration(
          gradient: LinearGradient(colors: [Colors.cyanAccent, Colors.red]),
          borderRadius: radius,
        ),
        child: ElevatedButton(
          onPressed: () {},
          child: Text('Elevated Button'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.transparent,
            shape: RoundedRectangleBorder(borderRadius: radius),
          ),
        ),
      ),
    ),
  );
}

Upvotes: 1

Debanjan
Debanjan

Reputation: 2836

There is a simple solution. Add the same border radius to both the button and the container inside the button. Here is a simple example.

RaisedButton(
   onPressed: () {},
   textColor: Colors.white,
   color: Colors.transparent,
   padding: EdgeInsets.all(0),
   shape: RoundedRectangleBorder(
      borderRadius: new BorderRadius.circular(18.0),
   ),
   child: Container(
      decoration: BoxDecoration(
         borderRadius: BorderRadius.circular(18),
         gradient: LinearGradient(
            colors: <Color>[
               Colors.black38,
               Colors.black26,
               Colors.white38,
            ],
         ),
      ),
      padding: const EdgeInsets.fromLTRB(24, 12, 24, 12),
      child: const Text('Sign In', style: TextStyle(fontSize: 20)),
   ),
),

screenshot

Upvotes: 3

Rick
Rick

Reputation: 2271

If anyone ever encounters the same issue. Here is my code on how I got it solved.

class GradientButton extends StatelessWidget {
  final Widget child;

  // final Gradient gradient;
  final double width;
  final double height;
  final bool isEnabled;
  final Function onPressed;

  const GradientButton({
    Key key,
    @required this.child,
    // this.gradient,
    this.isEnabled,
    this.width,
    this.height,
    this.onPressed,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Color _statusColor;
    if (isEnabled != null) {
      // Show gradient color by making material widget transparent
      if (isEnabled == true) {
        _statusColor = Colors.transparent;
      } else {
        // Show grey color if isEnabled is false
        _statusColor = Colors.grey;
      }
    } else {
      // Show grey color if isEnabled is null
      _statusColor = Colors.transparent;
    }

    return Container(
      width: width,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(8),
        gradient: LinearGradient(
          colors: [
            Color(0xFF3186E3),
            Color(0xFF1D36C4),
          ],
          begin: FractionalOffset.centerLeft,
          end: FractionalOffset.centerRight,
        ),
      ),
      child: Material(
          shape: RoundedRectangleBorder(
              borderRadius: new BorderRadius.circular(4)),
          color: _statusColor,
          child: InkWell(
              borderRadius: BorderRadius.circular(32),
              onTap: onPressed,
              child: Padding(
                padding: EdgeInsets.fromLTRB(24, 16, 24, 16),
                child: Center(
                  child: child,
                ),
              ))),
    );
  }
}

Upvotes: 0

foxanna
foxanna

Reputation: 1570

I suggest you put a Container with a gradient below the button in a Stack and cut its corners with ClipRRect while leaving the button's color transparent. This way you keep touch feedback and pressed button shadow, as well as accessibility support.

class RaisedGradientButton extends StatelessWidget {
  final Widget child;
  final Gradient gradient;
  final double width;
  final double height;
  final Function onPressed;
  final borderRadius = BorderRadius.circular(128.0);

  RaisedGradientButton({
    Key key,
    @required this.child,
    Gradient gradient,
    this.width = double.infinity,
    this.height = 50.0,
    this.onPressed,
  })  : this.gradient = gradient ??
            LinearGradient(
              colors: [
                Colors.blue,
                Colors.red,
              ],
              begin: FractionalOffset.centerLeft,
              end: FractionalOffset.centerRight,
            ),
        super(key: key);

  @override
  Widget build(BuildContext context) => Stack(
        children: [
          Positioned.fill(
            child: ClipRRect(
              borderRadius: borderRadius,
              child: Container(
                width: width,
                height: height,
                decoration: BoxDecoration(
                  gradient: gradient,
                ),
              ),
            ),
          ),
          Container(
            width: width,
            height: height,
            child: RaisedButton(
              shape: RoundedRectangleBorder(
                borderRadius: borderRadius,
              ),
              padding: EdgeInsets.zero,
              child: Center(child: child),
              onPressed: onPressed,
              color: Colors.transparent,
            ),
          ),
        ],
      );
}

Upvotes: 2

Related Questions