Android Flutter:那些不可忽视的基础布局!


前言

  • Flutter 作为Google出品的一个新兴的跨平台移动客户端UI开发框架,正在被越来越多的开发者和组织使用,包括阿里的咸鱼、腾讯的微信等。
    示意图
示意图

今天,我主要讲解Flutter中布局方面的基础布局组件,主要包括:

  • Container
  • Row
  • Column
  • Expanded
  • Center

1. Container

1.1 定义

布局容器,属于组合widget,内部有绘制widget、定位widget、尺寸widget

1.2 布局原理

由于Container结合了许多其他Widget;而每个Widget都有自己的布局行为,因此Container的布局行为十分复杂,具体介绍如下:

1.3 属性说明

Container({
    Key key, // 控制框架在widget重建时与哪些其他widget匹配
    this.alignment, // 子Widget对齐,生效范围:父Widget尺寸 > child Widget尺寸
    this.padding, // 内边距,即本Widget边框和内容区之间距离
    this.margin, // 外边距:本Widget与父边框的距离。
    Color color, // Container背景色
    Decoration decoration, // 绘制背景图案,注:container背景色和decoration不能同时设置
    this.foregroundDecoration, // 前景。设置了foregroundDecoration可能会遮盖child内容,一般半透明遮盖(蒙层)效果使用!
    double width, // container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。
    double height, // container的高度,设置为double.infinity可以强制在高度上撑满。
    BoxConstraints constraints, // 添加到child上额外的约束条件,用于设置child的宽高范围值
    this.child, // 控件内容widget。
  })

关于Decoratiton的使用,具体请看文章:

1.4 具体使用

import 'package:flutter/material.dart';// Material UI组件库

void main() => runApp(MyApp());

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyHomePage(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

// 返回的Widget对象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //设置appbar
        appBar: new AppBar(
          title: new Text('Flutter Demo'),
        ),
        //主体
        body: new Container(
          alignment: Alignment.center,// 对齐
          padding: const EdgeInsets.all(5.0),// 内边距
          margin: const EdgeInsets.all(10.0),// 外边距
          color: Colors.grey,// 背景色
          // 装饰(无法和color一起设置)
//          decoration: new BoxDecoration(
//            border: new Border.all(width: 2.0, color: Colors.red),
//            borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
//            image: new DecorationImage(
//              image: new AssetImage('assetImage/photo.jpg'),
//              centerSlice: new Rect.fromLTRB(270.0, 180.0, 1360.0, 730.0),
//            ),
//          ),
          // 添加到child上额外的约束条件,用于设置child的宽高范围值
          constraints: new BoxConstraints.expand(
            height: Theme
                .of(context)
                .textTheme
                .display1
                .fontSize * 1.1 + 200.0,
          ),

          // 设置子空间
          child: Text("carson ho Demo",),
        )
    );
  }
}

1.5 测试效果


2. Row

2.1 作用

水平展示多个子控件的控件,即将一系列控件排成一行显示

注:该控件无法滚动。若超过一行则会报错,应考虑使用ListView类。

2.2 概念解析:主轴 & 纵轴

对于线性布局:

  • 若布局沿水平方向(如Row),那么主轴 = 水平方向、纵轴 = 垂直方向
  • 若布局沿垂直方向(如Colum),那么主轴 = 垂直方向、纵轴 = 水平方向

2.3 属性说明

 // 属性说明
 Row({
    Key key,  // 全局key来唯一标识子widget
    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>[], // 子控件
  })

 // 属性详解
 // 1. mainAxisAlignment
 // 说明:子控件根据主轴的对齐方式,枚举对象(默认值为start)
 enum MainAxisAlignment {
  start,  // 内部的子组件将从主轴起始位置开始排列(正向排列)
   end, // 内部的子组件将从主轴末尾位置开始排列(反向排列)
  center, // 内部的子组件将从主轴中间位置开始排列(居中)
  spaceBetween, // 内部的首尾子组件靠近首尾两端,其余子组件居中排列且组件间的间距一样
  spaceAround,  // 内部的子组件居中排列,且每个子组件的左右边距一样大
  spaceEvenly,  // 内部的子组件居中显示,每个空间的左边和右边都有相同的间距
}

