Flutter 布局常用的 widgets(Common layout widgets)

簡(jiǎn)單列舉總結(jié)一下常用的布局widget。
Flutter有豐富的layout組件庫(kù)。其中有一些是常用庫(kù)。
下面的widget分為兩類:標(biāo)準(zhǔn)組件和來(lái)自Material Components的特殊組件。
只有Material App能夠使用Material Components的組件。

標(biāo)準(zhǔn)組件 - Standard widgets

  • Container
    • 給一個(gè)組件添加 padding, margins, 邊界(borders), 背景顏色或其它裝飾(decorations)。
  • GridView
    • 將多個(gè)widget放在一個(gè)可滑動(dòng)的表格中。
  • ListView
    • 將多個(gè)widget放在一個(gè)可滑動(dòng)的列表中。
  • Stack
    • 在一個(gè)widget上面蓋上另一個(gè)widget。

Material Components

  • Card
    • 將一些相近的信息裝進(jìn)一個(gè)有圓角和陰影的盒子里。
  • ListTile
    • 一個(gè)Row中裝載最多3行文字;可選則在前面或尾部添加圖標(biāo)。

Container

Container用法比較自由。可以把整個(gè)layout放進(jìn)container里面,然后改變背景顏色或圖片。

Container 小結(jié):

  • 添加 padding, margins, 和邊界(borders)
  • 能夠更好背景顏色和圖片
  • 包含一個(gè)單獨(dú)的子widget,這個(gè)子widget可以是Row、Column或一個(gè)widget樹(shù)的根widget
container結(jié)構(gòu)

測(cè)試代碼widgetdemo/container_page.dart

import 'package:flutter/material.dart';
import 'package:demo_flutter/widgetdemo/container_page.dart';
// 引入自定義的包......

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Container demo 1',
      theme: new ThemeData(primarySwatch: Colors.brown),
      home: new ContainerDemoPage(), // 這里換上想要測(cè)試的界面
    );
  }
}

widgetdemo/container_page.dart代碼

import 'package:flutter/material.dart';

/// container示例界面
class ContainerDemoPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _ContainerDemoPageState();
}

class _ContainerDemoPageState extends State<ContainerDemoPage> {
  @override
  Widget build(BuildContext context) {
    Expanded imageExpanded(String img) {
      return new Expanded(child: new Container(
        decoration: new BoxDecoration(
            border: new Border.all(width: 10.0, color: Colors.black38),
            borderRadius: const BorderRadius.all(
                const Radius.circular(8.0))),
        margin: const EdgeInsets.all(4.0),
        child: new Image.asset(img),
      ));
    }

    var container = new Container(
      decoration: new BoxDecoration(color: Colors.black26),
      child: new Column(
        children: <Widget>[
          new Row(children: <Widget>[
            imageExpanded('images/c1.jpg'),
            imageExpanded('images/c2.jpg'),
          ],),
          new Row(children: <Widget>[
            imageExpanded('images/d1.jpg'),
            imageExpanded('images/d2.jpg'),
          ],),
          new Row(children: <Widget>[
            imageExpanded('images/p1.jpg'),
          ],)
        ],
      ),
    );

    return new Scaffold(
      appBar: new AppBar(title: new Text('Container Page demo'),),
      body: new Center(
        child: container,
      ),
    );
  }
}
container示例

GridView

用GridView來(lái)將widget放入一個(gè)2維的列表中。
GridView提供了2個(gè)預(yù)裝配好的列表,也可以自己建立自定義列表。
GridView支持滾動(dòng)。

GridView 小結(jié):

  • 將多個(gè)widget放進(jìn)一個(gè)表格中
  • 當(dāng)超出渲染范圍時(shí),自動(dòng)提供滾動(dòng)功能
  • 可自定義格子,也可用下面提供的2種
    • GridView.count 指定列的數(shù)目
    • GridView.extent 允許指定子項(xiàng)的最大像素寬度

示例1 - 用GridView.extent

GridView.extent指定子項(xiàng)占據(jù)的最大寬度

import 'package:flutter/material.dart';

/// gridView示例界面1
class GridDemo1Page extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _GridDemo1PageState();
}

class _GridDemo1PageState extends State<GridDemo1Page> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text('Grid Page 1 demo'),),
      body: new Center(
        child: buildGrid(),
      ),
    );
  }

  List<Container> _buildGridTileList(int count) {
    return new List<Container>.generate(count, (int index) =>
    new Container(child: new Image.asset('images/pic${index + 1}.jpg'),));
  }

  Widget buildGrid() {
    return new GridView.extent(
      maxCrossAxisExtent: 150.0,
      padding: const EdgeInsets.all(4.0),
      mainAxisSpacing: 4.0,
      crossAxisSpacing: 4.0,
      children: _buildGridTileList(30),);
  }
}
用GridView.extent

