Flutter构建布局的思路

版权声明:天际流火叩响大地之门,岁月星辰刻画沧桑年轮! https://blog.csdn.net/ytfunnysite/article/details/81708490

本文参考链接:在Flutter中构建布局,主要解释一下这里的思路和遇到的坑。

Flutter布局机制简介

Flutter布局机制的核心就是widget。在Flutter中,几乎所有东西都是一个widget - 甚至布局模型都是widget。在Flutter应用中看到的图像、图标和文本都是widget。 甚至你看不到的东西也是widget,例如行(row)、列(column)以及用来排列、约束和对齐这些可见widget的网格(grid)。

要布局的页面

按照文档所述,我们要实现的就是下图页面的效果,将整个widget分割成数值排列的四个子widget,每个widget又可以单独设计。本身少费脑细胞的思路,我们从上向下来看,分别是:一个图片资源widget,一个标题widget,一个按钮widget,一个文本widget,这里概念很清晰,每个子布局都作为一个widget来进行处理。下边就各个击破。
布局分析

Flutter中图片资源加载方式(第一部分)

为了更有针对性,这里只介绍图片资源的加载方式,关于其他资源的加载方式,请参见资源与图像

  1. 图像添加到工程目录中,在project根目录下新建文件夹images,将图片放进去 (注意,wget不能保存此二进制文件);添加图片到项目
  2. 更新 pubspec.yaml 文件以包含 assets 标签. 这样才会使您的图片在代码中可用。更新方法如下:更新位置
  3. 要注意引用位置,不要写错了,不然就会报资源引用错误这里写图片描述

  4. 引用方法:

body: new ListView(
  children: [
    new Image.asset(
      'images/lake.jpg',
      height: 240.0,
      fit: BoxFit.cover,
    ),
    // ...
  ],
)

至此,图片的问题我们就解决了。

标题栏widget设计方式(第二部分)

标题栏

首先,构建标题部分左边栏。将Column(列)放入Expanded中会拉伸该列以使用该行中的所有剩余空闲空间。 设置crossAxisAlignment属性值为CrossAxisAlignment.start,这会将将列中的子项左对齐。
将第一行文本放入Container中,然后底部添加8像素填充。列中的第二个子项(也是文本)显示为灰色。
标题行中的最后两项是一个红色的星形图标和文字“41”。将整行放在容器中,并沿着每个边缘填充32像素

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Widget titleSection = new Container(
      padding: const EdgeInsets.all(32.0),
      child: new Row(
        children: [
          new Expanded(
            child: new Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                new Container(
                  padding: const EdgeInsets.only(bottom: 8.0),
                  child: new Text(
                    'Oeschinen Lake Campground',
                    style: new TextStyle(
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                new Text(
                  'Kandersteg, Switzerland',
                  style: new TextStyle(
                    color: Colors.grey[500],
                  ),
                ),
              ],
            ),
          ),
          new Icon(
            Icons.star,
            color: Colors.red[500],
          ),
          new Text('41'),
        ],
      ),
    );
  //...
}

代码解析:

标题栏

按钮布局widget设计方式(第三部分)

按钮

按钮部分包含3个使用相同布局的列 - 上面一个图标,下面一行文本。该行中的列平均分布行空间, 文本和图标颜色为主题中的primary color,它在应用程序的build()方法中设置为蓝色:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //...

    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),

    //...
}

.>由于三个按钮布局相同,大小一致,我们这里使用嵌套函数进行处理,如buildButtonColumn,它会创建一个颜色为primary color,包含一个Icon和Text的 Widget 列。

 Column buildButtonColumn(IconData icon, String label) {
      Color color = Theme.of(context).primaryColor;
      return new Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          new Icon(icon, color: color),
          new Container(
            margin: const EdgeInsets.only(top: 8.0),
            child: new Text(
              label,
              style: new TextStyle(
                fontSize: 12.0,
                fontWeight: FontWeight.w400,
                color: color,
              ),
            ),
          ),
        ],
      );
    }

构建函数将图标直接添加到列(Column)中。将文本放入容器以在文本上方添加填充,将其与图标分开。
通过调用函数并传递icon和文本来构建这些列。然后在行的主轴方向通过 MainAxisAlignment.spaceEvenly 平均的分配每个列占据的行空间。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //...

    Widget buttonSection = new Container(
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          buildButtonColumn(Icons.call, 'CALL'),
          buildButtonColumn(Icons.near_me, 'ROUTE'),
          buildButtonColumn(Icons.share, 'SHARE'),
        ],
      ),
    );
  //...
}

文本部分

将文本放入容器中,以便沿每条边添加32像素的填充。softwrap属性表示文本是否应在软换行符(例如句点或逗号)之间断开

  Widget textSection = new Container(
      padding: const EdgeInsets.all(32.0),
      child: new Text(
        '''
Lake Oeschinen lies at the foot of the Blüemlisalp in the Bernese Alps. Situated 1,578 meters above sea level, it is one of the larger Alpine Lakes. A gondola ride from Kandersteg, followed by a half-hour walk through pastures and pine forest, leads you to the lake, which warms to 20 degrees Celsius in the summer. Activities enjoyed here include rowing, and riding the summer toboggan run.
        ''',
        softWrap: true,
      ),
    );

整合

将上面这些组装在一起。这些widget放置到ListView中,而不是列中,因为在小设备上运行应用程序时,ListView会自动滚动。

body: new ListView(
  children: [
    new Image.asset(
      'images/lake.jpg',
      width: 600.0,
      height: 240.0,
      fit: BoxFit.cover,
    ),
    titleSection,
    buttonSection,
    textSection,
  ],
),

通过这一步步走来,我们可以看到,其实关于UI布局,我们的处理的东西其实只有一个,那就是widget,我们这里只是根据官方demo给了图片和文本的基本布局和简单的嵌套的方式,更多widget的介绍当然还是参考Widget目录

其实所有的布局全都是在一个widget中进行的,包括方法在内,dart的结构如下所示:
debugPaintSizeEnabled = true;//开启可视化调试

void main() {
  debugPaintSizeEnabled = true;  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
  //
    Widget titleSection = Container(
      padding: const EdgeInsets.all(32.0),
      child: Row(
        children: [
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [

      ),
    );

    Column buildButtonColumn(IconData icon, String label) {
    //自定义方法,用来布局那三个按钮
        }

    Widget buttonSection = Container(
    //这里是按钮widget
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          buildButtonColumn(Icons.call, 'CALL'),
          buildButtonColumn(Icons.near_me, 'ROUTE'),
          buildButtonColumn(Icons.share, 'SHARE'),
        ],
      ),
    );

    Widget textSection = Container(
    //这里是文本widget
         );

    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Top Lakes'),
        ),
        body: ListView(
          children: [
          //1、图片
            Image.asset(
              'images/lake.jpg',
              width: 600.0,
              height: 240.0,
              fit: BoxFit.cover,
            ),
           //2、标题栏 
            titleSection,
            //3、按钮
            buttonSection,
            //4、文本
            textSection,
          ],
        ),
      ),
    );
  }
}

猜你喜欢

转载自blog.csdn.net/ytfunnysite/article/details/81708490