Flutter第八章(RaisedButton ,FlatButton ,OutlineButton,IconButton,ButtonBar ,FloatingActionButton自定义W...

版权声明:本文为作者原创书籍。转载请注明作者和出处,未经授权,严禁私自转载,侵权必究!!!
情感语录:得之坦然,失之淡然;争其必然,顺其自然!

欢迎来到本章节,上一章节我们讲了侧边栏的使用,知识点回顾 戳这里 Flutter基础第七章

本章节将对Flutter中的按钮组件进行介绍,在前面章节的讲解中,其实已经使用到了一些按钮组件,比如 RaisedButtonIconButton 当然在Flutter中可不止这两个按钮,本篇会将常用的按钮组件都进行罗列讲解。

本章简要:

1、RaisedButton :Material Design 风格的凸起按钮

2、FlatButton :扁平化的按钮

3、OutlineButton:线框按钮

4、IconButton :图标按钮

5、ButtonBar:按钮组

6、FloatingActionButton:浮动按钮

7、自定义实现(左,上,右,下)的图标按钮

8、实战 闲鱼app 底部不规则按钮

按钮组件中的通用属性:

    名称                 属性值

    onPressed            按下按钮时触发的回调,接收一个方法,不填或者传 null 表示按钮禁用
                
                         
    child                文本控件

    textColor            文本颜色

    color                按钮的颜色

    disabledColor        按钮禁用时的颜色
     
    disabledTextColor    按钮禁用时的文本颜色

    splashColor          点击按钮时水波纹的颜色

    highlightColor       点击(长按)按钮后按钮的颜色

    elevation            阴影的范围,值越大阴影范围越大

    padding              内边距

    shape                设置按钮的形状:
                         shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(10),
                         )
                         shape: CircleBorder(
                            side: BorderSide(color: Colors.white)
                         )

一 、RaisedButton :

RaisedButton 是 Flutter 提供的 Material 风格的按钮,onPressed属性可以传递 null 值,如果传递了 null 值或者不写也为null,整个按钮是不可点击的,disabled 状态(灰色)

构造函数如下:

 const RaisedButton({
    Key key,
    @required VoidCallback onPressed,
    ValueChanged<bool> onHighlightChanged,
    ButtonTextTheme textTheme,
    Color textColor,
    Color disabledTextColor,
    Color color,
    Color disabledColor,
    Color focusColor,
    Color hoverColor,
    Color highlightColor,
    Color splashColor,
    Brightness colorBrightness,
    double elevation,
    double focusElevation,
    double hoverElevation,
    double highlightElevation,
    double disabledElevation,
    EdgeInsetsGeometry padding,
    ShapeBorder shape,
    Clip clipBehavior,
    FocusNode focusNode,
    MaterialTapTargetSize materialTapTargetSize,
    Duration animationDuration,
    Widget child,
  })
1、普通 Button 及背景颜色控制、阴影控制
  import 'package:flutter/material.dart';
  
  class RaisedButtonPage extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      return MaterialApp(
          home: Scaffold(
              appBar: AppBar(
                title: Text("RaisedButtonPage"),
              ),
              body:  Column(
                children: <Widget>[
                  Row(
                    children: <Widget>[
  
                      SizedBox(width: 5),
                      RaisedButton(
                        child: Text('无事件按钮'),
                      ),
                      SizedBox(width: 5),
                      RaisedButton(
                        child: Text('普通按钮'),
                        onPressed: () {},
                      ),
                      SizedBox(width: 5),
                      RaisedButton(
                        color: Colors.pink,
                        textColor: Colors.white,
                        child: Text('颜色按钮'),
                        onPressed: () {},
                      ),
                      SizedBox(width: 5),
                      RaisedButton(
                        elevation: 20,
                        focusElevation: 40,
                        child: Text('阴影按钮'),
                        onPressed: () {},
                      ),
  
                    ],
                  )
  
                ],
              )
          )
      );
    }
  }

效果如下:


RaisedButton1.gif
2、控制 Button 的宽度和高度

