likes
comments
collection
share

常用的Widget和弹性盒子布局~

作者站长头像
站长
· 阅读数 3

抽取Widget

打开我们上一篇的示例的代码,我们发现main.dart里面有很多Widget。我们可以抽取一下代码,也就是解耦。

  • 抽取listView: 右键选中New->Dart File,创建一个新的listview.dart文件, 输入s就可以快速联想出来有状态和无状态的两种widget的代码块

常用的Widget和弹性盒子布局~

选中stless回车

class  extends StatelessWidget {
  const ({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container();
  }
}

extends前面的类型为class ListViewDemo extends StatelessWidget 删除const ({Key? key}) : super(key: key);我们这里暂时用不到。此时这个文件中的代码就成为了

import 'package:flutter/material.dart';
import 'model/car.dart';

class ListViewDemo extends StatelessWidget {
  Widget _itemForRow(BuildContext context, int index) {
    return Container(
        color: Colors.white,
        margin: EdgeInsets.all(10),
        child: Column(
          children: [
            Image.network(datas[index].imageUrl!),
            Text(datas[index].name!)
          ],
        )
    );
  }

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

然后把main.dart的关于ListView全部剪切到这里,此时主工程的Home的body修改为当前的ListViewDemo()

import 'package:flutter/material.dart';
import 'package:hello_flutter/base_widget.dart';
import 'package:hello_flutter/listview.dart';

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

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey,
      appBar: AppBar(
        title: Text(
            'flutterDemo'
        ),
      ),
      body: ListViewDemo(),
    );
  }
}
  • 抽取model,把main.dart文件中的List<Car> datas数据源放置到当前的car.dart文件中。这样主文件中的代码就比较精简了。
  • 同理,把最开始创建的MyWidget也抽取出去,这样在main.dart如果想要切换使用的话,只需要修改对应的组件构造方法即可。

常用Widget

  1. Text组件: String拼接使用$
import 'package:flutter/material.dart';

class TextDemo extends StatelessWidget {

  final TextStyle _textStyle = TextStyle(
    fontSize: 16.0,
    backgroundColor: Colors.red,
  );
  final String _pre = '前缀';
  final String _end = '后缀';
  @override
  Widget build(BuildContext context) {
    return Text('$_pre 1. 抽取model:把main.dart文件中的List<Car> datas数据源放置到当前的car.dart文件中。这样主文件中的代码就比较精简了。3. 同理,把最开始创建的MyWidget也抽取出去,这样在main.dart如果想要切换使用的话,只需要修改对应的组件构造方法即可。$_end',
    textAlign: TextAlign.center,
    style: _textStyle);  // 这个TextStyle的构造也可以抽取出去
  }
}

运行之后:

常用的Widget和弹性盒子布局~

还可以设置最大行数,以及多余的行用省略号表示

Text(
    maxLines: 3, // 最大3行 
    overflow: TextOverflow.ellipsis, // 超过3行后缀省略
);

常用的Widget和弹性盒子布局~

  1. 富文本RichText组件:这个RichText组件有一个TextSpan可以嵌套使用,针对不同的文本设置不同的style
  @override
  Widget build(BuildContext context) {
    return RichText(text: TextSpan(
      children: <TextSpan>[
        TextSpan(
            text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',
            style: TextStyle(
                fontSize: 30,
                color: Colors.yellow
            )
        ),
        TextSpan(
            text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',
            style: TextStyle(
                fontSize: 20,
                color: Colors.red
            )
        ),
        TextSpan(
            text: '$_pre 1. 抽取model:把main.dart文件中的List<Car> ',
            style: TextStyle(
                fontSize: 40,
                color: Colors.purpleAccent
            )
        ),
      ],
    ));
  }

常用的Widget和弹性盒子布局~

3.Container组件:这个组件在布局的时候经常使用。因为它有一个childen而且会自适应布局。搭配着Row这个组件就可以无限套娃当然还有上一篇介绍的Column

class TextDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Row(
        children: [
          Container(
            color: Colors.red,
            child: Icon(Icons.add),
            //padding: EdgeInsets.all(30) , // 内边距
           // margin: EdgeInsets.all(20), // 外边距
          )
        ],
      ),
    );
  }
}

这里的padding是内边距,如果没有设置的话是这样的

常用的Widget和弹性盒子布局~

打开padding的注释可以清楚的看到是图片的内边距

常用的Widget和弹性盒子布局~

继续打开margin的注释,这样一对比就能看出,margin是图片的外边距。

常用的Widget和弹性盒子布局~

Flutter布局之Row

弹性盒子布局:横向Row、纵向Column、折叠Stack。在flutter中Alignment的中心点即为父控件的center

import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text('Layout Demo'),
      alignment: Alignment(0,0), // [-1,1]
    );
  }
}

