Android Flutter:那些不可忽視的基礎(chǔ)布局!


前言

  • Flutter 作為Google出品的一個(gè)新興的跨平臺(tái)移動(dòng)客戶端UI開發(fā)框架,正在被越來(lái)越多的開發(fā)者和組織使用,包括阿里的咸魚、騰訊的微信等。
    示意圖
示意圖

今天,我主要講解Flutter中布局方面的基礎(chǔ)布局組件,主要包括:

  • Container
  • Row
  • Column
  • Expanded
  • Center

1. Container

1.1 定義

布局容器,屬于組合widget,內(nèi)部有繪制widget、定位widget、尺寸widget

1.2 布局原理

由于Container結(jié)合了許多其他Widget;而每個(gè)Widget都有自己的布局行為,因此Container的布局行為十分復(fù)雜,具體介紹如下:

1.3 屬性說(shuō)明

Container({
    Key key, // 控制框架在widget重建時(shí)與哪些其他widget匹配
    this.alignment, // 子Widget對(duì)齊,生效范圍:父Widget尺寸 > child Widget尺寸
    this.padding, // 內(nèi)邊距,即本W(wǎng)idget邊框和內(nèi)容區(qū)之間距離
    this.margin, // 外邊距:本W(wǎng)idget與父邊框的距離。
    Color color, // Container背景色
    Decoration decoration, // 繪制背景圖案,注:container背景色和decoration不能同時(shí)設(shè)置
    this.foregroundDecoration, // 前景。設(shè)置了foregroundDecoration可能會(huì)遮蓋child內(nèi)容,一般半透明遮蓋(蒙層)效果使用!
    double width, // container的寬度,設(shè)置為double.infinity可以強(qiáng)制在寬度上撐滿,不設(shè)置,則根據(jù)child和父節(jié)點(diǎn)兩者一起布局。
    double height, // container的高度,設(shè)置為double.infinity可以強(qiáng)制在高度上撐滿。
    BoxConstraints constraints, // 添加到child上額外的約束條件,用于設(shè)置child的寬高范圍值
    this.child, // 控件內(nèi)容widget。
  })

關(guān)于Decoratiton的使用,具體請(qǐng)看文章:

1.4 具體使用

import 'package:flutter/material.dart';// Material UI組件庫(kù)

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

// 無(wú)狀態(tài)控件顯示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的組件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //標(biāo)題
      theme: ThemeData(primarySwatch: Colors.blue), //主題色
      home: MyHomePage(), // 返回一個(gè)Widget對(duì)象,用來(lái)定義當(dāng)前應(yīng)用打開的時(shí)候,所顯示的界面
    );
  }
}

// 返回的Widget對(duì)象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //設(shè)置appbar
        appBar: new AppBar(
          title: new Text('Flutter Demo'),
        ),
        //主體
        body: new Container(
          alignment: Alignment.center,// 對(duì)齊
          padding: const EdgeInsets.all(5.0),// 內(nèi)邊距
          margin: const EdgeInsets.all(10.0),// 外邊距
          color: Colors.grey,// 背景色
          // 裝飾(無(wú)法和color一起設(shè)置)
//          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上額外的約束條件,用于設(shè)置child的寬高范圍值
          constraints: new BoxConstraints.expand(
            height: Theme
                .of(context)
                .textTheme
                .display1
                .fontSize * 1.1 + 200.0,
          ),

          // 設(shè)置子空間
          child: Text("carson ho Demo",),
        )
    );
  }
}

1.5 測(cè)試效果


2. Row

2.1 作用

水平展示多個(gè)子控件的控件,即將一系列控件排成一行顯示

注:該控件無(wú)法滾動(dòng)。若超過一行則會(huì)報(bào)錯(cuò),應(yīng)考慮使用ListView類。

2.2 概念解析:主軸 & 縱軸

對(duì)于線性布局:

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

2.3 屬性說(shuō)明

 // 屬性說(shuō)明
 Row({
    Key key,  // 全局key來(lái)唯一標(biāo)識(shí)子widget
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,  // 子控件放置方式
    MainAxisSize mainAxisSize = MainAxisSize.max,  // 子控件應(yīng)該如何沿著主軸放置
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, // 子控件對(duì)齊方式
    TextDirection textDirection, // 排列方式:從左到右,還是從右到左排序
    VerticalDirection verticalDirection = VerticalDirection.down,  // 垂直排序
    TextBaseline textBaseline, // 對(duì)齊文本的水平線
    List<Widget> children = const <Widget>[], // 子控件
  })

 // 屬性詳解
 // 1. mainAxisAlignment
 // 說(shuō)明:子控件根據(jù)主軸的對(duì)齊方式,枚舉對(duì)象(默認(rèn)值為start)
 enum MainAxisAlignment {
  start,  // 內(nèi)部的子組件將從主軸起始位置開始排列(正向排列)
   end, // 內(nèi)部的子組件將從主軸末尾位置開始排列(反向排列)
  center, // 內(nèi)部的子組件將從主軸中間位置開始排列(居中)
  spaceBetween, // 內(nèi)部的首尾子組件靠近首尾兩端,其余子組件居中排列且組件間的間距一樣
  spaceAround,  // 內(nèi)部的子組件居中排列,且每個(gè)子組件的左右邊距一樣大
  spaceEvenly,  // 內(nèi)部的子組件居中顯示,每個(gè)空間的左邊和右邊都有相同的間距
}