示例2 - 用GridView.count

crossAxisCount設(shè)為2,分成2列。

  Widget buildGrid() {
    var countGrid = GridView.count(
      crossAxisCount: 2,
      mainAxisSpacing: 4.0,
      crossAxisSpacing: 4.0,
      padding: const EdgeInsets.all(4.0),
      childAspectRatio: 1.3,
      children: _buildGridTileList(30),
    );
    return countGrid;
  }
GridView.count示例

ListView

ListView能以列的形式展示數(shù)據(jù)。當(dāng)內(nèi)容超過(guò)渲染范圍時(shí),自動(dòng)提供滾動(dòng)的功能。

ListView 小結(jié)

  • 把子視圖裝進(jìn)列表中
  • 水平或豎直都可以
  • 支持滑動(dòng)
  • 相比于Column,可選配置比較少,但更易用并且支持滑動(dòng)

和Android中的ListView差別不大

示例1

ListTile當(dāng)做子項(xiàng)來(lái)裝載數(shù)據(jù)。

import 'package:flutter/material.dart';

class ListViewPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _ListViewPageState();
}

class _ListViewPageState extends State<ListViewPage> {

  @override
  Widget build(BuildContext context) {
    List<Widget> list = <Widget>[];
    for (int i = 0; i < 30; i++) {
      list.add(new ListTile(
        title: new Text('title$i', style: _itemTextStyle,),
        subtitle: new Text('A'),
        leading: i % 3 == 0
            ? new Icon(Icons.theaters, color: Colors.blue,)
            : new Icon(Icons.restaurant, color: Colors.blue,),
      ));
    }
    return new Scaffold(
      appBar: new AppBar(title: new Text('ListView Demo'),),
      body: new Center(child: new ListView(children: list,),),
    );
  }
}

TextStyle _itemTextStyle = new TextStyle(
    fontWeight: FontWeight.w500, fontSize: 14.0);
ListView參考效果圖1

另外可以參考 https://github.com/flutter/flutter/blob/master/examples/flutter_gallery/lib/demo/colors_demo.dart

Stack

使用Stack在widget之上顯示另一些widget,通常用來(lái)顯示圖片。
顯示的widget可以完全地把底部widget蓋住。

Stack 小結(jié):

  • 用來(lái)在當(dāng)前widget上面再蓋上一層widget
  • Stack children中的第一個(gè)widget放在最下,后面的widget會(huì)一層層蓋上去
  • Stack的內(nèi)容不支持滾動(dòng)
  • 可以裁剪超出范圍的子widget

Stack示例1

顯示一個(gè)CircleAvatar

import 'package:flutter/material.dart';

class StackPage1 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _StackPage1State();
}

class _StackPage1State extends State<StackPage1> {

  @override
  Widget build(BuildContext context) {
    var stack = new Stack(
      alignment: const Alignment(0.6, 0.6),
      children: <Widget>[
        new CircleAvatar(
          backgroundImage: new AssetImage('images/android_1.jpg'),
          radius: 100.0,),
        new Container(decoration: new BoxDecoration(color: Colors.black45),
          child: new Text(
            'Android Avatar', style: new TextStyle(color: Colors.white70),),),
        new Container(decoration: new BoxDecoration(color: Colors.transparent),
          padding: const EdgeInsets.fromLTRB(0.0, 0.0, 100.0, 0.0),
          child: new CircleAvatar(
            backgroundImage: new AssetImage('images/p_box1.png'),
            backgroundColor: Colors.transparent,
            radius: 10.0,),),
      ],
    );
    return new Scaffold(
      appBar: new AppBar(title: new Text('Stack Demo 1'),),
      body: new Center(child: stack,),
    );
  }
}
Stack示例1

Card

Card來(lái)自Material組件庫(kù),可包含一些數(shù)據(jù),通常用ListTile來(lái)組裝。Card只有一個(gè)子widget,可以是column、row、list、grid或其它組合widget。
默認(rèn)情況下,Card把自己的尺寸縮小為0像素??梢杂?a target="_blank" rel="nofollow">SizedBox來(lái)指定card的尺寸。

Flutter中的Card有圓角和陰影效果。修改elevation可改變陰影效果。

elevation取值范圍,參考 Elevation and Shadows

若設(shè)置的范圍外的值,陰影效果會(huì)消失。