RaisedButton 本身没有宽度和高度的属性控制,也没有 margin 属性可利用,如果要指定宽度和高度,可以借助 Container 容器,设置 Container 宽度和高度达到控制 RaisedButton 宽高,或者其他能设置宽高的布局widget也可以,如 :SizedBox

  Row(
    children: <Widget>[

      SizedBox(width: 5),

      Container(
        width: 200,
        height: 50,
        child:   RaisedButton(
          child: Text('宽:200,高:50 按钮'),
          onPressed: () {},
        ),
      ),

      SizedBox(width: 5),
      Container(
        width: 220,
        height: 40,
        child:    RaisedButton(
          color: Colors.pink,
          textColor: Colors.white,
          child: Text('宽:220,高:40 按钮'),
          onPressed: () {},
        ),
      )
    ],
  )

效果如下:

RaisedButton2.gif
3、宽度自适应按钮

某些场景下,我们可能期望一个 Button 充满整个屏幕宽度。和宽度高度的控制一样,我们需要借助 Row + Expanded ,或者使用 无穷值 double.infinity 方式。

  Row(
    children: <Widget>[
      Expanded(
        child: Container(
          height: 50,
          child: RaisedButton(
            child: Text('组合控制自适应'),
            onPressed: () {},
          ),
        ),
      )
    ],
  ),

  SizedBox(height: 30),

  Container(
    width: double.infinity,
    height: 40,
    child: RaisedButton(
      color: Colors.pink,
      textColor: Colors.white,
      child: Text('无穷宽值方式'),
      onPressed: () {},
    ),
  )

效果如下:

RaisedButton3.gif
4、圆角 & 圆形 按钮

RasedButton 圆角可以通过 shape 属性控制,shape 属性支持传入 RoundedRectangleBorder 并且指定 RoundedRectangleBorder.borderRadius 的圆角值实现按钮圆角。

  RaisedButton(
    child: Text('圆角按钮',style: TextStyle(color: Colors.white)),
    color: Colors.green,
    shape: RoundedRectangleBorder(
      borderRadius: BorderRadius.circular(25),
    ),
    onPressed: () {},
  ),

效果如下:

RaisedButton4.png

RasedButton 圆形可以借助 RaisedButton.shape 来实现,本身 shape 支持传入的属性是 ShapeBorder 即可,而 CircleBorder 也是继承自 ShapeBorder。需要注意的是通过这种方式实现圆形按钮,当内部文字过长就会显示不出来,需要外部容器包装下。

  SizedBox(
    height: 70,
    child:   RaisedButton(
      child: Text('圆形按钮',style: TextStyle(color: Colors.white)),
      color: Colors.green,
      shape: CircleBorder(
        side: BorderSide(color: Colors.blue),
      ),
      onPressed: () {},
    ),
  ),

效果如下:

RaisedButton5.png
5、图标按钮

造函数 RaisedButton.icon 中可以配置一个带有图标的按钮。

  factory RaisedButton.icon({
    Key key,
    @required VoidCallback onPressed,
    ValueChanged<bool> onHighlightChanged,
    ButtonTextTheme textTheme,
    Color textColor,
    Color disabledTextColor,
    Color color,
    Color disabledColor,
    Color focusColor,
    Color hoverColor,
    Color highlightColor,
    Color splashColor,
    Brightness colorBrightness,
    double elevation,
    double highlightElevation,
    double disabledElevation,
    ShapeBorder shape,
    Clip clipBehavior,
    FocusNode focusNode,
    MaterialTapTargetSize materialTapTargetSize,
    Duration animationDuration,
    @required Widget icon,
    @required Widget label,
  }) = _RaisedButtonWithIcon;

运用下这种方式:

  RaisedButton.icon(
    color: Colors.pink,
    textColor: Colors.white,
    icon: Icon(Icons.settings),
    label: Text('图标按钮'),
    onPressed: () {},
  ),

效果如下:

RaisedButton6.gif

开发中这种带有图标的按钮还是非常常见的,不过很遗憾的事 Flutter 就只给我们提供了图标放在左边的这种方式,那如果我想实现像Android 原生 TextView那样 左,上,右,下都可以定制一个图标那该怎么办呢?

