Flutter之Button,宽度占满屏幕,四周带icon的Button

一、Button宽度占满屏幕或自定义

Flutter为我们提供了各式各样的Button,包括FlatButtonRaisedButtonOutlineButtonRaisedButton.iconFlatButton.iconOutlineButton.icon......等,而这些Button都是直接或间接继承于MaterialButton,在MaterialButton基础上封装了一下属性,或拓展了一下child属性增加了icon。
但是,当我们用FlatButton、RaisedButton 、OutlineButton时发现Button的宽度是包裹内容的,那怎么能让宽度占满屏幕或自定义大小呢?

方案一:直接使用MaterialButton

我们看下MaterialButton中提供了2个属性:minWidthheight,我们直接设置这2个属性的宽度或者高度就可以,如果想宽度占满全屏可以直接设置成double.infinity,如下:

MaterialButton(
  onPressed: () {},
  child: Text("宽度占满了"),
  minWidth: double.infinity,
  height: 50.0,
  color: Colors.green,
  textColor: Colors.white,
 )
WechatIMG2.png

方案二:设置在ButtonTheme中设置宽度

我们看到MaterialButton源码中的宽高有这样一句话

/// Defaults to the value from the current [ButtonTheme].
final double minWidth;

可以知道Button默认的宽高是来源于ButtonTheme,其实MaterialButton的许多属性的默认值都来源于ButtonTheme,所以我们直接全局设置这个就好了,如下:

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        buttonTheme: ButtonThemeData(minWidth: double.infinity, height: 50.0),
      ),
      home: SplashPage(),
    );
  }
}

这样所有你用的Button,不管是FlatButtonRaisedButtonOutlineButton还是MaterialButton都默认成宽度最大,高度50了,大家根据具体情况去做就好了。

方案三:在Button之外再套一层控制大小

这种情况可直接使用FlatButtonRaisedButtonOutlineButton如下:

SizedBox(
  width: double.infinity,
  height: 50,
  child: RaisedButton(
    onPressed: () {},
    child: Text("宽度占满了"),
    color: Colors.green,
    textColor: Colors.white,
  ),
),

当然不止SizedBox可以控制大小,其他能设置宽高的布局widget也可以,大家视情况而定就好了。如Container,下面这个宽度占满,距左右边距20。

Container(
  width: double.infinity,
  height: 50,
  padding: EdgeInsets.only(left: 20,right: 20),
  child: RaisedButton(
    onPressed: () {},
    child: Text("宽度占满了"),
    color: Colors.green,
    textColor: Colors.white,
  ),
)

二、自定义Button,支持文字上下左右带icon

我们看下RaisedButton.iconFlatButton.iconOutlineButton.icon这些的icon都是怎么加上的,源码:

class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
  _FlatButtonWithIcon({
    Key key,
    @required VoidCallback onPressed,
    ...
    ...
    MaterialTapTargetSize materialTapTargetSize,
    @required Widget icon,
    @required Widget label,
  }) : assert(icon != null),
       assert(label != null),
       super(
         key: key,
         onPressed: onPressed,
         ...
         ...
         materialTapTargetSize: materialTapTargetSize,
         child: Row(
           mainAxisSize: MainAxisSize.min,
           children: [
             icon,
             const SizedBox(width: 8.0),
             label,
           ],
         ),
       );

}

其实很简单,就是定义了个icon,然后,把这个icon和label用Row给包起来了,照这样我们可以定义任何按钮里面的布局了,可以放任何东西进去。
于是,我们先自定义一个类似于Android中Button,支持android:drawableLeftandroid:drawableTop,android:drawableRight,android:drawableBottom,如下:

import 'package:flutter/material.dart';

///
/// Create by Hugo.Guo
/// Date: 2019-06-13
///
class FullIconButton extends MaterialButton with MaterialButtonWithIconMixin {
  FullIconButton({
    Key key,
    @required VoidCallback onPressed,
    ValueChanged 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: [
              Offstage(
                offstage: topIcon == null,
                child: topIcon,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Offstage(
                    offstage: leftIcon == null,
                    child: leftIcon,
                  ),
                  Padding(
                    padding: textPadding,
                    child: label,
                  ),
                  Offstage(
                    offstage: rightIcon == null,
                    child: rightIcon,
                  ),
                ],
              ),
              Offstage(
                offstage: bottomIcon == null,
                child: bottomIcon,
              ),
            ],
          ),
        );
}

这里构造函数里我加了这些属性

    double minWidth,
    double height,
    Widget leftIcon,
    Widget topIcon,
    Widget rightIcon,
    Widget bottomIcon,
    EdgeInsetsGeometry textPadding,

我们可以定义宽高,上下左右图标,还有文字和图标的间距,这样用起来会比较方便了。当然如果你有其他需求一样可以自己加进去。
另外我们用了Column,Row,OffstageColumn控制竖排的widget,Row控制横排的widget,Offstage控制icon的显示或隐藏,Offstage有2个属性offstagechild,其中offstage=true时Offstage就不显示了。
下面我们用下这个FullIconButton

FullIconButton(
  label: Text("GitHub登录"),
  color: Colors.blue,
  textColor: Colors.white,
  onPressed: () {},
  minWidth: double.infinity,
  leftIcon: Image.asset(
    "images/icon_github.png",
    width: 24,
    height: 24,
    color: Colors.white,
  ),
  rightIcon: Icon(Icons.group),
  topIcon: Text("我是"),
  bottomIcon: Text("我是"),
  textPadding: EdgeInsets.only(left: 10, right: 10),
)

效果如下:


WechatIMG3.png

当然四周定义的是widget,所以你可以放任何widget进去,不只是icon。通过这个自定义Button,我们可以定义任何我们想要的通用的widget,不明白或者遇到问题的时候查看下源码是怎么做的就可以了。

pub地址:https://pub.dev/packages/full_icon_button
github地址:https://github.com/tianyu704/full_icon_button

总结:初学Flutter不久,也还有好多不熟悉或不懂的地方,大家遇到问题可以查看源码或多跟同行交流,遇到问题总能解决的,加油。

你可能感兴趣的:(Flutter之Button,宽度占满屏幕,四周带icon的Button)