【问题标题】:How to add a gradient to a Button in Flutter?如何在 Flutter 中为按钮添加渐变?
【发布时间】:2019-02-14 00:52:44
【问题描述】:

有没有办法将ElevatedButton 背景颜色更改为渐变?

【问题讨论】:

  • 我过去在向墨水飞溅区域添加背景渐变时遇到过麻烦。渐变最终隐藏了飞溅。您是否对仅具有渐变或具有飞溅效果的渐变感兴趣? (至于具有高度、边框半径和渐变的按钮 - 是的,这是可能的
  • @AshtonThomas 正如你所说,渐变隐藏了墨水飞溅。这是因为墨迹飞溅需要一个 Material 小部件作为其父级。我也有同样的情况。所以最终创建了我自己的自定义按钮。
  • 我尝试了自定义按钮的想法,但我无法实现默认凸起按钮的阴影动画!你能帮我解决这个问题吗?

标签: android ios dart flutter


【解决方案1】:

2021 年更新:

由于RaisedButtonOutlineButton 已被弃用,您应该使用ElevatedButtonOutlinedButton

  • ElevatedButton

    Container(
      height: 44.0,
      decoration: BoxDecoration(gradient: LinearGradient(colors: [Colors.pink, Colors.green])),
      child: ElevatedButton(
        onPressed: () {},
        style: ElevatedButton.styleFrom(primary: Colors.transparent, shadowColor: Colors.transparent),
        child: Text('Elevated Button'),
      ),
    )
    

  • OutlinedButton

    创建一个类(null-safe):

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

【讨论】:

  • 谢谢,这是我找到的第一个使用提升按钮的解决方案!要移除阴影效果,请在提升按钮上使用以下样式:ElevatedButton.styleFrom(primary: Colors.transparent, elevation: 0,),
【解决方案2】:

这对我来说是什么工人。不推荐使用 RaisedButton 我使用了 ElevatedButton。所以这应该是要走的路。

import 'package:flutter/material.dart';

class MainButton extends StatelessWidget {
  final Widget thechild;
  final double width;
  final double height;
  final Function theaction;

  const MainButton({
    Key key,
    @required this.thechild,
    this.width = double.infinity,
    this.height = 50.0,
    this.theaction,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: theaction,
      style: ElevatedButton.styleFrom(
        primary: Colors.transparent,
        elevation: 4.0,
        minimumSize: Size(88.0, 45.0),
        padding: const EdgeInsets.all(0.0),
      ),
      child: Ink(
        decoration: const BoxDecoration(
          gradient: LinearGradient(
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter,
              stops: [
                0.1,
                0.8,
                0.9
              ],
              colors: [
                Color.fromARGB(255, 186, 252, 244),
                Color.fromARGB(255, 55, 183, 230),
                Color.fromARGB(255, 49, 175, 230),
              ]),
          borderRadius: BorderRadius.all(Radius.circular(8.0)),
        ),
        child: Container(
          constraints: const BoxConstraints(minWidth: 88.0, minHeight: 45.0),
          alignment: Alignment.center,
          child: thechild,
        ),
      ),
    );
  }
}

用法

先导入

import '../widgets/mainButton.dart';

那么

MainButton(
                        thechild: Text(AppLocalization.translate('loginbtn'),
                            textAlign: TextAlign.center,
                            style: TextStyle(
                                color: Colors.white,
                                fontWeight: FontWeight.bold,
                                fontSize: 20)),
                        theaction: () {},
                      ),

【讨论】:

    【解决方案3】:
    DecoratedBox(
        decoration: ShapeDecoration(
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
            gradient: RadialGradient(
                radius: 2, colors: [Colors.white, Colors.redAccent]),),
         child:RaisedButton(),
    ),
    

    使用 DecoratedBox 作为父小部件向任何小部件添加渐变

    Example

    【讨论】:

      【解决方案4】:

      文档最后一个例子https://api.flutter.dev/flutter/material/RaisedButton-class.html

      RaisedButton(
        onPressed: () {},
        textColor: Colors.white,
        padding: const EdgeInsets.all(0.0),
        child: Container(
          decoration: const BoxDecoration(
            gradient: LinearGradient(
              colors: <Color>[
                Color(0xFF0D47A1),
                Color(0xFF1976D2),
                Color(0xFF42A5F5),
              ],
            ),
          ),
          padding: const EdgeInsets.all(10.0),
          child: const Text(
            'Gradient Button',
            style: TextStyle(fontSize: 20)
          ),
        ),
      );
      

      【讨论】:

        【解决方案5】:

        如果没有一些小瑕疵或问题(例如缺少波纹效果、不需要的边框、不尊重主题的按钮 minWidth),上述所有解决方案都无法真正工作。

        下面的解决方案没有上述问题(关键部分是使用Ink 小部件来保留渐变上的波纹功能):

        RaisedButton(
          onPressed: () { },
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(80.0)),
          padding: const EdgeInsets.all(0.0),
          child: Ink(
            decoration: const BoxDecoration(
              gradient: myGradient,
              borderRadius: BorderRadius.all(Radius.circular(80.0)),
            ),
            child: Container(
              constraints: const BoxConstraints(minWidth: 88.0, minHeight: 36.0), // min sizes for Material buttons
              alignment: Alignment.center,
              child: const Text(
                'OK',
                textAlign: TextAlign.center,
              ),
            ),
          ),
        )
        

        【讨论】:

        • RaisedButton 现在已弃用。使用ElevatedButtonsolution
        【解决方案6】:

        Flutter API 文档有一个如何渲染带有渐变背景的RaisedButton 的示例 - 请参阅此处https://api.flutter.dev/flutter/material/RaisedButton-class.html

        Widget gradientButton = Container(
          child: RaisedButton(
            onPressed: () { },
            textColor: Colors.white,
            padding: const EdgeInsets.all(0.0),
            child: Container(
              width: 300,
              decoration: new BoxDecoration(
                gradient: new LinearGradient(
                  colors: [
                    Color.fromARGB(255, 148, 231, 225),
                    Color.fromARGB(255, 62, 182, 226)
                  ],
                )
              ),
              padding: const EdgeInsets.all(10.0),
              child: Text(
                "Gradient Button",
                textAlign: TextAlign.center,
              ),
            ),
          ),
        );
        

        【讨论】:

        • 这里不相关的问题。你在那个按钮上使用什么字体?
        • @AsyrafDayan Montserrat
        【解决方案7】:

        您可以使用material.dart 中的RawMaterialButton 来使用更简单的方法,也可以使其形状为圆形或圆形。 这是一个简单的例子。

          Card(
            elevation: 7,
            child: Container(
              width: 120.0,
              height: 75.0,
              decoration: BoxDecoration(
                gradient: LinearGradient(
                  begin: Alignment.bottomLeft,
                  end: Alignment.topRight,
                  colors: <Color>[
                    Colors.blue,
                    Colors.red,
                  ],
                ),
              ),
              child: RawMaterialButton(
                onPressed: () {},
                splashColor: Colors.grey,
                child: Text(
                  "Button",
                  style: TextStyle(color: Colors.white, fontSize: 20.0),
                ),
              ),
            ),
          ),
        

        【讨论】:

          【解决方案8】:

          我知道这个问题有点老了。但我发现自己有这个要求,我想分享我的解决方案。它使用Card 并在按下按钮时为海拔设置动画。

          import 'package:flutter/material.dart';
          
          class GradientButton extends StatefulWidget {
            final String label;
            final VoidCallback onPressed;
            final Gradient gradient;
            final double elevation;
            final double height;
            final TextStyle labelStyle;
          
            GradientButton({
              @required this.label,
              @required this.onPressed,
              @required this.gradient,
              this.elevation,
              this.height,
              this.labelStyle,
            })  : assert(label != null && onPressed != null),
                  assert(gradient != null);
          
            @override
            _GradientButtonState createState() => _GradientButtonState();
          }
          
          class _GradientButtonState extends State<GradientButton> with TickerProviderStateMixin {
            AnimationController _animationController;
            Animation _animation;
          
            elevateUp(TapDownDetails details) {
              _animationController.forward();
            }
          
            elevateDown() {
              _animationController.reverse();
            }
          
            @override
            void initState() {
              super.initState();
              _animationController = AnimationController(duration: Duration(milliseconds: 50), vsync: this);
              _animation = Tween(begin: widget.elevation ?? 2.0, end: 12.0).animate(_animationController);
            }
          
            @override
            Widget build(BuildContext context) {
              return AnimatedBuilder(
                animation: _animation,
                builder: (c, w) {
                  return GestureDetector(
                    onTapDown: elevateUp,
                    onTapCancel: elevateDown,
                    onTapUp: (value) {
                      elevateDown();
                      widget.onPressed();
                    },
                    child: Card(
                      elevation: _animation.value,
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(25.0),
                      ),
                      child: Container(
                        width: double.infinity,
                        height: widget.height ?? 50.0,
                        decoration: BoxDecoration(
                          gradient: widget.gradient,
                          borderRadius: BorderRadius.circular(25.0),
                        ),
                        child: Center(
                          child: Text(
                            widget.label,
                            style: widget.labelStyle ?? Theme.of(context).textTheme.button,
                          ),
                        ),
                      ),
                    ),
                  );
                },
              );
            }
          }
          

          还有改进的余地(也许您不希望默认使用那些圆形边框),但希望对你们中的某些人有用:D

          【讨论】:

            【解决方案9】:

            参考下面-

            RaisedButton(
                 onPressed: () {},
                 textColor: Colors.white,
                 padding: const EdgeInsets.all(0.0),
                 shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(80.0)),
                 child: Container(
                   decoration: const BoxDecoration(
                     gradient: LinearGradient(
                       colors: <Color>[
                         Color(0xFF0D47A1),
                         Color(0xFF1976D2),
                         Color(0xFF42A5F5),
                       ],
                     ),
                     borderRadius: BorderRadius.all(Radius.circular(80.0))
                   ),
                   padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
                   child: const Text(
                       'Gradient Button',
                       style: TextStyle(fontSize: 20)
                   ),
                 ),
               )
            

            【讨论】:

              【解决方案10】:

              只需再制作一个容器作为孩子设置该容器的装饰并根据需要制作渐变颜色

              然后在此之后使用 RaisedButton 作为上述容器的孩子 与 MaterialButton 相同

                 child: Container(
                    decoration: BoxDecoration(
                      gradient: LinearGradient(
                          colors: [Colors.red, Colors.blue],
                          begin: FractionalOffset(0.0, 0.0),
                          end: FractionalOffset(0.5, 0.0),
                          stops: [0.0, 1.0],
                          tileMode: TileMode.clamp),
                    ),
                    child: RaisedButton(
                      color: Colors.transparent,
                      child: Text("Ask Permssion"),
                      onPressed: () {
                        askPermission();
                      },
                    )),
              

              输出:

              【讨论】:

                【解决方案11】:

                Gradient 包可在 pub 商店获得,它支持少量预定义渐变

                您可以将渐变按钮创建为

                GradientButton(
                                 child: Text('Gradient'),
                                 callback: () {},
                                 gradient: Gradients.backToFuture,
                           ),
                

                包有 GradientCard, GradientProgressIndicator, GradientButton, CircularGradientButton 和 GradientText

                Gradient Widgets

                【讨论】:

                  【解决方案12】:

                  您可以自己创建一个自定义的

                  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: gradient, boxShadow: [
                          BoxShadow(
                            color: Colors.grey[500],
                            offset: Offset(0.0, 1.5),
                            blurRadius: 1.5,
                          ),
                        ]),
                        child: Material(
                          color: Colors.transparent,
                          child: InkWell(
                              onTap: onPressed,
                              child: Center(
                                child: child,
                              )),
                        ),
                      );
                    }
                  }
                  

                  并在任何地方使用它,如下所示:

                  RaisedGradientButton(
                    child: Text(
                      'Button',
                      style: TextStyle(color: Colors.white),
                    ),
                    gradient: LinearGradient(
                      colors: <Color>[Colors.green, Colors.black],
                    ),
                    onPressed: (){
                      print('button clicked');
                    }
                  ),
                  

                  您可以通过编辑 Container 的装饰属性来进一步使用阴影和圆角边框,直到它符合您的规范。

                  【讨论】:

                  • 实际上,我希望阴影与默认的凸起按钮完全相同,但无法实现。
                  • Vamsi,@MoeinHosseini,尝试在材质中添加 elevation 而不是阴影
                  猜你喜欢
                  • 2021-11-28
                  • 1970-01-01
                  • 2012-08-23
                  • 2020-04-11
                  • 2022-11-13
                  • 1970-01-01
                  • 2020-04-10
                  • 1970-01-01
                  • 2020-06-10
                  相关资源
                  最近更新 更多