// 2. mainAxisSize
// 說(shuō)明:子控件如何放置,枚舉對(duì)象(默認(rèn)值為max)
enum MainAxisSize {
  min, // 控件盡可能小,相當(dāng)于wrap_content(取此值時(shí),上面的MainAxisAlignment 無(wú)效),
  max, //  控件盡可能大,相當(dāng)于match_parent
}

// 3. crossAxisAlignment
// 說(shuō)明:子控件對(duì)于縱軸的對(duì)齊方式,當(dāng)子控件高度不一樣時(shí),如何被放置在主軸(中心軸),而MainAxisAlignment 決定了子控件間的間隔
enum CrossAxisAlignment {
  start,  // 內(nèi)部的子組件將從非主軸起始位置開始排列(正向排列)
  end, // 內(nèi)部的子組件將從非主軸末尾位置開始排列(反向排列)
  center, // 內(nèi)部的子組件將從非主軸中間位置開始排列(居中)
  stretch, // 內(nèi)部的子組件將從非主軸中間位置開始排列,并且完全填充非主軸方向
  baseline, // 內(nèi)部的子組件將從baseline的方向?qū)R,這個(gè)需要設(shè)置textBaseline屬性,不然的話會(huì)報(bào)錯(cuò)
}

// 4. textBaseline
// 說(shuō)明:對(duì)齊文本的水平線
enum TextBaseline {
  alphabetic, // 用于對(duì)齊字母字符的字形底部的水平線
  ideographic,  // 用于對(duì)齊表意文字的水平線
}

// 5. textDirection
// 說(shuō)明:子控件排序方向 (一般不用設(shè)置,除非想反轉(zhuǎn)子控件排序)
// Row 使用 TextDirection
// Column 使用 VerticalDirection
enum VerticalDirection {
  up,  //  子控件從下到上排序
  down, //  子控件從上到下排序
}
enum TextDirection {
  rtl, // 子控件從右到左排序
  ltr, // 子控件從左到右排序
}

// 6. children
// 設(shè)置子控件

2.4 具體使用

import 'package:flutter/material.dart'; // Material UI組件庫(kù)

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

// 無(wú)狀態(tài)控件顯示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的組件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //標(biāo)題
      theme: ThemeData(primarySwatch: Colors.blue), //主題色
      home: MyHomePage(), // 返回一個(gè)Widget對(duì)象,用來(lái)定義當(dāng)前應(yīng)用打開的時(shí)候,所顯示的界面
    );
  }
}

// 返回的Widget對(duì)象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //設(shè)置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 作用

垂直方向展示多個(gè)子控件的控件,即將一系列控件排成一列顯示

3.2 屬性說(shuō)明

屬性類似于Row的屬性,主要包括:

 // 屬性說(shuō)明
 Column({
    Key key,  // 全局key來(lái)唯一標(biāo)識(shí)子widget
    MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,  // 子控件放置方式
    MainAxisSize mainAxisSize = MainAxisSize.max,  // 子控件應(yīng)該如何沿著主軸放置
    CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, // 子控件對(duì)齊方式
    TextDirection textDirection, // 排列方式:從左到右,還是從右到左排序
    VerticalDirection verticalDirection = VerticalDirection.down,  // 垂直排序
    TextBaseline textBaseline, // 對(duì)齊文本的水平線
    List<Widget> children = const <Widget>[], // 子控件
  })

// 屬性詳解
 // 1. mainAxisAlignment
 // 說(shuō)明:子控件根據(jù)主軸的對(duì)齊方式,枚舉對(duì)象(默認(rèn)值為start)
 enum MainAxisAlignment {
  start,  // 內(nèi)部的子組件將從主軸起始位置開始排列(正向排列)
   end, // 內(nèi)部的子組件將從主軸末尾位置開始排列(反向排列)
  center, // 內(nèi)部的子組件將從主軸中間位置開始排列(居中)
  spaceBetween, // 內(nèi)部的首尾子組件靠近首尾兩端,其余子組件居中排列且組件間的間距一樣
  spaceAround,  // 內(nèi)部的子組件居中排列,且每個(gè)子組件的左右邊距一樣大
  spaceEvenly,  // 內(nèi)部的子組件居中顯示,每個(gè)空間的左邊和右邊都有相同的間距
}

// 2. mainAxisSize
// 說(shuō)明:子控件如何放置,枚舉對(duì)象(默認(rèn)值為max)
enum MainAxisSize {
  min, // 控件盡可能小,相當(dāng)于wrap_content(取此值時(shí),上面的MainAxisAlignment 無(wú)效),
  max, //  控件盡可能大,相當(dāng)于match_parent
}

