【问题标题】:Outlined transparent button with gradient border in flutter在颤动中带有渐变边框的轮廓透明按钮
【发布时间】:2019-08-19 02:36:17
【问题描述】:

是否可以在颤动中创建一个带有渐变边框的轮廓(透明)按钮?我尝试在 BorderSide 样式中使用 LinearGradient,但不允许这样做。

【问题讨论】:

    标签: flutter flutter-layout


    【解决方案1】:

    我尝试了很多方法来做到这一点,但它们都有其局限性,然后我找到了一个符合我预期的包:https://pub.dev/packages/outline_gradient_button

    【讨论】:

    • 这是来自用户接受的答案的包。他在评论中链接了它。
    【解决方案2】:

    使用OutlinedButton(推荐)


    创建这个类(空安全代码)

    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'),
    )
    

    【讨论】:

      【解决方案3】:

      你可以通过一个简单的技巧来实现这一点

      你必须定义两个容器。 第一个带有渐变背景的外部容器和第二个带有白色背景的内部容器。作为内部容器的子容器,您可以放置​​任何东西,例如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,
        ),
      

      完成

      【讨论】:

      • 这不仅仅是一个透明按钮,在孩子中你可以使用任何其他小部件
      • 哦,现在我明白你的意思了。是的,它不能用作透明按钮。不过我会推荐它。因为如果您将屏幕颜色设置为内部容器颜色,而不是白色,它将看起来是一个透明按钮。例如,如果屏幕背景颜色为蓝色,则将内部容器颜色设置为蓝色。谢谢。
      • 如果按钮下方有图片怎么办?你的答案是错误的,因为你的按钮不是透明的,你只是匹配颜色。
      • @Oleksandr 如果按钮内出现任何图像会很奇怪。当然,每个人都只想看到按钮的文本,而不是按钮内的屏幕内容。你可能是对的。这个答案可能没有满足您的要求。我刚刚分享了我一直在努力的代码。是否使用此代码完全由您决定。感谢您分享您的想法。
      • 谢谢@valeriana,我也真的不记得是什么颜色了。您可以根据需要采用任何颜色。
      【解决方案4】:

      要改变大小,你可以插入一个Container:

      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),
      ),
      

      【讨论】:

        【解决方案5】:

        我花了大约两个小时:)

        使用方法:

        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;
        }
        

        【讨论】:

        • 给出一些未实现的错误。我在 Flutter Web 中。
        • 那应该进入飞镖库!顺便问一下我们如何设置按钮的大小?
        • 我已经发布了包 pub.dev/packages/outline_gradient_button 它仍然无法在 web 上运行,因为创建着色器和路径操作现在不支持,等待可能会有所改变
        猜你喜欢
        • 1970-01-01
        • 2020-12-29
        • 1970-01-01
        • 2021-04-07
        • 1970-01-01
        • 2022-11-22
        • 2013-01-13
        • 2021-05-02
        • 1970-01-01
        相关资源
        最近更新 更多