Outlined transparent button with gradient border in flutter

后端 未结 3 1650
情歌与酒
情歌与酒 2021-02-02 00:11

Is it possible to create an outlined(transparent) button with gradient border in flutter? I tried to use LinearGradient in BorderSide style but it\'s not allowed.

3条回答
  •  一生所求
    2021-02-02 01:02

    I spent about two hours on it :)

    how to use:

    import 'package:flutter/material.dart';
    
    void main() => runApp(App());
    
    class App extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: SafeArea(
              child: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    UnicornOutlineButton(
                      strokeWidth: 2,
                      radius: 24,
                      gradient: LinearGradient(colors: [Colors.black, Colors.redAccent]),
                      child: Text('OMG', style: TextStyle(fontSize: 16)),
                      onPressed: () {},
                    ),
                    SizedBox(width: 0, height: 24),
                    UnicornOutlineButton(
                      strokeWidth: 4,
                      radius: 16,
                      gradient: LinearGradient(
                        colors: [Colors.blue, Colors.yellow],
                        begin: Alignment.topCenter,
                        end: Alignment.bottomCenter,
                      ),
                      child: Text('Wow', style: TextStyle(fontSize: 16)),
                      onPressed: () {},
                    ),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    

    and the class itself:

    class UnicornOutlineButton extends StatelessWidget {
      final _GradientPainter _painter;
      final Widget _child;
      final VoidCallback _callback;
      final double _radius;
    
      UnicornOutlineButton({
        @required double strokeWidth,
        @required double radius,
        @required Gradient gradient,
        @required Widget child,
        @required VoidCallback onPressed,
      })  : this._painter = _GradientPainter(strokeWidth: strokeWidth, radius: radius, gradient: gradient),
            this._child = child,
            this._callback = onPressed,
            this._radius = radius;
    
      @override
      Widget build(BuildContext context) {
        return CustomPaint(
          painter: _painter,
          child: GestureDetector(
            behavior: HitTestBehavior.translucent,
            onTap: _callback,
            child: InkWell(
              borderRadius: BorderRadius.circular(_radius),
              onTap: _callback,
              child: Container(
                constraints: BoxConstraints(minWidth: 88, minHeight: 48),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    _child,
                  ],
                ),
              ),
            ),
          ),
        );
      }
    }
    
    class _GradientPainter extends CustomPainter {
      final Paint _paint = Paint();
      final double radius;
      final double strokeWidth;
      final Gradient gradient;
    
      _GradientPainter({@required double strokeWidth, @required double radius, @required Gradient gradient})
          : this.strokeWidth = strokeWidth,
            this.radius = radius,
            this.gradient = gradient;
    
      @override
      void paint(Canvas canvas, Size size) {
        // create outer rectangle equals size
        Rect outerRect = Offset.zero & size;
        var outerRRect = RRect.fromRectAndRadius(outerRect, Radius.circular(radius));
    
        // create inner rectangle smaller by strokeWidth
        Rect innerRect = Rect.fromLTWH(strokeWidth, strokeWidth, size.width - strokeWidth * 2, size.height - strokeWidth * 2);
        var innerRRect = RRect.fromRectAndRadius(innerRect, Radius.circular(radius - strokeWidth));
    
        // apply gradient shader
        _paint.shader = gradient.createShader(outerRect);
    
        // create difference between outer and inner paths and draw it
        Path path1 = Path()..addRRect(outerRRect);
        Path path2 = Path()..addRRect(innerRRect);
        var path = Path.combine(PathOperation.difference, path1, path2);
        canvas.drawPath(path, _paint);
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => oldDelegate != this;
    }
    

提交回复
热议问题