// 3. crossAxisAlignment
// 說(shuō)明:子控件對(duì)于縱軸的對(duì)齊方式,當(dāng)子控件高度不一樣時(shí),如何被放置在主軸(中心軸),而MainAxisAlignment 決定了子控件間的間隔
enum CrossAxisAlignment {
  start,  // 內(nèi)部的子組件將從非主軸起始位置開始排列(正向排列)
  end, // 內(nèi)部的子組件將從非主軸末尾位置開始排列(反向排列)
  center, // 內(nèi)部的子組件將從非主軸中間位置開始排列(居中)
  stretch, // 內(nèi)部的子組件將從非主軸中間位置開始排列,并且完全填充非主軸方向
  baseline, // 內(nèi)部的子組件將從baseline的方向?qū)R,這個(gè)需要設(shè)置textBaseline屬性,不然的話會(huì)報(bào)錯(cuò)
}

// 4. textBaseline
// 說(shuō)明:對(duì)齊文本的水平線
enum TextBaseline {
  alphabetic, // 用于對(duì)齊字母字符的字形底部的水平線
  ideographic,  // 用于對(duì)齊表意文字的水平線
}

// 5. textDirection
// 說(shuō)明:子控件排序方向 (一般不用設(shè)置,除非想反轉(zhuǎn)子控件排序)
// Row 使用 TextDirection
// Column 使用 VerticalDirection
enum VerticalDirection {
  up,  //  子控件從下到上排序
  down, //  子控件從上到下排序
}
enum TextDirection {
  rtl, // 子控件從右到左排序
  ltr, // 子控件從左到右排序
}

// 6. children
// 設(shè)置子控件

3.3 具體使用

import 'package:flutter/material.dart'; // Material UI組件庫(kù)

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

// 無(wú)狀態(tài)控件顯示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的組件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //標(biāo)題
      theme: ThemeData(primarySwatch: Colors.blue), //主題色
      home: MyHomePage(), // 返回一個(gè)Widget對(duì)象,用來(lái)定義當(dāng)前應(yīng)用打開的時(shí)候,所顯示的界面
    );
  }
}

// 返回的Widget對(duì)象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //設(shè)置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 作用

按比例伸縮 / 擴(kuò)展 Row、Column和Flex子組件所占用的空間大小

4.2 屬性說(shuō)明

const Expanded({
    Key key, // 唯一標(biāo)識(shí)符
    int flex = 1, // 彈性系數(shù),默認(rèn)值 = 1
                 // 若為 0 或 null,則 child 是沒有彈性的,即不會(huì)被擴(kuò)伸占用的空間。
                 // 若大于 0,所有的Expanded按照其flex的比例來(lái)分割主軸的全部空閑空間。
    @required Widget child, // 子控件
}) 

4.3 具體使用

import 'package:flutter/material.dart'; // Material UI組件庫(kù)

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

// 無(wú)狀態(tài)控件顯示
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
// 主界面入口返回的組件 = MaterialApp
    return MaterialApp(
      title: 'Widget_Demo', //標(biāo)題
      theme: ThemeData(primarySwatch: Colors.blue), //主題色
      home: MyHomePage(), // 返回一個(gè)Widget對(duì)象,用來(lái)定義當(dāng)前應(yīng)用打開的時(shí)候,所顯示的界面
    );
  }
}

// 返回的Widget對(duì)象
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      //設(shè)置appbar
      appBar: new AppBar(
        title: new Text('Flutter Demo'),
      ),
      //主體:配合Row使用(采用兩個(gè)容器Container來(lái)展示)
      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 測(cè)試效果


5. Center

中心定位控件,能夠?qū)⒆涌丶旁谄鋬?nèi)部中心

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

總結(jié)

本文全面介紹了Flutter常用的基礎(chǔ)布局組件,總結(jié)如下:

接下來(lái)推出的文章,我將繼續(xù)講解Flutter的相關(guān)知識(shí),包括使用語(yǔ)法、實(shí)戰(zhàn)等,感興趣的讀者可以繼續(xù)關(guān)注我的博客哦:Carson_Ho的Android博客


請(qǐng)點(diǎn)贊!因?yàn)槟銈兊馁澩?鼓勵(lì)是我寫作的最大動(dòng)力!

相關(guān)文章閱讀
Android開發(fā):最全面、最易懂的Android屏幕適配解決方案
Android開發(fā):史上最全的Android消息推送解決方案
Android開發(fā):最全面、最易懂的Webview詳解
Android開發(fā):JSON簡(jiǎn)介及最全面解析方法!
Android四大組件:Service服務(wù)史上最全面解析
Android四大組件:BroadcastReceiver史上最全面解析


歡迎關(guān)注Carson_Ho的簡(jiǎn)書!

不定期分享關(guān)于安卓開發(fā)的干貨,追求短、平、快,但卻不缺深度。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容