美文网首页
Flutter UI基础控件和布局方式解析(1)

Flutter UI基础控件和布局方式解析(1)

作者: AiLearn | 来源:发表于2019-06-28 17:58 被阅读0次

    一,基础控件

    1,Text

    1.1,继承关系
    Object > Diagnosticable > DiagnosticableTree > Widget > StatelessWidget > Text

    1.2 创建Text
    Text一共有三种构造方法

    func 注释
    new Text() 构造方法创建,只能生成一种style
    Text.rich() 静态方法创建,能够生成多种style
    new RichText() 与Text.rich()一样

    1.3 Text

    • 构造方法源码:
     /// Creates a text widget.
      /// If the [style] argument is null, the text will use the style from the closest enclosing [DefaultTextStyle].
      const Text(this.data, {
        Key key,
        this.style,
        this.textAlign,
        this.textDirection,
        this.locale,
        this.softWrap,
        this.overflow,
        this.textScaleFactor,
        this.maxLines,
        this.semanticsLabel,
      }) : assert(data != null), textSpan = null, super(key: key);
    
    • 用法
    new Text(
                  '学习Text',
                  textAlign: TextAlign.center, //文本对齐方式  居中
                  textDirection: TextDirection.ltr, //文本方向
                  softWrap: false, //是否自动换行 false文字不考虑容器大小  单行显示   超出;屏幕部分将默认截断处理
                  overflow: TextOverflow
                      .ellipsis, //文字超出屏幕之后的处理方式  TextOverflow.clip剪裁   TextOverflow.fade 渐隐  TextOverflow.ellipsis省略号
                  textScaleFactor: 2.0, //字体显示的赔率
                  maxLines: 10, //最大行数
                  style: new TextStyle(
                    decorationColor: const Color(0xffffffff), //线的颜色
                    decoration: TextDecoration
                        .none, //none无文字装饰   lineThrough删除线   overline文字上面显示线    underline文字下面显示线
                    decorationStyle: TextDecorationStyle
                        .solid, //文字装饰的风格  dashed,dotted虚线(简短间隔大小区分)  double三条线  solid两条线
                    wordSpacing: 0.0, //单词间隙(负值可以让单词更紧凑)
                    letterSpacing: 0.0, //字母间隙(负值可以让字母更紧凑)
                    fontStyle: FontStyle.italic, //文字样式,斜体和正常
                    fontSize: 20.0, //字体大小
                    fontWeight: FontWeight.w900, //字体粗细  粗体和正常
                    color: const Color(0xffffffff), //文字颜色
                  )
    

    1.4 Text.rich()、new RichText()

    • 构造方法源码:
    /// Creates a text widget with a [TextSpan].
      const Text.rich(this.textSpan, {
        Key key,
        this.style,
        this.textAlign,
        this.textDirection,
        this.locale,
        this.softWrap,
        this.overflow,
        this.textScaleFactor,
        this.maxLines,
        this.semanticsLabel,
      }): assert(textSpan != null), data = null, super(key: key);
    
      /// Creates a paragraph of rich text.
      const RichText({
        Key key,
        @required this.text,
        this.textAlign = TextAlign.start,
        this.textDirection,
        this.softWrap = true,
        this.overflow = TextOverflow.clip,
        this.textScaleFactor = 1.0,
        this.maxLines,
        this.locale,
      }) : assert(text != null) ,assert(textAlign != null), assert(softWrap != null), assert(overflow != null),
           assert(textScaleFactor != null), assert(maxLines == null || maxLines > 0), super(key: key);
    
    • 用法:
    new TextSpan(
                    text: '拼接1',
                  ),
                  new TextSpan(
                    text: '拼接2',
                  ),
                  new TextSpan(
                    text: '拼接3',
                  ),
                  new TextSpan(
                    text: '拼接4',
                  ),
                  new TextSpan(
                    text: '拼接5',
                  ),
                  new TextSpan(
                    text: '拼接6',
                  ),
                  new TextSpan(
                      text: '拼接7',
                      style: new TextStyle(
                        color: Colors.yellow,
                      ),
                      recognizer:new TapGestureRecognizer()..onTap=(){//增加一个点击事件
                        print('@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@');
                      },
                  ),
    

    2,Image

    2.1,继承关系
    Object > Diagnosticablet > DiagnosticableTreet > Widgett > StatefulWidgett > Image

    2.2,支持类型
    支持 JPEG、PNG、GIF、Animated GIF、WebP、Animated WebP、BMP 和 WBMP 等格式

    2.3, 创建Image
    Image一共有五种创建方式

    func 注释
    Image() 构造方法创建
    Image.asset() 加载资源图片
    Image.file() 加载本地图片
    Image. network() 加载网络图片
    Image.memory() 加载Uint8List资源图片

    2.4, 创建Image

    • 构造方法源码:
    
      const Image({
        Key key,
        @required this.image,
        this.semanticLabel,
        this.excludeFromSemantics = false,
        this.width,
        this.height,
        this.color,
        this.colorBlendMode,
        this.fit,
        this.alignment = Alignment.center,
        this.repeat = ImageRepeat.noRepeat,
        this.centerSlice,
        this.matchTextDirection = false,
        this.gaplessPlayback = false,
        this.filterQuality = FilterQuality.low,
      }) : assert(image != null),
           assert(alignment != null),
           assert(repeat != null),
           assert(filterQuality != null),
           assert(matchTextDirection != null),
           super(key: key);
    
    • 用法
    // 资源图片
    new Image.asset('imgs/logo.jpeg'),
    //网络图片
    new Image.network(
        'https://flutter.io/images/homepage/header-illustration.png'),
    // 本地文件图片
    new Image.file(new File("/Users/gs/Downloads/1.jpeg")),
    // Uint8List图片
    new Image.memory(bytes),
    //使用ImageProvider加载图片
    new Image(image: new NetworkImage("https://flutter.io/images/homepage/screenshot-2.png"))
    

    tips:
    关于本地图片资源使用这里我需要说一下,首先在项目最顶部创建一个images文件夹放入一张图片xxx.jpeg,然后在pubspec.yaml添加几行代码,表示引用images文件夹下的xxx.jpeg图片,另外还可以设置2x和3x图片

    image

    2.5, 属性解析

    • alignment → AlignmentGeometry - 图像边界内对齐图像。

    • centerSlice → Rect - 九片图像的中心切片。

    • color → Color - 该颜色与每个图像像素混合colorBlendMode。

    • colorBlendMode → BlendMode - 用于 color 与此图像结合使用。

    • fit → BoxFit - 图像在布局中分配的空间。

    • gaplessPlayback → bool - 当图像提供者发生变化时,是继续显示旧图像(true)还是暂时不显示(false)。

    • image → ImageProvider - 要显示的图像。

    • matchTextDirection → bool - 是否在图像的方向上绘制图像 TextDirection。

    • repeat → ImageRepeat - 未充分容器时,是否重复图片。

    • height → double - 图像的高度。

    • width → double - 图像的宽度。

    2.6, 圆角图片

    Image 是不支持圆角和阴影的,目前可以通过使用 CircleAvatar 和 Container 实现。
    • CircleAvatar
    var img = 'https://b-ssl.duitang.com/uploads/item/' +
            '201602/15/20160215235057_EU3tS.thumb.700_0.jpeg';
    
    new CircleAvatar(
        backgroundImage: new NetworkImage(url),
        radius: 100.0,      // --> 半径越大,图片越大
    ),
    
    • Container
      使用 Container 实现,其原理是把图片放在 decoration 里,而不是 child 里,因为把图片放在 child 里并设置 borderRadius 时会出现一个图片穿透的问题,Container 还没有 overflow 属性。
    new Container(
        width: 200.0,
        height: 200.0,
        margin: const EdgeInsets.all(20.0),
        decoration: new BoxDecoration(
            color: Colors.white,
            image: new DecorationImage(image: new NetworkImage(this.imgsrc), fit: BoxFit.cover),
            shape: BoxShape.circle,
        ),
    ),
    

    上面实现的都是一个圆形图片,下面的实现一个真正的圆角图片。

    new Container(
        width: 200.0,
        height: 200.0,
        margin: const EdgeInsets.all(20.0),
        decoration: new BoxDecoration(
            color: Colors.white,
            image: new DecorationImage(image: new NetworkImage(this.imgsrc), fit: BoxFit.cover),
            shape: BoxShape.rectangle,              // <-- 这里需要设置为 rectangle
            borderRadius: new BorderRadius.all(
                const Radius.circular(20.0),        // <-- rectangle 时,BorderRadius 才有效
            ),
        ),
    ),
    

    3,Button

    3.1继承关系
    Object > Diagnosticable > DiagnosticableTree > Widget > StatelessWidget > MaterialButton

    在 Flutter 里有很多的 Button,包括了:MaterialButton、RaisedButton、FloatingActionButton、FlatButton、IconButton、ButtonBar、DropdownButton 等。
    一般常用的 Button 是 MaterialButton、IconButton、FloatingActionButton

    3.2构造方法

    • 3.2.1 MaterialButton
    
      const MaterialButton({
        Key key,
        @required this.onPressed,
        this.onHighlightChanged,
        this.textTheme,
        this.textColor,
        this.disabledTextColor,
        this.color,
        this.disabledColor,
        this.highlightColor,
        this.splashColor,
        this.colorBrightness,
        this.elevation,
        this.highlightElevation,
        this.disabledElevation,
        this.padding,
        this.shape,
        this.clipBehavior = Clip.none,
        this.materialTapTargetSize,
        this.animationDuration,
        this.minWidth,
        this.height,
        this.child,
      }) : super(key: key);
    

    tips:
    VoidCallback onPressedValueChanged<bool> onHighlightChanged
    VoidCallback onPressed: 点击激活按钮时调用的方法
    ValueChanged<bool> onHighlightChanged: 按下和抬起时都会调用的方法

    • 用法
    MaterialButton(
          key: ValueKey("text"),
          child: Text("MaterialButton"),
          onPressed: pressedBtn(context),
          onHighlightChanged: onHighlightChanged(context),
          textTheme: ButtonTextTheme.normal,
          textColor: Colors.blue,
          disabledTextColor: Colors.red,
          color: Color(0xFF82B1FF),
          disabledColor: Colors.grey,
          highlightColor: Colors.grey,
          // 按下的背景色
          splashColor: Colors.green,
          // 水波纹颜色
          colorBrightness: Brightness.light,
          // 主题
          elevation: 10,
          highlightElevation: 10,
          disabledElevation: 10,
          padding: EdgeInsets.all(10),
    //       MaterialButton shape 子类才起效
          shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.all(Radius.circular(20)),
              side: BorderSide(
                  color: Color(0xFFFFFFFF), style: BorderStyle.solid, width: 2)),
          clipBehavior: Clip.antiAlias,
          materialTapTargetSize: MaterialTapTargetSize.padded,
          animationDuration: Duration(seconds: 1),
          minWidth: 200,
          height: 50,
        );
    
    • 3.2.2 RaisedButton
      RaisedButton 与 MaterialButton 类似
    • 构造方法
    new RaisedButton(
        child: new Text('点我'),
        onPressed: () {},
    )
    
    • 3.2.3 FlatButton
      FlatButton 与 MaterialButton 类似,不同的是它是透明背景的。如果一个 Container 想要点击事件时,可以使用 FlatButton 包裹,而不是 MaterialButton。因为 MaterialButton 默认带背景,而 FlatButton 默认不带背景。
    • 构造方法
    new FlatButton(
        child: new Text('点我'),
        onPressed: () {},
    )
    
    • 3.2.4 IconButton
      IconButton 顾名思义就是 Icon + Button 的复合体,当某个 Icon 需要点击事件时,使用 IconButton 最好不过。
    • 构造方法
    new IconButton(
        icon: new Icon(Icons.volume_up),
        tooltip: 'Increase volume by 10%',
        onPressed: () {
            // ...
        },
    )
    

    tips: 还有已经定义好的 Icon Button:CloseButton、BackButton。他们都有导航返回的能力。

    • 3.2.5 FloatingActionButton
      FloatingActionButton 是一个浮动在页面右下角的浮动按钮。
    • 构造方法
    new Scaffold(
        // ...
        floatingActionButton: new FloatingActionButton(
            onPressed: () {},
            child: new Icon(Icons.add_a_photo),
            elevation: 3.0,
            highlightElevation: 2.0,
            backgroundColor: Colors.red,        // 红色
        ),
    )
    
    • 3.2.6 FloatingActionButton
      ButtonBar 是一个布局组件,可以让 Button 排列在一行。- 构造方法
    new ButtonBar(
        children: <Widget>[
            new CloseButton(),
            new BackButton(),
        ],
    )
    

    4,Container

    4.1继承关系
    Object > Diagnosticable > DiagnosticableTree > Widget > StatelessWidget > Container
    4.2构造方法

    Container({
        Key key,
        this.alignment,
        this.padding,
        Color color,
        Decoration decoration,
        this.foregroundDecoration,
        double width,
        double height,
        BoxConstraints constraints,
        this.margin,
        this.transform,
        this.child,
      })
    

    4.3用法

    new Container(
      constraints: new BoxConstraints.expand(
        height:Theme.of(context).textTheme.display1.fontSize * 1.1 + 200.0,
      ),
      decoration: new BoxDecoration(
        border: new Border.all(width: 2.0, color: Colors.red),
        color: Colors.grey,
        borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
        image: new DecorationImage(
          image: new NetworkImage('http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30dea167bbad014c086e06f06c.jpg'),
          centerSlice: new Rect.fromLTRB(270.0, 180.0, 1360.0, 730.0),
        ),
      ),
      padding: const EdgeInsets.all(8.0),
      alignment: Alignment.center,
      child: new Text('Hello World',
        style: Theme.of(context).textTheme.display1.copyWith(color: Colors.black)),
      transform: new Matrix4.rotationZ(0.3),
    )
    

    4.4 decoration
    decoration可以设置边框、背景色、背景图片、圆角等属性,非常实用。对于transform这个属性,一般有过其他平台开发经验的,都大致了解,这种变换,一般不是变换的实际位置,而是变换的绘制效果,也就是说它的点击以及尺寸、间距等都是按照未变换前的。

    decoration = decoration ?? (color != null ? new BoxDecoration(color: color) : null),
    

    可以看出,对于颜色的设置,最后都是转换为decoration来进行绘制的。如果同时包含decoration和color两种属性,则会报错。

    @override
      Widget build(BuildContext context) {
        Widget current = child;
    
        if (child == null && (constraints == null || !constraints.isTight)) {
          current = new LimitedBox(
            maxWidth: 0.0,
            maxHeight: 0.0,
            child: new ConstrainedBox(constraints: const BoxConstraints.expand())
          );
        }
    
        if (alignment != null)
          current = new Align(alignment: alignment, child: current);
    
        final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
        if (effectivePadding != null)
          current = new Padding(padding: effectivePadding, child: current);
    
        if (decoration != null)
          current = new DecoratedBox(decoration: decoration, child: current);
    
        if (foregroundDecoration != null) {
          current = new DecoratedBox(
            decoration: foregroundDecoration,
            position: DecorationPosition.foreground,
            child: current
          );
        }
    
        if (constraints != null)
          current = new ConstrainedBox(constraints: constraints, child: current);
    
        if (margin != null)
          current = new Padding(padding: margin, child: current);
    
        if (transform != null)
          current = new Transform(transform: transform, child: current);
    
        return current;
      }
    
    Container的build函数不长,绘制也是一个线性的判断的过程,一层一层的包裹着widget,去实现不同的样式。
    最里层的是child,如果为空或者其他约束条件,则最里层包含的为一个LimitedBox,然后依次是Align、Padding、DecoratedBox、前景DecoratedBox、ConstrainedBox、Padding(实现margin效果)、Transform。
    Container的源码本身并不复杂,复杂的是它的各种布局表现。我们谨记住一点,如果内部不设置约束,则按照父节点尽可能的扩大,如果内部有约束,则按照内部来。

    5, Row&Column

    5.1 Row

    • 5.1.1 继承关系
      Object > Diagnosticable > DiagnosticableTree > Widget > RenderObjectWidget > MultiChildRenderObjectWidget > Flex > Row
    • 5.1.2 简介
      在Flutter中非常常见的一个多子节点控件,将children排列成一行。估计是借鉴了Web中Flex布局,所以很多属性和表现,都跟其相似。但是注意一点,自身不带滚动属性,如果超出了一行,在debug下面则会显示溢出的提示。
    • 5.1.3 布局行为
      Row的布局有六个步骤,这种布局表现来自Flex(Row和Column的父类):
      首先按照不受限制的主轴(main axis)约束条件,对flex为null或者为0的child进行布局,然后按照交叉轴( cross axis)的约束,对child进行调整;
      按照不为空的flex值,将主轴方向上剩余的空间分成相应的几等分;
      对上述步骤flex值不为空的child,在交叉轴方向进行调整,在主轴方向使用最大约束条件,让其占满步骤2所分得的空间;
      Flex交叉轴的范围取自子节点的最大交叉轴;
      主轴Flex的值是由mainAxisSize属性决定的,其中MainAxisSize可以取max、min以及具体的value值;
      每一个child的位置是由mainAxisAlignment以及crossAxisAlignment所决定。
      Row的布局行为表面上看有这么多个步骤,其实也还算是简单,可以完全参照web中的Flex布局,包括主轴、交叉轴等概念。
    布局方式

    -5.1.4 构造方法

    Row({
      Key key,
      MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
      MainAxisSize mainAxisSize = MainAxisSize.max,
      CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
      TextDirection textDirection,
      VerticalDirection verticalDirection = VerticalDirection.down,
      TextBaseline textBaseline,
      List<Widget> children = const <Widget>[],
    })
    
    • 5.1.5 属性解析
      MainAxisAlignment:主轴方向上的对齐方式,会对child的位置起作用,默认是start。
      其中MainAxisAlignment枚举值:

    center:将children放置在主轴的中心;
    end:将children放置在主轴的末尾;
    spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
    spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
    spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
    start:将children放置在主轴的起点;

    其中spaceAround、spaceBetween以及spaceEvenly的区别,就是对待首尾child的方式。其距离首尾的距离分别是空白区域的1/2、0、1。
    MainAxisSize:在主轴方向占有空间的值,默认是max。
    MainAxisSize的取值有两种:

    max:根据传入的布局约束条件,最大化主轴方向的可用空间;
    min:与max相反,是最小化主轴方向的可用空间;

    CrossAxisAlignment:children在交叉轴方向的对齐方式,与MainAxisAlignment略有不同。
    CrossAxisAlignment枚举值有如下几种:

    baseline:在交叉轴方向,使得children的baseline对齐;
    center:children在交叉轴上居中展示;
    end:children在交叉轴上末尾展示;
    start:children在交叉轴上起点处展示;
    stretch:让children填满交叉轴方向;

    TextDirection:阿拉伯语系的兼容设置,一般无需处理。
    VerticalDirection:定义了children摆放顺序,默认是down。
    VerticalDirection枚举值有两种:

    down:从top到bottom进行布局;
    up:从bottom到top进行布局。

    top对应Row以及Column的话,就是左边和顶部,bottom的话,则是右边和底部。
    TextBaseline:使用的TextBaseline的方式,有两种,前面已经介绍过。

    • 5.1.6 用法
    Row(
      children: <Widget>[
        Expanded(
          child: Container(
            color: Colors.red,
            padding: EdgeInsets.all(5.0),
          ),
          flex: 1,
        ),
        Expanded(
          child: Container(
            color: Colors.yellow,
            padding: EdgeInsets.all(5.0),
          ),
          flex: 2,
        ),
        Expanded(
          child: Container(
            color: Colors.blue,
            padding: EdgeInsets.all(5.0),
          ),
          flex: 1,
        ),
      ],
    )
    

    5.2 Flex

    • 5.2.1 构造函数
    Flex({
      Key key,
      @required this.direction,
      this.mainAxisAlignment = MainAxisAlignment.start,
      this.mainAxisSize = MainAxisSize.max,
      this.crossAxisAlignment = CrossAxisAlignment.center,
      this.textDirection,
      this.verticalDirection = VerticalDirection.down,
      this.textBaseline,
      List<Widget> children = const <Widget>[],
    })
    

    tips: 可以看出,Flex的构造函数就比Row和Column的多了一个参数。Row跟Column的区别,正是这个direction参数的不同。当为Axis.horizontal的时候,则是Row,当为Axis.vertical的时候,则是Column。

    • 5.2.2 使用方法
    while (child != null) {
      final FlexParentData childParentData = child.parentData;
      totalChildren++;
      final int flex = _getFlex(child);
      if (flex > 0) {
        totalFlex += childParentData.flex;
        lastFlexChild = child;
      } else {
        BoxConstraints innerConstraints;
        if (crossAxisAlignment == CrossAxisAlignment.stretch) {
          switch (_direction) {
            case Axis.horizontal:
              innerConstraints = new BoxConstraints(minHeight: constraints.maxHeight,
                                                    maxHeight: constraints.maxHeight);
              break;
            case Axis.vertical:
              innerConstraints = new BoxConstraints(minWidth: constraints.maxWidth,
                                                    maxWidth: constraints.maxWidth);
              break;
          }
        } else {
          switch (_direction) {
            case Axis.horizontal:
              innerConstraints = new BoxConstraints(maxHeight: constraints.maxHeight);
              break;
            case Axis.vertical:
              innerConstraints = new BoxConstraints(maxWidth: constraints.maxWidth);
              break;
          }
        }
        child.layout(innerConstraints, parentUsesSize: true);
        allocatedSize += _getMainSize(child);
        crossSize = math.max(crossSize, _getCrossSize(child));
      }
      child = childParentData.nextSibling;
    }
    

    5.3 Column
    在讲解Row的时候,其实是按照Flex的一些布局行为来进行的,包括源码分析,也都是在用Flex进行分析的。Row和Column都是Flex的子类,只是direction参数不同。Column各方面同Row,因此在这里不再另行讲解。
    在讲解Flex的时候,也说过是参照了web的Flex布局,如果有相关开发经验的同学,完全可以参照着去理解,这样子更容易去理解它们的用法和原理。
    关于row和column转载链接:https://www.jianshu.com/p/0ce74751d970

    6,Text

    • 6.1 用法
    appBar: new AppBar(
        title: new Text('首页'),
        leading: new Icon(Icons.home),
        backgroundColor: Colors.blue,
        centerTitle: true,
        actions: <Widget>[
            // 非隐藏的菜单
            new IconButton(
                icon: new Icon(Icons.add_alarm),
                tooltip: 'Add Alarm',
                onPressed: () {}
            ),
            // 隐藏的菜单
            new PopupMenuButton<String>(
                itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
                    this.SelectView(Icons.message, '发起群聊', 'A'),
                    this.SelectView(Icons.group_add, '添加服务', 'B'),
                    this.SelectView(Icons.cast_connected, '扫一扫码', 'C'),
                ],
                onSelected: (String action) {
                    // 点击选项的时候
                    switch (action) {
                        case 'A': break;
                        case 'B': break;
                        case 'C': break;
                    }
                },
            ),
        ],
    ),
    
    图示
    • 6.2 属性说明
      leading → Widget - 在标题前面显示的一个控件,在首页通常显示应用的 logo;在其他界面通常显示为返回按钮。
      title → Widget - Toolbar 中主要内容,通常显示为当前界面的标题文字。
      actions → List - 一个 Widget 列表,代表 Toolbar 中所显示的菜单,对于常用的菜单,通常使用 IconButton 来表示;对于不常用的菜单通常使用 PopupMenuButton 来显示为三个点,点击后弹出二级菜单。
      bottom → PreferredSizeWidget - 一个 AppBarBottomWidget 对象,通常是 TabBar。用来在 Toolbar 标题下面显示一个 Tab 导航栏。
      elevation → double - 控件的 z 坐标顺序,默认值为 4,对于可滚动的 SliverAppBar,当 SliverAppBar 和内容同级的时候,该值为 0, 当内容滚动 SliverAppBar 变为 Toolbar 的时候,修改 elevation 的值。
      flexibleSpace → Widget - 一个显示在 AppBar 下方的控件,高度和 AppBar 高度一样,可以实现一些特殊的效果,该属性通常在 SliverAppBar 中使用。
      backgroundColor → Color - Appbar 的颜色,默认值为 ThemeData.primaryColor。改值通常和下面的三个属性一起使用。
      brightness → Brightness - Appbar 的亮度,有白色和黑色两种主题,默认值为 ThemeData.primaryColorBrightness。
      iconTheme → IconThemeData - Appbar 上图标的颜色、透明度、和尺寸信息。默认值为 ThemeData.primaryIconTheme。
      textTheme → TextTheme - Appbar 上的文字样式。
      centerTitle → bool - 标题是否居中显示,默认值根据不同的操作系统,显示方式不一样。

    toolbarOpacity → double

    关于app的转载链接: https://www.jianshu.com/p/77f8b7ee8460

    相关文章

      网友评论

          本文标题:Flutter UI基础控件和布局方式解析(1)

          本文链接:https://www.haomeiwen.com/subject/tvqrcctx.html