Card 小結(jié):

  • 實(shí)現(xiàn)了Material Design card
  • 用于展示相關(guān)的數(shù)據(jù)
  • 有一個(gè)子項(xiàng)(child),可以是column、row、list、grid或其它組合widget
  • 有圓角和陰影效果
  • 不支持滾動(dòng)

Card示例1

將前面的ListView示例修改一下

import 'package:flutter/material.dart';

class ListViewPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _ListViewPageState();
}

class _ListViewPageState extends State<ListViewPage> {

  @override
  Widget build(BuildContext context) {
    List<Widget> list = <Widget>[];
    for (int i = 0; i < 30; i++) {
      list.add(new Card(child: new Column(
        children: <Widget>[
          new Image.asset(
            'images/pic${i + 1}.jpg',),
          new ListTile(
            title: new Text('title$i', style: _itemTextStyle,),
            subtitle: new Text('A'),
            leading: i % 3 == 0
                ? new Icon(Icons.theaters, color: Colors.blue,)
                : new Icon(Icons.restaurant, color: Colors.blue,),
          ),
        ],
      ),));
    }
    return new Scaffold(
      appBar: new AppBar(title: new Text('ListView Demo'),),
      body: new Center(child: new ListView(children: list,),),
    );
  }
}

TextStyle _itemTextStyle = new TextStyle(
    fontWeight: FontWeight.w500, fontSize: 14.0);
Card示例1

ListTile

來(lái)自Material組件庫(kù)的橫向組件??勺远x3行文字及其可選的頭尾圖標(biāo)。
此控件常與Card或ListView一起用。

ListTile 小結(jié):

  • 可定制3行帶圖標(biāo)的文字
  • 相比于Row,配置更少,但更易用

加一個(gè)主界面

放置一些按鈕,點(diǎn)擊跳轉(zhuǎn)到相應(yīng)的界面。
使用Navigator.of(context).pushNamed(routeName)來(lái)跳轉(zhuǎn)。

import 'package:flutter/material.dart';
import 'package:demo_flutter/widgetdemo/container_page.dart';
import 'package:demo_flutter/widgetdemo/grid_page.dart';
import 'package:demo_flutter/widgetdemo/listview_demo.dart';
import 'package:demo_flutter/widgetdemo/stack_page1.dart';
import 'package:demo_flutter/widgetdemo/button_page.dart';

const String CONTAINER_DEMO_PAGE = '/a';

void main() {
  runApp(new MaterialApp(
    home: new HomePage(),
    routes: {
      CONTAINER_DEMO_PAGE: (BuildContext context) => new ContainerDemoPage(),
      '/b': (BuildContext context) => new GridDemo1Page(),
      '/c': (BuildContext context) => new ListViewPage(),
      '/d': (BuildContext context) => new StackPage1(),
      '/e': (BuildContext context) => new ButtonPage(),
    },
  ));
}

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _HomePageState();
}

class _HomePageState extends State<HomePage> {

  @override
  Widget build(BuildContext context) {
    getGestureDetector(String routeName, String content) {
      return new GestureDetector (
        onTap: () {
          Navigator.of(context).pushNamed(routeName);
        },
        child: new Container (
            padding: EdgeInsets.all(20.0),
            child: new Center(child: new Text (content),)),
      );
    }
    return new Scaffold(
      appBar: new AppBar(title: new Text('Home'),),
      body: new Column(children: <Widget>[
        getGestureDetector(CONTAINER_DEMO_PAGE, 'Container Demo'),
        getGestureDetector('/b', 'Grid Demo 1'),
        getGestureDetector('/c', 'ListView Demo'),
        getGestureDetector('/d', 'Stack Demo'),
        getGestureDetector('/e', 'Button Page'),
      ],),
    );
  }

}
最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,857評(píng)論 2 45
  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    wgl0419閱讀 6,575評(píng)論 1 9
  • App Core Account Realm Google Android
    Jacinth閱讀 889評(píng)論 0 0
  • 唯有星空浩瀚的夜晚 最適合靜靜的思念 那種淡淡的感覺(jué) 就著茶杯里散發(fā)出來(lái)的香氣 吸入了藏污納垢的肺里 夜晚沒(méi)有露珠...
    年輪止閱讀 333評(píng)論 2 5
  • 秋月新牙如玉嬰,夕陽(yáng)燒云錦天穹。 莫聽(tīng)夏蟬鼓瑟聲,鴻雁清鳴唱漁晚。 一杯濁酒一孤笛,哀轉(zhuǎn)三調(diào)哭潛蛟。萬(wàn)物如水月既逝...
    木易當(dāng)興閱讀 377評(píng)論 2 2

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