首先我们去看下Flutter中是怎么实现放置一个 Icon 的,跟进 RaisedButton.icon 源码:

    /// The type of of RaisedButtons created with [RaisedButton.icon].
    ///
    /// This class only exists to give RaisedButtons created with [RaisedButton.icon]
    /// a distinct class for the sake of [ButtonTheme]. It can not be instantiated.
    class _RaisedButtonWithIcon extends RaisedButton with MaterialButtonWithIconMixin {
      _RaisedButtonWithIcon({
        Key key,
        @required VoidCallback onPressed,
        ValueChanged<bool> onHighlightChanged,
        ButtonTextTheme textTheme,
         .....
         .....
         .....
        @required Widget icon,
        @required Widget label,
      }) : assert(elevation == null || elevation >= 0.0),
           assert(highlightElevation == null || highlightElevation >= 0.0),
           assert(disabledElevation == null || disabledElevation >= 0.0),
           assert(icon != null),
           assert(label != null),
           super(
             key: key,
             onPressed: onPressed,
             .....
             .....
             .....
             focusNode: focusNode,
             materialTapTargetSize: materialTapTargetSize,
             animationDuration: animationDuration,
             child: Row(   // 标记1
               mainAxisSize: MainAxisSize.min,
               children: <Widget>[
                 icon,
                 const SizedBox(width: 8.0),
                 label,
               ],
             ),
           );

删掉些无用相关代码,(标记1)发现其实很简单,就是定义了个 icon,然后,把这个 icon和 label用 Row 给包起来了,按照他这种方式,我们也可以去实现其他方位的图标添加了,比如我想实现顶部一个图标的我就用 Column组件去包装一个 Icon 和 一个Text 方式 ,如果想实现右边有个Icon的,我也用Row组件去包装,不过我先放Text 组件 然后在放 Icon组件。

不过每次都要这样去写是不是很麻烦啊,能像原生一样简单点吗? 没办法自己撸一个吧,我们先自定义一个类似于Android中支持 android:drawableLeft , android:drawableTop , android:drawableRight , android:drawableBottom ,的多功能按钮 如下:

  import 'package:flutter/material.dart';
  
  class FunIconButton extends MaterialButton with MaterialButtonWithIconMixin {
    FunIconButton({
      Key key,
      @required VoidCallback onPressed,
      ValueChanged<bool> onHighlightChanged,
      ButtonTextTheme textTheme,
      Color textColor,
      Color disabledTextColor,
      Color color,
      Color disabledColor,
      Color focusColor,
      Color hoverColor,
      Color highlightColor,
      Color splashColor,
      Brightness colorBrightness,
      double elevation,
      double highlightElevation,
      double disabledElevation,
      ShapeBorder shape,
      Clip clipBehavior = Clip.none,
      FocusNode focusNode,
      MaterialTapTargetSize materialTapTargetSize,
      Duration animationDuration,
      double minWidth,
      double height,
      Widget leftIcon,
      Widget topIcon,
      Widget rightIcon,
      Widget bottomIcon,
      EdgeInsetsGeometry textPadding,
      Widget label,
    })  : assert(elevation == null || elevation >= 0.0),
          assert(highlightElevation == null || highlightElevation >= 0.0),
          assert(disabledElevation == null || disabledElevation >= 0.0),
          super(
          key: key,
          onPressed: onPressed,
          onHighlightChanged: onHighlightChanged,
          textTheme: textTheme,
          textColor: textColor,
          disabledTextColor: disabledTextColor,
          color: color,
          disabledColor: disabledColor,
          focusColor: focusColor,
          hoverColor: hoverColor,
          highlightColor: highlightColor,
          splashColor: splashColor,
          colorBrightness: colorBrightness,
          elevation: elevation,
          highlightElevation: highlightElevation,
          disabledElevation: disabledElevation,
          shape: shape,
          clipBehavior: clipBehavior,
          focusNode: focusNode,
          materialTapTargetSize: materialTapTargetSize,
          animationDuration: animationDuration,
          minWidth: minWidth,
          height: height,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Offstage(
                offstage: topIcon == null,
                child: topIcon,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Offstage(
                    offstage: leftIcon == null,
                    child: leftIcon,
                  ),
                  Padding(
                    padding: textPadding,
                    child: label,
                  ),
                  Offstage(
                    offstage: rightIcon == null,
                    child: rightIcon,
                  ),
                ],
              ),
              Offstage(
                offstage: bottomIcon == null,
                child: bottomIcon,
              ),
            ],
          ),
        );
  }