// 2. mainAxisSize
// 说明:子控件如何放置,枚举对象(默认值为max)
enum MainAxisSize {
  min, // 控件尽可能小,相当于wrap_content(取此值时,上面的MainAxisAlignment 无效),
  max, //  控件尽可能大,相当于match_parent
}

// 3. crossAxisAlignment
// 说明:子控件对于纵轴的对齐方式,当子控件高度不一样时,如何被放置在主轴(中心轴),而MainAxisAlignment 决定了子控件间的间隔
enum CrossAxisAlignment {
  start,  // 内部的子组件将从非主轴起始位置开始排列(正向排列)
  end, // 内部的子组件将从非主轴末尾位置开始排列(反向排列)
  center, // 内部的子组件将从非主轴中间位置开始排列(居中)
  stretch, // 内部的子组件将从非主轴中间位置开始排列,并且完全填充非主轴方向
  baseline, // 内部的子组件将从baseline的方向对齐,这个需要设置textBaseline属性,不然的话会报错
}

// 4. textBaseline
// 说明:对齐文本的水平线
enum TextBaseline {
  alphabetic, // 用于对齐字母字符的字形底部的水平线
  ideographic,  // 用于对齐表意文字的水平线
}

// 5. textDirection
// 说明:子控件排序方向 (一般不用设置,除非想反转子控件排序)
// Row 使用 TextDirection
// Column 使用 VerticalDirection
enum VerticalDirection {
  up,  //  子控件从下到上排序
  down, //  子控件从上到下排序
}
enum TextDirection {
  rtl, // 子控件从右到左排序
  ltr, // 子控件从左到右排序
}

// 6. children
// 设置子控件

2.4 具体使用

import 'package:flutter/material.dart'; // Material UI组件库

void main() => runApp(MyApp());

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyHomePage(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

// 返回的Widget对象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //设置appbar
      appBar: new AppBar(
        title: new Text('Flutter Demo'),
      ),
      //主体
      body: new Row(
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        textDirection: TextDirection.ltr,
        children: <Widget>[
          Text(" Carson Ho "),
          Text(" Kobe Bryant "),
          Text(" LeBorn James  "),
          Text(" Michael Jordan  "),
        ],
      ),
    );
  }
}

2.5 效果图


3. Column

3.1 作用

垂直方向展示多个子控件的控件,即将一系列控件排成一列显示

3.2 属性说明

属性类似于Row的属性,主要包括:

 // 属性说明
 Column({
    Key key,  // 全局key来唯一标识子widget
    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>[], // 子控件
  })

// 属性详解
 // 1. mainAxisAlignment
 // 说明:子控件根据主轴的对齐方式,枚举对象(默认值为start)
 enum MainAxisAlignment {
  start,  // 内部的子组件将从主轴起始位置开始排列(正向排列)
   end, // 内部的子组件将从主轴末尾位置开始排列(反向排列)
  center, // 内部的子组件将从主轴中间位置开始排列(居中)
  spaceBetween, // 内部的首尾子组件靠近首尾两端,其余子组件居中排列且组件间的间距一样
  spaceAround,  // 内部的子组件居中排列,且每个子组件的左右边距一样大
  spaceEvenly,  // 内部的子组件居中显示,每个空间的左边和右边都有相同的间距
}

// 2. mainAxisSize
// 说明:子控件如何放置,枚举对象(默认值为max)
enum MainAxisSize {
  min, // 控件尽可能小,相当于wrap_content(取此值时,上面的MainAxisAlignment 无效),
  max, //  控件尽可能大,相当于match_parent
}

