11 布局综合示例

上面讲了这么多布局的组件,还没有做一个完整的页面。这里我们通过一个风景区的介绍来讲解布局的综合运用。先上效果图,如图7-42所示。

11.1 布局分析

整体布局使用一个垂直布局组件ListView进行滚动布局。一共有四大块;武当山图片、风景区地址、按钮组和景区介绍文本块。整体拆分如图7-43所示,共计四个方框。 接下来细拆分这四大块。最上面图片及最下面文本块由于是单个组件即可完成,不需要细拆。所以重点介绍风景区地址及按钮组。 风景区地址从横向上看需要使用一个水平排列的组件Row,水平方向总共有三个Child,分别为左侧文本区域、右侧图标及数字区域。如图7-44所示。其中左侧文本区域要继续细拆,需要用一个垂直布局的组件Column,上下各放一个文本组件即可。右侧图标及数字是两个组件,所以横向上来看总共是三个组件。 这里有个问题,左侧及右侧之间的空隙怎么解决?如图7-45方框区域所示。这里需要用Expanded组件来包裹风景区地址组件以达到填充空隙的目的。 接下来分析按钮组的布局,在横向上用Row组件排列三个按钮。在纵向上用Column做三个相同的按钮,上面为按钮图标,下面为按钮文本。这样布局拆分的好处是,最大化地复用组件。具体拆分如图7-46所示。

11.2 准备素材

这里还是使用helloworld工程,在工程的images目录下添加一张风景图片叫wudang.jpeg。如图7-47所示。 打开工程根目录下的pubspec.yaml文件,在assets配置选项下添加-images/wudang.jpeg。添加好后,点击上面的Packages get进行资源的更新。如图7-48所示。

11.3 编写代码

1.图片处理 图片的宽度尽量大一些,填充方式使用BoxFit.cover模式,这样可以填充整个父容器,如果不铺满则会显得很不美观。具体代码如下所示:

Image.asset(
  'images/wudang.jpeg',
  width: 600.0,
  height: 240.0,
  fit: BoxFit.cover, //图片填充整个父容器
),

2.风景地址处理 风景区地址部分相对复杂,首先横向添加了一个Row组件,然后用了一个Expanded组件包裹左侧文本区域,以便填充左右组件的空隙部分。在左侧部分又添加了一个垂直布局Column,用来放置两行文本,文字之间加了一个8.0的间距。最后右侧添加图标及数字组件。此部分的代码结构如下所示:

 child: Row(
    children: <Widget>[
      Expanded(
        child: Column(
          crossAxisAlignment//次轴对齐方式
          children: <Widget>[
            Container(
              padding//与下面文本间隔一定距离
              //添加标题文本
            ),
            //添加地址文本
          ],
        ),
      ),
      //右侧图标及数字
    ],
  ),
);

3.按钮组处理 首先编写一个方法,用来构建单个按钮,需要传入图标及文本这两个参数,采用垂直布局方式。代码如下所示:

Column buildButtonColumn(IconData icon, String label) {
  return Column(
    //按钮界面渲染 图标+文本
  );
}

组装三个按钮,首先添加一个水平布局Row,水平方向对齐方式采用均匀排列方式。然后调用buildButtonColumn方法传入三组数据,构造三个按钮。代码结构如下所示:

Widget buttonsContainer = Container(
    child: Row(
    mainAxisAlignment//水平方向对齐方式
    children: <Widget>[
      buildButtonColumn//构建三个按钮
    ],
  ),
);

4.风景区介绍文本部分 风景区介绍文本部分实现起来相对容易,只需要添加一个Text组件即可,需要注意大的文本块要使用三个单引号引用起来。具体代码如下所示:

child: Text(
    '''
  大文本块
    ''',
    softWrap: true,
),

5.自定义主题 由于是风景区的介绍,通常希望颜色以绿色风格为主,所以这里需要自定义主题。具体代码如下所示:

theme: new ThemeData(
  //设置主题各个颜色值
),

6.组装所有内容 将上面的所有内容组装起来,采用ListView组件以避免文本块过长导致无法查看下面文本的问题。代码结构如下:

return new MaterialApp(
  title//标题
  theme//自定义主题,
  home: Scaffold(
    appBar: AppBar(
    ),
    body: ListView(
      children: <Widget>[
        //景区图片
        //风景区地址
        //按钮组
        //风景区介绍文本 
      ],
    ),
  ),
);
布局示例的完整代码如下所示:
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //风景区地址部分
    Widget addressContainer = Container(
      padding: const EdgeInsets.all(32.0),//此部分四周间隔一定距离
      child: Row(
        children: <Widget>[
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start, //顶部对齐
              children: <Widget>[
                Container(
                  padding: const EdgeInsets.only(bottom: 8.0),//与下面文本间隔一定距离
                  child: Text(
                    '风景区地址',
                    style: TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                Text(
                  '湖北省十堰市丹江口市',
                  style: TextStyle(
                    color: Colors.grey[500],
                  ),
                ),
              ],
            ),
          ),
          Icon(
            Icons.star,
            color: Colors.red[500],
          ),
          Text('66'),
        ],
      ),
    );

    //构建按钮组中单个按钮 参数为图标及文本
    Column buildButtonColumn(IconData icon, String label) {
      return Column(
        mainAxisSize: MainAxisSize.min,//垂直方向大小最小化
        mainAxisAlignment: MainAxisAlignment.center,//垂直方向居中对齐
        children: <Widget>[
          Icon(icon, color: Colors.lightGreen[600]),//上面图标部分
          Container(
            margin: const EdgeInsets.only(top: 8.0),
            child: Text(//下面文本部分
              label,
              style: TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: Colors.lightGreen[600],
              ),
            ),
          )
        ],
      );
    }

    //按钮组部分
    Widget buttonsContainer = Container(
      //容器横向布局
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,//水平方向均匀排列每个元素
        children: <Widget>[
          buildButtonColumn(Icons.call, '电话'),
          buildButtonColumn(Icons.near_me, '导航'),
          buildButtonColumn(Icons.share, '分享'),
        ],
      ),
    );

    //风景区介绍文本部分
    Widget textContainer = Container(
      padding: const EdgeInsets.all(32.0),
      //文本块一定是用'''来引用起来
      child: Text(
        '''
        武当山,中国道教圣地,又名太和山、谢罗山、参上山、仙室山,古有“太岳”“玄岳”“大岳”之称。位于湖北西北部十堰市丹江口市境内。东接闻名古城襄阳市,西靠车城十堰市 ,南望原始森林神农架,北临高峡平湖 丹江口水库。
        明代,武当山被皇帝封为“大岳”、“治世玄岳”,被尊为“皇室家庙”。武当山以“四大名山皆拱揖,五方仙岳共朝宗”的“五岳之冠”地位闻名于世。
        1994年12月,武当山古建筑群入选《世界遗产名录》,2006年被整体列为“全国重点文物保护单位”。2007年,武当山和长城、丽江、周庄等景区一起入选“欧洲人最喜爱的中国十大景区”。2010至2013年,武当山分别被评为国家5A级旅游区、国家森林公园、中国十大避暑名山、海峡两岸交流基地,入选最美“国家地质公园”。 
        截至2013年,武当山有古建筑53处,建筑面积2.7万平方米,建筑遗址9处,占地面积20多万平方米,全山保存各类文物5035件。 
        武当山是道教名山和武当武术的发源地,被称为“亘古无双胜境,天下第一仙山”。武当武术,是中华武术的重要流派。元末明初,道士张三丰集其大成,开创武当派。
        ''',
        softWrap: true,
      ),
    );

    return new MaterialApp(
      title: '布局综合示例',
      //自定义主题,主体颜色为绿色风格
      theme: new ThemeData(
        brightness: Brightness.light, //应用程序整体主题的亮度
        primaryColor: Colors.lightGreen[600], //App主要部分的背景色
        accentColor: Colors.orange[600], //前景色(文本、按钮等)
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text(
            '武当山风景区',
            style: TextStyle(color: Colors.white),
          ),
        ),
        body: ListView(
          children: <Widget>[
            Image.asset(
              'images/wudang.jpeg',
              width: 600.0,
              height: 240.0,
              fit: BoxFit.cover, //图片填充整个父容器
            ),
            addressContainer,
            buttonsContainer,
            textContainer,
          ],
        ),
      ),
    );
  }
}