除了支持 Flutter Button中常用的属性外,我们还添了如下属性:

    属性名       类型              作用

    leftIcon     Widget           左边添加一个图标,可以是其他 Widget 组件
    
    topIcon      Widget           顶部添加一个图标,同理
    
    rightIcon    Widget           右边添加一个图标,同理
    
    bottomIcon   Widget           底部添加一个图标,同理

leftIcon接收的是一个 Widget 能很好拓展你放其他的组件进去,不一定就是一个图标,为了更加灵活。下面来运用试试。

  FunIconButton(
    label:Text('多功能按钮',style: TextStyle(color: Colors.deepPurple)),
    color: Colors.blue,
    textColor: Colors.white,
    onPressed: () {},
    minWidth: 240,
    leftIcon: Image.asset(
      "images/mm.jpg",
      width: 24,
      height: 24,
    ),
    rightIcon: Icon(Icons.group),
    topIcon: Icon(Icons.save),
    bottomIcon: Icon(Icons.score),
    textPadding: EdgeInsets.only(left: 10, right: 10),

  ),

效果如下:

自定义RaisedButton7.gif

二、FlatButton

FlatButton 没有 RaisedButton 默认的阴影,因此看起来是扁平化的,没有凸出感觉。

     FlatButton(
        //按钮文字颜色
        textColor: Colors.white,
        //按钮禁用时的背景颜色
        disabledColor:Colors.grey,
        //按钮禁用时的文字颜色
        disabledTextColor: Colors.grey,
        //正常状态下的背景颜色
        color: Colors.blue,
        //按钮按下时的背景颜色
        highlightColor: Colors.blue[700],
        //按钮主题,默认是浅色主题
        colorBrightness: Brightness.dark,
        //外形
        splashColor: Colors.grey,
        // button 显示的文字
        child: Text("纳尼"),
        //圆角边框
        shape:RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
        //按钮点击回调
        onPressed: () => {},
      )
FlatButton.png

三、OutlineButton 边框按钮

OutlineButton 允许我们给 Button 指定 边框和样式,开发中这种 Button 非常常见,运用下:

  OutlineButton(
    child: Text('边框按钮'),
    onPressed: () {},
  ),
  OutlineButton(
    borderSide: BorderSide(color: Colors.pink),
    child: Text('边框按钮'),
    onPressed: () {},
  ),

效果如下:

OutlineButton.gif

四、IconButton 图标按钮

此 Button 已经在案例中使用太多次了,常用且简单。 IconButton 默认实现了高度和宽度的设置,并且是一个圆形的 Button,因此在使用 IconButton 的时候我们可以通过 Icon.size 控制图标大小,也能够控制 padding 属性。

  //IconButton
  IconButton(
    splashColor: Colors.pink,
    color: Colors.pink,
    icon: Icon(Icons.send,size: 50,),
    onPressed: () {},
  ),
  IconButton(
    splashColor: Colors.pink,
    color: Colors.pink,
    padding: EdgeInsets.all(0),
    icon: Icon(Icons.settings),
    onPressed: () {},
  )

效果如下:

IconButton.gif

五、ButtonBar 按钮组

ButtonBar 可以默认实现一个按钮组,通过 children 属性可以传入多个 Button,说白了 ButtonBar 就是一个容器,可以统一管理子元素的位置信息。

构造函数:

   const ButtonBar({
    Key key,
    this.alignment = MainAxisAlignment.end,
    this.mainAxisSize = MainAxisSize.max,
    this.children = const <Widget>[],
  }) : super(key: key);

实践运用:

    ButtonBar(
      alignment:MainAxisAlignment.center ,
      children: <Widget>[
        RaisedButton(
          color: Colors.pink,
          textColor: Colors.white,
          child: Text('按钮组'),
          onPressed: () {},
        ),
        FlatButton(
          color: Colors.pink,
          textColor: Colors.white,
          child: Text('按钮组'),
          onPressed: () {},
        )
      ],
    )

效果如下:

ButtonBar.png

六、FloatingActionButton 悬浮按钮