// 3. crossAxisAlignment
// 说明:子控件对于纵轴的对齐方式,当子控件高度不一样时,如何被放置在主轴(中心轴),而MainAxisAlignment 决定了子控件间的间隔
enum CrossAxisAlignment {
  start,  // 内部的子组件将从非主轴起始位置开始排列(正向排列)
  end, // 内部的子组件将从非主轴末尾位置开始排列(反向排列)
  center, // 内部的子组件将从非主轴中间位置开始排列(居中)
  stretch, // 内部的子组件将从非主轴中间位置开始排列,并且完全填充非主轴方向
  baseline, // 内部的子组件将从baseline的方向对齐,这个需要设置textBaseline属性,不然的话会报错
}

// 4. textBaseline
// 说明:对齐文本的水平线
enum TextBaseline {
  alphabetic, // 用于对齐字母字符的字形底部的水平线
  ideographic,  // 用于对齐表意文字的水平线
}

// 5. textDirection
// 说明:子控件排序方向 (一般不用设置,除非想反转子控件排序)
// Row 使用 TextDirection
// Column 使用 VerticalDirection
enum VerticalDirection {
  up,  //  子控件从下到上排序
  down, //  子控件从上到下排序
}
enum TextDirection {
  rtl, // 子控件从右到左排序
  ltr, // 子控件从左到右排序
}

// 6. children
// 设置子控件

3.3 具体使用

import 'package:flutter/material.dart'; // Material UI组件库

void main() => runApp(MyApp());

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyHomePage(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

// 返回的Widget对象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //设置appbar
      appBar: new AppBar(
        title: new Text('Flutter Demo'),
      ),
      //主体
      body: new Column(
        mainAxisAlignment: MainAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        verticalDirection: VerticalDirection.down,
        children: <Widget>[
          Text(" Carson Ho "),
          Text(" Kobe Bryant "),
          Text(" LeBorn James  "),
          Text(" Michael Jordan  "),
        ],
      ),
    );
  }
}

3.4 具体效果


4. Expanded

4.1 作用

按比例伸缩 / 扩展 Row、Column和Flex子组件所占用的空间大小

4.2 属性说明

const Expanded({
    Key key, // 唯一标识符
    int flex = 1, // 弹性系数,默认值 = 1
                 // 若为 0 或 null,则 child 是没有弹性的,即不会被扩伸占用的空间。
                 // 若大于 0,所有的Expanded按照其flex的比例来分割主轴的全部空闲空间。
    @required Widget child, // 子控件
}) 

4.3 具体使用

import 'package:flutter/material.dart'; // Material UI组件库

void main() => runApp(MyApp());

// 无状态控件显示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的组件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //标题
      theme: ThemeData(primarySwatch: Colors.blue), //主题色
      home: MyHomePage(), // 返回一个Widget对象,用来定义当前应用打开的时候,所显示的界面
    );
  }
}

// 返回的Widget对象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //设置appbar
      appBar: new AppBar(
        title: new Text('Flutter Demo'),
      ),
      //主体:配合Row使用(采用两个容器Container来展示)
      body: new Row(
        children: <Widget>[
          Expanded(
              flex: 2, // 占2份空间
              child: Container(
                color: Colors.red,
              )),
          Expanded(
              flex: 1, // 占1份空间
              child: Container(
                color: Colors.green,
              )),
        ],
      ),
    );
  }
}

4.4 测试效果


5. Center

中心定位控件,能够将子控件放在其内部中心

class Page extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text("正中央"), // 将text放到文本中央
    );
  }
}

总结

本文全面介绍了Flutter常用的基础布局组件,总结如下:

接下来推出的文章,我将继续讲解Flutter的相关知识,包括使用语法、实战等,感兴趣的读者可以继续关注我的博客哦:Carson_Ho的Android博客


请点赞!因为你们的赞同/鼓励是我写作的最大动力!

相关文章阅读
Android开发:最全面、最易懂的Android屏幕适配解决方案
Android开发:史上最全的Android消息推送解决方案
Android开发:最全面、最易懂的Webview详解
Android开发:JSON简介及最全面解析方法!
Android四大组件:Service服务史上最全面解析
Android四大组件:BroadcastReceiver史上最全面解析


欢迎关注Carson_Ho的简书!

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度

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