常用的Widget和弹性盒子布局~

我们研究下搭配着row使用的对齐方式,为了方便观察,给每个Icon包装了一层Container用来设置颜色

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0,0),
      child: Row(
        children: [
          Container(child: Icon(Icons.add, size: 60,), color: Colors.yellow,),
          Container(child: Icon(Icons.sort, size: 60,), color: Colors.red,),
          Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),
          Container(child: Icon(Icons.access_alarm, size: 60,), color: Colors.greenAccent,),
        ],
      ),
    );
  }
}

常用的Widget和弹性盒子布局~

修改Alignment(-1,-1)的x坐标:

常用的Widget和弹性盒子布局~

修改Alignment(-1,-1)的y坐标:

常用的Widget和弹性盒子布局~

此时修改alignment: Alignment(-1,0)让它的横坐标修改为-1或者1都对这个没有影响。但是修改纵坐标y的话:y = -1时图像跑到了最上面,y = 1时图像跑到了最下面,所以说使用Row布局的时候,修改x的坐标不会产生影响。 ​

Flutter布局之Column

此时修改下布局的方式

import 'package:flutter/material.dart';

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(1,1),
      child: Column(
        children: [
          Container(child: Icon(Icons.add, size: 60,), color: Colors.yellow,),
          Container(child: Icon(Icons.sort, size: 60,), color: Colors.red,),
          Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),
          Container(child: Icon(Icons.access_alarm, size: 60,), color: Colors.greenAccent,),
        ],
      ),
    );
  }
}

常用的Widget和弹性盒子布局~ 常用的Widget和弹性盒子布局~

同理,如果搭配着Column来布局的话,此时修改alignment: Alignment(-1,0)让它的纵坐标修改为-1或者1都对这个没有影响。但是修改横坐标x的话:x = -1时图像跑到了最左面,x = 1时图像跑到了最右面,所以说使用Column布局的时候,修改y的坐标不会产生影响。

Flutter布局之Stack

import 'package:flutter/material.dart';

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0,0),
      child: Stack(
        children: [
          Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),
          Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),
          Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),
          Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),
        ],
      ),
    );
  }
}

常用的Widget和弹性盒子布局~

主轴和交叉轴

使用以上三种方向布局的时候我们需要知道主轴!主轴属性:居中、开始、结束 主轴方向:

  • 横向Row -> 右边
  • 纵向Column -> 下
  • 多层Stack -> 外
  1. 主轴添加属性(start/center/end):默认是从左边开始,如果想从右边开始我们可以添加主轴属性mainAxisAlignment: MainAxisAlignment.end。同理设置start就是左边,center就是中间
import 'package:flutter/material.dart';

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0,0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end, // 已结束位置
        children: [
          Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),
          Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),
          Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),
          Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),
        ],
      ),
    );
  }
}

设置主轴方向之后运行效果:

常用的Widget和弹性盒子布局~

  1. 主轴添加属性MainAxisAlignment.spaceBetween:剩下的空间平均分配到小部件之间。

常用的Widget和弹性盒子布局~

  1. 主轴添加属性MainAxisAlignment.spaceAround:剩下的空间平均分配到小部件周围。

常用的Widget和弹性盒子布局~

  1. 主轴添加属性MainAxisAlignment.spaceEvenly:剩下的空间和小部件一起平均分。

常用的Widget和弹性盒子布局~

  1. 交叉轴也就是y轴CrossAxisAlignment也有属性(start/center/end),除了基本的三个之外还有一个CrossAxisAlignment.baseline,使用Text组件的时候可以看的比较明显就是文字底部对齐,一般搭配着textBaseline 一起使用,不然会报错
import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0,0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly, // 已结束位置
        crossAxisAlignment: CrossAxisAlignment.baseline,
        textBaseline: TextBaseline.alphabetic,
        children: [
          Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,),
          Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,),
          Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,),
          Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,),
        ],
      ),
    );
  }
}

常用的Widget和弹性盒子布局~

Expanded

使用Expand的小组件会占满当前的主轴方法,在主轴方向不会剩下空隙,当横线布局不够用的时候会自动换行。

import 'package:flutter/material.dart';

class LayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      alignment: Alignment(0,0),
      child: Row(
        children: [
          Expanded(child: Container(child: Icon(Icons.add, size: 120,), color: Colors.yellow,)),
          Expanded(child: Container(child: Icon(Icons.sort, size: 90,), color: Colors.red,)),
          Expanded(child: Container(child: Icon(Icons.ac_unit, size: 60,), color: Colors.purpleAccent,)),
          Expanded(child: Container(child: Icon(Icons.access_alarm, size: 30,), color: Colors.greenAccent,)),
        ],
      ),
    );
  }
}

常用的Widget和弹性盒子布局~