FloatingActionButton 可以实现浮动按钮,使用场景也是非常多 如:各种购物商场的 返回顶部按钮。

常用属性:
    属性名称                属性值

    child                   子视图,一般为 Icon

    tooltip                 FAB 被长按时显示,也是无障碍功能

    backgroundColor         背景颜色
    
    foregroundColor         前景色

    elevation               未点击的时候的阴影

    hignlightElevation      点击时阴影值,默认 12.0

    onPressed               点击事件回调

    shape                   可以定义 FAB 的形状等

    mini                    是否是 mini 类型默认 false
    
    heroTag                 hero效果使用的tag,系统默认会给所有FAB使用同一个tag,方便做动画效果
    
    isExtended              是否为”extended”类型

简单运用:

    import 'package:flutter/foundation.dart';
    import 'package:flutter/material.dart';

    class HomePage extends StatefulWidget {
      HomePage({Key key}) : super(key: key);

      HomePageState createState() => HomePageState();
    }

    class HomePageState extends State<HomePage> {
      void handlerDrawerButton() {

      }
      @override
      Widget build(BuildContext context) {

        return Scaffold(

          //FloatingActionButton
          floatingActionButton: FloatingActionButton(
            elevation: 0,
            backgroundColor: Colors.green,
            foregroundColor: Colors.purpleAccent,
            child: Icon(
              Icons.build,
              size: 30,
              color: Colors.white,
            ),
            onPressed: () {},
          ),
          floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,

          backgroundColor: Colors.blue,
          
          body: Container(
            child: Center(
              child: Text("主页"),
            ),
          ),
        );
      }
    }

效果如下绿色悬浮按钮:

FAB.png
FloatingActionButton 的不同类型

FAB 分为三种类型:常规, mini, 和 extended。下面来看这三种有什么区别:

FAB对比.png

可以看出 设置mini 时,FAB按钮变小了。使用FloatingActionButton.extended 构造函数可以实现图文并茂的悬浮按钮。

FloatingActionButton 的位置选择

Scaffold Widget中有一个 floatingActionButtonLocation属性 结合FAB使用,可以指定悬浮按钮的摆放位置。

FAB_localtion.png

目前提供了 7 种位置可以选择,在使用时可以分别试试不同的位置效果吧。

七、模仿闲鱼底部导航效果:

为什么要模仿闲鱼? 因为他牛逼啊,哈哈。毕竟别人是国内 Flutter 最大的团队!!!

闲鱼的底部菜单按钮是这样子的:

闲鱼.png

结合上面学到的按钮组件 FloatingActionButton 其实我们可以很轻松实现闲鱼效果。我们的案例中已经有创建好的底部菜单,那就充分利用起来吧,进入我们之前写 Tabs.dart 中,在 Scaffold 配置 floatingActionButton 属性,之前没有跟着我写的同学,可以在文末去翻阅源码。

     floatingActionButton:Container(
            height: 80,
            width: 80,
            //实现一个圆形
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(40),
              color: Colors.white,
            ),
            //距离上边 10个单位
            margin: EdgeInsets.only(top:10),
            // 8个单位的内边距,让周边有浮出感
            padding: EdgeInsets.all(8),
            child: FloatingActionButton(
              child: Icon(Icons.add),
              backgroundColor: this._currentIndex==1?Colors.red:Colors.deepPurple,
              onPressed: (){
                setState(() {
                  this._currentIndex=1;
                });
              },
            ),
          ),
          //指定显示位置
          floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

最终效果如下:

实战闲鱼.gif

非常轻松的就实现了,没什么难度。O(∩_∩)O哈哈~

下面贴出本章中的全部实例图,看图回忆下本章知识点吧!

按钮实例图.png

好了本章节到此结束,又到了说再见的时候了,如果你喜欢请留下你的小红星,你们的支持才是创作的动力,如有错误,请热心的你留言指正, 谢谢大家观看,下章再会 O(∩_∩)O

实例源码地址: https://github.com/zhengzaihong/flutter_learn

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,047评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,807评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,501评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,839评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,951评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,117评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,188评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,929评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,372评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,679评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,837评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,536评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,168评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,886评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,129评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,665评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,739评论 2 351

推荐阅读更多精彩内容