flutter 带轮廓的透明按钮,带有飘动的渐变边框

643ylb08  于 2023-01-02  发布在  Flutter
关注(0)|答案(9)|浏览(246)

是否可以创建一个轮廓(透明)按钮与渐变边界在Flutter?我试图使用线性渐变在BorderSide风格,但它是不允许的。

7vhp5slm

7vhp5slm1#

我在上面花了大约两个小时:)

使用方法:

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: <Widget>[
                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: () {},
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

以及类本身:

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: <Widget>[
                _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;
}
ccrfmcuu

ccrfmcuu2#

你可以通过一个简单的技巧

你必须定义两个容器。第一个外部容器有渐变背景,第二个内部容器有白色背景。作为内部容器的子容器,你可以放置任何东西,例如TextFieldText,另一个按钮等。

final kInnerDecoration = BoxDecoration(
  color: Colors.white,
  border: Border.all(color: Colors.white),
  borderRadius: BorderRadius.circular(32),
);

final kGradientBoxDecoration = BoxDecoration(
  gradient: LinearGradient(colors: [Colors.black, Colors.redAccent]),
  border: Border.all(
    color: kHintColor,
  ),
  borderRadius: BorderRadius.circular(32),
);

现在这是您的视图

Container(
    child: Padding(
             padding: const EdgeInsets.all(2.0),
             child: Container(
                      child:Text("Button Title with your style"),
                      decoration: kInnerDecoration,
                    ),
           ),
    height: 66.0,
    decoration: kGradientBoxDecoration,
  ),

完成

ef1yzkbh

ef1yzkbh3#

使用OutlinedButton(推荐)

创建此类(null安全代码)

class MyOutlinedButton extends StatelessWidget {
  final VoidCallback onPressed;
  final Widget child;
  final ButtonStyle? style;
  final Gradient? gradient;
  final double thickness;

  const MyOutlinedButton({
    Key? key,
    required this.onPressed,
    required this.child,
    this.style,
    this.gradient,
    this.thickness = 2,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(gradient: gradient),
      child: Container(
        color: Colors.white,
        margin: EdgeInsets.all(thickness),
        child: OutlinedButton(
          onPressed: onPressed,
          style: style,
          child: child,
        ),
      ),
    );
  }
}

用法:

MyOutlinedButton(
  onPressed: () {},
  gradient: LinearGradient(colors: [Colors.indigo, Colors.pink]),
  child: Text('OutlinedButton'),
)
nhaq1z21

nhaq1z214#

要更改大小,您可以插入容器:

OutlineGradientButton(
  child: Container(
    constraints: BoxConstraints(maxWidth: 300, maxHeight: 50),
    height: 50,
    alignment: Alignment.center,
    child: Text(
      'Text',
      textAlign: TextAlign.center,
      style: TextStyle(
          color: Colors.white, fontSize: 20, fontWeight: FontWeight.w500),
    ),
  ),
  gradient: LinearGradient(
    colors: [Color(0xfff3628b), Color(0xffec3470)],
    begin: Alignment.topCenter,
    end: Alignment.bottomCenter,
  ),
  strokeWidth: 3,
  radius: Radius.circular(25),
),
ddrv8njm

ddrv8njm5#

你可以使用如下的结构。你也可以通过删除BorderRadius将它用作一个平面按钮。

InkWell(
      onTap: () {
        print("TAP");
      },
      child: Container(
        height: 85,
        width: 85,
        padding: EdgeInsets.all(6),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(100),
          gradient: LinearGradient(
            colors: [Colors.blue, Colors.black],
            begin: Alignment(-1, -1),
            end: Alignment(2, 2),
          ),
        ),
        child: Center(
          child: ClipRRect(
            borderRadius: BorderRadius.circular(100),
            child: Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(100),
                image: DecorationImage(
                  image: Image.network("https://images.unsplash.com/photo-1612151855475-877969f4a6cc?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8aGQlMjBpbWFnZXxlbnwwfHwwfHw%3D&w=400&q=80").image,
                  fit: BoxFit.fitHeight,
                ), //By deleting the image here, you can only use it text.
                color: Colors.white,
                border: Border.all(
                  color: Colors.white,
                  width: 4,
                ),
              ),
              child: Center(child: Text("sssss")), //By deleting the text here, you can only use it visually.
              width: 75,
              height: 75,
            ),
          ),
        ),
      ),
    )
ippsafx7

ippsafx76#

Package 您的构件宽度CustomPaint构件,并使用此扩展CustomPainter的**_CustomGradientBorder**。

CustomPaint(painter: const _CustomGradientBorder(thickness: 1,
      colors: [Colors.red, Colors.green, Colors.blue, Colors.tealAccent],
      radius: 8), child: //widget here)

class _CustomGradientBorder extends CustomPainter{
final double thickness;
final List<Color> colors;
final double radius;
const _CustomGradientBorder({required this.thickness, required this.colors, required this.radius});

@override
void paint(Canvas canvas, Size size) {
final Path path = Path();
path.moveTo(0, size.height/2);
path.lineTo(0, radius);
path.quadraticBezierTo(0, 0, radius, 0);
path.lineTo(size.width-radius, 0);
path.quadraticBezierTo(size.width, 0, size.width, radius);
path.lineTo(size.width, size.height-radius);
path.quadraticBezierTo(size.width, size.height, size.width-radius, size.height);
path.lineTo(radius, size.height);
path.quadraticBezierTo(0, size.height, 0, size.height-radius);
path.close();
final Paint paint = Paint()
..style = PaintingStyle.stroke
..shader = LinearGradient(colors: colors).createShader(Rect.fromCenter(center: Offset(size.width/2, size.height/2), width: size.width, height: size.height))
..strokeWidth = thickness;
canvas.drawPath(path, paint);
}

@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
  return true;
}

}

hm2xizp9

hm2xizp97#

class GradientBorderWidget extends StatelessWidget {
  final Widget child;
  const GradientBorderWidget({super.key, required this.child});
  @override
  Widget build(BuildContext context) {
  return Container(
  padding: const EdgeInsets.symmetric(horizontal: 1.5, vertical: 1.5),
  width: double.infinity,
  decoration: BoxDecoration(
      borderRadius: BorderRadius.circular(15),
      gradient: const LinearGradient(
          colors: [color1, color2, color3],
          begin: Alignment.centerLeft,
          end: Alignment.centerRight)),
    alignment: Alignment.center,
    child: ClipRRect(borderRadius: BorderRadius.circular(15), child: 
    child),
    );
    }
    }
byqmnocz

byqmnocz8#

现在有一个更简单的方法提供。Flutter现在有一个包,可以完美地完成这项工作。我留下了一个链接到文档,以供进一步使用https://pub.dev/packages/gradient_borders

qrjkbowd

qrjkbowd9#

我尝试了许多方法来做到这一点,但所有这些方法都有其局限性,然后我发现了一个包,工作如何我期望:https://pub.dev/packages/outline_gradient_button

相关问题