天天看點

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

Padding元件

在HTML中,常見的布局标簽都有padding屬性,但是在Flutter中,很多的widget是沒有padding屬性的。這時我們就可以使用padding元件來處理容器與子元素之間的間距。

Padding元件有兩個屬性:

  • padding,EdgeInsets 設定填充的值
  • child,子元件

先來看下面一段代碼:

class HomeContent extends StatelessWidget {

  List<Widget> _getChildren(){
    var children = listData.map((value){
      return Image.network(value["imgUrl", fit: BoxFit.cover,);
    });
    return children.toList();
  }

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      crossAxisCount: 3,
      children: this._getChildren(),
    );
  }
  
}           

複制

這段代碼的運作效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

可以看到,GridView的子元素是Image。現在我們想給圖檔元件加一些内邊距,但是Image元件是沒有padding屬性的,這個時候該怎麼辦呢?我們可以使用Padding元件。代碼如下:

class HomeContent extends StatelessWidget {
  List<Widget> _getChildren() {
    var children = listData.map((value) {
      return Padding(//Padding元件
        child: Image.network(
          value["imgUrl"],
          fit: BoxFit.cover,
        ),
        padding: EdgeInsets.fromLTRB(10, 10, 0, 0),
      );
    });
    return children.toList();
  }

  @override
  Widget build(BuildContext context) {
    return Padding(//Padding元件
      padding: EdgeInsets.fromLTRB(0, 0, 10, 10),
      child: GridView.count(
        crossAxisCount: 3,
        children: this._getChildren(),
      ),
    );
  }
}           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

對于一些沒有padding屬性的元件,比如Image,我們可以在其外部包一個Padding元件,來實作内邊距padding的效果。

如何自定義一個元件

自定義一個元件無非就是三步:

  1. 實作build方法來定義元件的樣式和布局;
  2. 聲明需要傳入的相關屬性;
  3. 實作構造方法

下面是自定義一個名為IconContainer的元件:

class IconContainer extends StatelessWidget {
  
  //聲明屬性
  Color bgColor = Colors.yellow;
  double iconSize = 16;
  IconData iconname = Icons.home;

  //構造方法(使用大括号包起來的都是可選命名參數)
  IconContainer({this.bgColor, this.iconname, this.iconSize});

  //build方法
  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      width: 100,
      color: this.bgColor,
      child: Center(
        child: Icon(this.iconname, size: this.iconSize, color: Colors.white,),
      ),
    );
  }

}           

複制

Row 水準布局元件

Row元件有如下三個屬性:

  • mainAxisAlignment,主軸的排列方式
  • crossAxisAlignment,交叉軸的排列方式
  • children,元件子元素
class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 500,
      color: Colors.pink,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, //調整主軸的排列方式(常用)
        crossAxisAlignment: CrossAxisAlignment.center, //調整交叉軸的排列方式(用的比較少)
        children: <Widget>[
          IconContainer(Colors.green, Icons.date_range, 30),
          IconContainer(Colors.red, Icons.edit_location, 35),
          IconContainer(Colors.yellow, Icons.fast_rewind, 40),
        ],
      ),
    );
  }
}           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

Column 垂直布局元件

Colume元件與Row元件的使用方式一模一樣:

class HomeContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 500,
      color: Colors.pink,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, //調整主軸的排列方式(常用)
        crossAxisAlignment: CrossAxisAlignment.end, //調整交叉軸的排列方式(用的比較少)
        children: <Widget>[
          IconContainer(Colors.green, Icons.date_range, 30),
          IconContainer(Colors.red, Icons.edit_location, 35),
          IconContainer(Colors.yellow, Icons.fast_rewind, 40),
        ],
      ),
    );
  }
}           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

Expanded 元件

Expanden元件可以用在Row和Column布局中,有如下兩個屬性:

  • flex,元素占整個父 Row/Column 的比例
  • child,子元素
Row(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: IconContainer(Colors.pink, Icons.fast_rewind, 30),
        ),
        Expanded(
          flex: 2,
          child: IconContainer(Colors.orange, Icons.hdr_strong, 40),
        ),
        Expanded(
          flex: 1,
          child: IconContainer(Colors.blue, Icons.screen_lock_rotation, 50),
        ),
      ],
    );           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

此外,我們也可以使用Expanded元件實作寬度或者高度的自适應。如下所示:

Row(
      children: <Widget>[
        Expanded(
          flex: 1,
          child: IconContainer(Colors.pink, Icons.fast_rewind, 30),
        ),
        IconContainer(Colors.orange, Icons.hdr_strong, 40),
      ],
    );           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

其他

可以使用SizedBox元件來定義元件的間隔。

Stack

Stack是堆的意思,有如下兩個參數:

  • alignment,配置所有子元素的顯示位置
  • children,子元件

Stack元件可以單獨使用。當其子元素隻有一個,或者隻有少數個元素并且這些子元素的布局是統一的,此時就可以 單獨使用Stack進行布局。如下所示:

Container(
      height: 400,
      width: 300,
      color: Colors.yellow,
      child: Stack(
        alignment: Alignment(0, 0),//這裡的效果是,使children裡面d額所有元素都居中展示
        children: <Widget>[
          Image.network(
              "http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg"),
          Text(
            "666888",
            style: TextStyle(color: Colors.white, fontSize: 20),
          ),
        ],
      ),
    );           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

但一個容器中有多個元素,而這些元素各有各自不同的布局的時候,可以使用Stack結合Align或者Stack結合Positioned來實作。

Stack & Align

Container(
      height: 400,
      width: 300,
      color: Colors.yellow,
      child: Stack(
        alignment: Alignment(0, 0),
        children: <Widget>[
          Align(
            alignment: Alignment.topLeft,
            child: IconContainer(Colors.red, Icons.aspect_ratio, 30),
          ),
          Align(
            alignment: Alignment.topRight,
            child: IconContainer(Colors.blue, Icons.sd_card, 40),
          ),
          Align(
            child: IconContainer(Colors.green, Icons.data_usage, 50),
          ),
        ],
      ),
    );           

複制

通過Stack結合ALign可以控制Stack元件内部的每個元素的具體位置。Stack的alignment可以控制所有子元素的布局,Align的alignment屬性可以控制某個具體子元素的布局,如果兩者同時存在,則以Align的alignment屬性為準。上述代碼的效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

Stack & Positioned

Container(
      height: 200,
      width: 300,
      color: Colors.yellow,
      child: Stack(
        children: <Widget>[
          Align(
            alignment: Alignment.center,
            child: Container(
              child: Image.network(
                "http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg",
                fit: BoxFit.cover,
              ),
            ),
          ),
          Positioned(
            left: 10,
            bottom: 10,
            right: 10,
            child: Text(
              "http://pic27.nipic.com/20130325/11918471_071536564166_2.jpg",
              style: TextStyle(color: Colors.white, fontSize: 18),
            ),
          )
        ],
      ),
    );           

複制

效果圖如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

AspectRatio

AspectRatio的作用是根據設定調整子元素child的寬高比。

AspectRatio首先會在布局限制條件允許的範圍内盡可能地擴充,Widget的寬度(高度)由高度(寬度)和比率決定,類似于BoxFit中的contain,按照固定比率去盡量占滿區域。

AspectRatio有如下兩個屬性:

  • aspectRatio,寬高比
  • child,子元件

如下代碼:

Container(
      width: 300,
      child: AspectRatio(
        aspectRatio: 2,
        child: Container(
          color: Colors.red,
        ),
      ),
    );           

複制

展示效果為:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

Card

Card是卡片元件塊,内容可以由大多數類型的Widget構成。Card具有圓角和陰影,這讓它看起來具有立體感。

Card有如下三個屬性:

  • margin,外邊距
  • child,子元件
  • shape,Card的陰影效果,預設的陰影效果為圓角的長方形邊

如下面代碼:

ListView(
      children: <Widget>[
        Card(
          margin: EdgeInsets.all(10),
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text(
                  "張三",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                subtitle: Text("進階軟體工程師"),
              ),
              ListTile(
                title: Text("電話:13241668866"),
              ),
              ListTile(
                title: Text("位址:北京市海澱區"),
              )
            ],
          ),
        ),

        Card(
          margin: EdgeInsets.all(10),
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text(
                  "李四",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                subtitle: Text("進階軟體工程師"),
              ),
              ListTile(
                title: Text("電話:13241668866"),
              ),
              ListTile(
                title: Text("位址:北京市海澱區"),
              )
            ],
          ),
        ),

        Card(
          margin: EdgeInsets.all(10),
          child: Column(
            children: <Widget>[
              ListTile(
                title: Text(
                  "王武",
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
                subtitle: Text("進階軟體工程師"),
              ),
              ListTile(
                title: Text("電話:13241668866"),
              ),
              ListTile(
                title: Text("位址:北京市海澱區"),
              )
            ],
          ),
        )
      ],
    );           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

下面再來看一個例子,代碼如下:

class HomeContent extends StatelessWidget {
  Widget _getItem(context, index) {
    Map itemdata = listData[index];
    return Card(
      margin: EdgeInsets.all(10),
      child: Column(
        children: <Widget>[
          AspectRatio(
            aspectRatio: 2,
            child: Image.network(
              itemdata["imgUrl"],
              fit: BoxFit.cover,
            ),
          ),
          ListTile(
            leading: CircleAvatar(
              backgroundImage: NetworkImage(itemdata["imgUrl"]),
            ),
            title: Text(itemdata["title"]),
            subtitle: Text(itemdata["detail"]),
          )
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: listData.length,
      itemBuilder: this._getItem,
    );
  }
}           

複制

效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

關于上面這個例子,有如下幾點說明。

圖檔的圓角,我們可以使用ClipOval元件,也可以使用該例中的CircleAvator元件。

可以使用AspectRatio元件來實作元件固定的寬高比。

Wrap

Wrap可以實作流布局,單行的Wrap跟Row表現幾乎一緻,單列的Wrap跟Column表現幾乎一緻。但是Row與Column都是單行單列的,Wrap則突破了這個限制,mainAxis上空間不足時,則向crossAxis上去擴充展示。

Wrap有如下常用屬性:

  • direction,主軸的方向,預設是水準
  • alignment,主軸的對齊方式
  • spacing,主軸方向上的間距
  • runSpacing,交叉軸方向上的間距
class HomeContent extends StatelessWidget {
  List<Widget> _getChildren() {
    var children = listData.map((value) {
      return MyButton(value["title"]);
    });
    return children.toList();
  }

  @override
  Widget build(BuildContext context) {
    return Wrap(
      children: this._getChildren(),
      alignment: WrapAlignment.start, //主軸方向上的對齊方式
      spacing: 30, //主軸方向上的間距
      runSpacing: 10, //交叉軸方向上的間距
    );
  }
}

class MyButton extends StatelessWidget {
  final String titleStr;
  MyButton(this.titleStr);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      child: Text(this.titleStr),
      onPressed: () {
        print(Text(this.titleStr));
      },
    );
  }
}           

複制

顯示效果如下:

Padding、Row、Column、Expanded、Stack、AspectRatio、Card、Wrap等布局元件初體驗

以上。